Browse Source

moving tools in subfolder

Johann 6 năm trước cách đây
mục cha
commit
3602be6ba7

+ 12 - 12
lazpaint/lazpaint.lpi

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

+ 22 - 10
lazpaint/lazpaintembeddedpack.lpk

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

+ 1 - 1
lazpaint/lazpaintembeddedpack.pas

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