unit sgSManager;

interface

uses Windows, Messages, Classes, Controls, sgConsts, Graphics, SysUtils,
     Dialogs, Forms, DXFImage, DXFConv, sgDrawingNavigator, sgSelection;

const
  BoxSize = 4;
  CursorRad = 5;
  SM_SELECTIONCHANGED = WM_USER + 2000;
type
  TsgManagerMode = (mmSelect, mmMultiSelect);

  TsgSelectionManager = class(TObject)
  private
    FDNavigator: TsgDrawingNavigator;
    FImg: TsgDXFImage;
    FConverter: TsgDXFConverter;
    FDownPoint: TPoint;
    FCurPoint: TPoint;
    FSelection: Boolean;
    FMode: TsgManagerMode;
    FEntities: TList;
    FSChanged: Boolean;
    FDraging: Boolean;
    FStartPoint: TPoint;
    FOnMouseDownOld: TMouseEvent;
    FOnMouseMoveOld: TMouseMoveEvent;
    FOnMouseUpOld: TMouseEvent;
    FOnImagePaint: TNotifyEvent;
    procedure SetImage(const Value: TsgDrawingNavigator);
    procedure DrawSelection;
    procedure ClearSelection;
    procedure AddEntities(NewEntities: TList; Shift: TShiftState);
    function FindEntities(ARect: TRect): TList;
    function GetRect(const ARect: TFRect): TRect;
    function GetRectByEntity(const AEntity: TsgDXFEntity): TRect;
    function IsEntityInRect(Entity: TsgDXFEntity; Rect: TRect): Boolean;
    function InList(AnEntity: TsgDXFEntity): Integer;
    function CheckList(NewEntities: TList; Shift: TShiftState): Boolean;
    function CheckListEnt(NewEntity: TsgDXFEntity; Shift: TShiftState): Boolean;
  protected
    procedure ImageMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure ImageMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure ImageMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure ImagePaint(Sender: TObject);
 public
    constructor Create;
    destructor Destroy; override;
    function FindEntity(const Point: TPoint): TsgDXFEntity;
    procedure Cancel;
    procedure ZoomSelected(const AParentWidth, AParentHeight: Double);
    procedure SelectAll;
    procedure DeselectAll;
    property Entities: TList read FEntities;
    property DNavigator: TsgDrawingNavigator read FDNavigator write SetImage;
    property Mode: TsgManagerMode read FMode write FMode;
    property SelectedEntities: TList read FEntities;
  end;

procedure DrawFrame(AHDC: HDC; const ARect: TRect);

implementation

uses fEntityInspector, fMain;

const
  cnstClassesEntityCount = 7;
  cnsrClassesEntity: array [0..cnstClassesEntityCount - 1] of TClass = (TsgDXFSpline,
    TsgDXFEllipse, TsgDXFCircle, TsgDXFPolyline, TsgDXFSolid, TsgDXFLine, TsgDXFCustomVertex);

type
  TsgDXFImageAccess = class(TsgDXFImage);
  TsgEntType = (etNone, etSpline, etEllipse, etCircle, etPolyline, etSolid, etLine, etCustomVertex);

procedure ExpandRect(var Rect: TRect; const P: TPoint);
begin
  if Rect.Left > P.X then
    Rect.Left := P.X;
  if Rect.Top > P.Y then
    Rect.Top := P.Y;
  if Rect.Right < P.X then
    Rect.Right := P.X;
  if Rect.Bottom < P.Y then
    Rect.Bottom := P.Y;
end;

procedure DrawFrame(AHDC: HDC; const ARect: TRect);
var
  Width, Height: Integer;
begin
  Width := ARect.Right - ARect.Left;
  Height := ARect.Bottom - ARect.Top;
  PatBlt(AHDC, ARect.Left, ARect.Top, Width, 1, PATINVERT);
  PatBlt(AHDC, ARect.Left + Width - 1, ARect.Top + 1, 1,
    Height - 2, PATINVERT);
  PatBlt(AHDC, ARect.Left, ARect.Top + Height - 1, Width, 1,
    PATINVERT);
  PatBlt(AHDC, ARect.Left, ARect.Top + 1, 1, Height - 2, PATINVERT);
