unit fLayers;

interface
{$INCLUDE SGDXF.INC}
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, ExtDlgs, Buttons, StdCtrls,
  DXFImage,
  {$IFDEF SGDEL_4}
  ImgList,
  {$ENDIF}
  CheckLst, ComCtrls;

type
  TfmLayers = class(TForm)
    btnOK: TButton;
    btnCancel: TButton;
    ImageList: TImageList;
    lvLayers: TListView;
    edSearch: TEdit;
    procedure edtNameKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure clbLayersKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
    procedure lvLayersDrawItem(Sender: TCustomListView; Item: TListItem;
      Rect: TRect; State: TOwnerDrawState);
    procedure lvLayersResize(Sender: TObject);
    procedure lvLayersDblClick(Sender: TObject);
    procedure lvLayersDeletion(Sender: TObject; Item: TListItem);
    procedure FormDestroy(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    FControl: TControl;
    FImage: TsgDXFImage;
    {$IFNDEF SGDEL_4}
    FLVProc: TWndMethod;
    procedure LVWndMethod(var Message: TMessage);
    {$ENDIF}
    function GetColumnNumber(APoint: TPoint): Integer;
  end;

var
  LayersRect: TRect;

function LayersDialogExecute(AImage: TsgDXFImage; Control: TControl): Boolean;

implementation

uses DXFConv;

type
  PLayers = ^TLayers;
  TLayers = record
    Color: TColor;
    Layer: TsgDXFLayer;
    Frozen: Boolean;
    IsPlotting: Boolean;
    Visible: Boolean;
  end;

var
  SSearch: string = 'Search for layer';

{$R *.dfm}

function LayersDialogExecute(AImage: TsgDXFImage; Control: TControl): Boolean;
var
  I: Integer;
  vItem: TListItem;
  P: PLayers;
  vLayer: TsgDXFLayer;
begin
  Result := False;
  if AImage = nil then Exit;
  with TfmLayers.Create(nil) do
    try
      FControl := Control;
      BoundsRect := LayersRect;
      FImage := AImage;
      for I := 0 to AImage.Converter.Counts[csLayers] - 1 do
      begin
        vItem := lvLayers.Items.Add;
        vItem.Caption := AImage.Converter.Layers[I].Name;
        New(P);
        P^.Color := AImage.Converter.Layers[I].Color;
        P^.Layer := AImage.Converter.Layers[I];
        P^.Frozen := AImage.Converter.Layers[I].Frozen;
        P^.IsPlotting := AImage.Converter.Layers[I].IsPlotting;
        P^.Visible := AImage.Converter.Layers[I].Visible;
        vItem.Data := P;
      end;
      ShowModal;
      Result := ModalResult = mrOk;
      if ModalResult = mrCancel then
      begin
        for I := 0 to lvLayers.Items.Count - 1 do
        begin
          P := PLayers(lvLayers.Items[I].Data);
          vLayer := P^.Layer;
          vLayer.Color := P^.Color;
          vLayer.Frozen := P^.Frozen;
          vLayer.IsPlotting := P^.IsPlotting;
          vLayer.Visible := P^.Visible;
        end;
        FControl.Invalidate;
      end;
      LayersRect := BoundsRect;
    finally
      Free;
    end;
end;

procedure TfmLayers.edtNameKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_RETURN then
  begin
    Close;
    ModalResult := mrOk;
  end;
end;

procedure TfmLayers.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
    VK_ESCAPE: Close;
  end;
end;

procedure TfmLayers.clbLayersKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_RETURN then
    ModalResult := mrOk;
end;

procedure TfmLayers.FormCreate(Sender: TObject);
{$IFDEF SGDEL_4}
var
  I: Integer;
  An: TAnchors;
{$ENDIF}
begin
  {$IFDEF SGDEL_4}
  lvLayers.OnDrawItem := lvLayersDrawItem;
  lvLayers.OwnerDraw := True;
  lvLayers.Anchors := [akLeft, akTop, akBottom, akRight];
  btnCancel.Anchors := [akBottom, akRight];
  btnOK.Anchors := [akBottom, akRight];
  if not (PixelsPerInch = 96) then
  begin
    for I := 0 to ControlCount - 1 do
      if Controls[I] is TWinControl then
      begin
        An := TWinControl(Controls[I]).Anchors;
        TWinControl(Controls[I]).Anchors := [akLeft, akTop];
        TWinControl(Controls[I]).ScaleBy(96, PixelsPerInch);
        Controls[I].Left := Round(Controls[I].Left * 96 / PixelsPerInch);
        Controls[I].Top := Round(Controls[I].Top * 96 / PixelsPerInch);
        if PixelsPerInch = 120 then
        begin
          Controls[I].Top := Controls[I].Top - 8;
        end;
        TWinControl(Controls[I]).Anchors := An;
      end;
  end;
  {$ELSE}
  FLVProc := lvLayers.WindowProc;
  lvLayers.WindowProc := LVWndMethod;
  {$ENDIF}
end;

procedure TfmLayers.lvLayersDrawItem(Sender: TCustomListView;
  Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var
  vBitmap: TBitmap;
  vLayer: TsgDXFLayer;
  vRect: TRect;
  vCanv: TCanvas;
  {$IFNDEF SGDEL_4}
  DC: HDC;
  {$ENDIF}

  function GetItemRect(ARect: TRect; AColumn: Integer): TRect;
  const
    LVM_FIRST               = $1000;      { ListView messages }
    LVM_GETCOLUMNWIDTH      = LVM_FIRST + 29;
  var
    I: Integer;
    function GetColWidth(ACol: Integer): Integer;
    begin
      Result := SendMessage(lvLayers.Handle, LVM_GETCOLUMNWIDTH, ACol, 0);
    end;
  begin
    Result.Left := 0;
    for I := 0 to AColumn - 1 do
      Inc(Result.Left, GetColWidth(I));
    Result.Top := ARect.Top;
    Result.Right := Result.Left + GetColWidth(AColumn);
    Result.Bottom := ARect.Bottom;
  end;

  procedure DrawGraphic(ItemIndex, ImageIndex: Integer);
  begin
    vRect := GetItemRect(Rect, ItemIndex);
    vCanv.FillRect(vRect);
    vRect.Left := (vRect.Right + vRect.Left) div 2;
    vRect.Left := vRect.Left - (vRect.Bottom - vRect.Top) div 2;
    vRect.Right := vRect.Left + (vRect.Bottom - vRect.Top) + 1;
    vBitmap.Canvas.Brush.Color := vCanv.Brush.Color;
    vBitmap.Canvas.FillRect(Classes.Rect(0, 0, vBitmap.Width, vBitmap.Height));
    ImageList.GetBitmap(ImageIndex, vBitmap);
    vCanv.StretchDraw(vRect, vBitmap);
  end;

begin
  vBitmap := TBitmap.Create;
  try
    {$IFDEF SGDEL_4}
    vCanv := lvLayers.Canvas;
    {$ELSE}
    vCanv := TCanvas.Create;
    DC := GetDC(lvLayers.Handle);
    vCanv.Handle := DC;
    {$ENDIF}
    try
     if odSelected in State then
     begin
       vCanv.Brush.Color := clHighlight;
       vCanv.Pen.Color := clHighlightText;
     end
     else
     begin
       vCanv.Brush.Color := clWindow;
       vCanv.Pen.Color := clWindowText;
     end;
     vCanv.FillRect(Rect);
     vRect := GetItemRect(Rect, 0);
     vLayer := PLayers(Item.Data)^.Layer;
     vCanv.TextOut(vRect.Left + 2, vRect.Top, Item.Caption);

     DrawGraphic(1, Ord(not vLayer.Visible)*2);
     DrawGraphic(2, Ord(not vLayer.Frozen)+5);
     DrawGraphic(4, Ord(not vLayer.IsPlotting)+3);

     vRect := GetItemRect(Rect, 3);
     vCanv.Brush.Color := vLayer.Color;
     vRect.Left := (vRect.Right + vRect.Left) div 2;
     vRect.Left := vRect.Left - (vRect.Bottom - vRect.Top) div 2;
     vRect.Right := vRect.Left + (vRect.Bottom - vRect.Top);
     InflateRect(vRect, -1, -1);
     vCanv.Rectangle(vRect.Left, vRect.Top, vRect.Right, vRect.Bottom);
    finally
      {$IFNDEF SGDEL_4}
      vCanv.Handle := 0;
      vCanv.Free;
      ReleaseDC(lvLayers.Handle, DC);
      {$ENDIF}
    end;
  finally
    vBitmap.Free;
  end;
end;

procedure TfmLayers.lvLayersResize(Sender: TObject);
begin
  Invalidate;
end;

procedure TfmLayers.lvLayersDblClick(Sender: TObject);
var
  vPt: TPoint;
  vItem: TListItem;
  vLayer: TsgDXFLayer;
  vColorDialog: TColorDialog;
  vCurrLayout: TsgDXFLayout;
  vIndex: Integer;
begin
  if GetCursorPos(vPt) then
  begin
    vPt := lvLayers.ScreenToClient(vPt);
    vIndex := GetColumnNumber(vPt);
    vItem := lvLayers.GetItemAt(vPt.X, vPt.Y);

    if Assigned(vItem) and (vIndex <> -1) then
    begin
      vLayer := PLayers(vItem.Data)^.Layer;
      case vIndex of
        1: vLayer.Visible := not vLayer.Visible;
        2: vLayer.Frozen := not vLayer.Frozen;
        3:
          begin
            vColorDialog := TColorDialog.Create(Self);
            try
              vColorDialog.Options := [];
              vColorDialog.Color := vLayer.Color;
              if vColorDialog.Execute then
                vLayer.Color := vColorDialog.Color;
            finally
              vColorDialog.Free;
            end;
          end;
        4: vLayer.IsPlotting := not vLayer.IsPlotting;
      end;
      if vIndex <> 0 then
      begin
        vCurrLayout := FImage.CurrentLayout;
        FImage.GetExtents;
        FImage.CurrentLayout := vCurrLayout;
        FControl.Invalidate;
        lvLayers.Refresh;
      end;
    end;
  end;
end;

function TfmLayers.GetColumnNumber(APoint: TPoint): Integer;
var
  I, X: Integer;
  vRect, vBounds: TRect;
begin
  Result := -1;
  if lvLayers.Selected = nil then Exit;
  vBounds := lvLayers.Selected.DisplayRect(drBounds);
  X := vBounds.Left;
  vRect := Rect(X, vBounds.Top, X + lvLayers.Columns[0].Width, vBounds.Top +
    Abs(vBounds.Right - vBounds.Top));
  for I := 0 to lvLayers.Columns.Count - 1 do
  begin
    vRect.Left := X;
    vRect.Right := X + lvLayers.Columns[I].Width;
    Inc(X, lvLayers.Columns[I].Width);
    if PtInRect(vRect, APoint) then
    begin
      Result := I;
      Exit;
    end;
  end;
end;

procedure TfmLayers.lvLayersDeletion(Sender: TObject; Item: TListItem);
begin
  {$IFDEF SGDEL_4}
  if not (fsModal in FormState) then
  {$ENDIF}
    Dispose(Item.Data);
end;

procedure TfmLayers.FormResize(Sender: TObject);
begin
  {$IFNDEF SGDEL_4}
  lvLayers.Width := Width - 3*lvLayers.Left;
  btnCancel.Left := Width - btnCancel.Width - 3*lvLayers.Left;
  btnCancel.Top := Height - btnCancel.Height - 5*lvLayers.Left;
  btnOK.Left := Width - btnOK.Width - btnCancel.Width - 4*lvLayers.Left;
  btnOK.Top := Height - btnOK.Height - 5*lvLayers.Left;
  lvLayers.Height := btnOK.Top - lvLayers.Top - 2*lvLayers.Left;
  {$ENDIF}
end;
{$IFNDEF SGDEL_4}
procedure TfmLayers.LVWndMethod(var Message: TMessage);
var
  I: Integer;
  R: TRect;
  vState: TOwnerDrawState;
begin
  FLVProc(Message);
  if Message.Msg = WM_PAINT then
  begin
    for I := 0 to lvLayers.Items.Count - 1 do
    begin
      vState := [];
      R := lvLayers.Items.Item[I].DisplayRect(drBounds);
      if lvLayers.Items.Item[I] = lvLayers.Selected then
         vState := [odSelected];
      lvLayersDrawItem(lvLayers, lvLayers.Items.Item[I], R, vState);
    end;
  end;
end;
{$ENDIF}

procedure TfmLayers.FormDestroy(Sender: TObject);
begin
  {$IFNDEF SGDEL_4}
  lvLayers.WindowProc := FLVProc;
  {$ENDIF}
end;

initialization
  LayersRect := Rect(0, 0, 461, 359);

end.
