unit Unit1;
{$INCLUDE CADSoftTools.INC}
//If you see error "File not found: 'CADSoftTools.INC'",
//then please contact info@cadsofttools.com to get a compilable version.
//If you have a compilable version, you need to copy the contents of
// Lib7/LibXE5win32/LibXE5win64... to Lib directory according to your
// Delphi version and target CPU platform.

{$INCLUDE SGDXF.INC}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, JPEG,
  ExtCtrls, StdCtrls, CADImage, DXFConv, DXF, ComCtrls, Menus, Printers, MVFont,
  ExtDlgs, Buttons, sgConsts, sgFunction,
  DWG, HPGL2, CGM, SVG, DWF, sgSTLImage{, XMLInterface},
  {$IFDEF CADExportVCL}
  DXFExport, CADtoDXF, CADtoSVG, CADtoCGM, CADtoHPGL, CADtoPDF, CADtoSWF, CADtoDWG,
  {$IFDEF SGDEL_2009}
    fPDFExportDlg,
  {$ENDIF}

  {$ENDIF}
  CADExport,
  ShellAPI,
  fLayers,
  sgLines,
  ShlObj, ActiveX, IniFiles, SHX, Math, sgDrawingNavigator, sgTools
  {$IFDEF SGDEL_4}
  ,ActnList
  {$ENDIF};

const
  sNotVectorial: string = 'Raster drawings can not be saved to CAD format';

  fAccuracy = 0.003;

type

  TSelectionMode = (smNone, smRectangle, smEllipse);

  TRectangleAround = record
    Box: TFRect;
    PaperSpace: Integer;
  end;

  TForm1 = class(TForm)
    Panel2: TPanel;
    prbProgress: TProgressBar;
    pgcDrawing: TPageControl;
    tbsImage: TTabSheet;
    tbsStructure: TTabSheet;
    TreeView1: TTreeView;
    Splitter1: TSplitter;
    ListBox1: TListBox;
    MainMenu1: TMainMenu;
    MIFile: TMenuItem;
    MIOpen: TMenuItem;
    MIClose: TMenuItem;
    N4: TMenuItem;
    MIExit: TMenuItem;
    pnlFileName: TPanel;
    pnlTime: TPanel;
    MIView: TMenuItem;
    PrintDialog1: TPrintDialog;
    MIPrint: TMenuItem;
    MIScale: TMenuItem;
    MIAuto: TMenuItem;
    MIx2: TMenuItem;
    MIx4: TMenuItem;
    MIx8: TMenuItem;
    MIx16: TMenuItem;
    MIPrev: TMenuItem;
    N1: TMenuItem;
    N251: TMenuItem;
    N501: TMenuItem;
    MIx1: TMenuItem;
    OpenDialog1: TOpenPictureDialog;
    Panel4: TPanel;
    BtnOpen: TSpeedButton;
    BtnPlus: TSpeedButton;
    BtnMinus: TSpeedButton;
    BtnReal: TSpeedButton;
    BtnPrev: TSpeedButton;
    BtnPrint: TSpeedButton;
    N2: TMenuItem;
    MIAbout: TMenuItem;
    BtnSave: TSpeedButton;
    mmiSaveAs: TMenuItem;
    SavePictureDialog: TSavePictureDialog;
    ImageColors1: TMenuItem;
    mmiDisabled: TMenuItem;
    mmiBlack: TMenuItem;
    mmiNormal: TMenuItem;
    btnLayers: TSpeedButton;
    BtnPrint1: TSpeedButton;
    pnlCoords: TPanel;
    btnFitToScreen: TSpeedButton;
    btnIsWithoutBorder: TSpeedButton;
    btnDrawAllColor: TSpeedButton;
    btnBlackWhite: TSpeedButton;
    btnWhiteBackground: TSpeedButton;
    btnBlackBackground: TSpeedButton;
    btnShowLineWeight: TSpeedButton;
    btnHideLineWeight: TSpeedButton;
    btnSplittedArc: TSpeedButton;
    btnArcNormal: TSpeedButton;
    sb3DOrbit: TSpeedButton;
    BtnPrint2: TSpeedButton;
    PopupMenu1: TPopupMenu;
    Printer1: TMenuItem;
    Metafile1: TMenuItem;
    mmiSaveAsBigEMF: TMenuItem;
    SavePictureDialogEMF: TSavePictureDialog;
    pnlLayouts: TPanel;
    lblLayouts: TLabel;
    cbLayouts: TComboBox;
    sb3DAxes: TSpeedButton;
    mmiShowpoint: TMenuItem;
    mmiFindtext: TMenuItem;
    mmiReopenSameView: TMenuItem;
    miFonts: TMenuItem;
    N3: TMenuItem;
    sbFonts: TSpeedButton;
    sbDrid: TSpeedButton;
    sbDrawingBox: TSpeedButton;
    mmiReopenSWIsometric: TMenuItem;
    sbShowBorder: TSpeedButton;
    OpenBorder: TOpenPictureDialog;
    Snap1: TMenuItem;
    mmiObjectSnapAll: TMenuItem;
    imgFrame: TImage;
    edtNumPartsCircle: TEdit;
    udNumPartsCircle: TUpDown;
    edtNumPartsSpline: TEdit;
    udNumPartsSpline: TUpDown;
    edtGridCount: TEdit;
    udGridCount: TUpDown;
    lblNumPartsCircle: TLabel;
    lblNumPartsSpline: TLabel;
    lblDridCount: TLabel;
    N5: TMenuItem;
    pmiDoublebuffered: TMenuItem;
    pnlSize: TPanel;
    procedure MIOpenClick(Sender: TObject);
    procedure MICloseClick(Sender: TObject);
    procedure MIExitClick(Sender: TObject);
    procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
    procedure MIPrintClick(Sender: TObject);
    procedure MIAutoClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure MIPrevClick(Sender: TObject);
    procedure BtnPlusClick(Sender: TObject);
    procedure BtnMinusClick(Sender: TObject);
    procedure pgcDrawingChanging(Sender: TObject;
      var AllowChange: Boolean);
    procedure MIHelpClick(Sender: TObject);
    procedure OpenDialog1Show(Sender: TObject);
    procedure OpenDialog1Close(Sender: TObject);
    procedure BtnSaveClick(Sender: TObject);
    procedure mmiDisabledClick(Sender: TObject);
    procedure mmiBlackClick(Sender: TObject);
    procedure mmiNormalClick(Sender: TObject);
    procedure SoftGoldHomePage1Click(Sender: TObject);
    procedure MIAboutClick(Sender: TObject);
    procedure btnLayersClick(Sender: TObject);
    procedure BtnPrint1Click(Sender: TObject);
    procedure btnFitToScreenClick(Sender: TObject);
    procedure btnIsWithoutBorderClick(Sender: TObject);
    procedure btnShowLineWeightClick(Sender: TObject);
    procedure btnSplittedArcClick(Sender: TObject);
    procedure btnDrawAllColorClick(Sender: TObject);
    procedure btnWhiteBackgroundClick(Sender: TObject);
    procedure sb3DOrbitClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Printer1Click(Sender: TObject);
    procedure Metafile1Click(Sender: TObject);
    procedure BtnPrint2Click(Sender: TObject);
    procedure mmiSaveAsBigEMFClick(Sender: TObject);
    procedure cbLayoutsChange(Sender: TObject);
    procedure pgcDrawingChange(Sender: TObject);
    procedure speNumPartsCircleChange(Sender: TObject);
    procedure speNumPartsSplineChange(Sender: TObject);
    procedure sb3DAxesClick(Sender: TObject);
    procedure mmiShowpointClick(Sender: TObject);
    procedure mmiFindtextClick(Sender: TObject);
    procedure mmiReopenSameViewClick(Sender: TObject);
    procedure miFontsClick(Sender: TObject);
    procedure speGridCountChange(Sender: TObject);
    procedure sbDrawingBoxClick(Sender: TObject);
    procedure mmiReopenSWIsometricClick(Sender: TObject);
    procedure sbShowBorderClick(Sender: TObject);
    procedure mmiObjectSnapAllClick(Sender: TObject);
    procedure actFormUpdate(Sender: TObject);
    procedure sbDridClick(Sender: TObject);
    procedure BtnRealClick(Sender: TObject);
    procedure mmiScaleClick(Sender: TObject);
    procedure pmiDoublebufferedClick(Sender: TObject);
  private
    FSearchingText: string;
    FTextPoint: TFPoint;
    FTextBox: TFRect;
    FCADParams: TsgCADIterate;
    FSearchResult: Boolean;
    FFindFlag: Boolean;
    FSelectionMode: TSelectionMode;
    FSearchModeIsAll: Boolean;
    FSelectedEntities: TList;
    FFileName: string;
    FOptions: TIniFile;
    FStoredNullWidth: Integer;
    FsgPaintBox: TsgDrawingNavigator;
    FStart: Cardinal;
    FIntPoints: TList;
    {$IFDEF SGDEL_4}
    FactForm: TAction;
    {$ENDIF}
    FSaveDialogFilter: TStrings;
    FGraphic: TGraphic;
    FImg: TsgCADImage;
    procedure Enable3DOrbit(AIsEnabled: Boolean);
    procedure Enable3DAxes(AIsEnabled: Boolean);
    procedure LoadStructure;
    procedure Time;
    procedure EnableControls;
    procedure Open(const AFileName: String);
    function  Save(const ASource: TGraphic; const AFileName: string;
      const AFormat: TsgExportFormat): Boolean;
    procedure RestoreNullWidth(AGraphic: TGraphic);
    procedure SetImgOpt;
    procedure SetNullWidth(AGraphic: TGraphic; AWidth: Integer);
    procedure ViewLayouts;
    {$IFNDEF SGDEL_4}
    procedure UpdateActions;
    procedure DoActionIdle;
    {$ENDIF}
    procedure AppIdle(Sender: TObject; var Done: Boolean);
    procedure sgPaintBoxScaling(Sender: TObject);
    procedure sgPaintBoxProgress(Sender: TObject; Stage: TProgressStage;
      PercentDone: Byte; RedrawNow: Boolean; const R: TRect; const Msg: String);
    procedure sgPaintBoxPaint(Sender: TObject);
    procedure sgPaintBoxPictureChange(Sender: TObject);
    procedure sgPaintBoxMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    function GetGraphic: TGraphic;
    function ExportCad(const ASource: TsgCADImage; const AFormat: TsgExportFormat;
      const AFileName: string): Boolean;
    function ExportRastr(const ASource: TsgCADImage;
      const AFormat: TsgExportFormat; const AFileName: string): Boolean;
  protected
    procedure ActualGraphic(var AResult: TGraphic);
    function AddRectToConv(ABox: TFRect): TsgDXFEntity;
    procedure SelectEntities;
    procedure LoadOptions;
    procedure BreakLoading(Sender: TObject);
    procedure DrawTo(const ADest: TObject; const ADstRect: TRect;
      const ASource: TGraphic); overload;
    function GetCADImage: TsgCADImage;
    function GetGridCount: Integer;
    function GetNumPartsCircle: Integer;
    function GetNumPartsSpline: Integer;
    procedure SetGridCount(AValue: Integer);
    procedure SetNumPartsCircle(AValue: Integer);
    procedure SetNumPartsSpline(AValue: Integer);
    procedure SetCADInfoVisible(const AVal: Boolean);
    function StartPrint(const ATitle: string): Boolean;
    procedure EndPrint;
    property GridCount: Integer read GetGridCount write SetGridCount;
    property NumPartsCircle: Integer read GetNumPartsCircle write SetNumPartsCircle;
    property NumPartsSpline: Integer read GetNumPartsSpline write SetNumPartsSpline;
  public
    function FindText(const S: String; const ASelection: TSelectionMode; const ASearch: Boolean): Boolean;
    function ReadCADEntities(Entity: TsgDXFEntity): Integer;
    procedure WndProc(var Message: TMessage); override;
    {$IFDEF SGDEL_4}
    property actForm: TAction read FactForm;
    {$ENDIF}
    property sgPaintBox: TsgDrawingNavigator read FsgPaintBox;
    property Img: TsgCADImage read GetCADImage;
    property Graphic: TGraphic read GetGraphic;
  end;