end;

function GetEntityType(const AEntity: TsgDXFEntity): TsgEntType;
var
  I: Integer;
begin
  I := 0;
  while (I < cnstClassesEntityCount) and (not (AEntity is cnsrClassesEntity[I])) do
    Inc(I);
  case I of
    0:  Result := etSpline;
    1:  Result := etEllipse;
    2:  Result := etCircle;
    3:  Result := etPolyline;
    4:  Result := etSolid;
    5:  Result := etLine;
    6:  Result := etCustomVertex;
  else
    Result := etNone;
  end;
end;

function TsgSelectionManager.FindEntity(const Point: TPoint): TsgDXFEntity;
begin
  Result := TsgDXFEntity(SelectionMatrix.Matrix[Point.X, Point.Y]);
end;

function TsgSelectionManager.FindEntities(ARect: TRect): TList;
  procedure ChangeRectBounds(var ARect: TRect);
  var
    Temp: Integer;
  begin
    if ARect.Right < ARect.Left then
    begin
      Temp := ARect.Left;
      ARect.Left := ARect.Right;
      ARect.Right := Temp;
    end;
    if ARect.Bottom < ARect.Top then
    begin
      Temp := ARect.Top;
      ARect.Top := ARect.Bottom;
      ARect.Bottom := Temp;
    end;
  end;
var
  I: Integer;
begin
  ChangeRectBounds(ARect);
  Result := TList.Create;
  for I := FConverter.Counts[csEntities] - 1 downto 0 do
    if IsEntityInRect(FConverter.Entities[I], ARect) then
      if (FConverter.Entities[I] is TsgDXFLine) or (FConverter.Entities[I] is TsgDXFPolyLine) or
        (FConverter.Entities[I] is TsgDXFText) or (FConverter.Entities[I] is TsgDXFInsert) then
        Result.Add(FConverter.Entities[I]);
end;

function TsgSelectionManager.GetRect(const ARect: TFRect): TRect;
  procedure ExpRect(const X, Y, Z: TsgFloat);
  begin
    ExpandRect(Result, FImg.GetPoint(MakeFPoint(X, Y, Z)));
  end;
begin
  Result := cnstBad2DRect;
  if FImg <> nil then
  begin
    ExpRect(ARect.Left, ARect.Top, ARect.Z1);
    ExpRect(ARect.Left, ARect.Top, ARect.Z2);
    ExpRect(ARect.Left, ARect.Bottom, ARect.Z1);
    ExpRect(ARect.Left, ARect.Bottom, ARect.Z2);
    ExpRect(ARect.Right, ARect.Top, ARect.Z1);
    ExpRect(ARect.Right, ARect.Top, ARect.Z2);
    ExpRect(ARect.Right, ARect.Bottom, ARect.Z1);
    ExpRect(ARect.Right, ARect.Bottom, ARect.Z2);
  end;
end;

function TsgSelectionManager.GetRectByEntity(const AEntity: TsgDXFEntity): TRect;
begin
  Result := GetRect(AEntity.Box);
  InflateRect(Result, BoxSize, BoxSize);
end;

function TsgSelectionManager.IsEntityInRect(Entity: TsgDXFEntity; Rect: TRect): Boolean;
var
  vTL, vBR: TPoint;
begin
  Result := False;
  if IsBadRect(Entity.Box) then
    Exit;
  vTL := FImg.GetPoint(Entity.Box.TopLeft);
  vBR := FImg.GetPoint(Entity.Box.BottomRight);
  Result :=  PtInRect(Rect, vTL) and PtInRect(Rect, vBR);
end;

