Browse Source

moving tools in subfolder

Johann 6 years ago
parent
commit
3602be6ba7

+ 12 - 12
lazpaint/lazpaint.lpi

@@ -36,7 +36,7 @@
           </Target>
           <SearchPaths>
             <IncludeFiles Value="$(ProjOutDir)"/>
-            <OtherUnitFiles Value="buttons;tablet;dialog;dialog\color;dialog\filter"/>
+            <OtherUnitFiles Value="buttons;tablet;dialog;dialog\color;dialog\filter;tools"/>
             <UnitOutputDirectory Value="release\lib\$(TargetCPU)-$(TargetOS)"/>
           </SearchPaths>
           <Parsing>
@@ -355,7 +355,7 @@
         <UnitName Value="UGraph"/>
       </Unit2>
       <Unit3>
-        <Filename Value="utool.pas"/>
+        <Filename Value="tools\utool.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UTool"/>
       </Unit3>
@@ -524,27 +524,27 @@
         <IsPartOfProject Value="True"/>
       </Unit27>
       <Unit28>
-        <Filename Value="utooldeformationgrid.pas"/>
+        <Filename Value="tools\utooldeformationgrid.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UToolDeformationGrid"/>
       </Unit28>
       <Unit29>
-        <Filename Value="utoolselect.pas"/>
+        <Filename Value="tools\utoolselect.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UToolSelect"/>
       </Unit29>
       <Unit30>
-        <Filename Value="utoolpolygon.pas"/>
+        <Filename Value="tools\utoolpolygon.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UToolPolygon"/>
       </Unit30>
       <Unit31>
-        <Filename Value="utoolfloodfill.pas"/>
+        <Filename Value="tools\utoolfloodfill.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UToolFloodFill"/>
       </Unit31>
       <Unit32>
-        <Filename Value="utoolbasic.pas"/>
+        <Filename Value="tools\utoolbasic.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UToolBasic"/>
       </Unit32>
@@ -562,12 +562,12 @@
         <UnitName Value="UPixelate"/>
       </Unit34>
       <Unit35>
-        <Filename Value="utoolphong.pas"/>
+        <Filename Value="tools\utoolphong.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UToolPhong"/>
       </Unit35>
       <Unit36>
-        <Filename Value="utooltext.pas"/>
+        <Filename Value="tools\utooltext.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UToolText"/>
       </Unit36>
@@ -753,7 +753,7 @@
         <ResourceBaseClass Value="Form"/>
       </Unit67>
       <Unit68>
-        <Filename Value="utoollayer.pas"/>
+        <Filename Value="tools\utoollayer.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UToolLayer"/>
       </Unit68>
@@ -794,7 +794,7 @@
         <UnitName Value="UFileSystem"/>
       </Unit74>
       <Unit75>
-        <Filename Value="utoolbrush.pas"/>
+        <Filename Value="tools\utoolbrush.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UToolBrush"/>
       </Unit75>
@@ -869,7 +869,7 @@
         <IsPartOfProject Value="True"/>
       </Unit89>
       <Unit90>
-        <Filename Value="utoolicon.pas"/>
+        <Filename Value="tools\utoolicon.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UToolIcon"/>
       </Unit90>

+ 22 - 10
lazpaint/lazpaintembeddedpack.lpk

@@ -10,7 +10,7 @@
       <PathDelim Value="\"/>
       <SearchPaths>
         <IncludeFiles Value="dialog\filter;dialog\color"/>
-        <OtherUnitFiles Value="tablet;dialog\filter;dialog\color"/>
+        <OtherUnitFiles Value="tablet;dialog\filter;dialog\color;tools"/>
         <UnitOutputDirectory Value="debug\$(TargetCPU)-$(TargetOS)"/>
       </SearchPaths>
       <CodeGeneration>
@@ -27,7 +27,7 @@
       </Linking>
     </CompilerOptions>
     <Version Major="7" Release="2"/>
-    <Files Count="88">
+    <Files Count="91">
       <Item1>
         <Filename Value="lazpaintinstance.pas"/>
         <UnitName Value="LazpaintInstance"/>
@@ -181,7 +181,7 @@
         <UnitName Value="UShiftColors"/>
       </Item38>
       <Item39>
-        <Filename Value="utool.pas"/>
+        <Filename Value="tools\utool.pas"/>
         <UnitName Value="UTool"/>
       </Item39>
       <Item40>
@@ -217,27 +217,27 @@
         <UnitName Value="UResourceStrings"/>
       </Item47>
       <Item48>
-        <Filename Value="utoolbasic.pas"/>
+        <Filename Value="tools\utoolbasic.pas"/>
         <UnitName Value="UToolBasic"/>
       </Item48>
       <Item49>
-        <Filename Value="utooldeformationgrid.pas"/>
+        <Filename Value="tools\utooldeformationgrid.pas"/>
         <UnitName Value="UToolDeformationGrid"/>
       </Item49>
       <Item50>
-        <Filename Value="utoolfloodfill.pas"/>
+        <Filename Value="tools\utoolfloodfill.pas"/>
         <UnitName Value="UToolFloodFill"/>
       </Item50>
       <Item51>
-        <Filename Value="utoolpolygon.pas"/>
+        <Filename Value="tools\utoolpolygon.pas"/>
         <UnitName Value="UToolPolygon"/>
       </Item51>
       <Item52>
-        <Filename Value="utoolselect.pas"/>
+        <Filename Value="tools\utoolselect.pas"/>
         <UnitName Value="UToolSelect"/>
       </Item52>
       <Item53>
-        <Filename Value="utooltext.pas"/>
+        <Filename Value="tools\utooltext.pas"/>
         <UnitName Value="UToolText"/>
       </Item53>
       <Item54>
@@ -313,7 +313,7 @@
         <UnitName Value="USharpen"/>
       </Item71>
       <Item72>
-        <Filename Value="utoolphong.pas"/>
+        <Filename Value="tools\utoolphong.pas"/>
         <UnitName Value="UToolPhong"/>
       </Item72>
       <Item73>
@@ -380,6 +380,18 @@
         <Filename Value="dialog\color\uadjustcurves.pas"/>
         <UnitName Value="uadjustcurves"/>
       </Item88>
+      <Item89>
+        <Filename Value="tools\utoolbrush.pas"/>
+        <UnitName Value="UToolBrush"/>
+      </Item89>
+      <Item90>
+        <Filename Value="tools\utoolicon.pas"/>
+        <UnitName Value="UToolIcon"/>
+      </Item90>
+      <Item91>
+        <Filename Value="tools\utoollayer.pas"/>
+        <UnitName Value="UToolLayer"/>
+      </Item91>
     </Files>
     <RequiredPkgs Count="6">
       <Item1>

+ 1 - 1
lazpaint/lazpaintembeddedpack.pas

@@ -18,7 +18,7 @@ uses
   ULoadImage, ULoading, UMenu, UObject3D, UPhongFilter, UScripting, USharpen, 
   UToolPhong, UTranslation, UVolatileScrollBar, UZoom, laztablet, 
   ugeometricbrush, UFilterFunction, UFormRain, unoisefilter, uposterize, 
-  uadjustcurves, LazarusPackageIntf;
+  uadjustcurves, UToolBrush, UToolIcon, UToolLayer, LazarusPackageIntf;
 
 implementation
 

+ 0 - 0
lazpaint/utool.pas → lazpaint/tools/utool.pas


+ 0 - 0
lazpaint/utoolbasic.pas → lazpaint/tools/utoolbasic.pas


+ 0 - 0
lazpaint/utoolbrush.pas → lazpaint/tools/utoolbrush.pas