var
  Form1: TForm1;

implementation

uses
  Unit2, Unit3,
  fFonts, fPaths
  {$IFDEF DEMO}
  ,fInfo
  {$ENDIF}
{$IFDEF SGDEL_2009}
  ,PNGImage
{$ENDIF}
;

{$R *.DFM}

const
  cnstExportMsg = ' software which is not part of CAD Import VCL package.';
  cnstExportMsgDXF = 'DXF/SVG/CGM/PDF/SWF Export is made via CAD Export VCL' + cnstExportMsg;
  cnstNotCAD = 'It is not CAD file. This operation does not work.';

  cnstDefGridCount = 20;
  cnstEMFExt = '.emf';
  cnstPrnOrient: array[Boolean] of TPrinterOrientation = (poPortrait, poLandscape);

type
  TsgDrawingNavigatorAccess = class(TsgDrawingNavigator);

function CreateLines(var AList: TList; D: Integer; AWidth, AHeight: Integer): boolean;
var
  I: Integer;
  vdx, vdy: Integer;
begin
  if AList = nil then
    AList := TList.Create
  else
    AList.Clear;
  I := 0;
  if D <= 0 then
    D := 1;
  vdx := D;
  vdy := D;
  while (I * vdx <= AWidth) do
  begin
    AList.Add(Pointer(I * vdx));
    AList.Add(Pointer(0));
    AList.Add(Pointer(I * vdx));
    AList.Add(Pointer(AHeight));
    inc(I);
  end;
  I := 0;
  while (I * vdy <= AHeight) do
  begin
    AList.Add(Pointer(0));
    AList.Add(Pointer(I * vdy));
    AList.Add(Pointer(AWidth));
    AList.Add(Pointer(I * vdy));
    inc(I);
  end;
  Result := True;
  if AList.Count < 2 then
    Result := False;
end;

procedure DrawPolyPolyLine(DC: HDC; IntPoints: TList);
var
  I, N, C: Integer;
  P: Pointer;
begin
  N := IntPoints.Count shr 2;
  if N = 0 then
    Exit;
  C := IntPoints.Count;
  for I := 0 to N - 1 do
    IntPoints.Add(Pointer(2));
  P := IntPoints.List;
  Inc(PInteger(P), C);
  PolyPolyline(DC, IntPoints.List[0], P^, N);
end;

{ TForm1 }

procedure TForm1.LoadOptions;
var
  vSet: string;
begin
  if not Assigned(FOptions) then
  begin
    vSet := ExtractFilePath(Application.ExeName) + sSettings;
    FOptions := TIniFile.Create(vSet);
  end;
  bUseSHXFonts := FOptions.ReadBool(sGeneral, sUseSHX, bUseSHXFonts);
  sSHXSearchPaths := FOptions.ReadString(sGeneral, sSHXPaths, sSHXSearchPaths);
  sDefaultSHXPath := FOptions.ReadString(sGeneral, sSHXPath, sDefaultSHXPath);
  sDefaultSHXFont := FOptions.ReadString(sGeneral, sSHXFont, sDefaultSHXFont);
end;

function TForm1.AddRectToConv(ABox: TFRect): TsgDXFEntity;

  function AddVertex(const AOwner: TsgDXFEntity;
    const APoint: TFPoint): TsgDXFVertex;
  begin
    Result := TsgDXFVertex.Create;
    Result.Point := APoint;
    AOwner.AddEntity(Result);
  end;

begin
  Result := TsgDXFPolyline.Create;
  AddVertex(Result, ABox.TopLeft);
  AddVertex(Result, MakeFPoint(ABox.BottomRight.X, ABox.TopLeft.Y, ABox.TopLeft.Z));
  AddVertex(Result, ABox.BottomRight);
  AddVertex(Result, MakeFPoint(ABox.TopLeft.X, ABox.BottomRight.Y, ABox.BottomRight.Z));
  Result.ColorCAD := MakeColorCAD(acRGBColor, clRed);
  Result.SetLWeight(1);
  TsgDXFPolyline(Result).Closed := True;
end;

function TForm1.ReadCADEntities(Entity: TsgDXFEntity): Integer;
var
  S1, S2: String;
  vRectAround: ^TRectangleAround;
  P: TFPoint;
  CurAttrib: TsgDXFAttrib;
  vBox: TFRect;
  vAttribFlag: Boolean;