procedure TsgSelectionManager.SetImage(const Value: TsgDrawingNavigator);
begin
  if FDNavigator = Value then
  begin
    if Assigned(FDNavigator) then
    begin
      FImg := TsgDXFImage(FDNavigator.Picture.Graphic);
      FConverter := FImg.Converter;
      if FDNavigator.Picture.Graphic is TsgDXFImage then
        fmEntityInspector.Load(FDNavigator);
    end;
  end
  else
  begin
    if Assigned(FDNavigator) then
    begin
      FDNavigator.OnMouseDown := FOnMouseDownOld;
      FDNavigator.OnMouseMove := FOnMouseMoveOld;
      FDNavigator.OnMouseUp := FOnMouseUpOld;
      FDNavigator.OnPaint := FOnImagePaint;
    end;
    FDNavigator := Value;
    if Assigned(FDNavigator) then
    begin
      FDNavigator.RectZooming := False;

      FOnMouseDownOld := Value.OnMouseDown;
      FOnMouseMoveOld := Value.OnMouseMove;
      FOnMouseUpOld := Value.OnMouseUp;
      FOnImagePaint := Value.OnPaint;

      FDNavigator.OnMouseDown := ImageMouseDown;
      FDNavigator.OnMouseMove := ImageMouseMove;
      FDNavigator.OnMouseUp := ImageMouseUp;
      FDNavigator.OnPaint := ImagePaint;
      FImg := TsgDXFImage(FDNavigator.Picture.Graphic);
      FConverter := FImg.Converter;
      if FDNavigator.Picture.Graphic is TsgDXFImage then
        fmEntityInspector.Load(FDNavigator);
    end;
  end;
end;

procedure TsgSelectionManager.ImageMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button <> mbLeft then Exit;
  FDownPoint := Point(X, Y);
  FCurPoint := FDownPoint;
  FSelection := True;
  if FMode = mmMultiSelect then
    DrawFrame(FDNavigator.Canvas.Handle, Rect(FDownPoint.x, FDownPoint.y, FDownPoint.x, FDownPoint.y));
  FStartPoint.X := X;
  FStartPoint.Y := Y;
  if (FEntities.Count > 0) and (FMode <> mmMultiSelect) then
    FDraging := True;
  if Assigned(FOnMouseDownOld) then
    FOnMouseDownOld(Sender, Button, Shift, X, Y);
end;

procedure TsgSelectionManager.ImageMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
var
  vRect: TRect;
begin
  if FSelection then
  begin
    case FMode of
      mmMultiSelect:
      begin
        vRect.TopLeft := FDownPoint;
        vRect.BottomRight := FCurPoint;
        DrawFrame(FDNavigator.Canvas.Handle, vRect);
        FCurPoint := Point(X, Y);
        vRect.BottomRight := FCurPoint;
        DrawFrame(FDNavigator.Canvas.Handle, vRect);
      end;
    end;
  end;
  if Assigned(FOnMouseMoveOld) then
    FOnMouseMoveOld(Sender, Shift, X, Y);
end;

procedure TsgSelectionManager.ImageMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  vRect, vInvRectPrev, vInvRectNew: TRect;
  Pos: Integer;
  I, J: Integer;
  vCurrentPoint: TFPoint;
  vLatsPoint: TFPoint;

  FSelectedObject: TsgDXFEntity;
  vPoly: TsgDXFPolyline absolute FSelectedObject;
  vLine: TsgDXFLine absolute FSelectedObject;
  vSolid: TsgDXFSolid absolute FSelectedObject;
  vSpline: TsgDXFSpline absolute FSelectedObject;
  vEntType: TsgEntType;

  function MovePoint(const APoint: TFPoint): TFPoint;
  begin
    Result.X := APoint.X + vCurrentPoint.X;
    Result.Y := APoint.Y + vCurrentPoint.Y;
    Result.Z := APoint.Z + vCurrentPoint.Z;
  end;