+ 0 - 0
lazpaint/utooldeformationgrid.pas → lazpaint/tools/utooldeformationgrid.pas


+ 0 - 0
lazpaint/utoolfloodfill.pas → lazpaint/tools/utoolfloodfill.pas


+ 0 - 0
lazpaint/utoolicon.pas → lazpaint/tools/utoolicon.pas


+ 750 - 0
lazpaint/tools/utoollayer.pas

@@ -0,0 +1,750 @@
+unit UToolLayer;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, UTool, BGRABitmap, BGRABitmapTypes,
+  BGRATransform, BGRALayers, ULayerAction, UImageDiff;
+
+type
+  { TToolMoveLayer }
+
+  TToolMoveLayer = class(TGenericTool)
+  protected
+    handMoving: boolean;
+    handOrigin: TPoint;
+    FStartLayerOffset: TPoint;
+    FStartLayerMatrix: TAffineMatrix;
+    FStartLayerOffsetDefined: boolean;
+    FLayerBounds: TRect;
+    FLayerBoundsDefined: boolean;
+    function GetIsSelectingTool: boolean; override;
+    function DoToolDown({%H-}toolDest: TBGRABitmap; pt: TPoint; {%H-}ptF: TPointF;
+      {%H-}rightBtn: boolean): TRect; override;
+    function DoToolMove({%H-}toolDest: TBGRABitmap; pt: TPoint; {%H-}ptF: TPointF): TRect; override;
+    procedure DoToolMoveAfter(pt: TPoint; {%H-}ptF: TPointF); override;
+    function UseOriginal: boolean;
+    procedure NeedLayerBounds;
+    function GetAction: TLayerAction; override;
+    function DoGetToolDrawingLayer: TBGRABitmap; override;
+  public
+    function ToolUp: TRect; override;
+    function ToolKeyDown(var key: Word): TRect; override;
+    function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth,
+      {%H-}VirtualScreenHeight: integer;
+      BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect; override;
+  end;
+
+  { TToolTransformLayer }
+
+  TToolTransformLayer = class(TGenericTool)
+  private
+    function GetInitialLayerBounds: TRect;
+    function GetTransformCenter: TPointF;
+    procedure SetTransformCenter(AValue: TPointF);
+    procedure NeedOriginal;
+  protected
+    FOriginalInit: boolean;
+    FBackupLayer: TReplaceLayerByImageOriginalDifference;
+    FInitialOriginalMatrix: TAffineMatrix;
+    FInitialLayerBounds: TRect;
+    FInitialLayerBoundsDefined: boolean;
+
+    FTransformCenter: TPointF;
+    FTransformCenterDefined: boolean;
+    FPreviousTransformCenter: TPointF;
+    FPreviousFilter: TResampleFilter;
+    FTransforming: boolean;
+    FPreviousMousePos: TPointF;
+    FCtrlDown: boolean;
+    FLastUpdateRect: TRect;
+    FLastUpdateRectDefined: boolean;
+    FOriginalBounds: TRect;
+    FOriginalBoundsDefined: boolean;
+    function GetIsSelectingTool: boolean; override;
+    function DoToolDown({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF;
+      rightBtn: boolean): TRect; override;
+    function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF): TRect;
+      override;
+    procedure CancelTransform;
+    procedure ValidateTransform;
+    function TransformOk: boolean; virtual; abstract;
+    function UpdateTransform: TRect; virtual; abstract;
+    procedure TransformCenterChanged; virtual; abstract;
+    function MouseChangesTransform(APrevPos, ANewPos: TPointF): boolean; virtual; abstract;
+    function CtrlChangesTransform: boolean; virtual; abstract;
+    property TransformCenter: TPointF read GetTransformCenter write SetTransformCenter;
+    function GetAction: TLayerAction; override;
+    function DoGetToolDrawingLayer: TBGRABitmap; override;
+  public
+    constructor Create(AManager: TToolManager); override;
+    destructor Destroy; override;
+    function ToolKeyDown(var key: Word): TRect; override;
+    function ToolKeyUp(var key: Word): TRect; override;
+    function ToolUp: TRect; override;
+    function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth,
+      {%H-}VirtualScreenHeight: integer;
+      BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect; override;
+  end;
+
+  { TToolZoomLayer }
+
+  TToolZoomLayer = class(TToolTransformLayer)
+  private
+    FZoom,FActualZoom,FPreviousActualZoom: single;
+    function GetActualZoom: single;
+  protected
+    function TransformOk: boolean; override;
+    function UpdateTransform: TRect; override;
+    procedure TransformCenterChanged; override;
+    function MouseChangesTransform(APrevPos, ANewPos: TPointF): boolean; override;
+    function CtrlChangesTransform: boolean; override;
+  public
+    constructor Create(AManager: TToolManager); override;
+  end;
+
+  { TToolRotateLayer }
+
+  TToolRotateLayer = class(TToolTransformLayer)
+  private
+    FAngle,FActualAngle,FPreviousActualAngle: single;
+    function GetActualAngle: single;
+  protected
+    function TransformOk: boolean; override;
+    function UpdateTransform: TRect; override;
+    procedure TransformCenterChanged; override;
+    function MouseChangesTransform(APrevPos, ANewPos: TPointF): boolean; override;
+    function CtrlChangesTransform: boolean; override;
+  public
+    constructor Create(AManager: TToolManager); override;
+  end;
+
+implementation
+
+uses LazPaintType, ugraph, LCLType, Types, BGRALayerOriginal;
+
+const
+  VeryBigValue = maxLongInt div 2;
+
+{ TToolMoveLayer }
+
+function TToolMoveLayer.GetIsSelectingTool: boolean;
+begin
+  result := false;
+end;
+
+function TToolMoveLayer.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF; rightBtn: boolean): TRect;
+var idx: integer;
+begin
+  result := EmptyRect;
+  if not handMoving then
+  begin
+    handMoving := true;
+    handOrigin := pt;
+    if not FStartLayerOffsetDefined then
+    begin
+      FStartLayerOffsetDefined := true;
+      idx := Manager.Image.CurrentLayerIndex;
+      NeedLayerBounds;
+      FStartLayerOffset := Manager.Image.LayerOffset[idx];
+      FStartLayerMatrix := Manager.Image.LayerOriginalMatrix[idx];
+    end;
+    if UseOriginal then Manager.Image.DraftOriginal := true;
+  end;
+end;
+
+function TToolMoveLayer.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF): TRect;
+var idx: integer;
+  prev: TPoint;
+begin
+  if handMoving and ((handOrigin.X <> pt.X) or (handOrigin.Y <> pt.Y)) then
+  begin
+    idx := Manager.Image.CurrentLayerIndex;
+    if UseOriginal then
+    begin
+      Manager.Image.LayerOriginalMatrix[idx] :=
+          AffineMatrixTranslation(pt.X-HandOrigin.X,pt.Y-HandOrigin.Y)*Manager.Image.LayerOriginalMatrix[idx];
+      result := OnlyRenderChange;
+    end else
+    begin
+      prev := Manager.Image.LayerOffset[idx];
+      Manager.Image.SetLayerOffset(idx, Point(prev.X+pt.X-HandOrigin.X,
+                                         prev.Y+pt.Y-HandOrigin.Y), FLayerBounds);
+      result := OnlyRenderChange;
+    end;
+  end else
+    result := EmptyRect;
+end;
+
+procedure TToolMoveLayer.DoToolMoveAfter(pt: TPoint; ptF: TPointF);
+begin
+  if handMoving then handOrigin := pt;
+end;
+
+function TToolMoveLayer.UseOriginal: boolean;
+begin
+  with Manager.Image do
+    result := LayerOriginalDefined[CurrentLayerIndex] and
+              LayerOriginalKnown[CurrentLayerIndex];
+end;
+
+procedure TToolMoveLayer.NeedLayerBounds;
+var
+  idx: Integer;
+begin
+  GetAction;
+  idx := Manager.Image.CurrentLayerIndex;
+  if not FLayerBoundsDefined then
+  begin
+    if UseOriginal then
+    begin
+      FLayerBounds := Manager.Image.LayerOriginal[idx].GetRenderBounds(
+                        Rect(-VeryBigValue,-VeryBigValue,VeryBigValue,VeryBigValue),
+                        AffineMatrixIdentity);
+      if FLayerBounds.Left = -VeryBigValue then FLayerBounds.Left := 0;
+      if FLayerBounds.Top = -VeryBigValue then FLayerBounds.Top := 0;
+      if FLayerBounds.Right = VeryBigValue then FLayerBounds.Right := Manager.Image.Width;
+      if FLayerBounds.Bottom = VeryBigValue then FLayerBounds.Bottom := Manager.Image.Height;
+    end
+    else
+      FLayerBounds := Manager.Image.LayerBitmap[idx].GetImageBounds;
+    FLayerBoundsDefined := true;
+  end;
+end;
+
+function TToolMoveLayer.GetAction: TLayerAction;
+begin
+  result := GetIdleAction;
+end;
+
+function TToolMoveLayer.DoGetToolDrawingLayer: TBGRABitmap;
+begin
+  Result:= Manager.Image.CurrentLayerReadOnly;   //do not modify layer data directly and ignore selection
+end;
+
+function TToolMoveLayer.ToolUp: TRect;
+begin
+  handMoving := false;
+  result := EmptyRect;
+  if UseOriginal then Manager.Image.DraftOriginal := false;
+end;
+
+function TToolMoveLayer.ToolKeyDown(var key: Word): TRect;
+var idx: integer;
+begin
+  if key = VK_RETURN then
+  begin
+    Manager.QueryExitTool;
+    result := EmptyRect;
+    Key := 0;
+  end
+  else if key = VK_ESCAPE then
+  begin
+    if FStartLayerOffsetDefined then
+    begin
+      idx := Manager.Image.CurrentLayerIndex;
+      if UseOriginal then
+        Manager.Image.LayerOriginalMatrix[idx] := FStartLayerMatrix
+      else
+        Manager.Image.SetLayerOffset(idx, FStartLayerOffset, FLayerBounds);
+      result := OnlyRenderChange;
+    end else
+      result := EmptyRect;
+    Manager.QueryExitTool;
+    Key := 0;
+  end else
+    Result:=inherited ToolKeyDown(key);
+end;
+
+function TToolMoveLayer.Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth,
+  VirtualScreenHeight: integer;
+  BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
+var
+  idx, i: integer;
+  m: TAffineMatrix;
+  ab: TAffineBox;
+  ptsF: ArrayOfTPointF;
+  pts: array of TPoint;
+begin
+  NeedLayerBounds;
+
+  if UseOriginal then
+  begin
+    idx := Manager.Image.CurrentLayerIndex;
+    m := Manager.Image.LayerOriginalMatrix[idx];
+    with Manager.Image.LayerOffset[idx] do
+      m := AffineMatrixTranslation(-x,-y)*m;
+  end else m := AffineMatrixIdentity;
+
+  ab := TAffineBox.AffineBox(BitmapToVirtualScreen(m*PointF(FLayerBounds.Left-0.499,FLayerBounds.Top-0.499)),
+            BitmapToVirtualScreen(m*PointF(FLayerBounds.Right-0.501,FLayerBounds.Top-0.499)),
+            BitmapToVirtualScreen(m*PointF(FLayerBounds.Left-0.499,FLayerBounds.Bottom-0.501)));
+  ptsF := ab.AsPolygon;
+  setlength(pts, length(ptsF));
+  for i := 0 to high(pts) do
+    pts[i] := ptsF[i].Round;
+
+  result := TRect.Union(pts);
+  result.Inflate(1,1);
+
+  if Assigned(VirtualScreen) then
+    virtualScreen.DrawpolygonAntialias(pts,BGRA(230,255,230,255),BGRA(0,0,0,255),FrameDashLength);
+end;
+
+{ TToolTransformLayer }
+
+function TToolTransformLayer.GetInitialLayerBounds: TRect;
+begin
+  if not FInitialLayerBoundsDefined then
+  begin
+    FInitialLayerBounds := GetToolDrawingLayer.GetImageBounds;
+    with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+      FInitialLayerBounds.Offset(X,Y);
+    FInitialLayerBoundsDefined := true;
+  end;
+  result := FInitialLayerBounds;
+end;
+
+function TToolTransformLayer.GetTransformCenter: TPointF;
+var bounds: TRect;
+begin
+  if not FTransformCenterDefined then
+  begin
+    bounds := GetInitialLayerBounds;
+    if IsRectEmpty(bounds) then
+      FTransformCenter := PointF(Manager.Image.Width/2 - 0.5,Manager.Image.Height/2 - 0.5)
+    else
+    begin
+      with bounds do
+        FTransformCenter := PointF((Left+Right)/2 - 0.5, (Top+Bottom)/2 - 0.5);
+    end;
+    FTransformCenterDefined := true;
+  end;
+  result := FTransformCenter;
+end;
+
+procedure TToolTransformLayer.SetTransformCenter(AValue: TPointF);
+begin
+  FTransformCenter := AValue;
+end;
+
+procedure TToolTransformLayer.NeedOriginal;
+var
+  layered: TBGRALayeredBitmap;
+  layerIdx: Integer;
+begin
+  if FOriginalInit then exit;
+  GetAction;
+  layerIdx := Manager.Image.CurrentLayerIndex;
+  layered := Manager.Image.CurrentState.LayeredBitmap;
+  if not (Manager.Image.LayerOriginalDefined[layerIdx] and
+     Manager.Image.LayerOriginalKnown[layerIdx]) then
+  begin
+    if Assigned(FBackupLayer) then raise exception.Create('Backup layer already assigned');
+    FBackupLayer:= TReplaceLayerByImageOriginalDifference.Create(Manager.Image.CurrentState, layerIdx, true);
+  end;
+  FInitialOriginalMatrix := layered.LayerOriginalMatrix[layerIdx];
+  FOriginalInit := true;
+end;
+
+function TToolTransformLayer.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF; rightBtn: boolean): TRect;
+begin
+  with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+    ptF += PointF(X,Y);
+
+  if not FTransforming and not rightBtn then
+  begin
+    FTransforming := true;
+    FPreviousMousePos := ptF;
+    if FCtrlDown then
+    begin
+      result := UpdateTransform;
+      if IsRectEmpty(result) then result := OnlyRenderChange;
+    end else result := EmptyRect;
+    Manager.Image.DraftOriginal := true;
+  end else
+  if rightBtn then
+  begin
+    FTransformCenter := ptF;
+    TransformCenterChanged;
+    result := UpdateTransform;
+    if IsRectEmpty(result) then result := OnlyRenderChange;
+  end else
+    result := EmptyRect;
+end;
+
+function TToolTransformLayer.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF): TRect;
+begin
+  with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+    ptF += PointF(X,Y);
+  if FTransforming then
+  begin
+    If MouseChangesTransform(FPreviousMousePos, ptF) then
+    begin
+      result := UpdateTransform;
+      if result.IsEmpty then result := OnlyRenderChange;
+    end
+    else result := EmptyRect;
+    FPreviousMousePos := ptF;
+  end else
+    result := EmptyRect;
+end;
+
+procedure TToolTransformLayer.CancelTransform;
+begin
+  if FOriginalInit then
+  begin
+    Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex] := FInitialOriginalMatrix;
+    if Assigned(FBackupLayer) then
+    begin
+      FBackupLayer.UnapplyTo(Manager.Image.CurrentState);
+      FreeAndNil(FBackupLayer);
+    end;
+    FOriginalInit := false;
+  end;
+  Manager.QueryExitTool;
+end;
+
+procedure TToolTransformLayer.ValidateTransform;
+var
+  transform: TAffineMatrix;
+begin
+  if FOriginalInit then
+  begin
+    if Assigned(FBackupLayer) then
+    begin
+      transform := Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex];
+      Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex] := FInitialOriginalMatrix;
+      Manager.Image.CurrentState.LayeredBitmap.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex] := transform;
+      Manager.Image.CurrentState.LayeredBitmap.RenderLayerFromOriginal(Manager.Image.CurrentLayerIndex);
+      FBackupLayer.nextMatrix := transform;
+      Manager.Image.AddUndo(FBackupLayer);
+      FBackupLayer := nil;
+    end;
+    FOriginalInit := false;
+  end;
+  Manager.QueryExitTool;
+end;
+
+function TToolTransformLayer.GetAction: TLayerAction;
+begin
+  result := GetIdleAction;
+end;
+
+function TToolTransformLayer.DoGetToolDrawingLayer: TBGRABitmap;
+begin
+  Result:= Manager.Image.CurrentLayerReadOnly   //do not modify layer data directly and ignore selection
+end;
+
+constructor TToolTransformLayer.Create(AManager: TToolManager);
+begin
+  inherited Create(AManager);
+  FCtrlDown:= false;
+  FTransformCenterDefined := false;
+  FLastUpdateRectDefined:= false;
+end;
+
+destructor TToolTransformLayer.Destroy;
+begin
+  if TransformOk then ValidateTransform
+  else CancelTransform;
+  inherited Destroy;
+end;
+
+function TToolTransformLayer.ToolKeyDown(var key: Word): TRect;
+begin
+  if key = VK_CONTROL then
+  begin
+    FCtrlDown:= true;
+    if FTransforming and CtrlChangesTransform then
+    begin
+      result := UpdateTransform;
+      if result.IsEmpty then result := OnlyRenderChange;
+    end
+      else result := EmptyRect;
+    Key := 0;
+  end else
+  if Key = VK_RETURN then
+  begin
+    if TransformOk then ValidateTransform
+    else CancelTransform;
+    result := OnlyRenderChange;
+    key := 0;
+  end else
+  if Key = VK_ESCAPE then
+  begin
+    CancelTransform;
+    result := OnlyRenderChange;
+    key := 0;
+  end else
+    result := EmptyRect;
+end;
+
+function TToolTransformLayer.ToolKeyUp(var key: Word): TRect;
+begin
+  if key = VK_CONTROL then
+  begin
+    FCtrlDown := false;
+    if FTransforming and CtrlChangesTransform then
+    begin
+      result := UpdateTransform;
+      if result.IsEmpty then result := OnlyRenderChange;
+    end
+      else result := EmptyRect;
+    Key := 0;
+  end else
+    result := EmptyRect;
+end;
+
+function TToolTransformLayer.ToolUp: TRect;
+begin
+  if FTransforming then
+  begin
+    FTransforming := false;
+    result := UpdateTransform;
+    if result.IsEmpty then result := OnlyRenderChange;
+    Manager.Image.DraftOriginal := false;
+  end else
+    Result:=EmptyRect;
+end;
+
+function TToolTransformLayer.Render(VirtualScreen: TBGRABitmap;
+  VirtualScreenWidth, VirtualScreenHeight: integer;
+  BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
+var
+  idx, i: integer;
+  m: TAffineMatrix;
+  ab: TAffineBox;
+  ptsF: ArrayOfTPointF;
+  pts: array of TPoint;
+  ptsRect: TRect;
+begin
+  idx := Manager.Image.CurrentLayerIndex;
+  with Manager.Image.LayerOffset[idx] do
+    Result:= NicePoint(VirtualScreen,BitmapToVirtualScreen(TransformCenter-PointF(X,Y)));
+
+  if not FOriginalBoundsDefined then
+  begin
+    if Manager.Image.LayerOriginalDefined[idx] then
+    begin
+      FOriginalBounds := Manager.Image.LayerOriginal[idx].GetRenderBounds(
+                        Rect(-VeryBigValue,-VeryBigValue,VeryBigValue,VeryBigValue),
+                        AffineMatrixIdentity);
+      if FOriginalBounds.Left = -VeryBigValue then FOriginalBounds.Left := 0;
+      if FOriginalBounds.Top = -VeryBigValue then FOriginalBounds.Top := 0;
+      if FOriginalBounds.Right = VeryBigValue then FOriginalBounds.Right := Manager.Image.Width;
+      if FOriginalBounds.Bottom = VeryBigValue then FOriginalBounds.Bottom := Manager.Image.Height;
+    end
+    else
+      FOriginalBounds := GetInitialLayerBounds;
+  end;
+  m := Manager.Image.LayerOriginalMatrix[idx];
+  with Manager.Image.LayerOffset[idx] do
+    m := AffineMatrixTranslation(-x,-y)*m;
+
+  ab := TAffineBox.AffineBox(BitmapToVirtualScreen(m*PointF(FOriginalBounds.Left-0.499,FOriginalBounds.Top-0.499)),
+            BitmapToVirtualScreen(m*PointF(FOriginalBounds.Right-0.501,FOriginalBounds.Top-0.499)),
+            BitmapToVirtualScreen(m*PointF(FOriginalBounds.Left-0.499,FOriginalBounds.Bottom-0.501)));
+  ptsF := ab.AsPolygon;
+  setlength(pts, length(ptsF));
+  for i := 0 to high(pts) do
+    pts[i] := ptsF[i].Round;
+
+  ptsRect := TRect.Union(pts);
+  ptsRect.Inflate(1,1);
+  Result.Union(ptsRect);
+
+  if Assigned(VirtualScreen) then
+    virtualScreen.DrawpolygonAntialias(pts,BGRA(230,255,230,255),BGRA(0,0,0,255),FrameDashLength);
+end;
+
+function TToolTransformLayer.GetIsSelectingTool: boolean;
+begin
+  result := false;
+end;
+
+{ TToolZoomLayer }
+
+function TToolZoomLayer.GetActualZoom: single;
+const log125 = 0.321928095;
+      log15 = 0.584962501;
+var
+  logZoom, fracZoom: single;
+  baseZoom: single;
+  invZoom: boolean;
+begin
+  if FCtrlDown then
+  begin
+    logZoom := ln(FZoom)/ln(2);
+    if logZoom < 0 then
+    begin
+      invZoom := true;
+      logZoom := -logZoom;
+    end else invZoom := false;
+    fracZoom := frac(logZoom);
+    baseZoom := 1 shl trunc(logZoom);
+
+    if fracZoom < log125/2 then result := baseZoom else
+    if fracZoom < (log125+log15)/2 then result := baseZoom*1.25 else
+    if fracZoom < (log15+1)/2 then result := baseZoom*1.5 else
+      result := baseZoom*2;
+
+    if invZoom then result := 1/result;
+  end
+  else
+    result := FZoom;
+end;
+
+function TToolZoomLayer.TransformOk: boolean;
+begin
+  result := FActualZoom <> 0;
+end;
+
+function TToolZoomLayer.UpdateTransform: TRect;
+begin
+  if (FActualZoom = FPreviousActualZoom) and ((FActualZoom = 1) or (TransformCenter = FPreviousTransformCenter)) then
+  begin
+    result := EmptyRect;
+    exit;
+  end;
+  FPreviousActualZoom := FActualZoom;
+  FPreviousTransformCenter := TransformCenter;
+  result := EmptyRect;
+  NeedOriginal;
+  Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex] :=
+    AffineMatrixTranslation(TransformCenter.X,TransformCenter.Y)*
+    AffineMatrixScale(FActualZoom,FActualZoom)*
+    AffineMatrixTranslation(-TransformCenter.X,-TransformCenter.Y)*
+    FInitialOriginalMatrix;
+end;
+
+procedure TToolZoomLayer.TransformCenterChanged;
+begin
+  FZoom := 1;
+  FActualZoom:= GetActualZoom;
+end;
+
+function TToolZoomLayer.MouseChangesTransform(APrevPos, ANewPos: TPointF): boolean;
+var
+  dist, prevDist: Single;
+begin
+  dist := VectLen(ANewPos-TransformCenter);
+  prevDist := VectLen(APrevPos-TransformCenter);
+  if (prevDist <> 0) and (dist <> 0) then
+  begin
+    FZoom *= dist/prevDist;
+    FActualZoom:= GetActualZoom;
+    result := true;
+  end
+  else result := false;
+end;
+
+function TToolZoomLayer.CtrlChangesTransform: boolean;
+var
+  newActualZoom: Single;
+begin
+  newActualZoom := GetActualZoom;
+  if FActualZoom<>newActualZoom then
+  begin
+    FActualZoom := newActualZoom;
+    result := true;
+  end else
+    result := false;
+end;
+
+constructor TToolZoomLayer.Create(AManager: TToolManager);
+begin
+  inherited Create(AManager);
+  FZoom:= 1;
+  FPreviousActualZoom := 1;
+end;
+
+{ TToolRotateLayer }
+
+function TToolRotateLayer.GetActualAngle: single;
+begin
+  if FCtrlDown then
+    result := round(FAngle/15)*15
+  else
+    result := FAngle;
+end;
+
+function TToolRotateLayer.TransformOk: boolean;
+begin
+  result := true;
+end;
+
+procedure TToolRotateLayer.TransformCenterChanged;
+begin
+  FAngle := 0;
+  FActualAngle:= GetActualAngle;
+end;
+
+function TToolRotateLayer.MouseChangesTransform(APrevPos, ANewPos: TPointF): boolean;
+var
+  angleDiff, newActualAngle: Single;
+begin
+  angleDiff := ComputeAngle(ANewPos.X-TransformCenter.X,ANewPos.Y-TransformCenter.Y)-
+             ComputeAngle(APrevPos.X-TransformCenter.X,APrevPos.Y-TransformCenter.Y);
+  FAngle += angleDiff;
+  newActualAngle := GetActualAngle;
+  if newActualAngle <> FActualAngle then
+  begin
+    FActualAngle:= newActualAngle;
+    result := true;
+  end
+  else result := false;
+end;
+
+function TToolRotateLayer.CtrlChangesTransform: boolean;
+var
+  newActualAngle: Single;
+begin
+  newActualAngle := GetActualAngle;
+  if newActualAngle<>FActualAngle then
+  begin
+    FActualAngle := newActualAngle;
+    result := true;
+  end else
+    result := false;
+end;
+
+function TToolRotateLayer.UpdateTransform: TRect;
+begin
+  if (FActualAngle = FPreviousActualAngle) and ((FActualAngle = 0) or (TransformCenter = FPreviousTransformCenter)) then
+  begin
+    result := EmptyRect;
+    exit;
+  end;
+  FPreviousActualAngle := FActualAngle;
+  FPreviousTransformCenter := TransformCenter;
+  result := EmptyRect;
+  NeedOriginal;
+  Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex] :=
+    AffineMatrixTranslation(TransformCenter.X,TransformCenter.Y)*
+    AffineMatrixRotationDeg(FActualAngle)*
+    AffineMatrixTranslation(-TransformCenter.X,-TransformCenter.Y)*
+    FInitialOriginalMatrix;
+end;
+
+constructor TToolRotateLayer.Create(AManager: TToolManager);
+begin
+  inherited Create(AManager);
+  FAngle:= 0;
+  FPreviousActualAngle := 0;
+end;
+
+initialization
+
+  RegisterTool(ptMoveLayer,TToolMoveLayer);
+  RegisterTool(ptRotateLayer,TToolRotateLayer);
+  RegisterTool(ptZoomLayer,TToolZoomLayer);
+
+end.
+