begin
  Result := 0;
  if FFindFlag then
    Exit;
  if Entity is TsgDXFMText then
  begin
    FTextPoint := TsgDXFMText(Entity).Point;
  end;
  if Entity is TsgDXFText then
  begin
    S1 := AnsiUpperCase(FSearchingText);
    S2 := AnsiUpperCase(TsgDXFText(Entity).Text);
    vAttribFlag := False;
    if FCADParams.Insert <> nil then
    begin
      P := FPointXMat(TsgDXFText(Entity).StartPoint, FCADParams.Matrix);
      CurAttrib := FCADParams.Insert.Attrib(S2, P);
      if CurAttrib <> nil then
      begin
        S2 := CurAttrib.Text;
        vBox := CurAttrib.Box;
        vAttribFlag := True;
      end;
    end;
    if AnsiPos(S1, S2) > 0 then
    begin
      FSearchResult := True;
      FTextPoint := FPointXMat(TsgDXFText(Entity).StartPoint, FCADParams.Matrix);
      FTextBox.TopLeft := FPointXMat(TsgDXFText(Entity).Box.TopLeft, FCADParams.Matrix);
      FTextBox.BottomRight := FPointXMat(TsgDXFText(Entity).Box.BottomRight, FCADParams.Matrix);
      if not(FSearchModeIsAll) then
        FFindFlag := True;
      if FSelectionMode = smRectangle then
      begin
        New(vRectAround);
        if not vAttribFlag then
        begin
          vRectAround^.Box.TopLeft := FPointXMat(Entity.Box.TopLeft, FCADParams.Matrix);
          vRectAround^.Box.BottomRight := FPointXMat(Entity.Box.BottomRight, FCADParams.Matrix);
        end
        else
          vRectAround^.Box := vBox;
        vRectAround.PaperSpace := Ord(Img.Layouts[0] <> Img.CurrentLayout);
        FSelectedEntities.Add(vRectAround);
      end;
    end;
  end;
end;

procedure TForm1.SelectEntities;
var
  I: Integer;
  Ent: TsgDXFEntity;
begin
  for I := 0 to FSelectedEntities.Count - 1 do
  begin
    Ent := AddRectToConv(TRectangleAround(FSelectedEntities[I]^).Box);
    if Ent <> nil then
    begin
      Img.Converter.Sections[csEntities].AddEntity(Ent);
      Img.Converter.DoCreate(Ent);
      Img.Converter.Loads(Ent);
      Ent.PaperSpace := TRectangleAround(FSelectedEntities[I]^).PaperSpace;
    end;
  end;
  sgPaintBox.Invalidate;
end;

function TForm1.FindText(const S: String; const ASelection: TSelectionMode; const ASearch: Boolean): Boolean;
var
  I: Integer;
begin
  FSearchingText := S;
  FSelectionMode := ASelection;
  FSearchModeIsAll := ASearch;
  FSearchResult := False;
  FCADParams.Matrix := cnstIdentityMat;
  Img.Converter.AutoInsert := True; // to get all the elements inside of inserts
  FFindFlag := False;
  FSelectedEntities := TList.Create;
  try
    Img.Converter.Iterate(ReadCADEntities, nil, FCADParams);
    SelectEntities;
  finally
    for I := 0 to FSelectedEntities.Count - 1 do
      Dispose(FSelectedEntities[I]);
    FSelectedEntities.Free;
  end;
  Result := FSearchResult;
end;

procedure TForm1.Time;
var
  T: Integer;
begin
  T := (GetCurrentTime - FStart) div 1000;
  pnlTime.Caption := Format('%.2d:%.2d', [T div 60, T mod 60]);
  pnlTime.Update;
end;

procedure TForm1.LoadStructure;

  procedure Add(Parent: TTreeNode; E: TsgDXFEntity);
  var
    I: Integer;
  begin
    Parent := TreeView1.Items.AddChildObject(Parent, E.EntName, E);
    Application.ProcessMessages;
    prbProgress.Position := prbProgress.Position + 1;
    for I := 0 to E.Count - 1 do Add(Parent, E[I]);
  end;

var
  I: Integer;
begin
  if Img = nil then Exit;
  prbProgress.Position := 0;
  prbProgress.Max := Img.Converter.Count;
  pnlFileName.Caption := 'Structure';
  pnlFileName.Update;
  TreeView1.Items.BeginUpdate;
  try
    for I := 0 to Img.Converter.Main.Count - 1 do
      Add(nil, Img.Converter.Main[I]);
  finally
    prbProgress.Position := 0;
    TreeView1.Items.EndUpdate;
  end;
end;

procedure TForm1.EnableControls;
var
  I: Integer;
  vNotEmpty: Boolean;
  vCAD: Boolean;
begin
  vNotEmpty := not sgPaintBox.Empty;
  vCAD := Assigned(Img);
  for I := 0 to MIScale.Count-1 do
    MIScale.Items[I].Enabled := vNotEmpty;
  MIPrint.Enabled := vNotEmpty;
  BtnSave.Enabled := vNotEmpty;
  BtnPrint.Enabled := vNotEmpty;
  BtnPrint1.Enabled := vNotEmpty;
  BtnPrint2.Enabled := vNotEmpty;
  BtnPlus.Enabled := vNotEmpty;
  BtnMinus.Enabled := vNotEmpty;
  BtnReal.Enabled := vNotEmpty and (Abs(1 - sgPaintBox.Scale) > fAccuracy);
  BtnPrev.Enabled := vNotEmpty and sgPaintBox.HasPreviousView;
  btnLayers.Enabled := vCAD;
  btnFitToScreen.Enabled := vNotEmpty;
  mmiSaveAsBigEMF.Enabled := vNotEmpty;
  mmiSaveAs.Enabled := vNotEmpty;
  MIPrint.Enabled := vNotEmpty;
  MIClose.Enabled := vNotEmpty;
  btnIsWithoutBorder.Enabled := vCAD;
  btnDrawAllColor.Enabled := vCAD;
  btnBlackWhite.Enabled := vCAD;
  //btnWhiteBackground.Enabled := vCAD;

  //btnBlackBackground.Enabled := vCAD;
  btnShowLineWeight.Enabled := vCAD;
  btnHideLineWeight.Enabled := vCAD;
  btnSplittedArc.Enabled := vCAD;
  btnArcNormal.Enabled := vCAD;
  sbDrawingBox.Enabled := vCAD;
  sb3DOrbit.Enabled := vCAD and Img.CurrentLayout.IsModel;
  sb3DAxes.Enabled := vCAD;
  sbDrid.Enabled := vCAD;
  sbShowBorder.Enabled := vCAD;

  mmiShowpoint.Enabled := vCAD;
  mmiFindtext.Enabled := vCAD;
  mmiReopenSameView.Enabled := vCAD;
  mmiReopenSWIsometric.Enabled := vCAD;
  mmiDisabled.Enabled := vCAD;
  mmiBlack.Enabled := vCAD;
  mmiNormal.Enabled := vCAD;
  mmiObjectSnapAll.Enabled := vCAD;
end;

procedure TForm1.EndPrint;
begin
  RestoreNullWidth(Graphic);
  sgPaintBox.Refresh;
end;

procedure TForm1.Open(const AFileName: String);
var
  vBreakForm: TForm;

  function MakeBreakForm: TForm;
  const
    sBreakFormName = 'fmBreakForm';
  var
    vB: TButton;
  begin
    Result := TForm(Application.FindComponent(sBreakFormName));
    if not Assigned(Result) then
    begin
      Result := TForm.Create(Application);
      Result.Name := sBreakFormName;
      Result.BorderStyle := bsDialog;
      Result.FormStyle := fsStayOnTop;
      Result.Caption := 'Loading...';
      vB := TButton.Create(Result);
      vB.Parent := Result;
      vB.SetBounds(8, 8, 125, 23);
      vB.Caption := 'Break loading';
      vB.OnClick := BreakLoading;
    end;
    Result.Show;
    Result.SetBounds(Left + Width div 2 - 151 div 2,
        Top + Height div 2 - 76 div 2, 151, 76);
  end;

begin
  sgPaintBox.BeginUpdate;
  try
    SetCADInfoVisible(False);
    TreeView1.Items.Clear;
    FStart := GetCurrentTime;
    Screen.Cursor := crAppStart;
    vBreakForm := MakeBreakForm;
    try
      sb3DAxes.Down := False;
      MICloseClick(nil);
      sgPaintBox.LoadFromFile(AFileName);
      FFileName := AFileName;
      pnlFileName.Caption := UpperCase(ExtractFileName(AFileName));
      pnlLayouts.Visible := False;
      if Assigned(Img) then
      begin
        SetImgOpt;
        tbsStructure.TabVisible := True;
        ViewLayouts;
        NumPartsCircle := sgConsts.GetNumberOfCircleParts;
        NumPartsSpline := sgConsts.GetNumberOfSplineParts;
      end;
      sgPaintBox.FitToSize;
    finally
      SetCADInfoVisible(Assigned(Img));
      if Assigned(vBreakForm) then
        vBreakForm.Close;
      EnableControls;
      prbProgress.Position := 0;
      Screen.Cursor := crDefault;
    end;
  finally
    sgPaintBox.EndUpdate;
  end;
end;