begin
  if Button <> mbLeft then Exit;
  FSelectedObject := nil;
  if (FStartPoint.X = X) and (FStartPoint.Y = Y) then
  begin
    ClearSelection;
    FSChanged := False;
    if FSelection then
    begin
      case FMode of
        mmSelect:
        begin
          FSChanged := CheckListEnt(FindEntity(Point(X, Y)), Shift);
          if not (ssShift in Shift) then
            FEntities.Clear;
          FSelectedObject := FindEntity(Point(X, Y));
          if FSelectedObject <> nil then
          begin
            Pos := InList(FSelectedObject);
            if Pos < 0 then
              FEntities.Add(FSelectedObject)
            else
            begin
              FSChanged := False;
              if ssShift in Shift then
              begin
                FEntities.Delete(Pos);
                FEntities.Capacity := FEntities.Capacity - 1;
                FSChanged := True;
              end;
            end;
          end;
        end;
      end;
      DrawSelection;
      {if FSChanged then
        SendMessage(FDNavigator.Parent.Parent.Handle, SM_SELECTIONCHANGED, 0, 0);}
      FSChanged := False;
      FSelection := False;
    end;
  end;
  if FMode = mmMultiSelect then
  begin
    ClearSelection;
    vRect.TopLeft := FDownPoint;
    vRect.BottomRight := FCurPoint;
    DrawFrame(FDNavigator.Canvas.Handle, vRect);
    AddEntities(FindEntities(vRect), Shift);
    DrawSelection;
    FSelection := False;
  end;
  if FDraging then
  begin
    vLatsPoint := FDNavigator.GetDrawingInternalCoordsWithoutSnap(FStartPoint.X, FStartPoint.Y);
    vCurrentPoint := FDNavigator.GetDrawingInternalCoordsWithoutSnap(X, Y);
    vCurrentPoint.X := vCurrentPoint.X - vLatsPoint.X;
    vCurrentPoint.Y := vCurrentPoint.Y - vLatsPoint.Y;
    vCurrentPoint.Z := vCurrentPoint.Z - vLatsPoint.Z;
    FDraging := False;
    vInvRectPrev := cnstBad2DRect;
    vInvRectNew := cnstBad2DRect;
    for J := 0 to FEntities.Count - 1 do
    begin
      FSelectedObject := TsgDXFEntity(FEntities[J]);
      UnionRect(vInvRectPrev, vInvRectPrev, GetRectByEntity(FSelectedObject));
      vEntType := GetEntityType(FSelectedObject);
      case vEntType of
        etSpline:
          begin
            for I := 0 to vSpline.ControlCount - 1 do
              PFPoint(vSpline.Controls[I])^ := MovePoint(vSpline.ControlPoints[I]);
          end;
        etEllipse, etCircle:
          TsgDXFEllipse(FSelectedObject).Point := MovePoint(TsgDXFEllipse(FSelectedObject).Point);
        etPolyline:
          begin
            for I := 0 to vPoly.Count - 1 do
              TsgDXFVertex(vPoly.Entities[I]).Point := MovePoint(TsgDXFVertex(vPoly.Entities[I]).Point);
          end;
        etSolid:
          begin
            vSolid.Point := MovePoint(vSolid.Point);
            vSolid.Point1 := MovePoint(vSolid.Point1);
            vSolid.Point2 := MovePoint(vSolid.Point2);
            vSolid.Point3 := MovePoint(vSolid.Point3);
          end;
        etLine:
          begin
            vLine.Point := MovePoint(vLine.Point);
            vLine.Point1 := MovePoint(vLine.Point1);
          end;
        etCustomVertex:// INSERT, DIMENSION, TEXT, MTEXT
          begin
            TsgDXFCustomVertex(FSelectedObject).Point := MovePoint(TsgDXFCustomVertex(FSelectedObject).Point);
            //if vText.HasSecond then// if TEXT
            //  vText.Point1 := MovePoint(vText.Point1);
          end;
      else
        Continue;  
      end;
      FConverter.Loads(FSelectedObject);
      UnionRect(vInvRectNew, vInvRectNew, GetRectByEntity(FSelectedObject));
    end;
    InvalidateRect(FDNavigator.Handle, @vInvRectPrev, True);
    InvalidateRect(FDNavigator.Handle, @vInvRectNew, True);
    FSelection := False;
  end;

  if FEntities.Count>1 then FSelectedObject := nil;
  fmEntityInspector.RefreshGrid(FSelectedObject);

  if FEntities.Count = 0 then
    FSelection := False;
  if Assigned(FOnMouseUpOld) then
    FOnMouseUpOld(Sender, Button, Shift, X, Y);