+ 0 - 0
lazpaint/utoolphong.pas → lazpaint/tools/utoolphong.pas


+ 165 - 0
lazpaint/tools/utoolpolygon.pas

@@ -0,0 +1,165 @@
+unit UToolPolygon;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, utool, utoolbasic, BGRABitmap, BGRABitmapTypes,
+  LCVectorOriginal, LCLType;
+
+const
+  EasyBezierMinimumDotProduct = 0.5;
+
+type
+  TToolSplineMode = (tsmMovePoint, tsmCurveModeAuto, tsmCurveModeAngle, tsmCurveModeSpline);
+
+  { TToolPolygon }
+
+  TToolPolygon = class(TVectorialTool)
+  protected
+    function CreateShape: TVectorShape; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
+    procedure UpdateUserMode; virtual;
+  end;
+
+  { TToolSpline }
+
+  TToolSpline = class(TToolPolygon)
+  private
+    FCurrentMode: TToolSplineMode;
+    FNextCurveMode: TEasyBezierCurveMode;
+    FCurveModeHintShown: Boolean;
+    function GetCurrentMode: TToolSplineMode;
+    procedure SetCurrentMode(AValue: TToolSplineMode);
+    procedure UpdateUserMode; override;
+  protected
+    function CreateShape: TVectorShape; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
+  public
+    constructor Create(AManager: TToolManager); override;
+    function ToolKeyPress(var key: TUTF8Char): TRect; override;
+    property CurrentMode: TToolSplineMode read GetCurrentMode write SetCurrentMode;
+  end;
+
+implementation
+
+uses LazPaintType, LCVectorPolyShapes;
+
+{ TToolSpline }
+
+function TToolSpline.GetCurrentMode: TToolSplineMode;
+var
+  c: TCurveShape;
+begin
+  if Assigned(FShape) then
+  begin
+    c := TCurveShape(FShape);
+    case c.Usermode of
+    vsuEdit: FCurrentMode := tsmMovePoint;
+    vsuCreate: if c.PointCount > 1 then
+               begin
+                 case c.CurveMode[c.PointCount-2] of
+                   cmAuto: FCurrentMode := tsmCurveModeAuto;
+                   cmAngle: FCurrentMode := tsmCurveModeAngle;
+                   cmCurve: FCurrentMode := tsmCurveModeSpline;
+                 end;
+               end else
+                 result := tsmCurveModeAuto;
+    vsuCurveSetAuto: FCurrentMode := tsmCurveModeAuto;
+    vsuCurveSetAngle: FCurrentMode := tsmCurveModeAngle;
+    vsuCurveSetCurve: FCurrentMode := tsmCurveModeSpline;
+    end;
+  end;
+  result := FCurrentMode;
+end;
+
+procedure TToolSpline.SetCurrentMode(AValue: TToolSplineMode);
+begin
+  if FCurrentMode = AValue then exit;
+  FCurrentMode := AValue;
+  UpdateUserMode;
+end;
+
+procedure TToolSpline.UpdateUserMode;
+var
+  c: TCurveShape;
+begin
+  if FShape = nil then exit;
+  if FQuickDefine then
+  begin
+    FShape.Usermode := vsuCreate;
+    exit;
+  end;
+  c := TCurveShape(FShape);
+  case FCurrentMode of
+  tsmMovePoint: if not (c.Usermode in [vsuEdit,vsuCreate]) then c.Usermode := vsuEdit;
+  tsmCurveModeAuto: if c.Usermode <> vsuCreate then c.Usermode := vsuCurveSetAuto else
+                    if c.PointCount > 1 then c.CurveMode[c.PointCount-2] := cmAuto;
+  tsmCurveModeAngle: if c.Usermode <> vsuCreate then c.Usermode := vsuCurveSetAngle else
+                     if c.PointCount > 1 then c.CurveMode[c.PointCount-2] := cmAngle;
+  tsmCurveModeSpline: if c.Usermode <> vsuCreate then c.Usermode := vsuCurveSetCurve else
+                      if c.PointCount > 1 then c.CurveMode[c.PointCount-2] := cmCurve;
+  end;
+end;
+
+function TToolSpline.CreateShape: TVectorShape;
+begin
+  result := TCurveShape.Create(nil);
+  result.Usermode := vsuCreate;
+  TCurveShape(result).CosineAngle:= EasyBezierMinimumDotProduct;
+  if not FCurveModeHintShown then
+  begin
+    Manager.ToolPopup(tpmCurveModeHint);
+    FCurveModeHintShown := true;
+  end;
+end;
+
+procedure TToolSpline.AssignShapeStyle(AMatrix: TAffineMatrix);
+begin
+  inherited AssignShapeStyle(AMatrix);
+  TCurveShape(FShape).SplineStyle:= Manager.ToolSplineStyle;
+end;
+
+constructor TToolSpline.Create(AManager: TToolManager);
+begin
+  inherited Create(AManager);
+  FNextCurveMode := cmAuto;
+end;
+
+function TToolSpline.ToolKeyPress(var key: TUTF8Char): TRect;
+begin
+  Result:=inherited ToolKeyPress(key);
+  if Key='x' then Key := #0;
+end;
+
+{ TToolPolygon }
+
+function TToolPolygon.CreateShape: TVectorShape;
+begin
+  result := TPolylineShape.Create(nil);
+end;
+
+procedure TToolPolygon.AssignShapeStyle(AMatrix: TAffineMatrix);
+begin
+  inherited AssignShapeStyle(AMatrix);
+  TCustomPolypointShape(FShape).Closed := Manager.ToolOptionCloseShape;
+  TCustomPolypointShape(FShape).ArrowStartKind := StrToArrowKind(Manager.ToolArrowStart);
+  TCustomPolypointShape(FShape).ArrowEndKind := StrToArrowKind(Manager.ToolArrowEnd);
+  TCustomPolypointShape(FShape).ArrowSize := Manager.ToolArrowSize;
+  UpdateUserMode;
+end;
+
+procedure TToolPolygon.UpdateUserMode;
+begin
+  if FShape = nil then exit;
+  if FQuickDefine then FShape.Usermode := vsuCreate;
+end;
+
+initialization
+
+  RegisterTool(ptPolygon,TToolPolygon);
+  RegisterTool(ptSpline,TToolSpline);
+
+end.
+