procedure TForm1.MIOpenClick(Sender: TObject);
begin
  OpenDialog1.FileName := '';
  CADPreview := True;
  try
    if OpenDialog1.Execute then
    begin
      CADPreview := False;
      MICloseClick(nil);
      Open(OpenDialog1.FileName);
    end;
  finally
    CADPreview := False;
  end;
end;

procedure TForm1.MICloseClick(Sender: TObject);
begin
  ListBox1.Clear;
  TreeView1.Items.Clear;
  sgPaintBox.Picture.Graphic := nil;
  FFileName := '';
  pnlFileName.Caption := '';
  pnlCoords.Caption := '';
  pnlTime.Caption := '';
  MIClose.Enabled := False;
  MIPrint.Enabled := False;
  BtnSave.Enabled := False;
  pgcDrawing.ActivePage := tbsImage;
  tbsStructure.TabVisible := False;
  prbProgress.Max := 100;
  EnableControls;
  cbLayouts.Items.Clear;
  pnlLayouts.Visible := False;
end;

procedure TForm1.MIExitClick(Sender: TObject);
begin
  Close;
end;

procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
var
  E: TsgDXFEntity;
  S: String;
begin
  if Node.Selected then
  begin
    E := TsgDXFEntity(Node.Data);
    if (E = nil) or (E.SrcStart = nil) or (E.SrcEnd = nil) then
      ListBox1.Clear
    else
    begin
      SetString(S, E.SrcStart, E.SrcEnd - E.SrcStart);
      ListBox1.Items.Text := S;
    end;
  end;
end;

procedure TForm1.SetNullWidth(AGraphic: TGraphic; AWidth: Integer);
begin
  if AGraphic is TsgCADImage then
  begin
    FStoredNullWidth := TsgCADImage(AGraphic).NullWidth;
    TsgCADImage(AGraphic).NullWidth := AWidth;
  end;
end;

procedure TForm1.SetNumPartsCircle(AValue: Integer);
begin
  udNumPartsCircle.Position := AValue;
  edtNumPartsCircle.Text := IntToStr(AValue);
end;

procedure TForm1.SetNumPartsSpline(AValue: Integer);
begin
  udNumPartsSpline.Position := AValue;
  edtNumPartsSpline.Text := IntToStr(AValue);
end;

procedure TForm1.RestoreNullWidth(AGraphic: TGraphic);
begin
  if AGraphic is TsgCADImage then
    TsgCADImage(AGraphic).NullWidth := FStoredNullWidth;
end;



function TForm1.ExportCad(const ASource: TsgCADImage; const AFormat: TsgExportFormat;
  const AFileName: string): Boolean;
var
  vExport: TsgCADExport;
  vExportParams: TsgExportParams;
begin
  {$IFDEF CADExportVCL}
  Result := False;
  vExport := nil;
  if Assigned(ASource) then
  begin
    case AFormat of
      efDxf:
        begin
          vExport := TsgCADtoDXF.Create(ASource) //direct export
        end;
      efSvg:  vExport := TsgCADtoSVG.Create(ASource);
      efCgm:  vExport := TsgCADtoCGM.Create(ASource);
      efPdf:
        begin
          vExportParams := DefExportParams;
          {$IFDEF SGDEL_2009}
          if PDFExportDlgExecute(Self, nil, @vExportParams) then
          {$ENDIF}
          begin
            vExport := TsgPDFExport.Create(ASource);
            TsgSimpleExport(vExport).ApplyParams(vExportParams);
          end;
        end;
      efSwf:  vExport := TsgCADtoSWF.Create(ASource);
      efPlt:
        begin
          vExport := TsgCADtoHPGL.Create(ASource);
          TsgCADtoHPGL(vExport).XScale := 40;
        end;
      efDwg:  vExport := TsgCADtoDWG.Create(ASource);
    end;
    if Assigned(vExport) then
    begin
      try
        vExport.SaveToFile(AFileName);
        Result := True;
        MessageBox(Application.Handle, PChar(cnstExportMsgDXF), 'WARNING', MB_ICONWARNING);
      finally
        vExport.Free;
      end;
    end;
  end
  else
    ShowMessage(sNotVectorial)
     {$ENDIF}
end;

function TForm1.ExportRastr(const ASource: TsgCADImage; const AFormat: TsgExportFormat;
  const AFileName: string): Boolean;
var
  vExport: TObject;
  vWidth, vHeight: Integer;
  vRatio: Double;
  vBmp: TBitmap;
  vStream: TStream;
  vStreamPersist: IStreamPersist;
begin
  Result := False;
  vExport := nil;
  if Assigned(ASource) then
    case AFormat of
      efBitmap:       vExport := TBitmap.Create;
      efJpg..efJpeg:  vExport := TJPEGImage.Create;
  {$IFDEF SGDEL_2009}
      efPng:          vExport := TPngImage.Create;
  {$ENDIF}
      efWmf..efEmf:   vExport := TMetafile.Create;
    end;
  if Assigned(vExport) then
  begin
    try
    // Converting CAD-drawing width/height to Screen size for export
      vWidth := ASource.Width;
      vHeight := ASource.Height;
      if vHeight <> 0 then
        vRatio := vWidth / vHeight
      else
        vRatio := 1;
      if vRatio <= 1 then
      begin
        vHeight := Screen.Height;
        vWidth := Round(vHeight * vRatio);
      end
      else
      begin
        vWidth := Screen.Width;
        vHeight := Round(vWidth / vRatio);
      end;
      if AFormat in [efBitmap, efJpg .. efJpeg, efPng] then
      begin
        if AFormat = efBitmap then
        begin
          SetSizeGraphic(TGraphic(vExport), vWidth, vHeight);
          DrawTo(vExport, Rect(0, 0, vWidth, vHeight), ASource);
        end
        else
        begin
          vBmp := TBitmap.Create;
          try
            SetSizeGraphic(vBmp, vWidth, vHeight);
            DrawTo(vBmp, Rect(0, 0, vWidth, vHeight), ASource);
            TGraphic(vExport).Assign(vBmp);
          finally
            vBmp.Free;
          end;
        end;
      end
      else
      begin
        if AFormat in [efWmf, efEmf] then
        begin
          SetSizeGraphic(TGraphic(vExport), vWidth, vHeight);
          DrawTo(vExport, Rect(0, 0, vWidth, vHeight), ASource);
          TMetafile(vExport).Enhanced := AFormat = efEmf;
        end;
      end;
      if vExport.GetInterface(IStreamPersist, vStreamPersist) then
      begin
        vStream := TFileStream.Create(AFileName, fmCreate);
        try
          vStreamPersist.SaveToStream(vStream);
          Result := True;
        finally
          vStream.Free;
        end;
      end;
    finally
      vExport.Free;
    end;
  end
  else
    ShowMessage('Unknown format');
end;

function TForm1.Save(const ASource: TGraphic; const AFileName: string;
  const AFormat: TsgExportFormat): Boolean;
var
  vFormatByFileName: TsgExportFormat;
  vFileName, vFileExt: string;
  vImg: TsgCADImage;
  vCur: TCursor;
begin
  Result := False;
  vFileName := AFileName;
  vFileExt := AnsiLowerCase(ExtractFileExt(vFileName));
  vFormatByFileName := GetExportFormat(vFileExt);
  if AFormat <> vFormatByFileName then
    vFileName := vFileName + GetExportExt(AFormat);
  vImg := nil;
  if ASource is TsgCADImage then
    vImg := TsgCADImage(ASource);
  vCur := Cursor;
  Cursor := crHourGlass;
  try
    case AFormat of
      efDxf, efSvg, efCgm, efPdf, efSwf, efPlt, efDwg:
        ExportCad(vImg, AFormat, vFileName);
      efBitmap, efJpg..efJpeg, efPng, efWmf..efEmf:
        ExportRastr(vImg, AFormat, vFileName);
      else
        ShowMessage('Unknown format');
    end;
  finally
    Cursor := vCur;
  end;
end;

// Printing funtcions

procedure TForm1.MIPrintClick(Sender: TObject);
var
  W, H: Double;
  PW, PH: Integer;
  R: TRect;
begin
  if StartPrint('Direct draw CAD to printer') then
  try
    W := Printer.PageWidth / Graphic.Width;
    H := Printer.PageHeight / Graphic.Height;
    if W > H then W := H;
    PW := Round(W * Graphic.Width);
    PH := Round(W * Graphic.Height);
    R := Bounds((Printer.PageWidth - PW) div 2, (Printer.PageHeight - PH) div 2, PW, PH);
    DrawTo(Printer, R, Graphic);
  finally
    EndPrint;
  end;
end;

procedure TForm1.BtnPrint1Click(Sender: TObject);
const
  cnstScaleFactor = 0.5;
var
  vPxlsX, vPxlsY: Double;
  R: TRect;