end;

procedure TsgSelectionManager.ClearSelection;
var
  I: Integer;
  vRect: TRect;
begin
  for I := 0 to FEntities.Count - 1 do
  begin
    vRect := GetRectByEntity(TsgDXFEntity(FEntities[I]));
    InvalidateRect(FDNavigator.Handle, @vRect, True);
  end;
end;

procedure TsgSelectionManager.DrawSelection;
var
  I, J: Integer;
  vRect: TRect;
  vLeft, vRight: TPoint;
  vBlockBorder: TRect;
  Cl: TColor;
  vEnt: TsgDXFEntity;

  procedure DrawMarker(APoint: TPoint);
  var
    vPrevWidth: Integer;
  begin
    vPrevWidth := FDNavigator.Canvas.Pen.Width;
    FDNavigator.Canvas.Pen.Width := 1;
    vRect.Top := APoint.Y + BoxSize;
    vRect.Left := APoint.X - BoxSize;
    vRect.Bottom := APoint.Y - BoxSize;
    vRect.Right := APoint.X + BoxSize;
    FDNavigator.Canvas.Rectangle(vRect.Left, vRect.Top, vRect.Right, vRect.Bottom);
    FDNavigator.Canvas.Pen.Width := vPrevWidth;
  end;

begin
  for I := 0 to FEntities.Count - 1 do
  begin
    vEnt:= TsgDXFEntity(FEntities[I]);
    if vEnt is TsgDXFPoint then
      DrawMarker(FImg.GetPoint(TsgDXFPoint(vEnt).Point));
    if vEnt is TsgDXFLine then
    begin
      DrawMarker(FImg.GetPoint(TsgDXFLine(vEnt).Point));
      DrawMarker(FImg.GetPoint(TsgDXFLine(vEnt).Point1));
    end;
    if vEnt is TsgDXFSolid then
    begin
      DrawMarker(FImg.GetPoint(TsgDXFSolid(vEnt).Point2));
      DrawMarker(FImg.GetPoint(TsgDXFSolid(vEnt).Point3));
    end;
    if vEnt is TsgDXFPolyLine then
      for J := 0 to TsgDXFPolyLine(vEnt).PolyPoints.Count - 1 do
        DrawMarker(FImg.GetPoint(TsgDXFPolyLine(vEnt).Points[J]));
    if (vEnt is TsgDXFText) or (TsgDXFEntity(vEnt) is TsgDXFMText) then
    begin
      vLeft := FImg.GetPoint(vEnt.Box.TopLeft);
      vRight := FImg.GetPoint(vEnt.Box.BottomRight);
      DrawMarker(vLeft);
      DrawMarker(vRight);
      vRect.Top := vRight.Y + BoxSize;
      vRect.Left := vLeft.X - BoxSize;
      vRect.Bottom := vRight.Y - BoxSize;
      vRect.Right := vLeft.X + BoxSize;
      FDNavigator.Canvas.Rectangle(vRect.Left, vRect.Top, vRect.Right, vRect.Bottom);
      vRect.Top := vLeft.Y + BoxSize;
      vRect.Bottom := vLeft.Y - BoxSize;
      vRect.Left := vRight.X - BoxSize;
      vRect.Right := vRight.X + BoxSize;
      FDNavigator.Canvas.Rectangle(vRect.Left, vRect.Top, vRect.Right, vRect.Bottom);
      vRect.Top := vLeft.Y + BoxSize;
      vRect.Bottom := vLeft.Y - BoxSize;
      vRect.Left := vLeft.X + (vRight.X - vLeft.X) div 2 - BoxSize;
      vRect.Right := vLeft.X + (vRight.X - vLeft.X) div 2 + BoxSize;
      FDNavigator.Canvas.Rectangle(vRect.Left, vRect.Top, vRect.Right, vRect.Bottom);
      vRect.Top := vRight.Y + BoxSize;
      vRect.Bottom := vRight.Y - BoxSize;
      vRect.Left := vLeft.X + (vRight.X - vLeft.X) div 2 - BoxSize;
      vRect.Right := vLeft.X + (vRight.X - vLeft.X) div 2 + BoxSize;
      FDNavigator.Canvas.Rectangle(vRect.Left, vRect.Top, vRect.Right, vRect.Bottom);
      vRect.Top := vRight.Y + (vLeft.Y - vRight.Y) div 2 + BoxSize;
      vRect.Bottom := vRight.Y + (vLeft.Y - vRight.Y) div 2 - BoxSize;
      vRect.Left := vLeft.X - BoxSize;
      vRect.Right := vLeft.X + BoxSize;
      FDNavigator.Canvas.Rectangle(vRect.Left, vRect.Top, vRect.Right, vRect.Bottom);
      vRect.Top := vRight.Y + (vLeft.Y - vRight.Y) div 2 + BoxSize;
      vRect.Bottom := vRight.Y + (vLeft.Y - vRight.Y) div 2 - BoxSize;
      vRect.Left := vRight.X - BoxSize;
      vRect.Right := vRight.X + BoxSize;
      FDNavigator.Canvas.Rectangle(vRect.Left, vRect.Top, vRect.Right, vRect.Bottom);
    end
    else
      if vEnt is TsgDXFInsert then
      begin
        vBlockBorder.TopLeft := FImg.GetPoint(vEnt.Box.TopLeft);
        vBlockBorder.BottomRight := FImg.GetPoint(vEnt.Box.BottomRight);
        Cl := FDNavigator.Canvas.Pen.Color;
        try
          FDNavigator.Canvas.Pen.Color := clRed;
          FDNavigator.Canvas.MoveTo(vBlockBorder.Left, vBlockBorder.Bottom);
          FDNavigator.Canvas.LineTo(vBlockBorder.Right, vBlockBorder.Bottom);
          FDNavigator.Canvas.LineTo(vBlockBorder.Right, vBlockBorder.Top);
          FDNavigator.Canvas.LineTo(vBlockBorder.Left, vBlockBorder.Top);
          FDNavigator.Canvas.LineTo(vBlockBorder.Left, vBlockBorder.Bottom);
        finally
          FDNavigator.Canvas.Pen.Color := Cl;
        end;
      end;
  end;