+ 561 - 0
lazpaint/tools/utoolselect.pas

@@ -0,0 +1,561 @@
+unit UToolSelect;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Graphics, utool, utoolpolygon, utoolbasic, BGRABitmapTypes, BGRABitmap,
+  ULayerAction, LCVectorOriginal;
+
+type
+  { TVectorialSelectTool }
+
+  TVectorialSelectTool = class(TVectorialTool)
+  protected
+    function GetIsSelectingTool: boolean; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
+    function RoundCoordinate(ptF: TPointF): TPointF; override;
+    function UpdateShape(toolDest: TBGRABitmap): TRect; override;
+    procedure QuickDefineEnd; override;
+    function BigImage: boolean;
+  end;
+
+  { TToolSelectRect }
+
+  TToolSelectRect = class(TVectorialSelectTool)
+  protected
+    function CreateShape: TVectorShape; override;
+  public
+    function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth, {%H-}VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction):TRect; override;
+  end;
+
+  { TToolSelectEllipse }
+
+  TToolSelectEllipse = class(TVectorialSelectTool)
+  protected
+    function CreateShape: TVectorShape; override;
+  public
+    function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth, {%H-}VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction):TRect; override;
+  end;
+
+  { TToolSelectPoly }
+
+  TToolSelectPoly = class(TToolPolygon)
+  protected
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
+    function GetIsSelectingTool: boolean; override;
+  end;
+
+  { TToolSelectSpline }
+
+  TToolSelectSpline = class(TToolSpline)
+  protected
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
+    function GetIsSelectingTool: boolean; override;
+  end;
+
+  { TToolMagicWand }
+
+  TToolMagicWand = class(TGenericTool)
+  protected
+    function GetIsSelectingTool: boolean; override;
+    function DoToolDown(toolDest: TBGRABitmap; pt: TPoint; {%H-}ptF: TPointF;
+      rightBtn: boolean): TRect; override;
+  end;
+
+  { TToolSelectionPen }
+
+  TToolSelectionPen = class(TToolPen)
+  protected
+    function GetIsSelectingTool: boolean; override;
+    function StartDrawing(toolDest: TBGRABitmap; ptF: TPointF; rightBtn: boolean): TRect; override;
+    function ContinueDrawing(toolDest: TBGRABitmap; originF, destF: TPointF): TRect; override;
+  end;
+
+  { TTransformSelectionTool }
+
+  TTransformSelectionTool = class(TGenericTool)
+  protected
+    function GetIsSelectingTool: boolean; override;
+    function GetAction: TLayerAction; override;
+    function FixSelectionTransform: boolean; override;
+    function DoGetToolDrawingLayer: TBGRABitmap; override;
+  end;
+
+  { TToolMoveSelection }
+
+  TToolMoveSelection = class(TTransformSelectionTool)
+  protected
+    handMoving: boolean;
+    handOrigin: TPoint;
+    function DoToolDown({%H-}toolDest: TBGRABitmap; pt: TPoint; {%H-}ptF: TPointF;
+      {%H-}rightBtn: boolean): TRect; override;
+    function DoToolMove({%H-}toolDest: TBGRABitmap; pt: TPoint; {%H-}ptF: TPointF): TRect; override;
+    procedure DoToolMoveAfter(pt: TPoint; {%H-}ptF: TPointF); override;
+  public
+    function ToolUp: TRect; override;
+    destructor Destroy; override;
+  end;
+
+  { TToolRotateSelection }
+
+  TToolRotateSelection = class(TTransformSelectionTool)
+  protected
+    class var HintShowed: boolean;
+    handMoving: boolean;
+    handOrigin: TPointF;
+    snapRotate: boolean;
+    snapAngle: single;
+    FOriginalTransform: TAffineMatrix;
+    FCurrentAngle: single;
+    FCurrentCenter: TPointF;
+    function DoToolDown({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF;
+      rightBtn: boolean): TRect; override;
+    function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF): TRect; override;
+    function GetStatusText: string; override;
+    procedure UpdateTransform;
+  public
+    constructor Create(AManager: TToolManager); override;
+    function ToolKeyDown(var key: Word): TRect; override;
+    function ToolKeyUp(var key: Word): TRect; override;
+    function ToolUp: TRect; override;
+    function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth, {%H-}VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction):TRect; override;
+    destructor Destroy; override;
+  end;
+
+implementation
+
+uses types, ugraph, LCLType, LazPaintType, Math, BGRATransform, BGRAPath,
+  BGRAPen, LCVectorRectShapes;
+
+procedure AssignSelectShapeStyle(AShape: TVectorShape; ASwapColor: boolean);
+var
+  f: TVectorShapeFields;
+begin
+  f:= AShape.Fields;
+  if vsfPenFill in f then AShape.PenFill.Clear;
+  if vsfPenStyle in f Then AShape.PenStyle := ClearPenStyle;
+  if vsfBackFill in f then
+  begin
+    if ASwapColor then
+      AShape.BackFill.SetSolid(BGRABlack)
+    else
+      AShape.BackFill.SetSolid(BGRAWhite);
+  end;
+end;
+
+{ TToolSelectSpline }
+
+procedure TToolSelectSpline.AssignShapeStyle(AMatrix: TAffineMatrix);
+begin
+  FShape.BeginUpdate;
+  inherited AssignShapeStyle(AMatrix);
+  AssignSelectShapeStyle(FShape, FSwapColor);
+  FShape.EndUpdate;
+end;
+
+function TToolSelectSpline.GetIsSelectingTool: boolean;
+begin
+  Result:= true;
+end;
+
+{ TToolSelectPoly }
+
+procedure TToolSelectPoly.AssignShapeStyle(AMatrix: TAffineMatrix);
+begin
+  FShape.BeginUpdate;
+  inherited AssignShapeStyle(AMatrix);
+  AssignSelectShapeStyle(FShape, FSwapColor);
+  FShape.EndUpdate;
+end;
+
+function TToolSelectPoly.GetIsSelectingTool: boolean;
+begin
+  Result:= true;
+end;
+
+{ TVectorialSelectTool }
+
+function TVectorialSelectTool.GetIsSelectingTool: boolean;
+begin
+  Result:= true;
+end;
+
+procedure TVectorialSelectTool.AssignShapeStyle(AMatrix: TAffineMatrix);
+begin
+  AssignSelectShapeStyle(FShape, FSwapColor);
+  if FShape is TCustomRectShape then
+  begin
+    if Manager.ToolRatio = 0 then
+      TCustomRectShape(FShape).FixedRatio:= EmptySingle
+    else
+      TCustomRectShape(FShape).FixedRatio:= Manager.ToolRatio;
+  end;
+end;
+
+function TVectorialSelectTool.RoundCoordinate(ptF: TPointF): TPointF;
+begin
+  Result:= PointF(floor(ptF.x)+0.5,floor(ptF.y)+0.5);
+end;
+
+function TVectorialSelectTool.UpdateShape(toolDest: TBGRABitmap): TRect;
+begin
+  if BigImage and FQuickDefine then
+    result := OnlyRenderChange
+  else
+    Result:= inherited UpdateShape(toolDest);
+end;
+
+procedure TVectorialSelectTool.QuickDefineEnd;
+var
+  toolDest: TBGRABitmap;
+  r: TRect;
+begin
+  toolDest := GetToolDrawingLayer;
+  r := UpdateShape(toolDest);
+  Action.NotifyChange(toolDest, r);
+end;
+
+function TVectorialSelectTool.BigImage: boolean;
+begin
+  result := Manager.Image.Width*Manager.Image.Height > 480000;
+end;
+
+{ TToolSelectRect }
+
+function TToolSelectRect.CreateShape: TVectorShape;
+begin
+  result := TRectShape.Create(nil);
+end;
+
+function TToolSelectRect.Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth,
+  VirtualScreenHeight: integer;
+  BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
+var
+  ab: TAffineBox;
+  ptsF: ArrayOfTPointF;
+  pts: array of TPoint;
+  i: Integer;
+  abBounds: TRect;
+begin
+  Result:= inherited Render(VirtualScreen, VirtualScreenWidth,
+      VirtualScreenHeight, BitmapToVirtualScreen);
+
+  if BigImage and FQuickDefine then
+  begin
+    ab := TCustomRectShape(FShape).GetAffineBox(FEditor.Matrix, true);
+    abBounds := ab.RectBounds;
+    abBounds.Inflate(1,1);
+    result := RectUnion(result, abBounds);
+    if Assigned(VirtualScreen) then
+    begin
+      ptsF := ab.AsPolygon;
+      setlength(pts, length(ptsF));
+      for i := 0 to high(ptsF) do
+        pts[i] := ptsF[i].Round;
+      VirtualScreen.DrawPolygonAntialias(pts,BGRAWhite,BGRABlack,FrameDashLength);
+    end;
+  end;
+end;
+
+{ TToolSelectEllipse }
+
+function TToolSelectEllipse.CreateShape: TVectorShape;
+begin
+  result := TEllipseShape.Create(nil);
+end;
+
+function TToolSelectEllipse.Render(VirtualScreen: TBGRABitmap;
+  VirtualScreenWidth, VirtualScreenHeight: integer;
+  BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
+var
+  ab: TAffineBox;
+  ptsF: ArrayOfTPointF;
+  pts: array of TPoint;
+  i: Integer;
+  abBounds: TRect;
+begin
+  Result:= inherited Render(VirtualScreen, VirtualScreenWidth,
+      VirtualScreenHeight, BitmapToVirtualScreen);
+
+  if BigImage and FQuickDefine then
+  begin
+    ab := TCustomRectShape(FShape).GetAffineBox(FEditor.Matrix, true);
+    abBounds := ab.RectBounds;
+    abBounds.Inflate(1,1);
+    result := RectUnion(result, abBounds);
+    if Assigned(VirtualScreen) then
+    begin
+      with TCustomRectShape(FShape) do
+        ptsF := BGRAPath.ComputeEllipse(FEditor.Matrix*Origin,
+                    FEditor.Matrix*XAxis,FEditor.Matrix*YAxis);
+      setlength(pts, length(ptsF));
+      for i := 0 to high(ptsF) do
+        pts[i] := ptsF[i].Round;
+      VirtualScreen.DrawPolygonAntialias(pts,BGRAWhite,BGRABlack,FrameDashLength);
+    end;
+  end;
+end;
+
+{ TTransformSelectionTool }
+
+function TTransformSelectionTool.GetIsSelectingTool: boolean;
+begin
+  result := true;
+end;
+
+function TTransformSelectionTool.GetAction: TLayerAction;
+begin
+  Result:= nil;
+end;
+
+function TTransformSelectionTool.FixSelectionTransform: boolean;
+begin
+  Result:= false;
+end;
+
+function TTransformSelectionTool.DoGetToolDrawingLayer: TBGRABitmap;
+begin
+  result := Manager.Image.SelectionMaskReadonly;
+end;
+
+{ TToolRotateSelection }
+
+function TToolRotateSelection.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF; rightBtn: boolean): TRect;
+begin
+  result := EmptyRect;
+  if not handMoving and not Manager.Image.SelectionMaskEmpty then
+  begin
+    if rightBtn then
+    begin
+      if FCurrentAngle <> 0 then
+      begin
+        FCurrentAngle := 0;
+        FCurrentCenter := ptF;
+        UpdateTransform;
+      end else
+      begin
+        FCurrentCenter := ptF;
+        UpdateTransform;
+      end;
+      result := OnlyRenderChange;
+    end else
+    begin
+      handMoving := true;
+      handOrigin := ptF;
+    end;
+  end;
+end;
+
+function TToolRotateSelection.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF): TRect;
+var angleDiff: single;
+begin
+  if not HintShowed then
+  begin
+    Manager.ToolPopup(tpmCtrlRestrictRotation);
+    HintShowed:= true;
+  end;
+  if handMoving and ((handOrigin.X <> ptF.X) or (handOrigin.Y <> ptF.Y)) then
+  begin
+    angleDiff := ComputeAngle(ptF.X-FCurrentCenter.X,ptF.Y-FCurrentCenter.Y)-
+                 ComputeAngle(handOrigin.X-FCurrentCenter.X,handOrigin.Y-FCurrentCenter.Y);
+    if snapRotate then
+    begin
+      snapAngle += angleDiff;
+      FCurrentAngle := round(snapAngle/15)*15;
+    end
+     else
+       FCurrentAngle := FCurrentAngle + angleDiff;
+    UpdateTransform;
+    handOrigin := ptF;
+    result := OnlyRenderChange;
+  end else
+    result := EmptyRect;
+end;
+
+function TToolRotateSelection.GetStatusText: string;
+begin
+  Result:= 'α = '+FloatToStrF(FCurrentAngle,ffFixed,5,1);
+end;
+
+procedure TToolRotateSelection.UpdateTransform;
+begin
+  Manager.Image.SelectionTransform := AffineMatrixTranslation(FCurrentCenter.X,FCurrentCenter.Y)*
+                                   AffineMatrixRotationDeg(FCurrentAngle)*
+                                   AffineMatrixTranslation(-FCurrentCenter.X,-FCurrentCenter.Y)*FOriginalTransform;
+end;
+
+constructor TToolRotateSelection.Create(AManager: TToolManager);
+begin
+  inherited Create(AManager);
+  FCurrentCenter := Manager.Image.SelectionTransform * Manager.Image.GetSelectionMaskCenter;
+  FOriginalTransform := Manager.Image.SelectionTransform;
+  FCurrentAngle := 0;
+end;
+
+function TToolRotateSelection.ToolKeyDown(var key: Word): TRect;
+begin
+  result := EmptyRect;
+  if key = VK_CONTROL then
+  begin
+    if not snapRotate then
+    begin
+      snapRotate := true;
+      snapAngle := FCurrentAngle;
+
+      if handMoving then
+      begin
+        FCurrentAngle := round(snapAngle/15)*15;
+        UpdateTransform;
+        result := OnlyRenderChange;
+      end;
+    end;
+    Key := 0;
+  end else
+  if key = VK_ESCAPE then
+  begin
+    if FCurrentAngle <> 0 then
+    begin
+      FCurrentAngle := 0;
+      UpdateTransform;
+      result := OnlyRenderChange;
+    end;
+    Key := 0;
+  end;
+end;
+
+function TToolRotateSelection.ToolKeyUp(var key: Word): TRect;
+begin
+  if key = VK_CONTROL then
+  begin
+    snapRotate := false;
+    Key := 0;
+  end;
+  result := EmptyRect;
+end;
+
+function TToolRotateSelection.ToolUp: TRect;
+begin
+  handMoving:= false;
+  Result:= EmptyRect;
+end;
+
+function TToolRotateSelection.Render(VirtualScreen: TBGRABitmap;
+  VirtualScreenWidth, VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
+var pictureRotateCenter: TPointF;
+begin
+  pictureRotateCenter := BitmapToVirtualScreen(FCurrentCenter);
+  result := NicePoint(VirtualScreen, pictureRotateCenter.X,pictureRotateCenter.Y);
+end;
+
+destructor TToolRotateSelection.Destroy;
+begin
+  if handMoving then handMoving := false;
+  inherited Destroy;
+end;
+
+{ TToolMoveSelection }
+
+function TToolMoveSelection.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF; rightBtn: boolean): TRect;
+begin
+  if not handMoving then
+  begin
+    handMoving := true;
+    handOrigin := pt;
+  end;
+  result := EmptyRect;
+end;
+
+function TToolMoveSelection.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF): TRect;
+var dx,dy: integer;
+begin
+  result := EmptyRect;
+  if handMoving and ((handOrigin.X <> pt.X) or (handOrigin.Y <> pt.Y)) then
+  begin
+    dx := pt.X-HandOrigin.X;
+    dy := pt.Y-HandOrigin.Y;
+    Manager.Image.SelectionTransform := AffineMatrixTranslation(dx,dy) * Manager.Image.SelectionTransform;
+    result := OnlyRenderChange;
+  end;
+end;
+
+procedure TToolMoveSelection.DoToolMoveAfter(pt: TPoint; ptF: TPointF);
+begin
+  if handMoving then handOrigin := pt;
+end;
+
+function TToolMoveSelection.ToolUp: TRect;
+begin
+  handMoving := false;
+  result := EmptyRect;
+end;
+
+destructor TToolMoveSelection.Destroy;
+begin
+  if handMoving then handMoving := false;
+  inherited Destroy;
+end;
+
+{ TToolSelectionPen }
+
+function TToolSelectionPen.GetIsSelectingTool: boolean;
+begin
+  Result:= true;
+end;
+
+function TToolSelectionPen.StartDrawing(toolDest: TBGRABitmap; ptF: TPointF;
+  rightBtn: boolean): TRect;
+begin
+  if rightBtn then penColor := BGRABlack else penColor := BGRAWhite;
+  toolDest.DrawLineAntialias(ptF.X,ptF.Y,ptF.X,ptF.Y,penColor,Manager.ToolPenWidth,True);
+  result := GetShapeBounds([ptF],Manager.ToolPenWidth+1);
+end;
+
+function TToolSelectionPen.ContinueDrawing(toolDest: TBGRABitmap; originF,
+  destF: TPointF): TRect;
+begin
+  toolDest.DrawLineAntialias(destF.X,destF.Y,originF.X,originF.Y,penColor,Manager.ToolPenWidth,False);
+  result := GetShapeBounds([destF,originF],Manager.ToolPenWidth+1);
+end;
+
+{ TToolMagicWand }
+
+function TToolMagicWand.GetIsSelectingTool: boolean;
+begin
+  Result:= true;
+end;
+
+function TToolMagicWand.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF; rightBtn: boolean): TRect;
+var penColor: TBGRAPixel;
+begin
+  if not Manager.Image.CurrentLayerVisible then
+  begin
+    result := EmptyRect;
+    exit;
+  end;
+  if rightBtn then penColor := BGRABlack else penColor := BGRAWhite;
+  Manager.Image.CurrentLayerReadOnly.ParallelFloodFill(pt.X,pt.Y,toolDest,penColor,fmDrawWithTransparency,Manager.ToolTolerance);
+  result := rect(0,0,toolDest.Width,toolDest.Height);
+  Action.NotifyChange(toolDest, result);
+  ValidateAction;
+end;
+
+initialization
+
+  RegisterTool(ptMagicWand,TToolMagicWand);
+  RegisterTool(ptSelectPen,TToolSelectionPen);
+  RegisterTool(ptSelectRect,TToolSelectRect);
+  RegisterTool(ptSelectEllipse,TToolSelectEllipse);
+  RegisterTool(ptSelectPoly,TToolSelectPoly);
+  RegisterTool(ptSelectSpline,TToolSelectSpline);
+  RegisterTool(ptMoveSelection,TToolMoveSelection);
+  RegisterTool(ptRotateSelection,TToolRotateSelection);
+
+end.
+

+ 0 - 0
lazpaint/utooltext.pas → lazpaint/tools/utooltext.pas