begin
  if StartPrint('CAD Import VCL printing 1:1') then
  try
    vPxlsX := 1;
    vPxlsY := 1;
    if Assigned(Img) then
    begin
      vPxlsX := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
      vPxlsY := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
      if Img.Millimetres then
      begin
        vPxlsX := vPxlsX / cnstMMPerInch;
        vPxlsY := vPxlsY / cnstMMPerInch;
      end;
    end;
    R := Rect(0, 0, Round(vPxlsX * Graphic.Width * cnstScaleFactor),
      Round(vPxlsY * Graphic.Height * cnstScaleFactor));
    DrawTo(Printer, R, Graphic);
  finally
    EndPrint;
  end;
end;

procedure TForm1.Printer1Click(Sender: TObject);
var
  W, H: Double;
  PW, PH: Integer;
  vGr: TGraphic;
  R: TRect;
begin
  if StartPrint('Draw actual CAD to printer throw metafile') then
  try
    vGr := TMetafile.Create;
    try
      ActualGraphic(vGr);
      W := Printer.PageWidth / vGr.Width;
      H := Printer.PageHeight / vGr.Height;
      if W > H then W := H;
      PW := Round(W * vGr.Width);
      PH := Round(W * vGr.Height);
      R := Bounds((Printer.PageWidth - PW) div 2, (Printer.PageHeight - PH) div 2, PW, PH);
      DrawTo(Printer, R, vGr);
    finally
      vGr.Free;
    end;
  finally
    EndPrint;
  end;
end;

procedure TForm1.Metafile1Click(Sender: TObject);
var
  vGr: TGraphic;
begin
  SavePictureDialog.FilterIndex := GetFilterIndexFromList(FSaveDialogFilter, cnstEMFExt);
  if sgPaintBox.Empty or not SavePictureDialog.Execute then Exit;
  vGr := TMetafile.Create;
  try
    ActualGraphic(vGr);
    Save(vGr, SavePictureDialog.FileName, efEmf);
  finally
    vGr.Free;
  end;
end;

procedure TForm1.BreakLoading(Sender: TObject);
begin
  if Loading <> nil then Loading.StopLoading;
end;

procedure TForm1.ActualGraphic(var AResult: TGraphic);
const
  cnstMMCf: array[Boolean] of Integer = (500, 1000);
  cnstExpandCf: array[Boolean] of Integer = (5, 10);
var
  vMC: TMetafileCanvas;
  vRect: TRect;
  vRGN: HRGN;
  DC: HDC;
  mmToPixelX, mmToPixelY: Double;
  vClientR: TRect;
  vW, vH: Integer;
  vIsNT: Boolean;
begin
  vClientR := sgPaintBox.ClientRect;
  vW := vClientR.Right - vClientR.Left;
  vH := vClientR.Bottom - vClientR.Top;
  DC := GetDC(0);
  try
    mmToPixelX := GetDeviceCaps(DC,HORZSIZE) /
      GetDeviceCaps(DC,HORZRES);
    mmToPixelY := GetDeviceCaps(DC,VERTSIZE) /
      GetDeviceCaps(DC,VERTRES);
  finally
    ReleaseDC(0, DC);
  end;
  vRect := sgPaintBox.PictureRect;
  vRect.Left := vRect.Left - vClientR.Left;
  vRect.Top := vRect.Top - vClientR.Top;
  vRect.Right := vRect.Right - vClientR.Left;
  vRect.Bottom := vRect.Bottom - vClientR.Top;
  vIsNT := Win32Platform = VER_PLATFORM_WIN32_NT;
  TMetafile(AResult).MMWidth := Round(vW * cnstMMCf[vIsNT] * mmToPixelX);
  TMetafile(AResult).MMHeight := Round(vH * cnstMMCf[vIsNT] * mmToPixelY);
  vRect.Left := vRect.Left * cnstExpandCf[vIsNT];
  vRect.Top := vRect.Top * cnstExpandCf[vIsNT];
  vRect.Right := vRect.Right * cnstExpandCf[vIsNT];
  vRect.Bottom := vRect.Bottom * cnstExpandCf[vIsNT];
  vMC := TMetafileCanvas.Create(TMetafile(AResult), 0);
  try
    vRGN := CreateRectRgn(0, 0, vW * cnstExpandCf[vIsNT], vH * cnstExpandCf[vIsNT]);
    SelectClipRgn(vMC.Handle, vRGN);
    vMC.StretchDraw(vRect, Graphic);
    DeleteObject(vRGN);
  finally
    vMC.Free;
    if Img <> nil then
      Img.IsShowBackground := True;
  end;
end;

procedure TForm1.MIAutoClick(Sender: TObject);
begin
  sgPaintBoxScaling(nil);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  sSHXSearchPaths := ExpandFileName('../../../SHX');
  FSaveDialogFilter := TsgStringList.Create;
{$IFDEF SGDEL_2009}
  SavePictureDialog.Filter := SavePictureDialog.Filter + '|PNG (*.png)|*.png';
{$ENDIF}
{$IFDEF CADExportVCL}
  SavePictureDialog.Filter := SavePictureDialog.Filter + '|SVG (*.svg)|*.svg';
  SavePictureDialog.Filter := SavePictureDialog.Filter + '|CGM (*.cgm)|*.cgm';
  SavePictureDialog.Filter := SavePictureDialog.Filter + '|PDF (*.pdf)|*.pdf';
  SavePictureDialog.Filter := SavePictureDialog.Filter + '|HPGL (*.plt)|*.plt';
  SavePictureDialog.Filter := SavePictureDialog.Filter + '|SWF (*.swf)|*.swf';
  SavePictureDialog.Filter := SavePictureDialog.Filter + '|DXF (*.dxf)|*.dxf';
  SavePictureDialog.Filter := SavePictureDialog.Filter + '|DWG (*.dwg)|*.dwg';
{$ENDIF}
  SetCADInfoVisible(False);
  FsgPaintBox := TsgDrawingNavigator.Create(Self);
  FsgPaintBox.SysMenuIconsVisible := False;
  FsgPaintBox.Parent := tbsImage;
  FsgPaintBox.AutoFocus := True;
  FsgPaintBox.RectZooming := True;
  FsgPaintBox.OnChangeScale := sgPaintBoxScaling;
  FsgPaintBox.OnPaint := sgPaintBoxPaint;
  FsgPaintBox.OnMouseMove := sgPaintBoxMouseMove;
  FsgPaintBox.OnProgress := sgPaintBoxProgress;
  FsgPaintBox.Align := alClient;
  FsgPaintBox.DoubleBuffered := True;
  FsgPaintBox.Color := clWhite;
  FsgPaintBox.OnPictureChange := sgPaintBoxPictureChange;
  {$IFDEF DEMO}
  fInfo.CreateInfoFrame(FsgPaintBox.Handle, Point(1, 1));
  {$ENDIF}
  {$IFDEF SGDEL_4}
  FactForm := TAction.Create(Self);
  FactForm.OnUpdate := actFormUpdate;
  FactForm.Caption := 'CAD Import VCL and CAD Export VCL demo viewer';
  Self.Action := actForm;
  {$ENDIF}
  FactForm.DisableIfNoHandler := False;
  Application.OnIdle := AppIdle;
  LoadOptions;
  OpenDialog1.Filter := GraphicFilter(TGraphic);
  pnlLayouts.Visible := False;
  if ParamCount > 0 then
  begin
    Open(ParamStr(1));
    OpenDialog1.FileName := ParamStr(1);
  end;
  sbDrawingBox.Enabled := False;
  NumPartsCircle := sgConsts.GetNumberOfCircleParts;
  NumPartsSpline := sgConsts.GetNumberOfSplineParts;
  GridCount := cnstDefGridCount;
  ParseDialogFilter(SavePictureDialog.Filter, FSaveDialogFilter);
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if Key = VK_ESCAPE then Close;
  if (pgcDrawing.ActivePage <> tbsImage) or (Shift-[ssCtrl] <> []) then Exit;
  case Key of
    VK_ADD: BtnPlusClick(nil);
    VK_SUBTRACT: BtnMinusClick(nil);
    VK_MULTIPLY:
      if ssCtrl in Shift then
        BtnReal.Click
      else
        btnFitToScreen.Click;
  end;
end;

procedure TForm1.MIPrevClick(Sender: TObject);
begin
  sgPaintBox.CallPreviousView;
end;

procedure TForm1.sgPaintBoxScaling(Sender: TObject);
begin
  MIPrev.Enabled := sgPaintBox.HasPreviousView;
  BtnPrev.Enabled := MIPrev.Enabled;
end;