end;

procedure TsgSelectionManager.AddEntities(NewEntities: TList; Shift: TShiftState);
var
  I: Integer;
begin
  FSChanged := CheckList(NewEntities, Shift);
  if not (ssShift in Shift) then
    FEntities.Clear;
  for I := 0 to NewEntities.Count - 1 do
    if InList(NewEntities[I]) < 0 then
      FEntities.Add(NewEntities[I]);
  NewEntities.Free;
end;

procedure TsgSelectionManager.ImagePaint(Sender: TObject);
begin
  DrawSelection;
  if Assigned(FOnImagePaint) then
    FOnImagePaint(Sender);
end;

procedure TsgSelectionManager.Cancel;
begin
  ClearSelection;
  FEntities.Clear;
  DrawSelection;
  fmEntityInspector.Clear;
end;

procedure TsgSelectionManager.SelectAll;
var
  I: Integer;
begin
  ClearSelection;
  if FEntities.Count <> FConverter.Counts[csEntities] then
    FSChanged := True
  else
    FSChanged := False;
  for I := 0 to FConverter.Counts[csEntities] - 1 do
    if (FConverter.Entities[I] is TsgDXFLine) or (FConverter.Entities[I] is TsgDXFPolyLine) or
      (FConverter.Entities[I] is TsgDXFText) or (FConverter.Entities[I] is TsgDXFMText) then
      FEntities.Add(FConverter.Entities[I]);
  DrawSelection;
  {if FSChanged then
    SendMessage(FDNavigator.Parent.Parent.Handle, SM_SELECTIONCHANGED, 0, 0);}
  FSChanged := False;