procedure TForm1.sgPaintBoxProgress(Sender: TObject; Stage: TProgressStage;
  PercentDone: Byte; RedrawNow: Boolean; const R: TRect; const Msg: String);
begin
  if Stage = psStarting then
  begin
    pnlFileName.Caption := Msg;
    pnlFileName.Update;
  end;
  prbProgress.Position := PercentDone;
  Time;
  if Stage = psEnding then
  begin
    prbProgress.Position := 0;
    pnlFileName.Caption := UpperCase(ExtractFileName(OpenDialog1.FileName))
  end;
end;

procedure TForm1.BtnPlusClick(Sender: TObject);
begin
  sgPaintBox.AlterScale(2, False, sgPaintBox.Center);
end;

procedure TForm1.BtnMinusClick(Sender: TObject);
begin
  sgPaintBox.AlterScale(0.5, False, sgPaintBox.Center);
end;

procedure TForm1.pgcDrawingChanging(Sender: TObject; var AllowChange: Boolean);
begin
  AllowChange := Assigned(Img);
  FocusControl(nil);
end;

procedure TForm1.pmiDoublebufferedClick(Sender: TObject);
begin
  sgPaintBox.DoubleBuffered := pmiDoublebuffered.Checked;
end;

procedure TForm1.MIHelpClick(Sender: TObject);
begin
  Application.HelpCommand(HELP_CONTENTS,0);
end;

procedure TForm1.OpenDialog1Show(Sender: TObject);
begin
  MinDXFSize := 140;
end;

procedure TForm1.OpenDialog1Close(Sender: TObject);
begin
  MinDXFSize := 0;
end;

procedure TForm1.DrawTo(const ADest: TObject; const ADstRect: TRect;
  const ASource: TGraphic);
var
  vCanvas: TCanvas;
begin
  vCanvas := nil;
  if ADest is TCanvas then
    vCanvas := TCanvas(ADest)
  else
    if ADest is TBitmap then
      vCanvas := TBitmap(ADest).Canvas
    else
      if ADest is TMetafile then
        vCanvas := TMetafileCanvas.Create(TMetafile(ADest), 0)
      else
        if ADest is TPrinter then
        begin
          vCanvas := TPrinter(ADest).Canvas;
          TPrinter(ADest).BeginDoc;
        end
{$IFDEF CADExportVCL}
        else
          if ADest is TsgDXFExport then
            vCanvas := TsgDXFExport(ADest).Canvas
{$ENDIF};
  try
    if vCanvas <> nil then
      vCanvas.StretchDraw(ADstRect, ASource);
{$IFDEF CADExportVCL}
    if ADest is TsgDXFExport then
      TsgDXFExport(ADest).EndDraw;
{$ENDIF}
  finally
    if ADest is TMetafile then
      vCanvas.Free
    else
      if ADest is TPrinter then
        TPrinter(ADest).EndDoc;
  end;
end;

procedure TForm1.BtnSaveClick(Sender: TObject);
var
  I: Integer;
  vExt: string;
  vFormat: TsgExportFormat;
begin
  if not sgPaintBox.Empty then
  begin
    SavePictureDialog.FileName := ExtractFileName(OpenDialog1.FileName);
    if SavePictureDialog.Execute then
    begin
      I := SavePictureDialog.FilterIndex - 1;
      // first item is default extension
      vExt := AnsiLowerCase(TStrings(FSaveDialogFilter.Objects[I])[0]);
      vFormat := GetExportFormat(vExt);
      Save(Graphic, SavePictureDialog.FileName, vFormat);
    end;
  end;
end;

procedure TForm1.mmiDisabledClick(Sender: TObject);
begin
  if Assigned(Img) then
    Img.DrawMode := dmGray;
end;

procedure TForm1.mmiBlackClick(Sender: TObject);
begin
  if Assigned(Img) then
    Img.DrawMode := dmBlack;
end;

procedure TForm1.mmiNormalClick(Sender: TObject);
begin
  if Assigned(Img) then
    Img.DrawMode := dmNormal;
end;

procedure TForm1.SoftGoldHomePage1Click(Sender: TObject);
begin
  ShellExecute(Handle, 'open', 'www.cadsofttools.com', '', '', SW_SHOW);
end;

procedure TForm1.MIAboutClick(Sender: TObject);
begin
  ShowMessage('CAD Import VCL / CAD Export VCL demo version '+ #13#10 +
             'Please contact info@cadsofttools.com to order a full version');
end;

procedure TForm1.btnLayersClick(Sender: TObject);
begin
  if Assigned(Img) then
    LayersDialogExecute(Img, sgPaintBox);
end;

procedure TForm1.sgPaintBoxPaint(Sender: TObject);
var
  vLeftTop, vRightBottom: TPoint;
  vExt: TFRect;
  vBMPFrame: TBitmap;
  vImgRect, vPicRect: TRect;
  vPt: TPoint;