end;

procedure TsgSelectionManager.DeselectAll;
//var vBlockBorder: TFRect;
begin
  ClearSelection;
  if FEntities.Capacity <> 0 then
    FSChanged := True
  else
    FSChanged := False;
  FEntities.Clear;
  {vBlockBorder := FSelectedObject.Box;
  InvalidateRect(FDNavigator.Parent.Handle, @vBlockBorder, False);
  if FSChanged then
    SendMessage(FDNavigator.Parent.Parent.Handle, SM_SELECTIONCHANGED, 0, 0); }
  FSChanged := False;
  DrawSelection;
end;

function TsgSelectionManager.InList(AnEntity: TsgDXFEntity): Integer;
var
  I: Integer;
begin
  Result := -1;
  for I := 0 to FEntities.Count - 1 do
    if AnEntity = FEntities[I] then
    begin
      Result := I;
      Break;
    end;
end;

function TsgSelectionManager.CheckList(NewEntities: TList; Shift: TShiftState): Boolean;
var
  I: Integer;
begin
  Result := False;
  if NewEntities.Capacity = 0 then
  begin
    if (FEntities.Capacity <> 0) and (not(ssShift in Shift)) then
      Result := True;
  end
  else
  begin
    for I := 0 to NewEntities.Count - 1 do
      if InList(NewEntities[I]) < 0 then
        Result := True;
  end;
end;

function TsgSelectionManager.CheckListEnt(NewEntity: TsgDXFEntity; Shift: TShiftState): Boolean;
begin
  Result := False;
  if NewEntity = nil then
  begin
    if (FEntities.Capacity <> 0) and (not(ssShift in Shift)) then
      Result := True;
  end
  else
  begin
    if InList(NewEntity) < 0 then
        Result := True;
  end;
end;

constructor TsgSelectionManager.Create;
begin
  FEntities := TList.Create;
end;

destructor TsgSelectionManager.Destroy;
begin
  if FDNavigator <> nil then
  begin
    FDNavigator.OnMouseDown := FOnMouseDownOld;
    FDNavigator.OnMouseMove := FOnMouseMoveOld;
    FDNavigator.OnMouseUp := FOnMouseUpOld;
    FDNavigator.OnPaint := FOnImagePaint;
  end;
  FEntities.Free;
  inherited Destroy;
end;

procedure TsgSelectionManager.ZoomSelected(const AParentWidth, AParentHeight: Double);
var
  vSelRect: TFRect;
  vRect: TRect;
  vPoint: TFPoint;
  vScale: Double;
  I, vRectWidth, vRectHeight: Integer;
begin
  if FEntities.Count < 1 then Exit;
  vSelRect := TsgDXFEntity(FEntities[0]).Box;
  for I := 1 to FEntities.Count - 1 do
    UnionFRect(vSelRect, TsgDXFEntity(FEntities[I]).Box);
  vPoint := MakeFPoint(
    0.5*(vSelRect.Left + vSelRect.Right),
    0.5*(vSelRect.Top + vSelRect.Bottom),
    0.5*(vSelRect.Z2 + vSelRect.Z1));
  vRect := TsgDXFImageAccess(FImg).GetRect(vSelRect);
  vRectHeight :=  (vRect.Bottom - vRect.Top);
  vRectWidth := (vRect.Right - vRect.Left);
  if vRectWidth > vRectHeight then
    vScale := AParentWidth / vRectWidth
  else
    vScale := AParentHeight / vRectHeight;
  FDNavigator.ShowPoint(vPoint, vScale);
end;

end.