begin
  if Assigned(Img) and not Img.Empty then
  begin
    vExt := Img.Extents;
    vPicRect := sgPaintBox.PictureRect;
    if FSelectionMode = smEllipse then
    begin
      vLeftTop.X := Round((vPicRect.Right - vPicRect.Left) * (FTextBox.Left - vExt.Left) / (vExt.Right - vExt.Left)) + vPicRect.Left;
      vLeftTop.Y := Round((vPicRect.Bottom - vPicRect.Top) * (1 - (FTextBox.Top - vExt.Bottom) / (vExt.Top - vExt.Bottom))) + vPicRect.Top;
      vRightBottom.X := Round((vPicRect.Right - vPicRect.Left) *  (FTextBox.Right - vExt.Left) / (vExt.Right - vExt.Left)) + vPicRect.Left;
      vRightBottom.Y := Round((vPicRect.Bottom - vPicRect.Top) * (1 - (FTextBox.Bottom - vExt.Bottom) / (vExt.Top - vExt.Bottom))) + vPicRect.Top;
      sgPaintBox.Canvas.Pen.Color := clRed;
      sgPaintBox.Canvas.Brush.Style := bsClear;
      sgPaintBox.Canvas.Ellipse(vLeftTop.X - 10, vLeftTop.Y - 10, vRightBottom.X + 10, vRightBottom.Y + 10);
    end;
    if sbShowBorder.Enabled and sbShowBorder.Down then
    begin
      vBMPFrame := TBitmap.Create;
      try
        Graphic.Transparent := True;
        vBMPFrame.PixelFormat := pf8bit;
        vBMPFrame.Width := sgPaintBox.Width;
        vBMPFrame.Height := sgPaintBox.Height;
        vBMPFrame.Assign(imgFrame.Picture.Bitmap);

        // draw stretched border bitmap
        sgPaintBox.Canvas.StretchDraw(Rect(0, 0, sgPaintBox.Width, sgPaintBox.Height),
          vBMPFrame);

        FillChar(vImgRect, SizeOf(TRect), #0);
        vImgRect.Left := sgPaintBox.Width div 4;
        vImgRect.Top := sgPaintBox.Height div 4;
        vImgRect.Right := vImgRect.Left + sgPaintBox.Width div 2;
        vImgRect.Bottom := vImgRect.Top + sgPaintBox.Height div 2;
        // draw stretched CAD graphic
        sgPaintBox.Canvas.StretchDraw(sgPaintBox.PictureRect, Img);
      finally
        vBMPFrame.Free;
      end;
    end;
    if sbDrid.Down and (GridCount > 0) then
    begin
      if CreateLines(FIntPoints, Round(Img.AbsWidth*Img.Scale.X/GridCount),
        Round(Img.AbsWidth*Img.Scale.X),
        Round(Img.AbsHeight*Img.Scale.Y)) then
      begin
        sgPaintBox.Canvas.Pen.Color := clGray;
        OffsetViewportOrgEx(sgPaintBox.Canvas.Handle, vPicRect.Left, vPicRect.Top, vPt);
        DrawPolyPolyLine(sgPaintBox.Canvas.Handle, FIntPoints);
        SetViewportOrgEx(sgPaintBox.Canvas.Handle, vPt.X, vPt.Y, nil);
      end;
    end;
  end;
end;

procedure TForm1.sgPaintBoxPictureChange(Sender: TObject);
var
  S: string;
  R: TFRect;
begin
  if FGraphic <> sgPaintBox.Picture.Graphic then
  begin
    FGraphic := sgPaintBox.Picture.Graphic;
    if FGraphic is TsgCADImage then
      FImg := TsgCADImage(FGraphic)
    else
      FImg := nil;
  end;
  S := '';
  if Assigned(FImg) then
  begin
    R := FImg.Extents;
    S := Format('%.3f x %.3f x %.3f', [R.Right - R.Left, R.Top - R.Bottom, R.Z2 - R.Z1]);
  end
  else
    if Assigned(Graphic) then
      S := Format('%d x %d', [Graphic.Width, Graphic.Height]);
  pnlSize.Width := Canvas.TextWidth(S) + 4;
  pnlSize.Caption := S;
end;

procedure TForm1.sgPaintBoxMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var
  vPt: TFPoint;
  vUnits: string;
begin
  vPt := sgPaintBox.GetDrawingCoords(X, Y, vUnits);
  pnlCoords.Caption := Format('%.3f; %.3f; %.3f', [vPt.X, vPt.Y, vPt.Z]);
  if vUnits <> '' then
    pnlCoords.Caption := pnlCoords.Caption + ' (' + vUnits + ')';
end;

procedure TForm1.btnFitToScreenClick(Sender: TObject);
begin
  sgPaintBox.FitToSize;
  sgPaintBoxScaling(Self);
end;

procedure TForm1.btnIsWithoutBorderClick(Sender: TObject);
begin
  if Assigned(Img) then
    Img.IsWithoutBorder := not Img.IsWithoutBorder;
end;

procedure TForm1.btnShowLineWeightClick(Sender: TObject);
begin
  Img.IsShowLineWeight := btnShowLineWeight.Down;
end;

procedure TForm1.btnSplittedArcClick(Sender: TObject);
begin
  Img.UseWinEllipse := not btnSplittedArc.Down;
end;

procedure TForm1.btnDrawAllColorClick(Sender: TObject);
begin
  if btnDrawAllColor.Down then
    Img.DrawMode := dmNormal
  else
    Img.DrawMode := dmBlack;
end;

procedure TForm1.SetCADInfoVisible(const AVal: Boolean);
begin
  if csDestroying in pnlLayouts.ComponentState then Exit;
  cbLayouts.Visible := AVal;
  lblDridCount.Visible := AVal;
  lblLayouts.Visible := AVal;
  lblNumPartsCircle.Visible := AVal;
  lblNumPartsSpline.Visible := AVal;
  edtNumPartsCircle.Visible := AVal;
  edtNumPartsSpline.Visible := AVal;
  edtGridCount.Visible := AVal;
  udNumPartsCircle.Visible := AVal;
  udNumPartsSpline.Visible := AVal;
  udGridCount.Visible := AVal;
end;

procedure TForm1.SetGridCount(AValue: Integer);
begin
  udGridCount.Position := AValue;
  edtGridCount.Text := IntToStr(AValue);
end;

procedure TForm1.SetImgOpt;
begin
  btnShowLineWeightClick(nil);
  btnSplittedArcClick(nil);
  btnDrawAllColorClick(nil);
  btnWhiteBackgroundClick(nil);
end;

procedure TForm1.btnWhiteBackgroundClick(Sender: TObject);
begin
  sgPaintBox.BeginUpdate;
  try
    if btnWhiteBackground.Down then
    begin
      if Assigned(Img) then
      begin
        Img.BackgroundColor := clWhite;
        Img.DefaultColor := clBlack;
      end;
      sgPaintBox.Color := clWhite;
    end
    else
    begin
      if Assigned(Img) then
      begin
        Img.BackgroundColor := clBlack;
        Img.DefaultColor := clWhite;
      end;
      sgPaintBox.Color := clBlack;
    end;
  finally
    sgPaintBox.EndUpdate;
  end;
end;

procedure TForm1.sb3DAxesClick(Sender: TObject);
begin
  sb3DAxes.Down := sb3DAxes.Down or False;
  if sb3DAxes.Down then
    Img.IsDraw3DAxes := True
  else
    Img.IsDraw3DAxes := False;
  sgPaintBox.Invalidate;
end;


procedure TForm1.sb3DOrbitClick(Sender: TObject);
begin
  sb3DOrbit.Down := sb3DOrbit.Down or False;
  sgPaintBox.Orbit3D.Visible := sb3DOrbit.Down;
  sgPaintBox.Invalidate;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FOptions.Free;
  FIntPoints.Free;
  ClearFilterList(FSaveDialogFilter);
  FSaveDialogFilter.Free;
end;

procedure TForm1.BtnPrint2Click(Sender: TObject);
var
  P: TPoint;
begin
//  SysUtils.Win32Check(Windows.GetCursorPos(P));
  GetCursorPos(P);
  PopupMenu1.Popup(P.X, P.Y);
end;

procedure TForm1.mmiSaveAsBigEMFClick(Sender: TObject);
const
  cnstMaxEMFDim = 3276700;
{$IFDEF SGDEL_4}
var
  vM: TMetafile;
{$ENDIF}
begin
  if sgPaintBox.Empty or not Assigned(Img) then Exit;
  SavePictureDialogEMF.FileName := '*' + cnstEMFExt;
  if not SavePictureDialogEMF.Execute then Exit;
  if LowerCase(ExtractFileExt(SavePictureDialogEMF.FileName)) <> cnstEMFExt then
    SavePictureDialogEMF.FileName := ChangeFileExt(SavePictureDialogEMF.FileName, cnstEMFExt);
  {$IFNDEF SGDEL_4}
  Img.ExportToMetafile(SavePictureDialogEMF.FileName,
    cnstMaxEMFDim, Round(cnstMaxEMFDim * Img.AbsHeight / Img.AbsWidth));
  {$ELSE}
  vM := Img.ExportToMetafile(cnstMaxEMFDim);
  try
    vM.SaveToFile(SavePictureDialogEMF.FileName);   // this metafile can be opened in this viewer
  finally
    vM.Free;
  end;
  {$ENDIF}
end;

procedure TForm1.ViewLayouts;
var
  I: Integer;
begin
  if Assigned(Img) then
  begin
    sgPaintBox.BeginUpdate;
    try
      cbLayouts.Items.BeginUpdate;
      try
        cbLayouts.Items.Clear;
        for I := 0 to Img.LayoutsCount - 1 do
          cbLayouts.Items.AddObject(Img.Layouts[I].Name, Img.Layouts[I]);
        I := Img.Converter.DefaultLayoutIndex;
        if I >= Img.LayoutsCount then
          I := 0;
        cbLayouts.ItemIndex := I;
        Img.CurrentLayout := Img.Layouts[I];
      finally
        cbLayouts.Items.EndUpdate;
      end;
      pnlLayouts.Visible := cbLayouts.Items.Count > 0;
      Enable3DAxes(Img.CurrentLayout.CADSpace <> csUndefined);
      Enable3DOrbit(Img.CurrentLayout.CADSpace <> csUndefined);
      SetCADInfoVisible(True);
    finally
      sgPaintBox.EndUpdate;
    end;
  end;
end;

procedure TForm1.Enable3DAxes(AIsEnabled: Boolean);
begin
  sb3DAxes.Down := False;
  sb3DAxes.Enabled := AIsEnabled;
  if AIsEnabled = False then
    Img.IsDraw3DAxes := AIsEnabled;
end;

procedure TForm1.Enable3DOrbit(AIsEnabled: Boolean);
begin
  sb3DOrbit.Down := False;
  sb3DOrbit.Enabled := AIsEnabled;
end;

procedure TForm1.cbLayoutsChange(Sender: TObject);
begin
  if cbLayouts.Items.Objects[cbLayouts.ItemIndex] <> nil then
  begin
    sgPaintBox.BeginUpdate;
    try
      Img.CurrentLayout := Img.Layouts[cbLayouts.ItemIndex];
      sbDrawingBoxClick(nil);
      Enable3DAxes(Img.CurrentLayout.CADSpace <> csUndefined);
      Enable3DOrbit(Img.CurrentLayout.CADSpace <> csUndefined);
    finally
      sgPaintBox.EndUpdate;
    end;
  end;
end;

procedure TForm1.pgcDrawingChange(Sender: TObject);
begin
  if TreeView1.Items.Count = 0 then
    LoadStructure;
  if Assigned(pgcDrawing.ActivePage) and (pgcDrawing.ActivePage.PageIndex = 0) then
    pnlFileName.Caption := ExtractFileName(FFileName);
end;

procedure TForm1.speNumPartsCircleChange(Sender: TObject);
var
  vVal: Integer;
begin
  vVal := NumPartsCircle;
  if vVal >= iMinNumberOfPart then
  begin
    sgConsts.SetNumberOfCircleParts(vVal);
    if Assigned(Img) then
      Img.Converter.NumberOfPartsInCircle := sgConsts.GetNumberOfCircleParts;
    sgPaintBox.Refresh;
  end
  else
    NumPartsCircle := iMinNumberOfPart;
end;

procedure TForm1.speNumPartsSplineChange(Sender: TObject);
var
  vVal: Integer;
begin
  vVal := NumPartsSpline;
  if vVal >= iMinNumberOfPart then
  begin
    sgConsts.SetNumberOfSplineParts(vVal);
    if Assigned(Img) then
      Img.Converter.NumberOfPartsInSpline := sgConsts.GetNumberOfSplineParts;
    sgPaintBox.Refresh;
  end
  else
    NumPartsSpline := iMinNumberOfPart;
end;

function TForm1.StartPrint(const ATitle: string): Boolean;
begin
  Result := False;
  if Assigned(Graphic) then
  begin
    Printer.Orientation := cnstPrnOrient[Graphic.Width > Graphic.Height];
    Result := PrintDialog1.Execute;
    if Result then
    begin
      SetNullWidth(Graphic, 3);
      Printer.Title := ATitle;
    end;
  end;
end;

procedure TForm1.mmiShowpointClick(Sender: TObject);
var
  Form2: TForm2;
begin
  Form2 := TForm2.Create(Self);
  try
    Form2.ShowModal;
  finally
    Form2.Free;
  end;
end;

procedure TForm1.mmiFindtextClick(Sender: TObject);
var
  Form3: TForm3;
begin
  Form3 := TForm3.Create(Self);
  try
    Form3.ShowModal;
  finally
    Form3.Free;
  end;
end;

procedure TForm1.mmiReopenSameViewClick(Sender: TObject);
var
  vFPoint: TFPoint;
  vRect: TRect;
  vScale: Extended;
  vLayoutName, vUnits, vFileName: String;
begin
  if Assigned(Img) then
  begin
    sgPaintBox.BeginUpdate;
    try
      vLayoutName := Img.CurrentLayout.Name;
      vRect := sgPaintBox.ClientRect;
      vFPoint := sgPaintBox.GetDrawingCoords((vRect.Left + vRect.Right) div 2,
        (vRect.Top + vRect.Bottom) div 2, vUnits);
      vScale := sgPaintBox.Scale;
      vFileName := FFileName;
      MICloseClick(Self);
      Open(vFileName);
      Img.CurrentLayout := TsgDXFLayout(Img.Converter.Sections[csLayouts].FindEntByName(vLayoutName));
      sgPaintBox.ShowPoint(vFPoint, vScale);
    finally
      sgPaintBox.EndUpdate;
    end;
  end
  else
    ShowMessage(cnstNotCAD);
end;

procedure TForm1.miFontsClick(Sender: TObject);
begin
  if FontsOptionsExecute(FOptions, Form1) and (FFileName <> '') then
    Open(FFileName)
  else
    sgPaintBox.Invalidate;
end;

procedure TForm1.speGridCountChange(Sender: TObject);
begin
//  sgPaintBox.Picture.Graphic.Transparent := not sbDrid.Down;
  sgPaintBox.Invalidate;
end;

procedure TForm1.sbDridClick(Sender: TObject);
begin
  speGridCountChange(nil);
end;

procedure TForm1.sbDrawingBoxClick(Sender: TObject);
var
  vBox: TFRect;
begin
  if Img = nil then Exit;
  sgPaintBox.BeginUpdate;
  try
    sbDrawingBox.Down := sbDrawingBox.Down or False;
    Enable3DOrbit(not sbDrawingBox.Down);
    if sbDrawingBox.Down then
    begin
      vBox := Img.CurrentLayout.Box;
      Img.DrawingBox := MakeFRect((vBox.Left + vBox.Right) / 2,
        vBox.Top, vBox.Z1, vBox.Right, vBox.Bottom, vBox.Z2)
    end
    else
      Img.ResetDrawingBox;
  finally
    sgPaintBox.EndUpdate;
  end;
end;

procedure TForm1.mmiReopenSWIsometricClick(Sender: TObject);
var
  vLayoutName, vFileName: String;
begin
  if Assigned(Img) then
  begin
    sgPaintBox.BeginUpdate;
    try
      vLayoutName := Img.CurrentLayout.Name;
      if FFileName = '' then Exit;
      vFileName := FFileName;
      MICloseClick(Self);
      Open(vFileName);
      Img.CurrentLayout := TsgDXFLayout(Img.Converter.Sections[csLayouts].FindEntByName(vLayoutName));
      if Img.CurrentLayout.CADSpace = cs3D then
      begin
        Img.RotToView(vdTop);
        Img.Rotate(AxisZ, 45);
        Img.Rotate(AxisX, -54.735610317245345684622999669981);
      end
      else ShowMessage('The current layout of this file is not model. This operation does not work.');
    finally
      sgPaintBox.EndUpdate;
    end;
  end
  else ShowMessage(cnstNotCAD);
end;

procedure TForm1.sbShowBorderClick(Sender: TObject);
begin
  if sbShowBorder.Down then
  begin
    if OpenBorder.Execute then
    begin
      imgFrame.Picture.LoadFromFile(OpenBorder.FileName);
      sb3DOrbit.Enabled := False;
      sb3DAxes.Enabled := False;
    end
    else
    begin
      sbShowBorder.Down := False;
      sb3DOrbit.Enabled := True;
      sb3DAxes.Enabled := True;
      Graphic.Transparent := False;
    end;
  end
  else
  begin
    if not imgFrame.Picture.Bitmap.Empty then
      imgFrame.Picture.Graphic := nil;
    Graphic.Transparent := False;
    sb3DOrbit.Enabled := True;
    sb3DAxes.Enabled := True;
  end;
  sgPaintBox.Invalidate;
end;


procedure TForm1.mmiObjectSnapAllClick(Sender: TObject);
begin
  {$IFDEF SGDEL_4}
  mmiObjectSnapAll.Checked := not mmiObjectSnapAll.Checked;
  //Object Snap. Snap mode setup
  if mmiObjectSnapAll.Checked then
    sgPaintBox.SnapControl.SnapMask := cnstSnapMaskAll
  else
    sgPaintBox.SnapControl.SnapMask := cnstSnapMaskNone;
  {$ENDIF}
end;

function TForm1.GetCADImage: TsgCADImage;
begin
  Result := FImg;
end;

function TForm1.GetGraphic: TGraphic;
begin
  Result := FGraphic;
end;

function TForm1.GetGridCount: Integer;
begin
  Result := StrToIntDef(edtGridCount.Text, cnstDefGridCount);
end;

function TForm1.GetNumPartsCircle: Integer;
begin
  Result := StrToIntDef(edtNumPartsCircle.Text, sgConsts.GetNumberOfCircleParts);
end;

function TForm1.GetNumPartsSpline: Integer;
begin
  Result := StrToIntDef(edtNumPartsSpline.Text, sgConsts.GetNumberOfSplineParts);
end;

procedure TForm1.actFormUpdate(Sender: TObject);
begin
  EnableControls;
end;

{$IFNDEF SGDEL_4}
procedure TForm1.UpdateActions;
var
  I: Integer;

  procedure TraverseClients(Container: TWinControl);
  var
    I: Integer;
    Control: TControl;
  begin
    if Container.Showing then
      for I := 0 to Container.ControlCount - 1 do
      begin
        Control := Container.Controls[I];
        if Control.Visible then
            Control.Update;
        if Control is TWinControl then
          TraverseClients(TWinControl(Control));
      end;
  end;

begin
  if (csDesigning in ComponentState) or not Showing then Exit;
  { Update form }
  Update;
  { Update main menu's top-most items }
  if Menu <> nil then
    for I := 0 to Menu.Items.Count - 1 do
        if Menu.Items[I].Visible then Update;
  { Update any controls }
  TraverseClients(Self);
  actFormUpdate(nil);
end;

procedure TForm1.DoActionIdle;
var
  I: Integer;
begin
  for I := 0 to Screen.CustomFormCount - 1 do
    if Screen.CustomForms[I].HandleAllocated and
       IsWindowVisible(Screen.CustomForms[I].Handle) and
       IsWindowEnabled(Screen.CustomForms[I].Handle) then
      UpdateActions;
end;

{$ENDIF}

procedure TForm1.WndProc(var Message: TMessage);
begin
  inherited;
  {$IFNDEF SGDEL_4}
  DoActionIdle;
  {$ENDIF}
end;

procedure TForm1.AppIdle(Sender: TObject; var Done: Boolean);
begin
  {$IFNDEF SGDEL_4}
  DoActionIdle;
  {$ENDIF}
end;

procedure TForm1.BtnRealClick(Sender: TObject);
begin
  sgPaintBox.Scale := 1.0;
  BtnReal.Enabled := False;
end;

procedure TForm1.mmiScaleClick(Sender: TObject);
begin
  sgPaintBox.Scale := TComponent(Sender).Tag / 100.0;
end;

end.
