Browse Source

Merge pull request #34 from bgrabitmap/dev-lazpaint

Dev lazpaint 7.0.2
circular17 6 years ago
parent
commit
3256a03c40
56 changed files with 3081 additions and 1507 deletions
  1. BIN
      lazpaint/buttons/rasterize.lzp
  2. BIN
      lazpaint/buttons/rasterize.png
  3. BIN
      lazpaint/buttons/rasterize48.lzp
  4. BIN
      lazpaint/buttons/rasterize48.png
  5. 1 1
      lazpaint/lazpaint.lpi
  6. 1 1
      lazpaint/lazpaintembeddedpack.lpk
  7. 43 36
      lazpaint/lazpaintinstance.pas
  8. 342 64
      lazpaint/lazpaintmainform.lfm
  9. 33 11
      lazpaint/lazpaintmainform.pas
  10. 1 1
      lazpaint/lazpainttype.pas
  11. 50 19
      lazpaint/maintoolbar.inc
  12. 28 4
      lazpaint/release/i18n/lazpaint.ar.po
  13. 28 4
      lazpaint/release/i18n/lazpaint.cs.po
  14. 28 4
      lazpaint/release/i18n/lazpaint.de.po
  15. 28 4
      lazpaint/release/i18n/lazpaint.es.po
  16. 28 4
      lazpaint/release/i18n/lazpaint.fi.po
  17. 29 5
      lazpaint/release/i18n/lazpaint.fr.po
  18. 28 4
      lazpaint/release/i18n/lazpaint.ja.po
  19. 28 4
      lazpaint/release/i18n/lazpaint.lv.po
  20. 28 4
      lazpaint/release/i18n/lazpaint.nl.po
  21. 28 4
      lazpaint/release/i18n/lazpaint.po
  22. 28 4
      lazpaint/release/i18n/lazpaint.pt_BR.po
  23. 28 4
      lazpaint/release/i18n/lazpaint.ru.po
  24. 28 4
      lazpaint/release/i18n/lazpaint.sv.po
  25. 8 5
      lazpaint/ucanvassize.pas
  26. 5 5
      lazpaint/uchoosecolor.pas
  27. 18 17
      lazpaint/uconfig.pas
  28. 46 5
      lazpaint/ufilesystem.pas
  29. 5 16
      lazpaint/ufilterconnector.pas
  30. 9 29
      lazpaint/ugraph.pas
  31. 1 1
      lazpaint/ugridbitmap.pas
  32. 86 17
      lazpaint/uimage.pas
  33. 36 31
      lazpaint/uimageaction.pas
  34. 452 164
      lazpaint/uimagediff.pas
  35. 21 37
      lazpaint/uimagestate.pas
  36. 5 4
      lazpaint/uimageview.pas
  37. 53 114
      lazpaint/ulayeraction.pas
  38. 10 3
      lazpaint/ulayerstack.lfm
  39. 132 76
      lazpaint/ulayerstack.pas
  40. 14 3
      lazpaint/umenu.pas
  41. 6 6
      lazpaint/uphongfilter.pas
  42. 6 0
      lazpaint/uresourcestrings.pas
  43. 55 10
      lazpaint/ustatetype.pas
  44. 54 59
      lazpaint/utool.pas
  45. 196 58
      lazpaint/utoolbasic.pas
  46. 24 4
      lazpaint/utoolfloodfill.pas
  47. 367 455
      lazpaint/utoollayer.pas
  48. 18 7
      lazpaint/utoolphong.pas
  49. 146 8
      lazpaint/utoolpolygon.pas
  50. 60 103
      lazpaint/utoolselect.pas
  51. 30 6
      lazpaint/utooltext.pas
  52. 52 17
      lazpaintcontrols/lcvectororiginal.pas
  53. 174 10
      lazpaintcontrols/lcvectorpolyshapes.pas
  54. 61 35
      lazpaintcontrols/lcvectorrectshapes.pas
  55. 87 11
      lazpaintcontrols/lcvectortextshapes.pas
  56. 8 5
      vectoredit/umain.pas

BIN
lazpaint/buttons/rasterize.lzp


BIN
lazpaint/buttons/rasterize.png


BIN
lazpaint/buttons/rasterize48.lzp


BIN
lazpaint/buttons/rasterize48.png


+ 1 - 1
lazpaint/lazpaint.lpi

@@ -21,7 +21,7 @@
     <VersionInfo>
     <VersionInfo>
       <UseVersionInfo Value="True"/>
       <UseVersionInfo Value="True"/>
       <MajorVersionNr Value="7"/>
       <MajorVersionNr Value="7"/>
-      <RevisionNr Value="1"/>
+      <RevisionNr Value="2"/>
       <CharSet Value="04B0"/>
       <CharSet Value="04B0"/>
       <StringTable CompanyName="http://sourceforge.net/projects/lazpaint/" ProductName="LazPaint" InternalName="lazpaint" OriginalFilename="lazpaint.exe"/>
       <StringTable CompanyName="http://sourceforge.net/projects/lazpaint/" ProductName="LazPaint" InternalName="lazpaint" OriginalFilename="lazpaint.exe"/>
     </VersionInfo>
     </VersionInfo>

+ 1 - 1
lazpaint/lazpaintembeddedpack.lpk

@@ -25,7 +25,7 @@
         </Debugging>
         </Debugging>
       </Linking>
       </Linking>
     </CompilerOptions>
     </CompilerOptions>
-    <Version Major="7" Release="1"/>
+    <Version Major="7" Release="2"/>
     <Files Count="78">
     <Files Count="78">
       <Item1>
       <Item1>
         <Filename Value="lazpaintinstance.pas"/>
         <Filename Value="lazpaintinstance.pas"/>

+ 43 - 36
lazpaint/lazpaintinstance.pas

@@ -6,7 +6,7 @@ interface
 
 
 uses
 uses
   Classes, SysUtils, LazPaintType, BGRABitmap, BGRABitmapTypes, BGRALayers,
   Classes, SysUtils, LazPaintType, BGRABitmap, BGRABitmapTypes, BGRALayers,
-  Menus, Controls,
+  Menus, Controls, fgl,
 
 
   LazPaintMainForm, UMainFormLayout,
   LazPaintMainForm, UMainFormLayout,
 
 
@@ -20,6 +20,7 @@ const
   MaxToolPopupShowCount = 2;
   MaxToolPopupShowCount = 2;
 
 
 type
 type
+  TImageListList = specialize TFPGObjectList<TImageList>;
 
 
   { TLazPaintInstance }
   { TLazPaintInstance }
 
 
@@ -72,6 +73,7 @@ type
     FChooseColorPositionDefined,
     FChooseColorPositionDefined,
     FLayerStackPositionDefined,
     FLayerStackPositionDefined,
     FImageListPositionDefined : boolean;
     FImageListPositionDefined : boolean;
+    FCustomImageList: TImageListList;
 
 
     function GetIcons(ASize: integer): TImageList; override;
     function GetIcons(ASize: integer): TImageList; override;
     function GetToolBoxWindowPopup: TPopupMenu; override;
     function GetToolBoxWindowPopup: TPopupMenu; override;
@@ -280,6 +282,7 @@ end;
 procedure TLazPaintInstance.Init(AEmbedded: boolean);
 procedure TLazPaintInstance.Init(AEmbedded: boolean);
 begin
 begin
   Title := 'LazPaint ' + LazPaintCurrentVersion;
   Title := 'LazPaint ' + LazPaintCurrentVersion;
+  FCustomImageList := TImageListList.Create;
   FTopMostInfo.choosecolorHidden := 0;
   FTopMostInfo.choosecolorHidden := 0;
   FTopMostInfo.layerstackHidden := 0;
   FTopMostInfo.layerstackHidden := 0;
   FTopMostInfo.toolboxHidden := 0;
   FTopMostInfo.toolboxHidden := 0;
@@ -319,7 +322,7 @@ begin
   Application.CreateForm(TFImageList, FImageList);
   Application.CreateForm(TFImageList, FImageList);
   FImageList.LazPaintInstance := self;
   FImageList.LazPaintInstance := self;
 
 
-  TFChooseColor_CustomDPI := round(Power(Config.DefaultIconSize(18)/16,0.7)*96);
+  TFChooseColor_CustomDPI := (Config.DefaultIconSize(DoScaleX(16,OriginalDPI))*96+8) div 16;
   Application.CreateForm(TFChooseColor, FChooseColor);
   Application.CreateForm(TFChooseColor, FChooseColor);
   FChooseColor.LazPaintInstance := self;
   FChooseColor.LazPaintInstance := self;
 
 
@@ -386,6 +389,7 @@ end;
 procedure TLazPaintInstance.CreateLayerStack;
 procedure TLazPaintInstance.CreateLayerStack;
 begin
 begin
   if Assigned(FLayerStack) then exit;
   if Assigned(FLayerStack) then exit;
+  TFLayerStack_CustomDPI := (Config.DefaultIconSize(DoScaleX(16,OriginalDPI))*96+8) div 16;
   Application.CreateForm(TFLayerStack,FLayerStack);
   Application.CreateForm(TFLayerStack,FLayerStack);
   FLayerStack.LazPaintInstance := self;
   FLayerStack.LazPaintInstance := self;
 
 
@@ -393,6 +397,7 @@ begin
   FLayerStack.AddButton(FMain.LayerFromFile);
   FLayerStack.AddButton(FMain.LayerFromFile);
   FLayerStack.AddButton(FMain.LayerDuplicate);
   FLayerStack.AddButton(FMain.LayerDuplicate);
   FLayerStack.AddButton(FMain.LayerMergeOver);
   FLayerStack.AddButton(FMain.LayerMergeOver);
+  FLayerStack.AddButton(FMain.LayerRasterize);
   FLayerStack.AddSeparator;
   FLayerStack.AddSeparator;
   FLayerStack.AddButton(FMain.LayerMove);
   FLayerStack.AddButton(FMain.LayerMove);
   FLayerStack.AddButton(FMain.LayerRotate);
   FLayerStack.AddButton(FMain.LayerRotate);
@@ -414,30 +419,30 @@ begin
   FToolbox.AddButton(FToolbox.Toolbar1, FMain.ToolBrush);
   FToolbox.AddButton(FToolbox.Toolbar1, FMain.ToolBrush);
   FToolbox.AddButton(FToolbox.Toolbar1, FMain.ToolEraser);
   FToolbox.AddButton(FToolbox.Toolbar1, FMain.ToolEraser);
   FToolbox.AddButton(FToolbox.Toolbar1, FMain.ToolFloodfill);
   FToolbox.AddButton(FToolbox.Toolbar1, FMain.ToolFloodfill);
-  FToolbox.AddButton(FToolbox.Toolbar1, FMain.ToolGradient);
+  FToolbox.AddButton(FToolbox.Toolbar1, FMain.ToolClone);
 
 
   FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolRect);
   FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolRect);
   FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolEllipse);
   FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolEllipse);
   FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolPolygon);
   FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolPolygon);
   FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolSpline);
   FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolSpline);
-  FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolText);
+  FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolGradient);
   FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolPhong);
   FToolbox.AddButton(FToolbox.Toolbar2, FMain.ToolPhong);
 
 
   FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolSelectRect);
   FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolSelectRect);
   FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolSelectEllipse);
   FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolSelectEllipse);
   FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolSelectPoly);
   FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolSelectPoly);
   FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolSelectSpline);
   FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolSelectSpline);
-  FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolDeformation);
-  FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolTextureMapping);
+  FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolSelectPen);
+  FToolbox.AddButton(FToolbox.Toolbar3, FMain.ToolText);
 
 
   FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolColorPicker);
   FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolColorPicker);
-  FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolClone);
-  FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolSelectPen);
+  FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolMagicWand);
   FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolMoveSelection);
   FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolMoveSelection);
   FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolRotateSelection);
   FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolRotateSelection);
-  FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolMagicWand);
+  FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolDeformation);
+  FToolbox.AddButton(FToolbox.Toolbar4, FMain.ToolTextureMapping);
 
 
-  FToolBox.SetImages(Icons[Config.DefaultIconSize(DoScaleX(24,OriginalDPI))]);
+  FToolBox.SetImages(Icons[Config.DefaultIconSize(DoScaleX(20,OriginalDPI))]);
 
 
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolChangeDocking);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolChangeDocking);
 
 
@@ -446,22 +451,20 @@ begin
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolPen);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolPen);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolBrush);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolBrush);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolEraser);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolEraser);
+  FMain.Layout.DockedToolBoxAddButton(FMain.ToolFloodfill);
+  FMain.Layout.DockedToolBoxAddButton(FMain.ToolClone);
 
 
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolRect);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolRect);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolEllipse);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolEllipse);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolPolygon);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolPolygon);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolSpline);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolSpline);
-
-  FMain.Layout.DockedToolBoxAddButton(FMain.ToolFloodfill);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolGradient);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolGradient);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolPhong);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolPhong);
-
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolText);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolText);
+
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolDeformation);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolDeformation);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolTextureMapping);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolTextureMapping);
 
 
-  FMain.Layout.DockedToolBoxAddButton(FMain.ToolClone);
-
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolSelectRect);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolSelectRect);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolSelectEllipse);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolSelectEllipse);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolSelectPoly);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolSelectPoly);
@@ -474,7 +477,7 @@ begin
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolRotateSelection);
   FMain.Layout.DockedToolBoxAddButton(FMain.ToolRotateSelection);
   FMain.Layout.DockedToolBoxAddButton(FMain.EditDeselect);
   FMain.Layout.DockedToolBoxAddButton(FMain.EditDeselect);
 
 
-  FMain.Layout.DockedToolBoxSetImages(Icons[Config.DefaultIconSize(DoScaleX(24,OriginalDPI))]);
+  FMain.Layout.DockedToolBoxSetImages(Icons[Config.DefaultIconSize(DoScaleX(20,OriginalDPI))]);
 end;
 end;
 
 
 procedure TLazPaintInstance.SetBlackAndWhite(AValue: boolean);
 procedure TLazPaintInstance.SetBlackAndWhite(AValue: boolean);
@@ -843,33 +846,36 @@ begin
 end;
 end;
 
 
 function TLazPaintInstance.GetIcons(ASize: integer): TImageList;
 function TLazPaintInstance.GetIcons(ASize: integer): TImageList;
+var
+  i: Integer;
 begin
 begin
   if Assigned(FMain) then
   if Assigned(FMain) then
   begin
   begin
+    for i := 0 to FCustomImageList.Count-1 do
+      if FCustomImageList[i].Height = ASize then
+        exit(FCustomImageList[i]);
+
     if ASize < 24 then
     if ASize < 24 then
-      result := FMain.ImageList16
-    else
-    if ASize < 32 then
-    begin
-      result := FMain.ImageList24;
-      if result.Count = 0 then
-        ScaleImageList(FMain.ImageList48, 24,24, result);
+    begin;
+      if ASize = 16 then
+        result := FMain.ImageList16
+      else
+      begin
+        result := TImageList.Create(nil);
+        ScaleImageList(FMain.ImageList16, ASize,ASize, result);
+        FCustomImageList.Add(result);
+      end;
     end
     end
     else
     else
-    if ASize < 48 then
-    begin
-      result := FMain.ImageList32;
-      if result.Count = 0 then
-        ScaleImageList(FMain.ImageList48, 32,32, result);
-    end
-    else
-    if ASize < 64 then
-      result := FMain.ImageList48
-    else
     begin
     begin
-      result := FMain.ImageList64;
-      if result.Count = 0 then
-        ScaleImageList(FMain.ImageList48, 64,64, result);
+      if ASize = 48 then
+        result := FMain.ImageList48
+      else
+      begin
+        result := TImageList.Create(nil);
+        ScaleImageList(FMain.ImageList48, ASize,ASize, result);
+        FCustomImageList.Add(result);
+      end;
     end;
     end;
   end else
   end else
     result := nil;
     result := nil;
@@ -1098,6 +1104,7 @@ begin
   //MessageDlg(FScriptContext.RecordedScript,mtInformation,[mbOk],0);
   //MessageDlg(FScriptContext.RecordedScript,mtInformation,[mbOk],0);
   FreeAndNil(FScriptContext);
   FreeAndNil(FScriptContext);
   FreeAndNil(FImageList);
   FreeAndNil(FImageList);
+  FreeAndNil(FCustomImageList);
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 

+ 342 - 64
lazpaint/lazpaintmainform.lfm

@@ -688,20 +688,6 @@ object FMain: TFMain
       Width = 45
       Width = 45
       DropDownCount = 12
       DropDownCount = 12
       ItemHeight = 17
       ItemHeight = 17
-      Items.Strings = (
-        'None'
-        'Tail'
-        'Tip'
-        'Normal'
-        'Cut'
-        'Flipped'
-        'FlippedCut'
-        'Triangle'
-        'TriangleBack1'
-        'TriangleBack2'
-        'HollowTriangle'
-        'HollowTriangleBack1'
-      )
       Style = csOwnerDrawFixed
       Style = csOwnerDrawFixed
       TabOrder = 1
       TabOrder = 1
     end
     end
@@ -712,20 +698,6 @@ object FMain: TFMain
       Width = 45
       Width = 45
       DropDownCount = 12
       DropDownCount = 12
       ItemHeight = 17
       ItemHeight = 17
-      Items.Strings = (
-        'None'
-        'Tail'
-        'Tip'
-        'Normal'
-        'Cut'
-        'Flipped'
-        'FlippedCut'
-        'Triangle'
-        'TriangleBack1'
-        'TriangleBack2'
-        'HollowTriangle'
-        'HollowTriangleBack1'
-      )
       Style = csOwnerDrawFixed
       Style = csOwnerDrawFixed
       TabOrder = 2
       TabOrder = 2
     end
     end
@@ -1617,10 +1589,10 @@ object FMain: TFMain
     end
     end
   end
   end
   object ImageList16: TBGRAImageList
   object ImageList16: TBGRAImageList
-    left = 120
-    top = 432
+    left = 150
+    top = 540
     Bitmap = {
     Bitmap = {
-      4C697C0000001000000010000000FFFFFF00B6B6B6FFB6B6B6FFB6B6B6FFB6B6
+      4C697D0000001000000010000000FFFFFF00B6B6B6FFB6B6B6FFB6B6B6FFB6B6
       B6FFB6B6B6FFB6B6B6FFB6B6B6FFB6B6B6FFB6B6B6FFB6B6B6EFB6B6B6300000
       B6FFB6B6B6FFB6B6B6FFB6B6B6FFB6B6B6FFB6B6B6FFB6B6B6EFB6B6B6300000
       000000000000FFFFFF00FFFFFF00FFFFFF00B6B6B6FFFFFFFFFFFFFFFFFFFFFF
       000000000000FFFFFF00FFFFFF00FFFFFF00B6B6B6FFFFFFFFFFFFFFFFFFFFFF
       FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6B6B6FFDDDDDDFFB6B6B6EFB6B6
       FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6B6B6FFDDDDDDFFB6B6B6EFB6B6
@@ -5588,13 +5560,45 @@ object FMain: TFMain
       000000000000000000000000000000000000000000000000000000000000C098
       000000000000000000000000000000000000000000000000000000000000C098
       3DF9CBA349FFCAA248F8C9A147EF000000000000000000000000000000000000
       3DF9CBA349FFCAA248F8C9A147EF000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000
+      000000000000000000000000000093375CFF8E3559FF8E3559FF8E3559FF0F0E
+      84FF0F0E84FF0F0E84FF0F0E84FF062753FF062753FF062753FF062753FF0000
+      00FF000000FF000000FF000000FF8E3559FFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF8E3559FFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF8E3559FFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF9F7290FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FF743319FF9F7290FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FF743319FF9F7290FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FF743319FF9F7290FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FF743319FF859E9FFFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FF996E2CFF859E9FFFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FF996E2CFF859E9FFFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FF996E2CFF859E9FFFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FF996E2CFF8585A0FFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFA2A373FF8585A0FFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFA2A373FF8585A0FFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFA2A373FF8A8AA6008585A0FF8585A0FF8585A0FF2E98
+      A2FF2E98A2FF2E98A2FF2E98A2FF607745FF607745FF607745FF607745FFA2A3
+      73FFA2A373FFA2A373FFA8A977FF
     }
     }
   end
   end
   object ActionList1: TActionList
   object ActionList1: TActionList
     Images = ImageList16
     Images = ImageList16
-    left = 200
-    top = 432
+    left = 250
+    top = 540
     object FileNew: TAction
     object FileNew: TAction
       Category = 'File'
       Category = 'File'
       Caption = 'New...'
       Caption = 'New...'
@@ -6532,6 +6536,7 @@ object FMain: TFMain
       Hint = 'Zoom layer'
       Hint = 'Zoom layer'
       ImageIndex = 123
       ImageIndex = 123
       OnExecute = LayerZoomExecute
       OnExecute = LayerZoomExecute
+      OnUpdate = LayerZoomUpdate
     end
     end
     object SelectionHorizontalFlip: TAction
     object SelectionHorizontalFlip: TAction
       Category = 'SelectTool'
       Category = 'SelectTool'
@@ -6552,6 +6557,13 @@ object FMain: TFMain
       Hint = 'Remember save format'
       Hint = 'Remember save format'
       OnExecute = FileRememberSaveFormatExecute
       OnExecute = FileRememberSaveFormatExecute
     end
     end
+    object LayerRasterize: TAction
+      Category = 'Layer'
+      Hint = 'Rasterize layer'
+      ImageIndex = 124
+      OnExecute = ScriptExecute
+      OnUpdate = LayerRasterizeUpdate
+    end
   end
   end
   object ColorDialog1: TColorDialog
   object ColorDialog1: TColorDialog
     Title = 'Choose color'
     Title = 'Choose color'
@@ -6583,8 +6595,8 @@ object FMain: TFMain
   end
   end
   object MainMenu1: TMainMenu
   object MainMenu1: TMainMenu
     Images = ImageList16
     Images = ImageList16
-    left = 48
-    top = 432
+    left = 56
+    top = 464
     object MenuFile: TMenuItem
     object MenuFile: TMenuItem
       Caption = 'File'
       Caption = 'File'
       OnClick = MenuFileClick
       OnClick = MenuFileClick
@@ -6618,10 +6630,6 @@ object FMain: TFMain
           Caption = '48px'
           Caption = '48px'
           OnClick = ItemIconSize48Click
           OnClick = ItemIconSize48Click
         end
         end
-        object ItemIconSize64: TMenuItem
-          Caption = '64px'
-          OnClick = ItemIconSize64Click
-        end
         object ItemIconSizeAuto: TMenuItem
         object ItemIconSizeAuto: TMenuItem
           Caption = 'auto'
           Caption = 'auto'
           OnClick = ItemIconSizeAutoClick
           OnClick = ItemIconSizeAutoClick
@@ -6834,8 +6842,8 @@ object FMain: TFMain
   end
   end
   object PopupToolbox: TPopupMenu
   object PopupToolbox: TPopupMenu
     OnPopup = PopupToolboxPopup
     OnPopup = PopupToolboxPopup
-    left = 336
-    top = 354
+    left = 152
+    top = 464
     object MenuDockToolboxLeft: TMenuItem
     object MenuDockToolboxLeft: TMenuItem
       Caption = 'Dock left'
       Caption = 'Dock left'
       OnClick = MenuDockToolboxLeftClick
       OnClick = MenuDockToolboxLeftClick
@@ -6852,10 +6860,10 @@ object FMain: TFMain
   object ImageList48: TBGRAImageList
   object ImageList48: TBGRAImageList
     Height = 48
     Height = 48
     Width = 48
     Width = 48
-    left = 24
-    top = 354
+    left = 56
+    top = 540
     Bitmap = {
     Bitmap = {
-      4C697C0000003000000030000000000000000000000000000000000000000000
+      4C697D0000003000000030000000000000000000000000000000000000000000
       0000000000000000000F000000720000007F0000007F0000007F0000007F0000
       0000000000000000000F000000720000007F0000007F0000007F0000007F0000
       007F0000007F0000007F0000007F0000007F0000007F0000007F0000007F0000
       007F0000007F0000007F0000007F0000007F0000007F0000007F0000007F0000
       007F0000007F0000007F0000007F0000007F0000007F0000007F000000850000
       007F0000007F0000007F0000007F0000007F0000007F0000007F000000850000
@@ -42567,25 +42575,295 @@ object FMain: TFMain
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000
+      000000000000000000000000000096385E9090365BFF8E3559FF8E3559FF8E35
+      59FF8E3559FF8E3559FF8E3559FF8E3559FF8E3559FF8E3559FF8E3559FF0F0E
+      84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E
+      84FF0F0E84FF0F0E84FF0F0E84FF062753FF062753FF062753FF062753FF0627
+      53FF062753FF062753FF062753FF062753FF062753FF062753FF062753FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF0000009090365BFF8E3559FF8E3559FF8E3559FF8E35
+      59FF8E3559FF8E3559FF8E3559FF8E3559FF8E3559FF8E3559FF8E3559FF0F0E
+      84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E
+      84FF0F0E84FF0F0E84FF0F0E84FF062753FF062753FF062753FF062753FF0627
+      53FF062753FF062753FF062753FF062753FF062753FF062753FF062753FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF8E3559FF8E3559FF8E3559FF8E3559FF8E35
+      59FF8E3559FF8E3559FF8E3559FF8E3559FF8E3559FF8E3559FF8E3559FF0F0E
+      84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E84FF0F0E
+      84FF0F0E84FF0F0E84FF0F0E84FF062753FF062753FF062753FF062753FF0627
+      53FF062753FF062753FF062753FF062753FF062753FF062753FF062753FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF8E3559FF8E3559FF8E3559FFDE538CFFDE53
+      8CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D
+      83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF8E3559FF8E3559FF8E3559FFDE538CFFDE53
+      8CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D
+      83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF8E3559FF8E3559FF8E3559FFDE538CFFDE53
+      8CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D
+      83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF8E3559FF8E3559FF8E3559FFDE538CFFDE53
+      8CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D
+      83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF8E3559FF8E3559FF8E3559FFDE538CFFDE53
+      8CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D
+      83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF8E3559FF8E3559FF8E3559FFDE538CFFDE53
+      8CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D
+      83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF8E3559FF8E3559FF8E3559FFDE538CFFDE53
+      8CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D
+      83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF8E3559FF8E3559FF8E3559FFDE538CFFDE53
+      8CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D
+      83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF8E3559FF8E3559FF8E3559FFDE538CFFDE53
+      8CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFFDE538CFF1817
+      CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817CFFF1817
+      CFFF1817CFFF1817CFFF1817CFFF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D
+      83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0A3D83FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF9F7290FF9F7290FF9F7290FFF9B3E2FFF9B3
+      E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FFF9B3E2FF566E
+      FCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566EFCFF566E
+      FCFF566EFCFF566EFCFF566EFCFF287765FF287765FF287765FF287765FF2877
+      65FF287765FF287765FF287765FF287765FF287765FF287765FF287765FFB650
+      28FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB65028FFB650
+      28FF743319FF743319FF743319FF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF859E9FFF859E9FFF859E9FFFD1F7F9FFD1F7
+      F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FFD1F7F9FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6F1FF6FD6
+      F1FF6FD6F1FF6FD6F1FF6FD6F1FF39B23DFF39B23DFF39B23DFF39B23DFF39B2
+      3DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFF39B23DFFF0AD
+      45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD45FFF0AD
+      45FF996E2CFF996E2CFF996E2CFF8585A0FF8585A0FF8585A0FFD0D0FAFFD0D0
+      FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA
+      6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFF
+      B4FFA2A373FFA2A373FFA2A373FF8585A0FF8585A0FF8585A0FFD0D0FAFFD0D0
+      FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA
+      6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFF
+      B4FFA2A373FFA2A373FFA2A373FF8585A0FF8585A0FF8585A0FFD0D0FAFFD0D0
+      FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA
+      6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFF
+      B4FFA2A373FFA2A373FFA2A373FF8585A0FF8585A0FF8585A0FFD0D0FAFFD0D0
+      FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA
+      6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFF
+      B4FFA2A373FFA2A373FFA2A373FF8585A0FF8585A0FF8585A0FFD0D0FAFFD0D0
+      FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA
+      6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFF
+      B4FFA2A373FFA2A373FFA2A373FF8585A0FF8585A0FF8585A0FFD0D0FAFFD0D0
+      FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA
+      6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFF
+      B4FFA2A373FFA2A373FFA2A373FF8585A0FF8585A0FF8585A0FFD0D0FAFFD0D0
+      FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA
+      6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFF
+      B4FFA2A373FFA2A373FFA2A373FF8585A0FF8585A0FF8585A0FFD0D0FAFFD0D0
+      FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA
+      6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFF
+      B4FFA2A373FFA2A373FFA2A373FF8585A0FF8585A0FF8585A0FFD0D0FAFFD0D0
+      FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFFD0D0FAFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EEFEFF48EE
+      FEFF48EEFEFF48EEFEFF48EEFEFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA
+      6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFF96BA6CFFFEFF
+      B4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFFB4FFFEFF
+      B4FFA2A373FFA2A373FFA2A373FF8585A0FF8585A0FF8585A0FF8585A0FF8585
+      A0FF8585A0FF8585A0FF8585A0FF8585A0FF8585A0FF8585A0FF8585A0FF2E98
+      A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98
+      A2FF2E98A2FF2E98A2FF2E98A2FF607745FF607745FF607745FF607745FF6077
+      45FF607745FF607745FF607745FF607745FF607745FF607745FF607745FFA2A3
+      73FFA2A373FFA2A373FFA2A373FFA2A373FFA2A373FFA2A373FFA2A373FFA2A3
+      73FFA2A373FFA2A373FFA2A373FF8787A3FF8585A0FF8585A0FF8585A0FF8585
+      A0FF8585A0FF8585A0FF8585A0FF8585A0FF8585A0FF8585A0FF8585A0FF2E98
+      A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98
+      A2FF2E98A2FF2E98A2FF2E98A2FF607745FF607745FF607745FF607745FF6077
+      45FF607745FF607745FF607745FF607745FF607745FF607745FF607745FFA2A3
+      73FFA2A373FFA2A373FFA2A373FFA2A373FFA2A373FFA2A373FFA2A373FFA2A3
+      73FFA2A373FFA2A373FFA5A675FF8C8CA8908787A3FF8585A0FF8585A0FF8585
+      A0FF8585A0FF8585A0FF8585A0FF8585A0FF8585A0FF8585A0FF8585A0FF2E98
+      A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98A2FF2E98
+      A2FF2E98A2FF2E98A2FF2E98A2FF607745FF607745FF607745FF607745FF6077
+      45FF607745FF607745FF607745FF607745FF607745FF607745FF607745FFA2A3
+      73FFA2A373FFA2A373FFA2A373FFA2A373FFA2A373FFA2A373FFA2A373FFA2A3
+      73FFA2A373FFA5A675FFABAC7990
     }
     }
   end
   end
-  object ImageList32: TBGRAImageList
-    Height = 32
-    Width = 32
-    left = 184
-    top = 354
-  end
-  object ImageList64: TBGRAImageList
-    Height = 64
-    Width = 64
-    left = 256
-    top = 354
-  end
-  object ImageList24: TBGRAImageList
-    Height = 24
-    Width = 24
-    left = 104
-    top = 354
-  end
 end
 end

+ 33 - 11
lazpaint/lazpaintmainform.pas

@@ -28,6 +28,7 @@ type
   { TFMain }
   { TFMain }
 
 
   TFMain = class(TForm)
   TFMain = class(TForm)
+    LayerRasterize: TAction;
     FileRememberSaveFormat: TAction;
     FileRememberSaveFormat: TAction;
     SelectionVerticalFlip: TAction;
     SelectionVerticalFlip: TAction;
     SelectionHorizontalFlip: TAction;
     SelectionHorizontalFlip: TAction;
@@ -50,9 +51,6 @@ type
     Tool_Aliasing: TToolButton;
     Tool_Aliasing: TToolButton;
     ViewPalette: TAction;
     ViewPalette: TAction;
     ViewStatusBar: TAction;
     ViewStatusBar: TAction;
-    ImageList24: TBGRAImageList;
-    ImageList64: TBGRAImageList;
-    ImageList32: TBGRAImageList;
     ImageList48: TBGRAImageList;
     ImageList48: TBGRAImageList;
     ItemViewPalette: TMenuItem;
     ItemViewPalette: TMenuItem;
     MenuIconSize: TMenuItem;
     MenuIconSize: TMenuItem;
@@ -60,7 +58,6 @@ type
     ItemIconSize32: TMenuItem;
     ItemIconSize32: TMenuItem;
     ItemIconSize48: TMenuItem;
     ItemIconSize48: TMenuItem;
     ItemIconSizeAuto: TMenuItem;
     ItemIconSizeAuto: TMenuItem;
-    ItemIconSize64: TMenuItem;
     ItemIconSize24: TMenuItem;
     ItemIconSize24: TMenuItem;
     ItemViewStatusBar: TMenuItem;
     ItemViewStatusBar: TMenuItem;
     MenuShowPalette: TMenuItem;
     MenuShowPalette: TMenuItem;
@@ -456,7 +453,9 @@ type
     procedure ItemFullscreenClick(Sender: TObject);
     procedure ItemFullscreenClick(Sender: TObject);
     procedure ItemIconSize24Click(Sender: TObject);
     procedure ItemIconSize24Click(Sender: TObject);
     procedure ItemViewDockToolboxClick(Sender: TObject);
     procedure ItemViewDockToolboxClick(Sender: TObject);
+    procedure LayerRasterizeUpdate(Sender: TObject);
     procedure LayerZoomExecute(Sender: TObject);
     procedure LayerZoomExecute(Sender: TObject);
+    procedure LayerZoomUpdate(Sender: TObject);
     procedure MenuCoordinatesToolbarClick(Sender: TObject);
     procedure MenuCoordinatesToolbarClick(Sender: TObject);
     procedure MenuCopyPasteToolbarClick(Sender: TObject);
     procedure MenuCopyPasteToolbarClick(Sender: TObject);
     procedure MenuDockToolboxLeftClick(Sender: TObject);
     procedure MenuDockToolboxLeftClick(Sender: TObject);
@@ -820,7 +819,8 @@ implementation
 
 
 uses LCLIntf, BGRAUTF8, ugraph, math, umac, uclipboard, ucursors,
 uses LCLIntf, BGRAUTF8, ugraph, math, umac, uclipboard, ucursors,
    ufilters, ULoadImage, ULoading, UFileExtensions, UBrushType,
    ufilters, ULoadImage, ULoading, UFileExtensions, UBrushType,
-   ugeometricbrush, UPreviewDialog, UQuestion, BGRALayerOriginal;
+   ugeometricbrush, UPreviewDialog, UQuestion, BGRALayerOriginal,
+   BGRATransform, LCVectorPolyShapes;
 
 
 const PenWidthFactor = 10;
 const PenWidthFactor = 10;
 
 
@@ -876,7 +876,6 @@ begin
   InFormMouseMove:= false;
   InFormMouseMove:= false;
   InFormPaint := false;
   InFormPaint := false;
 
 
-  CreateMenuAndToolbar;
   {$IFDEF LINUX}
   {$IFDEF LINUX}
   ComboBox_BrushSelect.Top := ComboBox_BrushSelect.Top - 2;
   ComboBox_BrushSelect.Top := ComboBox_BrushSelect.Top - 2;
   ComboBox_BrushSelect.Font.Height := -10;
   ComboBox_BrushSelect.Font.Height := -10;
@@ -906,6 +905,7 @@ begin
     Panel_Tool,Panel_Color,Panel_Texture,Panel_Grid,Panel_PenWidth,Panel_Aliasing,Panel_ShapeOption,Panel_LineCap,Panel_JoinStyle,
     Panel_Tool,Panel_Color,Panel_Texture,Panel_Grid,Panel_PenWidth,Panel_Aliasing,Panel_ShapeOption,Panel_LineCap,Panel_JoinStyle,
     Panel_PenStyle,Panel_SplineStyle,Panel_Eraser,Panel_Tolerance,Panel_GradientType,Panel_Text,Panel_TextOutline,
     Panel_PenStyle,Panel_SplineStyle,Panel_Eraser,Panel_Tolerance,Panel_GradientType,Panel_Text,Panel_TextOutline,
     Panel_PhongShape,Panel_Altitude,Panel_PerspectiveOption,Panel_Brush,Panel_Ratio],Panel_ToolbarBackground);
     Panel_PhongShape,Panel_Altitude,Panel_PerspectiveOption,Panel_Brush,Panel_Ratio],Panel_ToolbarBackground);
+  m.ImageList := LazPaintInstance.Icons[ScaleY(16, 96)];
   m.Apply;
   m.Apply;
   FLayout.Menu := m;
   FLayout.Menu := m;
 end;
 end;
@@ -965,6 +965,7 @@ end;
 procedure TFMain.Init;
 procedure TFMain.Init;
 begin
 begin
   initialized := false;
   initialized := false;
+  CreateMenuAndToolbar;
   Config := LazPaintInstance.Config;
   Config := LazPaintInstance.Config;
   if Config.Default3dObjectDirectory = '' then
   if Config.Default3dObjectDirectory = '' then
     Config.SetDefault3dObjectDirectory(StartDirectory);
     Config.SetDefault3dObjectDirectory(StartDirectory);
@@ -1132,8 +1133,7 @@ begin
   updateForVSCursor:= false;
   updateForVSCursor:= false;
   if ToolManager.ToolMove(BmpPos,CurrentPressure) then
   if ToolManager.ToolMove(BmpPos,CurrentPressure) then
   begin
   begin
-    FImageView.UpdatePicture(PictureCanvasOfs, FLayout.WorkArea,
-                             {$IFDEF USEPAINTBOXPICTURE}PaintBox_Picture{$ELSE}self{$ENDIF});
+    FImageView.UpdatePicture(PictureCanvasOfs, FLayout.WorkArea, self);
     ToolManager.ToolMoveAfter(FImageView.FormToBitmap(FormMouseMovePos)); //new BmpPos after repaint
     ToolManager.ToolMoveAfter(FImageView.FormToBitmap(FormMouseMovePos)); //new BmpPos after repaint
   end else
   end else
     updateForVSCursor := true;
     updateForVSCursor := true;
@@ -2711,9 +2711,22 @@ begin
           end;
           end;
           ptMoveLayer, ptRotateLayer, ptZoomLayer:
           ptMoveLayer, ptRotateLayer, ptZoomLayer:
           begin
           begin
-            if image.CurrentLayerEquals(BGRAPixelTransparent) then
+            if image.LayerOriginalDefined[image.CurrentLayerIndex] and
+               image.LayerOriginalKnown[image.CurrentLayerIndex] and
+               (image.LayerOriginal[image.CurrentLayerIndex]=nil) then
+            begin
+              Tool := ptHand;
+              result := srException;
+            end;
+
+            if image.CurrentLayerEquals(BGRAPixelTransparent) and not
+              (image.LayerOriginalDefined[image.CurrentLayerIndex] and
+               image.LayerOriginalKnown[image.CurrentLayerIndex] and
+               not image.LayerOriginal[image.CurrentLayerIndex].GetRenderBounds(
+                 rect(-maxLongInt div 2,-maxLongInt div 2,maxLongInt div 2,maxLongInt div 2),
+                 AffineMatrixIdentity).IsEmpty) then
             begin
             begin
-              MessagePopup(rsLazPaint, 4000);
+              MessagePopup(rsEmptyLayer, 4000);
               Tool := ptHand;
               Tool := ptHand;
               result := srException;
               result := srException;
             end;
             end;
@@ -2943,11 +2956,21 @@ begin
     Layout.ToolBoxDocking := twWindow;
     Layout.ToolBoxDocking := twWindow;
 end;
 end;
 
 
+procedure TFMain.LayerRasterizeUpdate(Sender: TObject);
+begin
+  LayerRasterize.Enabled := Image.LayerOriginalDefined[Image.CurrentLayerIndex];
+end;
+
 procedure TFMain.LayerZoomExecute(Sender: TObject);
 procedure TFMain.LayerZoomExecute(Sender: TObject);
 begin
 begin
   ChooseTool(ptZoomLayer);
   ChooseTool(ptZoomLayer);
 end;
 end;
 
 
+procedure TFMain.LayerZoomUpdate(Sender: TObject);
+begin
+  LayerZoom.Enabled := Image.CurrentLayerVisible and Image.SelectionMaskEmpty;
+end;
+
 procedure TFMain.MenuCoordinatesToolbarClick(Sender: TObject);
 procedure TFMain.MenuCoordinatesToolbarClick(Sender: TObject);
 begin
 begin
   Panel_Coordinates.Visible := not Panel_Coordinates.Visible;
   Panel_Coordinates.Visible := not Panel_Coordinates.Visible;
@@ -3010,7 +3033,6 @@ begin
   ItemIconSize24.Checked := iconSize=24;
   ItemIconSize24.Checked := iconSize=24;
   ItemIconSize32.Checked := iconSize=32;
   ItemIconSize32.Checked := iconSize=32;
   ItemIconSize48.Checked := iconSize=48;
   ItemIconSize48.Checked := iconSize=48;
-  ItemIconSize64.Checked := iconSize=64;
   ItemIconSizeAuto.Checked := iconSize=0;
   ItemIconSizeAuto.Checked := iconSize=0;
 end;
 end;
 
 

+ 1 - 1
lazpaint/lazpainttype.pas

@@ -10,7 +10,7 @@ uses
   {$IFDEF LINUX}, InterfaceBase{$ENDIF};
   {$IFDEF LINUX}, InterfaceBase{$ENDIF};
 
 
 const
 const
-  LazPaintVersion = 7000100;
+  LazPaintVersion = 7000200;
 
 
   function LazPaintVersionStr: string;
   function LazPaintVersionStr: string;
 
 

+ 50 - 19
lazpaint/maintoolbar.inc

@@ -282,6 +282,7 @@ end;
 procedure TFMain.InitToolbarElements;
 procedure TFMain.InitToolbarElements;
 var
 var
   i: Integer;
   i: Integer;
+  ak: TArrowKind;
 begin
 begin
   Panel_Embedded.Visible := LazPaintInstance.Embedded;
   Panel_Embedded.Visible := LazPaintInstance.Embedded;
   Panel_File.Visible := not LazPaintInstance.Embedded;
   Panel_File.Visible := not LazPaintInstance.Embedded;
@@ -292,6 +293,13 @@ begin
   Shape_BackColor.Brush.Color := BGRAToColor(ToolManager.ToolBackColor);
   Shape_BackColor.Brush.Color := BGRAToColor(ToolManager.ToolBackColor);
   SpinEdit_BackOpacity.Value := ToolManager.ToolBackColor.alpha;
   SpinEdit_BackOpacity.Value := ToolManager.ToolBackColor.alpha;
   SpinEdit_PenWidth.Value := Round(ToolManager.ToolPenWidth*PenWidthFactor);
   SpinEdit_PenWidth.Value := Round(ToolManager.ToolPenWidth*PenWidthFactor);
+  for ak := low(TArrowKind) to high(TArrowKind) do
+  begin
+    ComboBox_ArrowStart.Items.Add(ArrowKindToStr[ak]);
+    ComboBox_ArrowEnd.Items.Add(ArrowKindToStr[ak]);
+  end;
+  ComboBox_ArrowStart.ItemIndex := 0;
+  ComboBox_ArrowEnd.ItemIndex := 0;
   SpinEdit_ArrowSizeX.Value := round(ToolManager.ToolArrowSize.x*PenWidthFactor);
   SpinEdit_ArrowSizeX.Value := round(ToolManager.ToolArrowSize.x*PenWidthFactor);
   SpinEdit_ArrowSizeY.Value := round(ToolManager.ToolArrowSize.y*PenWidthFactor);
   SpinEdit_ArrowSizeY.Value := round(ToolManager.ToolArrowSize.y*PenWidthFactor);
   Tool_DrawShapeBorder.Down := ToolManager.ToolOptionDrawShape;
   Tool_DrawShapeBorder.Down := ToolManager.ToolOptionDrawShape;
@@ -305,10 +313,7 @@ begin
   Tool_GridMoveWithoutDeformation.Down := ToolManager.ToolDeformationGridMoveWithoutDeformation;
   Tool_GridMoveWithoutDeformation.Down := ToolManager.ToolDeformationGridMoveWithoutDeformation;
   SpinEdit_GridNbX.Value := ToolManager.ToolDeformationGridNbX-1;
   SpinEdit_GridNbX.Value := ToolManager.ToolDeformationGridNbX-1;
   SpinEdit_GridNbY.Value := ToolManager.ToolDeformationGridNbY-1;
   SpinEdit_GridNbY.Value := ToolManager.ToolDeformationGridNbY-1;
-  if ToolManager.ToolSplineEasyBezier then
-    Combo_SplineStyle.ItemIndex := Combo_SplineStyle.Items.IndexOf('Easy Bézier')
-  else
-    Combo_SplineStyle.ItemIndex:= ord(ToolManager.ToolSplineStyle);
+  Combo_SplineStyle.ItemIndex:= ord(ToolManager.ToolSplineStyle);
   UpdateCurveMode;
   UpdateCurveMode;
   Tool_TextOutline.Down := ToolManager.ToolTextOutline;
   Tool_TextOutline.Down := ToolManager.ToolTextOutline;
   SpinEdit_TextOutlineWidth.Value := round(ToolManager.ToolTextOutlineWidth*PenWidthFactor);
   SpinEdit_TextOutlineWidth.Value := round(ToolManager.ToolTextOutlineWidth*PenWidthFactor);
@@ -755,8 +760,9 @@ begin
   if initialized then
   if initialized then
   begin
   begin
      if not Tool_DrawShapeBorder.Down and not Tool_FillShape.Down then
      if not Tool_DrawShapeBorder.Down and not Tool_FillShape.Down then
-        Tool_DrawShapeBorder.Down := true;
+       Tool_FillShape.Down := true;
      ToolManager.ToolOptionDrawShape:= Tool_DrawShapeBorder.Down;
      ToolManager.ToolOptionDrawShape:= Tool_DrawShapeBorder.Down;
+     ToolManager.ToolOptionFillShape:= Tool_FillShape.Down;
      UpdateEditPicture;
      UpdateEditPicture;
   end;
   end;
 end;
 end;
@@ -766,7 +772,8 @@ begin
   if initialized then
   if initialized then
   begin
   begin
      if not Tool_DrawShapeBorder.Down and not Tool_FillShape.Down then
      if not Tool_DrawShapeBorder.Down and not Tool_FillShape.Down then
-        Tool_FillShape.Down := true;
+        Tool_DrawShapeBorder.Down := true;
+     ToolManager.ToolOptionDrawShape:= Tool_DrawShapeBorder.Down;
      ToolManager.ToolOptionFillShape:= Tool_FillShape.Down;
      ToolManager.ToolOptionFillShape:= Tool_FillShape.Down;
      UpdateEditPicture;
      UpdateEditPicture;
   end;
   end;
@@ -821,20 +828,30 @@ end;
 
 
 procedure TFMain.ComboBox_ArrowStartChange(Sender: TObject);
 procedure TFMain.ComboBox_ArrowStartChange(Sender: TObject);
 begin
 begin
-  if initialized then UpdateEditPicture;
+  if initialized then
+  begin
+    ToolManager.ToolArrowStart:= ComboBox_ArrowStart.Text;
+    UpdateEditPicture;
+  end;
 end;
 end;
 
 
 procedure TFMain.ComboBox_ArrowStartDrawItem(Control: TWinControl;
 procedure TFMain.ComboBox_ArrowStartDrawItem(Control: TWinControl;
   Index: Integer; ARect: TRect; State: TOwnerDrawState);
   Index: Integer; ARect: TRect; State: TOwnerDrawState);
+var
+  kind: String;
 begin
 begin
   if Index = -1 then exit;
   if Index = -1 then exit;
-  ToolManager.ToolArrowStart := ComboBox_ArrowStart.Items[Index];
-  DrawArrow(ComboBox_ArrowStart.Canvas,ARect,True,ToolManager.ToolArrowStart,ToolManager.ToolLineCap,State);
+  kind := ComboBox_ArrowStart.Items[Index];
+  DrawArrow(ComboBox_ArrowStart.Canvas,ARect,True,kind,ToolManager.ToolLineCap,State);
 end;
 end;
 
 
 procedure TFMain.ComboBox_ArrowEndChange(Sender: TObject);
 procedure TFMain.ComboBox_ArrowEndChange(Sender: TObject);
 begin
 begin
-  if initialized then UpdateEditPicture;
+  if initialized then
+  begin
+    ToolManager.ToolArrowEnd:= ComboBox_ArrowEnd.Text;
+    UpdateEditPicture;
+  end;
 end;
 end;
 
 
 procedure TFMain.BrushLoadFromFileExecute(Sender: TObject);
 procedure TFMain.BrushLoadFromFileExecute(Sender: TObject);
@@ -860,10 +877,12 @@ end;
 
 
 procedure TFMain.ComboBox_ArrowEndDrawItem(Control: TWinControl;
 procedure TFMain.ComboBox_ArrowEndDrawItem(Control: TWinControl;
   Index: Integer; ARect: TRect; State: TOwnerDrawState);
   Index: Integer; ARect: TRect; State: TOwnerDrawState);
+var
+  kind: String;
 begin
 begin
   if Index = -1 then exit;
   if Index = -1 then exit;
-  ToolManager.ToolArrowEnd := ComboBox_ArrowEnd.Items[Index];
-  DrawArrow(ComboBox_ArrowEnd.Canvas,ARect,False,ToolManager.ToolArrowEnd,ToolManager.ToolLineCap,State);
+  kind := ComboBox_ArrowEnd.Items[Index];
+  DrawArrow(ComboBox_ArrowEnd.Canvas,ARect,False,kind,ToolManager.ToolLineCap,State);
 end;
 end;
 
 
 procedure TFMain.SpinEdit_ArrowSizeChange(Sender: TObject);
 procedure TFMain.SpinEdit_ArrowSizeChange(Sender: TObject);
@@ -974,9 +993,9 @@ end;
 procedure TFMain.SetCurveMode(AMode: TToolSplineMode);
 procedure TFMain.SetCurveMode(AMode: TToolSplineMode);
 begin
 begin
   if (ToolManager.CurrentTool <> nil) and
   if (ToolManager.CurrentTool <> nil) and
-     (ToolManager.CurrentTool is TToolGenericSpline) then
+     (ToolManager.CurrentTool is TToolSpline) then
   begin
   begin
-    (ToolManager.CurrentTool as TToolGenericSpline).CurrentMode := AMode;
+    (ToolManager.CurrentTool as TToolSpline).CurrentMode := AMode;
     UpdateCurveMode;
     UpdateCurveMode;
   end;
   end;
 end;
 end;
@@ -984,11 +1003,11 @@ end;
 procedure TFMain.UpdateCurveMode;
 procedure TFMain.UpdateCurveMode;
 var
 var
   cm: TToolSplineMode;
   cm: TToolSplineMode;
-  splineTool: TToolGenericSpline;
+  splineTool: TToolSpline;
 begin
 begin
-  if (ToolManager.CurrentTool <> nil) and (ToolManager.CurrentTool is TToolGenericSpline) then
+  if (ToolManager.CurrentTool <> nil) and (ToolManager.CurrentTool is TToolSpline) then
   begin
   begin
-    splineTool := ToolManager.CurrentTool as TToolGenericSpline;
+    splineTool := ToolManager.CurrentTool as TToolSpline;
     Tool_CurveMovePoint.Enabled := not splineTool.IsHandDrawing and not splineTool.IsIdle;
     Tool_CurveMovePoint.Enabled := not splineTool.IsHandDrawing and not splineTool.IsIdle;
     cm := splineTool.CurrentMode;
     cm := splineTool.CurrentMode;
     if Tool_CurveMovePoint.Down <> (cm = tsmMovePoint) then
     if Tool_CurveMovePoint.Down <> (cm = tsmMovePoint) then
@@ -1008,7 +1027,6 @@ begin
   if initialized then
   if initialized then
   begin
   begin
     v := Combo_SplineStyle.Text;
     v := Combo_SplineStyle.Text;
-    ToolManager.ToolSplineEasyBezier := false;
     if v = 'Inside' then ToolManager.ToolSplineStyle := ssInside else
     if v = 'Inside' then ToolManager.ToolSplineStyle := ssInside else
     if v = 'Inside + ends' then ToolManager.ToolSplineStyle := ssInsideWithEnds else
     if v = 'Inside + ends' then ToolManager.ToolSplineStyle := ssInsideWithEnds else
     if v = 'Crossing' then ToolManager.ToolSplineStyle := ssCrossing else
     if v = 'Crossing' then ToolManager.ToolSplineStyle := ssCrossing else
@@ -1016,7 +1034,20 @@ begin
     if v = 'Outside' then ToolManager.ToolSplineStyle := ssOutside else
     if v = 'Outside' then ToolManager.ToolSplineStyle := ssOutside else
     if v = 'Round outside' then ToolManager.ToolSplineStyle:= ssRoundOutside else
     if v = 'Round outside' then ToolManager.ToolSplineStyle:= ssRoundOutside else
     if v = 'Vertex to side' then ToolManager.ToolSplineStyle:= ssVertexToSide else
     if v = 'Vertex to side' then ToolManager.ToolSplineStyle:= ssVertexToSide else
-    if v = 'Easy Bézier' then ToolManager.ToolSplineEasyBezier := true;
+    if v = 'Easy Bézier' then ToolManager.ToolSplineStyle := ssEasyBezier;
+    if ToolManager.ToolSplineStyle<>ssEasyBezier then
+    begin
+      Tool_CurveMovePoint.Down := true;
+      SetCurveMode(tsmMovePoint);
+      Tool_CurveModeAuto.Enabled := false;
+      Tool_CurveModeAngle.Enabled := false;
+      Tool_CurveModeCurve.Enabled := false;
+    end else
+    begin
+      Tool_CurveModeAuto.Enabled := true;
+      Tool_CurveModeAngle.Enabled := true;
+      Tool_CurveModeCurve.Enabled := true;
+    end;
     UpdateEditPicture(True);
     UpdateEditPicture(True);
     UpdateCurveMode;
     UpdateCurveMode;
   end;
   end;

+ 28 - 4
lazpaint/release/i18n/lazpaint.ar.po

@@ -1101,10 +1101,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1259,6 +1255,10 @@ msgctxt "tfmain.layermove.hint"
 msgid "Move layer"
 msgid "Move layer"
 msgstr "تحريك الطبقة"
 msgstr "تحريك الطبقة"
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "tfmain.layerremovecurrent.hint"
 msgctxt "tfmain.layerremovecurrent.hint"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2919,6 +2919,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr ""
 msgstr ""
@@ -3311,6 +3315,10 @@ msgstr "px"
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr "المجلدات الأخيرة:"
 msgstr "المجلدات الأخيرة:"
@@ -3428,6 +3436,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr ""
 msgstr ""
@@ -3436,6 +3448,10 @@ msgstr ""
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr "نقل التحديد إلى طبقة أخرى؟"
 msgstr "نقل التحديد إلى طبقة أخرى؟"
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3456,6 +3472,14 @@ msgstr "لايمكن حفظ الملف :"
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "الأمر غير معروف :"
 msgstr "الأمر غير معروف :"
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr "نعم"
 msgstr "نعم"

+ 28 - 4
lazpaint/release/i18n/lazpaint.cs.po

@@ -1089,10 +1089,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1247,6 +1243,10 @@ msgctxt "tfmain.layermove.hint"
 msgid "Move layer"
 msgid "Move layer"
 msgstr "Přesunout vrstvu"
 msgstr "Přesunout vrstvu"
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "tfmain.layerremovecurrent.hint"
 msgctxt "tfmain.layerremovecurrent.hint"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2906,6 +2906,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr "Chyba"
 msgstr "Chyba"
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr ""
 msgstr ""
@@ -3298,6 +3302,10 @@ msgstr "px"
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr "Nedávné adresáře:"
 msgstr "Nedávné adresáře:"
@@ -3415,6 +3423,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr ""
 msgstr ""
@@ -3423,6 +3435,10 @@ msgstr ""
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr "Přenést výběr do jiné vrstvy?"
 msgstr "Přenést výběr do jiné vrstvy?"
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3443,6 +3459,14 @@ msgstr "Nelze uložit soubor :"
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "Neznámý příkaz :"
 msgstr "Neznámý příkaz :"
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr "Ano"
 msgstr "Ano"

+ 28 - 4
lazpaint/release/i18n/lazpaint.de.po

@@ -1106,10 +1106,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1264,6 +1260,10 @@ msgctxt "tfmain.layermove.hint"
 msgid "Move layer"
 msgid "Move layer"
 msgstr "Ebene verschieben"
 msgstr "Ebene verschieben"
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "tfmain.layerremovecurrent.hint"
 msgctxt "tfmain.layerremovecurrent.hint"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2924,6 +2924,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr "Fehler"
 msgstr "Fehler"
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr "Fehler beim Öffnen der Datei \"%1\""
 msgstr "Fehler beim Öffnen der Datei \"%1\""
@@ -3316,6 +3320,10 @@ msgstr "px"
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr "RAM-Disk"
 msgstr "RAM-Disk"
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr "Letzte Verzeichnisse"
 msgstr "Letzte Verzeichnisse"
@@ -3433,6 +3441,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr "Zu viel Ebene"
 msgstr "Zu viel Ebene"
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr "Bilder Gesamt: %1"
 msgstr "Bilder Gesamt: %1"
@@ -3441,6 +3453,10 @@ msgstr "Bilder Gesamt: %1"
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr "Auswahl auf andere Ebene verschieben?"
 msgstr "Auswahl auf andere Ebene verschieben?"
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3461,6 +3477,14 @@ msgstr "Kann Datei nicht sichern: "
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "Unbekannter Befehl: "
 msgstr "Unbekannter Befehl: "
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr "Ja"
 msgstr "Ja"

+ 28 - 4
lazpaint/release/i18n/lazpaint.es.po

@@ -1085,10 +1085,6 @@ msgstr "32px"
 msgid "48px"
 msgid "48px"
 msgstr "48px"
 msgstr "48px"
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr "64px"
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr "automático"
 msgstr "automático"
@@ -1243,6 +1239,10 @@ msgctxt "tfmain.layermove.hint"
 msgid "Move layer"
 msgid "Move layer"
 msgstr "Mover capa"
 msgstr "Mover capa"
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr "Pixelar capa"
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "tfmain.layerremovecurrent.hint"
 msgctxt "tfmain.layerremovecurrent.hint"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2904,6 +2904,10 @@ msgstr "Entradas"
 msgid "Error"
 msgid "Error"
 msgstr "Error"
 msgstr "Error"
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr "Error cargando el original pero se puedo pixelar la capa."
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr "Error abriendo archivo \"%1\""
 msgstr "Error abriendo archivo \"%1\""
@@ -3308,6 +3312,10 @@ msgstr "px"
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr "Disco RAM"
 msgstr "Disco RAM"
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr "Capa de trama"
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr "Carpetas recientes:"
 msgstr "Carpetas recientes:"
@@ -3427,6 +3435,10 @@ msgstr "La herramienta no puede ser usada en una capa invisible"
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr "Demasiado capas"
 msgstr "Demasiado capas"
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr "Demasiado figuras en la capa"
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr "Total: %1"
 msgstr "Total: %1"
@@ -3435,6 +3447,10 @@ msgstr "Total: %1"
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr "¿Transferir selección a otra capa?"
 msgstr "¿Transferir selección a otra capa?"
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr "Capa de trama transformada"
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr "¿Quieres transformar el contenido de la selección?"
 msgstr "¿Quieres transformar el contenido de la selección?"
@@ -3455,6 +3471,14 @@ msgstr "Imposible guardar archivo: "
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "Comando desconocido: "
 msgstr "Comando desconocido: "
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr "Original desconocido"
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr "Capa vectorial"
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr "Sí"
 msgstr "Sí"

+ 28 - 4
lazpaint/release/i18n/lazpaint.fi.po

@@ -1075,10 +1075,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1233,6 +1229,10 @@ msgctxt "TFMAIN.LAYERMOVE.HINT"
 msgid "Move layer"
 msgid "Move layer"
 msgstr "Siirrä kerrosta"
 msgstr "Siirrä kerrosta"
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "TFMAIN.LAYERREMOVECURRENT.HINT"
 msgctxt "TFMAIN.LAYERREMOVECURRENT.HINT"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2889,6 +2889,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr "Virhe"
 msgstr "Virhe"
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr "Virhe avattaessa tiedostoa \"%1\""
 msgstr "Virhe avattaessa tiedostoa \"%1\""
@@ -3281,6 +3285,10 @@ msgstr ""
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr "Viimeisimmät kansiot:"
 msgstr "Viimeisimmät kansiot:"
@@ -3398,6 +3406,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr "Kuvia kaikkiaan: %1"
 msgstr "Kuvia kaikkiaan: %1"
@@ -3406,6 +3418,10 @@ msgstr "Kuvia kaikkiaan: %1"
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3426,6 +3442,14 @@ msgstr ""
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr "Kyllä"
 msgstr "Kyllä"

+ 29 - 5
lazpaint/release/i18n/lazpaint.fr.po

@@ -1091,10 +1091,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1249,6 +1245,10 @@ msgctxt "tfmain.layermove.hint"
 msgid "Move layer"
 msgid "Move layer"
 msgstr "Déplacer le calque"
 msgstr "Déplacer le calque"
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr "Pixéliser le calque"
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "tfmain.layerremovecurrent.hint"
 msgctxt "tfmain.layerremovecurrent.hint"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2364,7 +2364,7 @@ msgstr "OK"
 #: tfpixelate.caption
 #: tfpixelate.caption
 msgctxt "tfpixelate.caption"
 msgctxt "tfpixelate.caption"
 msgid "Pixelate"
 msgid "Pixelate"
-msgstr "Pixeliser"
+msgstr "Pixéliser"
 
 
 #: tfpixelate.label_pixelsize.caption
 #: tfpixelate.label_pixelsize.caption
 msgctxt "tfpixelate.label_pixelsize.caption"
 msgctxt "tfpixelate.label_pixelsize.caption"
@@ -2911,6 +2911,10 @@ msgstr "Entrées"
 msgid "Error"
 msgid "Error"
 msgstr "Erreur"
 msgstr "Erreur"
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr "Erreur au chargement de l'original alors le calque peut être pixelisé."
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr "Erreur lors de l'ouverture de \"%1\""
 msgstr "Erreur lors de l'ouverture de \"%1\""
@@ -3315,6 +3319,10 @@ msgstr "px"
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr "RAM disque"
 msgstr "RAM disque"
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr "Calque en pixels"
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr "Répertoires récents :"
 msgstr "Répertoires récents :"
@@ -3434,6 +3442,10 @@ msgstr "L'outil ne peut pas être utilisé sur un calque invisible"
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr "Trop de calques"
 msgstr "Trop de calques"
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr "Trop de formes dans le calque"
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr "Nb. total d'images : %1"
 msgstr "Nb. total d'images : %1"
@@ -3442,6 +3454,10 @@ msgstr "Nb. total d'images : %1"
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr "Voulez-vous transférer la sélection vers un autre calque ?"
 msgstr "Voulez-vous transférer la sélection vers un autre calque ?"
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr "Calque en pixels transformé"
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr "Voulez-vous transformer le contenu de la sélection ?"
 msgstr "Voulez-vous transformer le contenu de la sélection ?"
@@ -3462,6 +3478,14 @@ msgstr "Impossible d'enregistrer le fichier : "
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "Commande inconnue : "
 msgstr "Commande inconnue : "
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr "Original inconnu"
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr "Calque vectoriel"
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr "Oui"
 msgstr "Oui"

+ 28 - 4
lazpaint/release/i18n/lazpaint.ja.po

@@ -1096,10 +1096,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1254,6 +1250,10 @@ msgctxt "tfmain.layermove.hint"
 msgid "Move layer"
 msgid "Move layer"
 msgstr ""
 msgstr ""
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "tfmain.layerremovecurrent.hint"
 msgctxt "tfmain.layerremovecurrent.hint"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2912,6 +2912,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr ""
 msgstr ""
@@ -3303,6 +3307,10 @@ msgstr ""
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr ""
 msgstr ""
@@ -3420,6 +3428,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr ""
 msgstr ""
@@ -3428,6 +3440,10 @@ msgstr ""
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3448,6 +3464,14 @@ msgstr "ファイルの保存に失敗しました:"
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "Unknown command:"
 msgstr "Unknown command:"
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr ""
 msgstr ""

+ 28 - 4
lazpaint/release/i18n/lazpaint.lv.po

@@ -1092,10 +1092,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1250,6 +1246,10 @@ msgctxt "TFMAIN.LAYERMOVE.HINT"
 msgid "Move layer"
 msgid "Move layer"
 msgstr "Pārvietot slāni"
 msgstr "Pārvietot slāni"
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "TFMAIN.LAYERREMOVECURRENT.HINT"
 msgctxt "TFMAIN.LAYERREMOVECURRENT.HINT"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2907,6 +2907,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr "Kļūda"
 msgstr "Kļūda"
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr "Nevar atvērt failu \"%1\""
 msgstr "Nevar atvērt failu \"%1\""
@@ -3299,6 +3303,10 @@ msgstr "pikseļi"
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr "Nesen lietotās mapes:"
 msgstr "Nesen lietotās mapes:"
@@ -3416,6 +3424,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr "Attēlu kopskaits: %1"
 msgstr "Attēlu kopskaits: %1"
@@ -3424,6 +3436,10 @@ msgstr "Attēlu kopskaits: %1"
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr "Pārvietot iezīmējumu uz citu slāni?"
 msgstr "Pārvietot iezīmējumu uz citu slāni?"
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3444,6 +3460,14 @@ msgstr "Nevar saglabāt failu:"
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "Nepazīstama komanda:"
 msgstr "Nepazīstama komanda:"
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr "Jā"
 msgstr "Jā"

+ 28 - 4
lazpaint/release/i18n/lazpaint.nl.po

@@ -1113,10 +1113,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1272,6 +1268,10 @@ msgctxt "tfmain.layermove.hint"
 msgid "Move layer"
 msgid "Move layer"
 msgstr "Laag verplaatsen"
 msgstr "Laag verplaatsen"
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "tfmain.layerremovecurrent.hint"
 msgctxt "tfmain.layerremovecurrent.hint"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2933,6 +2933,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr "Fout"
 msgstr "Fout"
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr ""
 msgstr ""
@@ -3325,6 +3329,10 @@ msgstr "px"
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr "Recente directories:"
 msgstr "Recente directories:"
@@ -3442,6 +3450,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr ""
 msgstr ""
@@ -3450,6 +3462,10 @@ msgstr ""
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr "Verplaats selectie naar andere laag?"
 msgstr "Verplaats selectie naar andere laag?"
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3470,6 +3486,14 @@ msgstr "Kan bestand niet opslaan : "
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "Onbekend commando : "
 msgstr "Onbekend commando : "
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr "Ja"
 msgstr "Ja"

+ 28 - 4
lazpaint/release/i18n/lazpaint.po

@@ -1075,10 +1075,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1233,6 +1229,10 @@ msgctxt "TFMAIN.LAYERMOVE.HINT"
 msgid "Move layer"
 msgid "Move layer"
 msgstr ""
 msgstr ""
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "TFMAIN.LAYERREMOVECURRENT.HINT"
 msgctxt "TFMAIN.LAYERREMOVECURRENT.HINT"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2889,6 +2889,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr ""
 msgstr ""
@@ -3280,6 +3284,10 @@ msgstr ""
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr ""
 msgstr ""
@@ -3397,6 +3405,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr ""
 msgstr ""
@@ -3405,6 +3417,10 @@ msgstr ""
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3425,6 +3441,14 @@ msgstr ""
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr ""
 msgstr ""

+ 28 - 4
lazpaint/release/i18n/lazpaint.pt_BR.po

@@ -1099,10 +1099,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1257,6 +1253,10 @@ msgctxt "TFMAIN.LAYERMOVE.HINT"
 msgid "Move layer"
 msgid "Move layer"
 msgstr "Mover camada"
 msgstr "Mover camada"
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "TFMAIN.LAYERREMOVECURRENT.HINT"
 msgctxt "TFMAIN.LAYERREMOVECURRENT.HINT"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2915,6 +2915,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr ""
 msgstr ""
@@ -3307,6 +3311,10 @@ msgstr ""
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr "Diretórios recentes:"
 msgstr "Diretórios recentes:"
@@ -3424,6 +3432,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr ""
 msgstr ""
@@ -3432,6 +3444,10 @@ msgstr ""
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr "Transferir seleção para outra camada?"
 msgstr "Transferir seleção para outra camada?"
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3452,6 +3468,14 @@ msgstr "Não foi possível salvar o arquivo : "
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "Comando desconhecido : "
 msgstr "Comando desconhecido : "
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr ""
 msgstr ""

+ 28 - 4
lazpaint/release/i18n/lazpaint.ru.po

@@ -1093,10 +1093,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1251,6 +1247,10 @@ msgctxt "tfmain.layermove.hint"
 msgid "Move layer"
 msgid "Move layer"
 msgstr "Переместить слой"
 msgstr "Переместить слой"
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "tfmain.layerremovecurrent.hint"
 msgctxt "tfmain.layerremovecurrent.hint"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2909,6 +2909,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr ""
 msgstr ""
@@ -3301,6 +3305,10 @@ msgstr ""
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr ""
 msgstr ""
@@ -3418,6 +3426,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr ""
 msgstr ""
@@ -3426,6 +3438,10 @@ msgstr ""
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr "Перенести выделение на другой слой?"
 msgstr "Перенести выделение на другой слой?"
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3446,6 +3462,14 @@ msgstr "Не удается сохранить файл:"
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "Неизвестная команда:"
 msgstr "Неизвестная команда:"
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr ""
 msgstr ""

+ 28 - 4
lazpaint/release/i18n/lazpaint.sv.po

@@ -1081,10 +1081,6 @@ msgstr ""
 msgid "48px"
 msgid "48px"
 msgstr ""
 msgstr ""
 
 
-#: tfmain.itemiconsize64.caption
-msgid "64px"
-msgstr ""
-
 #: tfmain.itemiconsizeauto.caption
 #: tfmain.itemiconsizeauto.caption
 msgid "auto"
 msgid "auto"
 msgstr ""
 msgstr ""
@@ -1239,6 +1235,10 @@ msgctxt "tfmain.layermove.hint"
 msgid "Move layer"
 msgid "Move layer"
 msgstr ""
 msgstr ""
 
 
+#: tfmain.layerrasterize.hint
+msgid "Rasterize layer"
+msgstr ""
+
 #: tfmain.layerremovecurrent.hint
 #: tfmain.layerremovecurrent.hint
 msgctxt "tfmain.layerremovecurrent.hint"
 msgctxt "tfmain.layerremovecurrent.hint"
 msgid "Remove layer"
 msgid "Remove layer"
@@ -2897,6 +2897,10 @@ msgstr ""
 msgid "Error"
 msgid "Error"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rserrorloadingoriginal
+msgid "Error while loading original however layer can be rasterized."
+msgstr ""
+
 #: uresourcestrings.rserroronopeningfile
 #: uresourcestrings.rserroronopeningfile
 msgid "Error on opening file \"%1\""
 msgid "Error on opening file \"%1\""
 msgstr ""
 msgstr ""
@@ -3288,6 +3292,10 @@ msgstr ""
 msgid "RAM disk"
 msgid "RAM disk"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rsrasterlayer
+msgid "Raster layer"
+msgstr ""
+
 #: uresourcestrings.rsrecentdirectories
 #: uresourcestrings.rsrecentdirectories
 msgid "Recent directories:"
 msgid "Recent directories:"
 msgstr ""
 msgstr ""
@@ -3405,6 +3413,10 @@ msgstr ""
 msgid "Too many layers"
 msgid "Too many layers"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstoomanyshapesinlayer
+msgid "Too many shapes in layer"
+msgstr ""
+
 #: uresourcestrings.rstotalimages
 #: uresourcestrings.rstotalimages
 msgid "Total images: %1"
 msgid "Total images: %1"
 msgstr ""
 msgstr ""
@@ -3413,6 +3425,10 @@ msgstr ""
 msgid "Transfer selection to other layer?"
 msgid "Transfer selection to other layer?"
 msgstr ""
 msgstr ""
 
 
+#: uresourcestrings.rstransformedrasterlayer
+msgid "Transformed raster layer"
+msgstr ""
+
 #: uresourcestrings.rstransformselectioncontent
 #: uresourcestrings.rstransformselectioncontent
 msgid "Do you want to transform content of the selection?"
 msgid "Do you want to transform content of the selection?"
 msgstr ""
 msgstr ""
@@ -3433,6 +3449,14 @@ msgstr "Kunde inte spara fil :"
 msgid "Unknown command : "
 msgid "Unknown command : "
 msgstr "Okänt kommando :"
 msgstr "Okänt kommando :"
 
 
+#: uresourcestrings.rsunknownoriginal
+msgid "Unknown original"
+msgstr ""
+
+#: uresourcestrings.rsvectoriallayer
+msgid "Vectorial layer"
+msgstr ""
+
 #: uresourcestrings.rsyes
 #: uresourcestrings.rsyes
 msgid "Yes"
 msgid "Yes"
 msgstr ""
 msgstr ""

+ 8 - 5
lazpaint/ucanvassize.pas

@@ -68,11 +68,14 @@ begin
     if not repeatImage and layeredBmp.LayerOriginalDefined[i] and layeredBmp.LayerOriginalKnown[i] then
     if not repeatImage and layeredBmp.LayerOriginalDefined[i] and layeredBmp.LayerOriginalKnown[i] then
     begin
     begin
       orig := layeredBmp.LayerOriginal[i];
       orig := layeredBmp.LayerOriginal[i];
-      if result.IndexOfOriginal(orig)=-1 then result.AddOriginal(orig,false);
-      result.LayerOriginalGuid[idx] := orig.Guid;
-      newOrigin := ChangeCanvasSizeOrigin(layeredBmp.Width,layeredBmp.Height,newwidth,newHeight,anchor);
-      result.LayerOriginalMatrix[idx] := AffineMatrixTranslation(newOrigin.X,newOrigin.Y)*layeredBmp.LayerOriginalMatrix[i];
-      result.RenderLayerFromOriginal(idx);
+      if Assigned(orig) then
+      begin
+        if result.IndexOfOriginal(orig)=-1 then result.AddOriginal(orig,false);
+        result.LayerOriginalGuid[idx] := orig.Guid;
+        newOrigin := ChangeCanvasSizeOrigin(layeredBmp.Width,layeredBmp.Height,newwidth,newHeight,anchor);
+        result.LayerOriginalMatrix[idx] := AffineMatrixTranslation(newOrigin.X,newOrigin.Y)*layeredBmp.LayerOriginalMatrix[i];
+        result.RenderLayerFromOriginal(idx);
+      end;
     end;
     end;
   end;
   end;
 end;
 end;

+ 5 - 5
lazpaint/uchoosecolor.pas

@@ -85,7 +85,7 @@ type
     property AvailableBmpWidth: integer read GetAvailableBmpWidth;
     property AvailableBmpWidth: integer read GetAvailableBmpWidth;
   end;
   end;
 
 
-var TFChooseColor_CustomDPI: integer = 0;
+var TFChooseColor_CustomDPI: integer = 96;
 
 
 implementation
 implementation
 
 
@@ -98,10 +98,10 @@ begin
    {$IFDEF LINUX}
    {$IFDEF LINUX}
    BorderStyle:= bsDialog;
    BorderStyle:= bsDialog;
    {$ENDIF}
    {$ENDIF}
-   ClientHeight := DoScaleY(160,OriginalDPI,TFChooseColor_CustomDPI);
+   ClientHeight := DoScaleY(150,OriginalDPI,TFChooseColor_CustomDPI);
    ScaleControl(Self,OriginalDPI,TFChooseColor_CustomDPI);
    ScaleControl(Self,OriginalDPI,TFChooseColor_CustomDPI);
-   EColor.Font.Height := -FontEmHeightSign*DoScaleY(12,OriginalDPI,TFChooseColor_CustomDPI);
-   LColor.Font.Height := -FontEmHeightSign*DoScaleY(12,OriginalDPI,TFChooseColor_CustomDPI);
+   EColor.Font.Height := -FontEmHeightSign*DoScaleY(14,OriginalDPI,TFChooseColor_CustomDPI);
+   LColor.Font.Height := -FontEmHeightSign*DoScaleY(14,OriginalDPI,TFChooseColor_CustomDPI);
    EColor.AdjustSize;
    EColor.AdjustSize;
    EColor.Text:= '';
    EColor.Text:= '';
    EColor.Top := ClientHeight;
    EColor.Top := ClientHeight;
@@ -118,7 +118,7 @@ begin
    EColor.Visible := false;
    EColor.Visible := false;
 
 
    topmargin := DoScaleY(27,OriginalDPI,TFChooseColor_CustomDPI);
    topmargin := DoScaleY(27,OriginalDPI,TFChooseColor_CustomDPI);
-   barwidth := DoScaleX(20,OriginalDPI,TFChooseColor_CustomDPI);
+   barwidth := DoScaleX(18,OriginalDPI,TFChooseColor_CustomDPI);
    cursorplace := DoScaleX(10,OriginalDPI,TFChooseColor_CustomDPI);
    cursorplace := DoScaleX(10,OriginalDPI,TFChooseColor_CustomDPI);
    margin := DoScaleY(8,OriginalDPI,TFChooseColor_CustomDPI);
    margin := DoScaleY(8,OriginalDPI,TFChooseColor_CustomDPI);
    cursormargin := DoScaleX(2,OriginalDPI,TFChooseColor_CustomDPI);
    cursormargin := DoScaleX(2,OriginalDPI,TFChooseColor_CustomDPI);

+ 18 - 17
lazpaint/uconfig.pas

@@ -209,12 +209,12 @@ type
     function ToolPopupMessageShownCount(index: integer): integer;
     function ToolPopupMessageShownCount(index: integer): integer;
     procedure SetToolPopupMessageShownCount(index: integer; AValue: integer);
     procedure SetToolPopupMessageShownCount(index: integer; AValue: integer);
 
 
-    function DefaultToolLightPositionX: integer;
-    procedure SetDefaultToolLightPositionX(value: integer);
-    function DefaultToolLightPositionY: integer;
-    procedure SetDefaultToolLightPositionY(value: integer);
-    procedure SetDefaultToolLightPosition(value: TPoint);
-    function DefaultToolLightPosition: TPoint;
+    function DefaultToolLightPositionX: single;
+    procedure SetDefaultToolLightPositionX(value: single);
+    function DefaultToolLightPositionY: single;
+    procedure SetDefaultToolLightPositionY(value: single);
+    procedure SetDefaultToolLightPosition(const value: TPointF);
+    function DefaultToolLightPosition: TPointF;
     function DefaultToolLightAltitude: integer;
     function DefaultToolLightAltitude: integer;
     procedure SetDefaultToolLightAltitude(value: integer);
     procedure SetDefaultToolLightAltitude(value: integer);
     function DefaultToolShapeAltitude: integer;
     function DefaultToolShapeAltitude: integer;
@@ -891,35 +891,35 @@ begin
   iniOptions.WriteInteger('Popup','ToolPopupMessage' + inttostr(index), avalue);
   iniOptions.WriteInteger('Popup','ToolPopupMessage' + inttostr(index), avalue);
 end;
 end;
 
 
-function TLazPaintConfig.DefaultToolLightPositionX: integer;
+function TLazPaintConfig.DefaultToolLightPositionX: single;
 begin
 begin
-  result := iniOptions.ReadInteger('Tool','LightPositionX',0);
+  result := iniOptions.ReadFloat('Tool','LightPositionX',0);
 end;
 end;
 
 
-procedure TLazPaintConfig.SetDefaultToolLightPositionX(value: integer);
+procedure TLazPaintConfig.SetDefaultToolLightPositionX(value: single);
 begin
 begin
-  iniOptions.WriteInteger('Tool','LightPositionX',value);
+  iniOptions.WriteFloat('Tool','LightPositionX',value);
 end;
 end;
 
 
-function TLazPaintConfig.DefaultToolLightPositionY: integer;
+function TLazPaintConfig.DefaultToolLightPositionY: single;
 begin
 begin
-  result := iniOptions.ReadInteger('Tool','LightPositionY',0);
+  result := iniOptions.ReadFloat('Tool','LightPositionY',0);
 end;
 end;
 
 
-procedure TLazPaintConfig.SetDefaultToolLightPositionY(value: integer);
+procedure TLazPaintConfig.SetDefaultToolLightPositionY(value: single);
 begin
 begin
-  iniOptions.WriteInteger('Tool','LightPositionY',value);
+  iniOptions.WriteFloat('Tool','LightPositionY',value);
 end;
 end;
 
 
-procedure TLazPaintConfig.SetDefaultToolLightPosition(value: TPoint);
+procedure TLazPaintConfig.SetDefaultToolLightPosition(const value: TPointF);
 begin
 begin
   SetDefaultToolLightPositionX(value.X);
   SetDefaultToolLightPositionX(value.X);
   SetDefaultToolLightPositionY(value.Y);
   SetDefaultToolLightPositionY(value.Y);
 end;
 end;
 
 
-function TLazPaintConfig.DefaultToolLightPosition: TPoint;
+function TLazPaintConfig.DefaultToolLightPosition: TPointF;
 begin
 begin
-  result := Point(DefaultToolLightPositionX,DefaultToolLightPositionY);
+  result := PointF(DefaultToolLightPositionX,DefaultToolLightPositionY);
 end;
 end;
 
 
 function TLazPaintConfig.DefaultToolLightAltitude: integer;
 function TLazPaintConfig.DefaultToolLightAltitude: integer;
@@ -1467,6 +1467,7 @@ end;
 function TLazPaintConfig.DefaultIconSize(defaultValue: integer): integer;
 function TLazPaintConfig.DefaultIconSize(defaultValue: integer): integer;
 begin
 begin
   result := iniOptions.ReadInteger('General','DefaultIconSize',0);
   result := iniOptions.ReadInteger('General','DefaultIconSize',0);
+  if result > 48 then result := 48;
   if result = 0 then result := defaultValue;
   if result = 0 then result := defaultValue;
 end;
 end;
 
 

+ 46 - 5
lazpaint/ufilesystem.pas

@@ -113,13 +113,41 @@ const LinuxFileSystems: array[0..20] of string =
   {HPFS} 'hpfs', {NWFS} 'ncp',
   {HPFS} 'hpfs', {NWFS} 'ncp',
   'nfs', 'smb', 'ncpfs');
   'nfs', 'smb', 'ncpfs');
 
 
+function ReadBooleanFromFile(AFilename: string): boolean;
+var t: textfile;
+  s: string;
+begin
+  assignfile(t, AFilename);
+  reset(t);
+  readln(t,s);
+  closefile(t);
+  result := trim(s)='1';
+end;
+
+function UnespacePath(APath: string): string;
+var
+  i, charCode: Integer;
+begin
+  result := APath;
+  for i := length(result)-3 downto 1 do
+    if (result[i]='\') and (result[i+1] in['0','1']) and
+      (result[i+2] in ['0'..'9']) and (result[i+3] in ['0'..'9']) then
+    begin
+      charCode := (ord(result[i+3])-ord('0'))+
+                  (ord(result[i+2])-ord('0'))*8+
+                  (ord(result[i+1])-ord('0'))*64;
+      delete(result,i+1,3);
+      result[i] := chr(charCode);
+    end;
+end;
+
 function GetLinuxFileSystems(AMountsFile: string): TFileSystemArray;
 function GetLinuxFileSystems(AMountsFile: string): TFileSystemArray;
 var mtab: TextFile;
 var mtab: TextFile;
   desc: string;
   desc: string;
   parsedDesc: TStringList;
   parsedDesc: TStringList;
-  lFileSystem: string;
+  lFileSystem, removableInfo, lPath: string;
   i: integer;
   i: integer;
-  found: boolean;
+  found, isRemovable: boolean;
 begin
 begin
   result := nil;
   result := nil;
   parsedDesc := TStringList.Create;
   parsedDesc := TStringList.Create;
@@ -135,6 +163,7 @@ begin
         if parsedDesc.Count >= 4 then
         if parsedDesc.Count >= 4 then
         begin
         begin
           lFileSystem:= parsedDesc[2];
           lFileSystem:= parsedDesc[2];
+          lPath := parsedDesc[1];
           found := false;
           found := false;
           for i := low(LinuxFileSystems) to high(LinuxFileSystems) do
           for i := low(LinuxFileSystems) to high(LinuxFileSystems) do
             if LinuxFileSystems[i] = lFileSystem then
             if LinuxFileSystems[i] = lFileSystem then
@@ -142,13 +171,13 @@ begin
               found := true;
               found := true;
               break;
               break;
             end;
             end;
-          if found then
+          if found and not lPath.StartsWith('/boot/') then
           begin
           begin
             setlength(result, length(result)+1);
             setlength(result, length(result)+1);
             with result[high(result)] do
             with result[high(result)] do
             begin
             begin
               fileSystem := lFileSystem;
               fileSystem := lFileSystem;
-              path := parsedDesc[1];
+              path := UnespacePath(parsedDesc[1]);
               device := parsedDesc[0];
               device := parsedDesc[0];
               longFilenames := (fileSystem <> 'minix') and
               longFilenames := (fileSystem <> 'minix') and
                 (fileSystem <> 'msdos');
                 (fileSystem <> 'msdos');
@@ -167,8 +196,20 @@ begin
                   device := rsFixedDrive;
                   device := rsFixedDrive;
               end
               end
               else
               else
-              if (copy(device,1,2) = 'fd') or (copy(device,1,2) = 'sd') then
+              if copy(device,1,2) = 'fd' then
                 device := rsRemovableDrive
                 device := rsRemovableDrive
+              else if copy(device,1,2) = 'sd' then
+              begin
+                removableInfo := '/sys/block/'+copy(device,1,3)+'/removable';
+                if FileExists(removableInfo) then
+                  isRemovable := ReadBooleanFromFile(removableInfo)
+                else
+                  isRemovable := false;
+                if isRemovable then
+                  device := rsRemovableDrive
+                else
+                  device := rsFixedDrive;
+              end
               else if copy(device,1,3) = 'scd' then
               else if copy(device,1,3) = 'scd' then
                 device := rsCdRom;
                 device := rsCdRom;
               if (fileSystem = 'nfs') or (fileSystem = 'smb') or (fileSystem = 'ncpfs') then device := rsNetworkDrive;
               if (fileSystem = 'nfs') or (fileSystem = 'smb') or (fileSystem = 'ncpfs') then device := rsNetworkDrive;

+ 5 - 16
lazpaint/ufilterconnector.pas

@@ -23,7 +23,6 @@ type
     FWorkArea: TRect;
     FWorkArea: TRect;
     FWorkAreaFullySelected: boolean;
     FWorkAreaFullySelected: boolean;
     FParameters: TVariableSet;
     FParameters: TVariableSet;
-    FLayerBackupImage: TBGRABitmap;
     function GetActionDone: boolean;
     function GetActionDone: boolean;
     function GetActiveLayeOffset: TPoint;
     function GetActiveLayeOffset: TPoint;
     function GetActiveLayer: TBGRABitmap;
     function GetActiveLayer: TBGRABitmap;
@@ -60,7 +59,7 @@ type
 
 
 implementation
 implementation
 
 
-uses Types, BGRABitmapTypes, BGRATransform;
+uses Types, BGRABitmapTypes;
 
 
 { TFilterConnector }
 { TFilterConnector }
 
 
@@ -90,9 +89,7 @@ end;
 
 
 function TFilterConnector.GetBackupLayer: TBGRABitmap;
 function TFilterConnector.GetBackupLayer: TBGRABitmap;
 begin
 begin
-  if Assigned(FLayerBackupImage) then
-    result := FLayerBackupImage
-  else if ApplyOnSelectionLayer then
+  if ApplyOnSelectionLayer then
     result := FAction.BackupSelectionLayer
     result := FAction.BackupSelectionLayer
   else
   else
     result := FAction.BackupSelectedLayer;
     result := FAction.BackupSelectedLayer;
@@ -122,16 +119,9 @@ begin
   ApplyOnSelectionLayer:= not FLazPaintInstance.Image.SelectionLayerIsEmpty;
   ApplyOnSelectionLayer:= not FLazPaintInstance.Image.SelectionLayerIsEmpty;
 
 
   if AAction = nil then
   if AAction = nil then
-    AAction := ALazPaintInstance.Image.CreateAction(AApplyOfsBefore and not ApplyOnSelectionLayer);
-
-  if ApplyOnSelectionLayer and not IsAffineMatrixIdentity(AAction.SelectionTransform) then
-  begin
-    AAction.ApplySelectionTransform;
-    FLayerBackupImage := AAction.GetOrCreateSelectionLayer.Duplicate as TBGRABitmap;
-  end else
-  begin
-    FLayerBackupImage := nil;
-  end;
+    AAction := ALazPaintInstance.Image.CreateAction(
+                  AApplyOfsBefore and not ApplyOnSelectionLayer,
+                  ApplyOnSelectionLayer);
 
 
   FAction := AAction;
   FAction := AAction;
   FActionOwned:= AOwned;
   FActionOwned:= AOwned;
@@ -191,7 +181,6 @@ end;
 destructor TFilterConnector.Destroy;
 destructor TFilterConnector.Destroy;
 begin
 begin
   DiscardAction;
   DiscardAction;
-  FLayerBackupImage.Free;
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 

+ 9 - 29
lazpaint/ugraph.pas

@@ -51,15 +51,14 @@ function ClearTypeFilter(source: TBGRACustomBitmap): TBGRACustomBitmap;
 function ClearTypeInverseFilter(source: TBGRACustomBitmap): TBGRACustomBitmap;
 function ClearTypeInverseFilter(source: TBGRACustomBitmap): TBGRACustomBitmap;
 
 
 function DoResample(source :TBGRABitmap; newWidth, newHeight: integer; StretchMode: TResampleMode): TBGRABitmap;
 function DoResample(source :TBGRABitmap; newWidth, newHeight: integer; StretchMode: TResampleMode): TBGRABitmap;
-procedure DrawArrow(ACanvas: TCanvas; ARect: TRect; AStart: boolean; AKind: string; ALineCap: TPenEndCap; State: TOwnerDrawState);
-procedure ApplyArrowStyle(AStart: boolean; AKind: string; ABmp: TBGRABitmap; ASize: TPointF);
+procedure DrawArrow(ACanvas: TCanvas; ARect: TRect; AStart: boolean; AKindStr: string; ALineCap: TPenEndCap; State: TOwnerDrawState);
 procedure BCAssignSystemStyle(AButton: TBCButton);
 procedure BCAssignSystemStyle(AButton: TBCButton);
 
 
 implementation
 implementation
 
 
 uses GraphType, math, Types, BGRAUTF8, FileUtil, dialogs, BGRAAnimatedGif,
 uses GraphType, math, Types, BGRAUTF8, FileUtil, dialogs, BGRAAnimatedGif,
   BGRAGradients, BGRATextFX, uresourcestrings, LCScaleDPI, BCTypes,
   BGRAGradients, BGRATextFX, uresourcestrings, LCScaleDPI, BCTypes,
-  BGRAThumbnail;
+  BGRAThumbnail, LCVectorPolyShapes;
 
 
 procedure BCAssignSystemState(AState: TBCButtonState; AFontColor, ATopColor, AMiddleTopColor, AMiddleBottomColor, ABottomColor, ABorderColor: TColor);
 procedure BCAssignSystemState(AState: TBCButtonState; AFontColor, ATopColor, AMiddleTopColor, AMiddleBottomColor, ABottomColor, ABorderColor: TColor);
 begin
 begin
@@ -733,11 +732,13 @@ begin
   result := source.Resample(newWidth,newHeight,StretchMode) as TBGRABitmap;
   result := source.Resample(newWidth,newHeight,StretchMode) as TBGRABitmap;
 end;
 end;
 
 
-procedure DrawArrow(ACanvas: TCanvas; ARect: TRect; AStart: boolean; AKind: string; ALineCap: TPenEndCap; State: TOwnerDrawState);
+procedure DrawArrow(ACanvas: TCanvas; ARect: TRect; AStart: boolean; AKindStr: string; ALineCap: TPenEndCap; State: TOwnerDrawState);
 var bmp : TBGRABitmap;
 var bmp : TBGRABitmap;
   c,c2: TBGRAPixel;
   c,c2: TBGRAPixel;
   x1,x2,xm1,xm2,y,w,temp: single;
   x1,x2,xm1,xm2,y,w,temp: single;
+  kind: TArrowKind;
 begin
 begin
+  kind := StrToArrowKind(AKindStr);
   if odSelected in State then
   if odSelected in State then
   begin
   begin
     c2 := ColorToBGRA(ColorToRGB(clHighlight));
     c2 := ColorToBGRA(ColorToRGB(clHighlight));
@@ -748,7 +749,7 @@ begin
     c := ColorToBGRA(ColorToRGB(clWindowText));
     c := ColorToBGRA(ColorToRGB(clWindowText));
   end;
   end;
   with Size(ARect) do bmp:= TBGRABitmap.Create(cx,cy,c2);
   with Size(ARect) do bmp:= TBGRABitmap.Create(cx,cy,c2);
-  ApplyArrowStyle(AStart,AKind,bmp,PointF(1.5,1.5));
+  ApplyArrowStyle(bmp.Arrow,AStart,kind,PointF(1.5,1.5));
   bmp.LineCap := ALineCap;
   bmp.LineCap := ALineCap;
   w := bmp.Height/5;
   w := bmp.Height/5;
   if w > 0 then
   if w > 0 then
@@ -757,8 +758,8 @@ begin
     x2 := 0;
     x2 := 0;
     xm1 := 0;
     xm1 := 0;
     xm2 := w*2.5;
     xm2 := w*2.5;
-    if (AKind = 'Normal') or (AKind = 'Cut') then x1 -= w*0.7 else
-    if (AKind = 'Flipped') or (AKind = 'FlippedCut') then x1 += w*0.7;
+    if kind in[akNone,akCut] then x1 -= w*0.7 else
+    if kind in[akFlipped,akFlippedCut] then x1 += w*0.7;
     if not AStart then
     if not AStart then
     begin
     begin
       temp := x1;
       temp := x1;
@@ -772,7 +773,7 @@ begin
     x1 -= 0.5;
     x1 -= 0.5;
     x2 += bmp.Width-0.5;
     x2 += bmp.Width-0.5;
     y := (bmp.Height-1)/2;
     y := (bmp.Height-1)/2;
-    if (AKind='Tail') or (AKind='None') or (AKind = 'Tip') then w *= 2;
+    if kind in[akTail,akNone,akTip] then w *= 2;
     bmp.DrawLineAntialias(x1,y,x2,y,c,w);
     bmp.DrawLineAntialias(x1,y,x2,y,c,w);
     if bmp.Width > bmp.Height*2 then
     if bmp.Width > bmp.Height*2 then
       bmp.GradientFill(0,0,bmp.width,bmp.height,c2,BGRAPixelTransparent,gtLinear,PointF(xm1,0),PointF(xm2,0),dmDrawWithTransparency);
       bmp.GradientFill(0,0,bmp.width,bmp.height,c2,BGRAPixelTransparent,gtLinear,PointF(xm1,0),PointF(xm2,0),dmDrawWithTransparency);
@@ -781,27 +782,6 @@ begin
   bmp.Free;
   bmp.Free;
 end;
 end;
 
 
-procedure ApplyArrowStyle(AStart: boolean; AKind: string; ABmp: TBGRABitmap; ASize: TPointF);
-var backOfs: single;
-begin
-  backOfs := 0;
-  if (ASize.x = 0) or (ASize.y = 0) then AKind := 'None';
-  if (length(AKind)>0) and (AKind[length(AKind)] in['1'..'9']) then backOfs := (ord(AKind[length(AKind)])-ord('0'))*0.25;
-  case AKind of
-  'Tail': if AStart then ABmp.ArrowStartAsTail else ABmp.ArrowEndAsTail;
-  'Tip': if AStart then ABmp.ArrowStartAsTriangle else ABmp.ArrowEndAsTriangle;
-  'Normal','Cut','Flipped','FlippedCut': if AStart then ABmp.ArrowStartAsClassic((AKind='Flipped') or (AKind='FlippedCut'),(AKind='Cut') or (AKind='FlippedCut'))
-    else ABmp.ArrowEndAsClassic((AKind='Flipped') or (AKind='FlippedCut'),(AKind='Cut') or (AKind='FlippedCut'));
-  'Triangle','TriangleBack1','TriangleBack2': if AStart then ABmp.ArrowStartAsTriangle(backOfs) else ABmp.ArrowEndAsTriangle(backOfs);
-  'HollowTriangle','HollowTriangleBack1','HollowTriangleBack2': if AStart then ABmp.ArrowStartAsTriangle(backOfs,False,True) else ABmp.ArrowEndAsTriangle(backOfs,False,True);
-  else if AStart then ABmp.ArrowStartAsNone else ABmp.ArrowEndAsNone;
-  end;
-  if (AKind = 'Tip') and not ((ASize.x = 0) or (ASize.y = 0)) then
-    ASize := ASize*(0.5/ASize.y);
-  if AStart then ABmp.ArrowStartSize := ASize
-  else ABmp.ArrowEndSize := ASize;
-end;
-
 function CreateMarbleTexture(tx,ty: integer): TBGRABitmap;
 function CreateMarbleTexture(tx,ty: integer): TBGRABitmap;
 var
 var
   colorOscillation: integer;
   colorOscillation: integer;

+ 1 - 1
lazpaint/ugridbitmap.pas

@@ -133,7 +133,7 @@ begin
     m[1,3] := 0;
     m[1,3] := 0;
     m[2,3] := 0;
     m[2,3] := 0;
     ofs := m*PointF(ACellRect.Left,ACellRect.Top);
     ofs := m*PointF(ACellRect.Left,ACellRect.Top);
-    Destination.PutImageAffine(AffineMatrixTranslation(ofs.x,ofs.y)*Matrix,ACellBitmap,Filter,Opacity);
+    Destination.PutImageAffine(AffineMatrixTranslation(ofs.x,ofs.y)*Matrix,ACellBitmap,Filter,Mode,Opacity);
   end;
   end;
 end;
 end;
 
 

+ 86 - 17
lazpaint/uimage.pas

@@ -138,7 +138,7 @@ type
     procedure CompressUndo;
     procedure CompressUndo;
     function UsedMemory: int64;
     function UsedMemory: int64;
 
 
-    function CreateAction(AApplyOfsBefore: boolean=false): TLayerAction;
+    function CreateAction(AApplyOfsBefore: boolean=false; AApplySelTransformBefore: boolean=false): TLayerAction;
 
 
     // invalidating
     // invalidating
     procedure ImageMayChange(ARect: TRect; ADiscardSelectionLayerAfterMask: boolean = true);
     procedure ImageMayChange(ARect: TRect; ADiscardSelectionLayerAfterMask: boolean = true);
@@ -172,6 +172,7 @@ type
     procedure AddNewLayer(AOriginal: TBGRALayerCustomOriginal; AName: string; ABlendOp: TBlendOperation; AMatrix: TAffineMatrix);
     procedure AddNewLayer(AOriginal: TBGRALayerCustomOriginal; AName: string; ABlendOp: TBlendOperation; AMatrix: TAffineMatrix);
     procedure AddNewLayer(ALayer: TBGRABitmap; AName: string; ABlendOp: TBlendOperation);
     procedure AddNewLayer(ALayer: TBGRABitmap; AName: string; ABlendOp: TBlendOperation);
     procedure DuplicateLayer;
     procedure DuplicateLayer;
+    procedure RasterizeLayer;
     procedure MergeLayerOver;
     procedure MergeLayerOver;
     procedure MoveLayer(AFromIndex,AToIndex: integer);
     procedure MoveLayer(AFromIndex,AToIndex: integer);
     procedure RemoveLayer;
     procedure RemoveLayer;
@@ -1016,15 +1017,18 @@ begin
       result += (TObject(FUndoList[i]) as TStateDifference).UsedMemory;
       result += (TObject(FUndoList[i]) as TStateDifference).UsedMemory;
 end;
 end;
 
 
-function TLazPaintImage.CreateAction(AApplyOfsBefore: boolean=false): TLayerAction;
+function TLazPaintImage.CreateAction(AApplyOfsBefore: boolean;
+                                     AApplySelTransformBefore: boolean): TLayerAction;
 begin
 begin
   if not CheckNoAction(True) then
   if not CheckNoAction(True) then
     raise exception.Create(rsConflictingActions);
     raise exception.Create(rsConflictingActions);
-  result := TLayerAction.Create(FCurrentState, AApplyOfsBefore);
+  result := TLayerAction.Create(FCurrentState, AApplyOfsBefore, AApplySelTransformBefore);
   result.OnNotifyChange:= @LayerActionNotifyChange;
   result.OnNotifyChange:= @LayerActionNotifyChange;
   result.OnDestroy:=@LayerActionDestroy;
   result.OnDestroy:=@LayerActionDestroy;
   result.OnNotifyUndo:=@LayerActionNotifyUndo;
   result.OnNotifyUndo:=@LayerActionNotifyUndo;
   FActionInProgress := result;
   FActionInProgress := result;
+  if Assigned(result.Prediff) then
+    InvalidateImageDifference(result.Prediff);
 end;
 end;
 
 
 procedure TLazPaintImage.ImageMayChange(ARect: TRect;
 procedure TLazPaintImage.ImageMayChange(ARect: TRect;
@@ -1097,7 +1101,14 @@ end;
 
 
 procedure TLazPaintImage.SelectionMaskMayChangeCompletely;
 procedure TLazPaintImage.SelectionMaskMayChangeCompletely;
 begin
 begin
-  SelectionMaskMayChange(rect(0,0,Width,Height));
+  DiscardSelectionLayerAfterMask;
+  FRenderUpdateRectInPicCoord := rect(0,0,Width,Height);
+  FCurrentState.DiscardSelectionMaskBounds;
+  if Assigned(FOnSelectionMaskChanged) then FOnSelectionMaskChanged(self, rect(0,0,Width,Height));
+  if FCurrentState.SelectionLayer <> nil then
+    LayerMayChange(FCurrentState.SelectionLayer, rect(0,0,Width,Height))
+  else
+    OnImageChanged.NotifyObservers;
 end;
 end;
 
 
 procedure TLazPaintImage.RenderMayChange(ARect: TRect; APicCoords: boolean = false);
 procedure TLazPaintImage.RenderMayChange(ARect: TRect; APicCoords: boolean = false);
@@ -1207,7 +1218,15 @@ end;
 
 
 function TLazPaintImage.GetLayerOriginal(AIndex: integer): TBGRALayerCustomOriginal;
 function TLazPaintImage.GetLayerOriginal(AIndex: integer): TBGRALayerCustomOriginal;
 begin
 begin
-  result := FCurrentState.LayerOriginal[AIndex];
+  try
+    result := FCurrentState.LayerOriginal[AIndex];
+  except
+    on ex:exception do
+    begin
+      MessagePopup(rsErrorLoadingOriginal, 4000);
+      result := nil;
+    end;
+  end;
 end;
 end;
 
 
 function TLazPaintImage.GetLayerOriginalClass(AIndex: integer): TBGRALayerOriginalAny;
 function TLazPaintImage.GetLayerOriginalClass(AIndex: integer): TBGRALayerOriginalAny;
@@ -1445,10 +1464,15 @@ end;
 
 
 function TLazPaintImage.GetRenderedImage: TBGRABitmap;
 function TLazPaintImage.GetRenderedImage: TBGRABitmap;
 var
 var
-  backupCurrentLayer : TBGRABitmap;
-  backupTopLeft, ofs: TPoint;
+  backupFullLayer: TBGRABitmap;
+  backupFullLayerTopLeft: TPoint;
+  backupFullLayerGuid: TGuid;
+  backupFullLayerRenderStatus: TOriginalRenderStatus;
+  backupFullLayerMatrix: TAffineMatrix;
+  backupLayerPart : TBGRABitmap;
+  backupLayerPartTopLeft, ofs: TPoint;
   shownSelectionLayer , temp: TBGRABitmap;
   shownSelectionLayer , temp: TBGRABitmap;
-  rectOutput, invalidatedRect: TRect;
+  rectOutput, invalidatedRect, layerRect: TRect;
   actualTransformation: TAffineMatrix;
   actualTransformation: TAffineMatrix;
 begin
 begin
   if (FRenderedImage = nil) or ((FRenderedImageInvalidated.Right > FRenderedImageInvalidated.Left) and
   if (FRenderedImage = nil) or ((FRenderedImageInvalidated.Right > FRenderedImageInvalidated.Left) and
@@ -1462,14 +1486,35 @@ begin
     end;
     end;
     PrepareForRendering;
     PrepareForRendering;
 
 
-    backupCurrentLayer := nil;
-    backupTopLeft := Point(0,0);
+    backupLayerPart := nil;
+    backupLayerPartTopLeft := Point(0,0);
+    backupFullLayer := nil;
+    backupFullLayerTopLeft := Point(0,0);
     //if there is an overlapping selection, then we must draw it on current layer
     //if there is an overlapping selection, then we must draw it on current layer
     if (SelectionMask <> nil) and (GetSelectedImageLayer <> nil) then
     if (SelectionMask <> nil) and (GetSelectedImageLayer <> nil) then
     begin
     begin
       shownSelectionLayer := FCurrentState.SelectionLayer;
       shownSelectionLayer := FCurrentState.SelectionLayer;
       if shownSelectionLayer <> nil then
       if shownSelectionLayer <> nil then
       begin
       begin
+         if LayerOriginalDefined[CurrentLayerIndex] and LayerOriginalKnown[CurrentLayerIndex] then
+         begin
+           layerRect := RectWithSize(LayerOffset[CurrentLayerIndex].X,LayerOffset[CurrentLayerIndex].Y,
+                                     LayerBitmap[CurrentLayerIndex].Width,LayerBitmap[CurrentLayerIndex].Height);
+           layerRect.Intersect(rect(0,0,Width,Height));
+           if (layerRect.Width <> Width) or (layerRect.Height <> Height) then
+           begin
+             backupFullLayer := CurrentState.LayeredBitmap.TakeLayerBitmap(CurrentLayerIndex);
+             backupFullLayerTopLeft := CurrentState.LayeredBitmap.LayerOffset[CurrentLayerIndex];
+             backupFullLayerGuid := CurrentState.LayeredBitmap.LayerOriginalGuid[CurrentLayerIndex];
+             backupFullLayerRenderStatus := CurrentState.LayeredBitmap.LayerOriginalRenderStatus[CurrentLayerIndex];
+             backupFullLayerMatrix := CurrentState.LayeredBitmap.LayerOriginalMatrix[CurrentLayerIndex];
+             temp := TBGRABitmap.Create(Width,Height);
+             temp.PutImage(backupFullLayerTopLeft.X,backupFullLayerTopLeft.Y, backupFullLayer, dmSet);
+             CurrentState.LayeredBitmap.SetLayerBitmap(CurrentLayerIndex, temp,true);
+             CurrentState.LayeredBitmap.LayerOffset[CurrentLayerIndex] := Point(0,0);
+             temp := nil;
+           end;
+         end;
          if not IsAffineMatrixIdentity(SelectionTransform) then
          if not IsAffineMatrixIdentity(SelectionTransform) then
          begin
          begin
            NeedSelectionLayerAfterMask;
            NeedSelectionLayerAfterMask;
@@ -1487,8 +1532,11 @@ begin
              IntersectRect(rectOutput,rectOutput,invalidatedRect);
              IntersectRect(rectOutput,rectOutput,invalidatedRect);
              if not IsRectEmpty(rectOutput) then
              if not IsRectEmpty(rectOutput) then
              begin
              begin
-               backupCurrentLayer := GetSelectedImageLayer.GetPart(rectOutput) as TBGRABitmap;
-               backupTopLeft := rectoutput.TopLeft;
+               if backupFullLayer=nil then
+               begin
+                 backupLayerPart := GetSelectedImageLayer.GetPart(rectOutput) as TBGRABitmap;
+                 backupLayerPartTopLeft := rectoutput.TopLeft;
+               end;
                GetSelectedImageLayer.PutImageAffine(
                GetSelectedImageLayer.PutImageAffine(
                  actualTransformation, shownSelectionLayer,
                  actualTransformation, shownSelectionLayer,
                  rectOutput,255,True);
                  rectOutput,255,True);
@@ -1504,8 +1552,11 @@ begin
            OffsetRect(rectoutput, -ofs.X,-ofs.Y);
            OffsetRect(rectoutput, -ofs.X,-ofs.Y);
            if not IsRectEmpty(rectoutput) then
            if not IsRectEmpty(rectoutput) then
            begin
            begin
-             backupTopLeft := rectOutput.TopLeft;
-             backupCurrentLayer := GetSelectedImageLayer.GetPart(rectoutput) as TBGRABitmap;
+             if backupFullLayer=nil then
+             begin
+               backupLayerPartTopLeft := rectOutput.TopLeft;
+               backupLayerPart := GetSelectedImageLayer.GetPart(rectoutput) as TBGRABitmap;
+             end;
              shownSelectionLayer.ScanOffset := Point(ofs.x,ofs.y);
              shownSelectionLayer.ScanOffset := Point(ofs.x,ofs.y);
              GetSelectedImageLayer.ClipRect := rectOutput;
              GetSelectedImageLayer.ClipRect := rectOutput;
              GetSelectedImageLayer.FillMask(-ofs.X,-ofs.Y,SelectionMask, shownSelectionLayer, dmDrawWithTransparency);
              GetSelectedImageLayer.FillMask(-ofs.X,-ofs.Y,SelectionMask, shownSelectionLayer, dmDrawWithTransparency);
@@ -1542,10 +1593,18 @@ begin
     end;
     end;
 
 
     //restore
     //restore
-    if backupCurrentLayer <> nil then
+    if backupLayerPart <> nil then
+    begin
+      GetSelectedImageLayer.PutImage(backupLayerPartTopLeft.X,backupLayerPartTopLeft.Y,backupLayerPart,dmSet);
+      backupLayerPart.Free;
+    end;
+    if backupFullLayer <> nil then
     begin
     begin
-      GetSelectedImageLayer.PutImage(backupTopLeft.X,backupTopLeft.Y,backupCurrentLayer,dmSet);
-      backupCurrentLayer.Free;
+      CurrentState.LayeredBitmap.SetLayerBitmap(CurrentLayerIndex, backupFullLayer, true);
+      CurrentState.LayeredBitmap.LayerOffset[CurrentLayerIndex] := backupFullLayerTopLeft;
+      CurrentState.LayeredBitmap.LayerOriginalGuid[CurrentLayerIndex] := backupFullLayerGuid;
+      CurrentState.LayeredBitmap.LayerOriginalMatrix[CurrentLayerIndex] := backupFullLayerMatrix;
+      CurrentState.LayeredBitmap.LayerOriginalRenderStatus[CurrentLayerIndex] := backupFullLayerRenderStatus;
     end;
     end;
     FRenderedImageInvalidated := EmptyRect; //up to date
     FRenderedImageInvalidated := EmptyRect; //up to date
   end;
   end;
@@ -1744,6 +1803,16 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TLazPaintImage.RasterizeLayer;
+begin
+  if LayerOriginalDefined[CurrentLayerIndex] then
+  try
+    AddUndo(FCurrentState.DiscardOriginal(True));
+    OnImageChanged.NotifyObservers;
+  except on ex: exception do NotifyException('RasterizeLayer',ex);
+  end;
+end;
+
 procedure TLazPaintImage.MergeLayerOver;
 procedure TLazPaintImage.MergeLayerOver;
 begin
 begin
   if not CheckNoAction then exit;
   if not CheckNoAction then exit;

+ 36 - 31
lazpaint/uimageaction.pas

@@ -55,6 +55,7 @@ type
     function NewLayer(ALayer: TBGRABitmap; AName: string; ABlendOp: TBlendOperation): boolean; overload;
     function NewLayer(ALayer: TBGRABitmap; AName: string; ABlendOp: TBlendOperation): boolean; overload;
     function NewLayer(ALayer: TBGRALayerCustomOriginal; AName: string; ABlendOp: TBlendOperation; AMatrix: TAffineMatrix): boolean; overload;
     function NewLayer(ALayer: TBGRALayerCustomOriginal; AName: string; ABlendOp: TBlendOperation; AMatrix: TAffineMatrix): boolean; overload;
     procedure DuplicateLayer;
     procedure DuplicateLayer;
+    procedure RasterizeLayer;
     procedure MergeLayerOver;
     procedure MergeLayerOver;
     procedure RemoveLayer;
     procedure RemoveLayer;
     procedure EditSelection(ACallback: TModifyImageCallback);
     procedure EditSelection(ACallback: TModifyImageCallback);
@@ -133,6 +134,7 @@ begin
   Scripting.RegisterScriptFunction('LayerVerticalFlip',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerVerticalFlip',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerAddNew',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerAddNew',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerDuplicate',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerDuplicate',@GenericScriptFunction,ARegister);
+  Scripting.RegisterScriptFunction('LayerRasterize',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerMergeOver',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerMergeOver',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerRemoveCurrent',@GenericScriptFunction,ARegister);
   Scripting.RegisterScriptFunction('LayerRemoveCurrent',@GenericScriptFunction,ARegister);
 end;
 end;
@@ -186,6 +188,7 @@ begin
   if f = 'LayerVerticalFlip' then VerticalFlip(foCurrentLayer) else
   if f = 'LayerVerticalFlip' then VerticalFlip(foCurrentLayer) else
   if f = 'LayerAddNew' then NewLayer else
   if f = 'LayerAddNew' then NewLayer else
   if f = 'LayerDuplicate' then DuplicateLayer else
   if f = 'LayerDuplicate' then DuplicateLayer else
+  if f = 'LayerRasterize' then RasterizeLayer else
   if f = 'LayerMergeOver' then MergeLayerOver else
   if f = 'LayerMergeOver' then MergeLayerOver else
   if f = 'LayerRemoveCurrent' then RemoveLayer else
   if f = 'LayerRemoveCurrent' then RemoveLayer else
     result := srFunctionNotDefined;
     result := srFunctionNotDefined;
@@ -650,10 +653,8 @@ var LayerAction: TLayerAction;
 begin
 begin
   LayerAction := nil;
   LayerAction := nil;
   try
   try
-    if not (CurrentTool in[ptSelectRect,ptSelectEllipse]) then ChooseTool(ptSelectRect);
-    LayerAction := Image.CreateAction(false);
+    LayerAction := Image.CreateAction(false,true);
     LayerAction.QuerySelection;
     LayerAction.QuerySelection;
-    LayerAction.ApplySelectionTransform;
     p := LayerAction.CurrentSelection.Data;
     p := LayerAction.CurrentSelection.Data;
     for n := LayerAction.CurrentSelection.NbPixels-1 downto 0 do
     for n := LayerAction.CurrentSelection.NbPixels-1 downto 0 do
     begin
     begin
@@ -669,22 +670,21 @@ begin
       FInstance.ShowError('InvertSelection',ex.Message);
       FInstance.ShowError('InvertSelection',ex.Message);
   end;
   end;
   LayerAction.Free;
   LayerAction.Free;
+  if Image.SelectionMaskEmpty then ChooseTool(ptHand) else
+  if not (CurrentTool in[ptSelectRect,ptSelectEllipse]) then ChooseTool(ptSelectRect);
 end;
 end;
 
 
 procedure TImageActions.Deselect;
 procedure TImageActions.Deselect;
-var LayerAction: TLayerAction;
 begin
 begin
   if (CurrentTool in[ptRotateSelection,ptMoveSelection]) then
   if (CurrentTool in[ptRotateSelection,ptMoveSelection]) then
     ChooseTool(ptHand);
     ChooseTool(ptHand);
   if not Image.CheckNoAction then exit;
   if not Image.CheckNoAction then exit;
-  LayerAction := nil;
   try
   try
     if not image.SelectionMaskEmpty then ReleaseSelection;
     if not image.SelectionMaskEmpty then ReleaseSelection;
   except
   except
     on ex:Exception do
     on ex:Exception do
       FInstance.ShowError('Deselect',ex.Message);
       FInstance.ShowError('Deselect',ex.Message);
   end;
   end;
-  LayerAction.Free;
 end;
 end;
 
 
 procedure TImageActions.CopySelection;
 procedure TImageActions.CopySelection;
@@ -697,10 +697,9 @@ begin
     if not image.CheckNoAction then exit;
     if not image.CheckNoAction then exit;
     bounds := Image.SelectionMaskBounds;
     bounds := Image.SelectionMaskBounds;
     if IsRectEmpty(bounds) then exit;
     if IsRectEmpty(bounds) then exit;
-    LayerAction := Image.CreateAction;
+    LayerAction := Image.CreateAction(true,true);
     LayerAction.ApplySelectionMask;
     LayerAction.ApplySelectionMask;
-    if Image.SelectionLayerIsEmpty then
-      LayerAction.RetrieveSelection;
+    if Image.SelectionLayerIsEmpty then LayerAction.RetrieveSelection;
     layer := LayerAction.GetOrCreateSelectionLayer;
     layer := LayerAction.GetOrCreateSelectionLayer;
     r := layer.GetImageBounds; //bounds may have been changed
     r := layer.GetImageBounds; //bounds may have been changed
     if (r.right > r.left) and (r.bottom > r.top) then
     if (r.right > r.left) and (r.bottom > r.top) then
@@ -727,20 +726,19 @@ begin
   LayerAction := nil;
   LayerAction := nil;
   try
   try
     CopySelection;
     CopySelection;
-    LayerAction := Image.CreateAction;
-    LayerAction.ApplySelectionTransform;
+    LayerAction := Image.CreateAction(false,true);
     if (LayerAction.GetSelectionLayerIfExists = nil) or (LayerAction.GetSelectionLayerIfExists.Empty) then
     if (LayerAction.GetSelectionLayerIfExists = nil) or (LayerAction.GetSelectionLayerIfExists.Empty) then
       LayerAction.EraseSelectionInBitmap;
       LayerAction.EraseSelectionInBitmap;
     LayerAction.RemoveSelection;
     LayerAction.RemoveSelection;
     LayerAction.Validate;
     LayerAction.Validate;
-    if (CurrentTool = ptRotateSelection) or
-       (CurrentTool = ptMoveSelection) then
-      ChooseTool(ptHand);
   except
   except
     on ex:Exception do
     on ex:Exception do
       FInstance.ShowError('CutSelection',ex.Message);
       FInstance.ShowError('CutSelection',ex.Message);
   end;
   end;
   LayerAction.Free;
   LayerAction.Free;
+  if (CurrentTool = ptRotateSelection) or
+     (CurrentTool = ptMoveSelection) then
+    ChooseTool(ptHand);
 end;
 end;
 
 
 procedure TImageActions.RetrieveSelection;
 procedure TImageActions.RetrieveSelection;
@@ -751,7 +749,7 @@ begin
   if not image.CheckNoAction then exit;
   if not image.CheckNoAction then exit;
   LayerAction := nil;
   LayerAction := nil;
   try
   try
-    LayerAction := Image.CreateAction(false);
+    LayerAction := Image.CreateAction(false, true);
     if LayerAction.RetrieveSelectionIfLayerEmpty(True) then
     if LayerAction.RetrieveSelectionIfLayerEmpty(True) then
     begin
     begin
       r := Image.SelectionMaskBounds;
       r := Image.SelectionMaskBounds;
@@ -768,27 +766,25 @@ end;
 
 
 procedure TImageActions.DeleteSelection;
 procedure TImageActions.DeleteSelection;
 var LayerAction: TLayerAction;
 var LayerAction: TLayerAction;
+  doErase: Boolean;
 begin
 begin
   if image.SelectionMaskEmpty then exit;
   if image.SelectionMaskEmpty then exit;
   if not image.CheckNoAction then exit;
   if not image.CheckNoAction then exit;
   LayerAction := nil;
   LayerAction := nil;
   try
   try
-    LayerAction := Image.CreateAction;
-    if Image.SelectionLayerIsEmpty then
-    begin
-      LayerAction.ApplySelectionTransform;
-      LayerAction.EraseSelectionInBitmap;
-    end;
+    doErase := Image.SelectionLayerIsEmpty;
+    LayerAction := Image.CreateAction(false, doErase);
+    if doErase then LayerAction.EraseSelectionInBitmap;
     LayerAction.RemoveSelection;
     LayerAction.RemoveSelection;
     LayerAction.Validate;
     LayerAction.Validate;
-    if (CurrentTool = ptRotateSelection) or
-       (CurrentTool = ptMoveSelection) then
-      ChooseTool(ptHand);
   except
   except
     on ex:Exception do
     on ex:Exception do
       FInstance.ShowError('DeleteSelection',ex.Message);
       FInstance.ShowError('DeleteSelection',ex.Message);
   end;
   end;
   LayerAction.Free;
   LayerAction.Free;
+  if (CurrentTool = ptRotateSelection) or
+     (CurrentTool = ptMoveSelection) then
+    ChooseTool(ptHand);
 end;
 end;
 
 
 procedure TImageActions.RemoveSelection;
 procedure TImageActions.RemoveSelection;
@@ -801,19 +797,20 @@ begin
     LayerAction := Image.CreateAction;
     LayerAction := Image.CreateAction;
     LayerAction.RemoveSelection;
     LayerAction.RemoveSelection;
     LayerAction.Validate;
     LayerAction.Validate;
-    if (CurrentTool = ptRotateSelection) or
-       (CurrentTool = ptMoveSelection) then
-      ChooseTool(ptHand);
   except on ex:exception do FInstance.ShowError('RemoveSelection',ex.Message);
   except on ex:exception do FInstance.ShowError('RemoveSelection',ex.Message);
   end;
   end;
   LayerAction.Free;
   LayerAction.Free;
+  if (CurrentTool = ptRotateSelection) or
+     (CurrentTool = ptMoveSelection) then
+    ChooseTool(ptHand);
 end;
 end;
 
 
 procedure TImageActions.ReleaseSelection;
 procedure TImageActions.ReleaseSelection;
 var
 var
   layeraction: TLayerAction;
   layeraction: TLayerAction;
 begin
 begin
-  layeraction := image.CreateAction;
+  if image.SelectionMaskEmpty then exit;
+  layeraction := image.CreateAction(true, true);
   layeraction.ReleaseSelection;
   layeraction.ReleaseSelection;
   layeraction.Validate;
   layeraction.Validate;
   layeraction.Free;
   layeraction.Free;
@@ -831,7 +828,7 @@ begin
       if partial.NbPixels <> 0 then
       if partial.NbPixels <> 0 then
       begin
       begin
         ToolManager.ToolCloseDontReopen;
         ToolManager.ToolCloseDontReopen;
-        layeraction := Image.CreateAction(true);
+        layeraction := Image.CreateAction(true, true);
         layeraction.ReleaseSelection;
         layeraction.ReleaseSelection;
         layeraction.QuerySelection;
         layeraction.QuerySelection;
         pastePos := Point((image.Width - partial.Width) div 2 - image.ImageOffset.X,
         pastePos := Point((image.Width - partial.Width) div 2 - image.ImageOffset.X,
@@ -881,13 +878,13 @@ procedure TImageActions.SelectAll;
 var LayerAction : TLayerAction;
 var LayerAction : TLayerAction;
 begin
 begin
   try
   try
-    if not ToolManager.IsSelectingTool then ChooseTool(ptSelectRect);
     LayerAction := Image.CreateAction;
     LayerAction := Image.CreateAction;
     LayerAction.QuerySelection;
     LayerAction.QuerySelection;
     LayerAction.currentSelection.Fill(BGRAWhite);
     LayerAction.currentSelection.Fill(BGRAWhite);
     Image.SelectionMaskMayChangeCompletely;
     Image.SelectionMaskMayChangeCompletely;
     LayerAction.Validate;
     LayerAction.Validate;
     LayerAction.Free;
     LayerAction.Free;
+    if not ToolManager.IsSelectingTool then ChooseTool(ptSelectRect);
   except
   except
     on ex:Exception do
     on ex:Exception do
       FInstance.ShowError('SelectAll',ex.Message);
       FInstance.ShowError('SelectAll',ex.Message);
@@ -900,7 +897,7 @@ var LayerAction: TLayerAction;
 begin
 begin
   if not image.CheckNoAction then exit;
   if not image.CheckNoAction then exit;
   try
   try
-    LayerAction := Image.CreateAction;
+    LayerAction := Image.CreateAction(false,true);
     LayerAction.ChangeBoundsNotified := true;
     LayerAction.ChangeBoundsNotified := true;
 
 
     if image.SelectionMaskEmpty then
     if image.SelectionMaskEmpty then
@@ -1002,6 +999,14 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TImageActions.RasterizeLayer;
+begin
+  if CurrentTool in[ptMoveLayer,ptRotateLayer,ptZoomLayer,ptLayerMapping] then
+    ChooseTool(ptHand);
+  Image.RasterizeLayer;
+  FInstance.ScrollLayerStackOnItem(Image.CurrentLayerIndex);
+end;
+
 procedure TImageActions.MergeLayerOver;
 procedure TImageActions.MergeLayerOver;
 begin
 begin
   if (Image.CurrentLayerIndex <> -1) and (image.NbLayers > 1) then
   if (Image.CurrentLayerIndex <> -1) and (image.NbLayers > 1) then

+ 452 - 164
lazpaint/uimagediff.pas

@@ -6,7 +6,7 @@ interface
 
 
 uses
 uses
   Classes, SysUtils, UStateType, BGRABitmap, BGRABitmapTypes, BGRALayers,
   Classes, SysUtils, UStateType, BGRABitmap, BGRABitmapTypes, BGRALayers,
-  BGRALayerOriginal;
+  BGRALayerOriginal, LCVectorOriginal;
 
 
 function IsInverseImageDiff(ADiff1, ADiff2: TCustomImageDifference): boolean;
 function IsInverseImageDiff(ADiff1, ADiff2: TCustomImageDifference): boolean;
 function TryCombineImageDiff(ANewDiff, APrevDiff: TCustomImageDifference): boolean;
 function TryCombineImageDiff(ANewDiff, APrevDiff: TCustomImageDifference): boolean;
@@ -57,18 +57,12 @@ type
     function GetChangingBounds: TRect; override;
     function GetChangingBounds: TRect; override;
     procedure Init(AToState: TState; APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
     procedure Init(AToState: TState; APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
         APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
         APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
-        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect;
-        APreviousSelectionTransform: TAffineMatrix; APreviousLayerOriginalData: TStream;
-        APreviousLayerOriginalMatrix: TAffineMatrix);
+        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect);
   public
   public
     layerId: integer;
     layerId: integer;
     imageOfs: TPoint;
     imageOfs: TPoint;
     imageDiff, selectionLayerDiff: TImageDiff;
     imageDiff, selectionLayerDiff: TImageDiff;
     selectionMaskDiff: TGrayscaleImageDiff;
     selectionMaskDiff: TGrayscaleImageDiff;
-    prevSelectionTransform, nextSelectionTransform: TAffineMatrix;
-    layerOriginalChange: boolean;
-    prevLayerOriginalData, nextLayerOriginalData: TStream;
-    prevLayerOriginalMatrix, nextLayerOriginalMatrix: TAffineMatrix;
     function TryCompress: boolean; override;
     function TryCompress: boolean; override;
     procedure ApplyTo(AState: TState); override;
     procedure ApplyTo(AState: TState); override;
     procedure UnapplyTo(AState: TState); override;
     procedure UnapplyTo(AState: TState); override;
@@ -76,16 +70,10 @@ type
     constructor Create(AFromState, AToState: TState);
     constructor Create(AFromState, AToState: TState);
     constructor Create(AToState: TState; APreviousImage: TBGRABitmap; APreviousImageDefined: boolean;
     constructor Create(AToState: TState; APreviousImage: TBGRABitmap; APreviousImageDefined: boolean;
         APreviousSelection: TBGRABitmap; APreviousSelectionDefined: boolean;
         APreviousSelection: TBGRABitmap; APreviousSelectionDefined: boolean;
-        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerDefined: boolean;
-        APreviousSelectionTransform: TAffineMatrix;
-        APreviousLayerOriginalData: TStream;
-        APreviousLayerOriginalMatrix: TAffineMatrix); overload;
+        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerDefined: boolean); overload;
     constructor Create(AToState: TState; APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
     constructor Create(AToState: TState; APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
         APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
         APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
-        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect;
-        APreviousSelectionTransform: TAffineMatrix;
-        APreviousLayerOriginalData: TStream;
-        APreviousLayerOriginalMatrix: TAffineMatrix); overload;
+        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect); overload;
     function ToString: ansistring; override;
     function ToString: ansistring; override;
     destructor Destroy; override;
     destructor Destroy; override;
     property ChangeImageLayer: boolean read GetChangeImageLayer;
     property ChangeImageLayer: boolean read GetChangeImageLayer;
@@ -191,6 +179,22 @@ type
     procedure UnapplyTo(AState: TState); override;
     procedure UnapplyTo(AState: TState); override;
   end;
   end;
 
 
+  { TSelectionTransformDifference }
+
+  TSelectionTransformDifference = class(TCustomImageDifference)
+    FPrevTransform: TAffineMatrix;
+    FPrevSelectionMask, FPrevSelectionLayer: TStoredImage;
+  protected
+    function GetImageDifferenceKind: TImageDifferenceKind; override;
+    function GetIsIdentity: boolean; override;
+  public
+    constructor Create(ADestination: TState; AApplyNow: boolean);
+    function TryCompress: boolean; override;
+    destructor Destroy; override;
+    procedure ApplyTo(AState: TState); override;
+    procedure UnapplyTo(AState: TState); override;
+  end;
+
   { TSetLayerVisibleStateDifference }
   { TSetLayerVisibleStateDifference }
 
 
   TSetLayerVisibleStateDifference = class(TCustomImageDifference)
   TSetLayerVisibleStateDifference = class(TCustomImageDifference)
@@ -279,9 +283,9 @@ type
     destructor Destroy; override;
     destructor Destroy; override;
   end;
   end;
 
 
-  { TReplaceLayerByImageOriginalDifference }
+  { TReplaceLayerByOriginalDifference }
 
 
-  TReplaceLayerByImageOriginalDifference = class(TCustomImageDifference)
+  TReplaceLayerByOriginalDifference = class(TCustomImageDifference)
   private
   private
     function GetLayerId: integer;
     function GetLayerId: integer;
   protected
   protected
@@ -289,8 +293,9 @@ type
     FPrevMatrix,FNextMatrix: TAffineMatrix;
     FPrevMatrix,FNextMatrix: TAffineMatrix;
     FSourceBounds: TRect;
     FSourceBounds: TRect;
     function GetImageDifferenceKind: TImageDifferenceKind; override;
     function GetImageDifferenceKind: TImageDifferenceKind; override;
+    function CreateOriginal(AState: TState; ALayerIndex: integer): TBGRALayerCustomOriginal; virtual; abstract;
   public
   public
-    constructor Create(AFromState: TState; AIndex: integer);
+    constructor Create(AFromState: TState; AIndex: integer; AAlwaysStoreBitmap: boolean);
     function UsedMemory: int64; override;
     function UsedMemory: int64; override;
     function TryCompress: boolean; override;
     function TryCompress: boolean; override;
     procedure ApplyTo(AState: TState); override;
     procedure ApplyTo(AState: TState); override;
@@ -301,6 +306,62 @@ type
     destructor Destroy; override;
     destructor Destroy; override;
   end;
   end;
 
 
+  { TDiscardOriginalDifference }
+
+  TDiscardOriginalDifference = class(TCustomImageDifference)
+  private
+    function GetLayerId: integer;
+  protected
+    FPreviousOriginalData: TStream;
+    FPreviousOriginalGuid: TGuid;
+    FOriginalUsedInOtherLayer: boolean;
+    FPreviousOriginalMatrix: TAffineMatrix;
+    FPreviousOriginalRenderStatus: TOriginalRenderStatus;
+    FLayerId: integer;
+    function GetImageDifferenceKind: TImageDifferenceKind; override;
+  public
+    constructor Create(AFromState: TState; AIndex: integer; AApplyNow: boolean);
+    function UsedMemory: int64; override;
+    function TryCompress: boolean; override;
+    procedure ApplyTo(AState: TState); override;
+    procedure UnapplyTo(AState: TState); override;
+    property LayerId: integer read GetLayerId;
+    destructor Destroy; override;
+  end;
+
+  { TReplaceLayerByImageOriginalDifference }
+
+  TReplaceLayerByImageOriginalDifference = class(TReplaceLayerByOriginalDifference)
+  protected
+    function CreateOriginal(AState: TState; ALayerIndex: integer): TBGRALayerCustomOriginal; override;
+  end;
+
+  { TReplaceLayerByVectorOriginalDifference }
+
+  TReplaceLayerByVectorOriginalDifference = class(TReplaceLayerByOriginalDifference)
+  protected
+    function CreateOriginal(AState: TState; ALayerIndex: integer): TBGRALayerCustomOriginal; override;
+  end;
+
+  { TAddShapeToVectorOriginalDifference }
+
+  TAddShapeToVectorOriginalDifference = class(TCustomImageDifference)
+  private
+    FShapeIndex, FShapeId: integer;
+    FLayerId: integer;
+    FShapeData: TBGRAMemOriginalStorage;
+    FShapeBounds: TRect;
+  protected
+    function GetImageDifferenceKind: TImageDifferenceKind; override;
+    function GetChangingBounds: TRect; override;
+    function GetChangingBoundsDefined: boolean; override;
+  public
+    constructor Create(ADestination: TState; ALayerId: integer; AShape: TVectorShape; AShapeIndex: integer = -1);
+    destructor Destroy; override;
+    procedure ApplyTo(AState: TState); override;
+    procedure UnapplyTo(AState: TState); override;
+  end;
+
   { TDiscardOriginalStateDifference }
   { TDiscardOriginalStateDifference }
 
 
   TDiscardOriginalStateDifference = class(TCustomImageDifference)
   TDiscardOriginalStateDifference = class(TCustomImageDifference)
@@ -391,7 +452,7 @@ type
 implementation
 implementation
 
 
 uses BGRAWriteLzp, BGRAReadLzp, UImageState, BGRAStreamLayers, BGRALzpCommon, ugraph, Types,
 uses BGRAWriteLzp, BGRAReadLzp, UImageState, BGRAStreamLayers, BGRALzpCommon, ugraph, Types,
-  BGRATransform, zstream;
+  BGRATransform, zstream, LCVectorRectShapes, BGRAPen, math;
 
 
 function IsInverseImageDiff(ADiff1, ADiff2: TCustomImageDifference): boolean;
 function IsInverseImageDiff(ADiff1, ADiff2: TCustomImageDifference): boolean;
 begin
 begin
@@ -481,11 +542,11 @@ begin
     else result := false;
     else result := false;
   end
   end
   else
   else
-  if (APrevDiff is TReplaceLayerByImageOriginalDifference) and (ANewDiff is TSetLayerMatrixDifference) then
+  if (APrevDiff is TReplaceLayerByOriginalDifference) and (ANewDiff is TSetLayerMatrixDifference) then
   begin
   begin
-    if (APrevDiff as TReplaceLayerByImageOriginalDifference).nextMatrix = (ANewDiff as TSetLayerMatrixDifference).previousMatrix then
+    if (APrevDiff as TReplaceLayerByOriginalDifference).nextMatrix = (ANewDiff as TSetLayerMatrixDifference).previousMatrix then
     begin
     begin
-      (APrevDiff as TReplaceLayerByImageOriginalDifference).nextMatrix := (ANewDiff as TSetLayerMatrixDifference).nextMatrix;
+      (APrevDiff as TReplaceLayerByOriginalDifference).nextMatrix := (ANewDiff as TSetLayerMatrixDifference).nextMatrix;
       result := true;
       result := true;
     end
     end
     else result := false;
     else result := false;
@@ -514,61 +575,388 @@ begin
     result := false;
     result := false;
 end;
 end;
 
 
+{ TDiscardOriginalDifference }
+
+function TDiscardOriginalDifference.GetLayerId: integer;
+begin
+  result := FLayerId;
+end;
+
+function TDiscardOriginalDifference.GetImageDifferenceKind: TImageDifferenceKind;
+begin
+  Result:= idkChangeStack;
+end;
+
+constructor TDiscardOriginalDifference.Create(AFromState: TState;
+  AIndex: integer; AApplyNow: boolean);
+var
+  imgState: TImageState;
+  i: Integer;
+begin
+  imgState := AFromState as TImageState;
+  FLayerId := imgState.LayerId[AIndex];
+  if not imgState.LayerOriginalDefined[AIndex] then
+    raise exception.Create('Layer original is not defined');
+  FPreviousOriginalGuid := imgState.LayeredBitmap.LayerOriginalGuid[AIndex];
+  FOriginalUsedInOtherLayer := false;
+  for i := 0 to imgState.NbLayers-1 do
+    if (i <> AIndex) and (imgState.LayeredBitmap.LayerOriginalGuid[i] = FPreviousOriginalGuid) then
+    begin
+      FOriginalUsedInOtherLayer:= true;
+      break;
+    end;
+  if not FOriginalUsedInOtherLayer then
+  begin
+    FPreviousOriginalData := TMemoryStream.Create;
+    imgState.LayeredBitmap.SaveOriginalToStream(
+      imgState.LayeredBitmap.LayerOriginalGuid[AIndex],
+      FPreviousOriginalData);
+  end;
+  FPreviousOriginalMatrix := imgState.LayerOriginalMatrix[AIndex];
+  FPreviousOriginalRenderStatus:= imgState.layeredBitmap.LayerOriginalRenderStatus[AIndex];
+  if AApplyNow then ApplyTo(AFromState)
+end;
+
+function TDiscardOriginalDifference.UsedMemory: int64;
+begin
+  if Assigned(FPreviousOriginalData) then
+    Result:= FPreviousOriginalData.Size
+  else
+    result:= 0;
+end;
+
+function TDiscardOriginalDifference.TryCompress: boolean;
+begin
+  Result:= false;
+end;
+
+procedure TDiscardOriginalDifference.ApplyTo(AState: TState);
+var
+  imgState: TImageState;
+  layerIdx: Integer;
+begin
+  imgState := AState as TImageState;
+  layerIdx := imgState.LayeredBitmap.GetLayerIndexFromId(FLayerId);
+  imgState.LayeredBitmap.LayerOriginalGuid[layerIdx] := GUID_NULL;
+  imgState.LayeredBitmap.LayerOriginalMatrix[layerIdx] := AffineMatrixIdentity;
+  if not FOriginalUsedInOtherLayer then
+    imgState.LayeredBitmap.RemoveUnusedOriginals;
+  inherited ApplyTo(AState);
+end;
+
+procedure TDiscardOriginalDifference.UnapplyTo(AState: TState);
+var
+  imgState: TImageState;
+  layerIdx, origIdx: Integer;
+begin
+  imgState := AState as TImageState;
+  layerIdx := imgState.LayeredBitmap.GetLayerIndexFromId(FLayerId);
+  if FOriginalUsedInOtherLayer then
+  begin
+    imgState.LayeredBitmap.LayerOriginalGuid[layerIdx] := FPreviousOriginalGuid;
+  end else
+  begin
+    FPreviousOriginalData.Position := 0;
+    origIdx := imgState.LayeredBitmap.AddOriginalFromStream(FPreviousOriginalData, FPreviousOriginalGuid, true);
+    imgState.LayeredBitmap.LayerOriginalGuid[layerIdx] := imgState.LayeredBitmap.OriginalGuid[origIdx];
+  end;
+  imgState.LayeredBitmap.LayerOriginalMatrix[layerIdx] := FPreviousOriginalMatrix;
+  imgState.LayeredBitmap.LayerOriginalRenderStatus[layerIdx] := FPreviousOriginalRenderStatus;
+  inherited UnapplyTo(AState);
+end;
+
+destructor TDiscardOriginalDifference.Destroy;
+begin
+  FPreviousOriginalData.Free;
+  inherited Destroy;
+end;
+
+{ TAddShapeToVectorOriginalDifference }
+
+function TAddShapeToVectorOriginalDifference.GetImageDifferenceKind: TImageDifferenceKind;
+begin
+  Result:= idkChangeImage;
+end;
+
+function TAddShapeToVectorOriginalDifference.GetChangingBounds: TRect;
+begin
+  Result:= FShapeBounds;
+end;
+
+function TAddShapeToVectorOriginalDifference.GetChangingBoundsDefined: boolean;
+begin
+  Result:= true;
+end;
+
+constructor TAddShapeToVectorOriginalDifference.Create(ADestination: TState;
+  ALayerId: integer; AShape: TVectorShape; AShapeIndex: integer);
+var
+  imgState: TImageState;
+  layerIdx, idxShapeAdd: Integer;
+  orig: TBGRALayerCustomOriginal;
+begin
+  FLayerId := ALayerId;
+  imgState := ADestination as TImageState;
+  layerIdx := imgState.LayeredBitmap.GetLayerIndexFromId(FLayerId);
+  orig := imgState.LayerOriginal[layerIdx];
+  if not (orig is TVectorOriginal) then
+  begin
+    AShape.Free;
+    raise exception.Create('Vector original expected');
+  end;
+  if AShapeIndex = -1 then AShapeIndex := TVectorOriginal(orig).ShapeCount;
+  FShapeIndex:= AShapeIndex;
+  FShapeData := TBGRAMemOriginalStorage.Create;
+  AShape.SaveToStorage(FShapeData);
+  FShapeData.RawString['class'] := AShape.StorageClassName;
+
+  inherited ApplyTo(ADestination);
+  idxShapeAdd := TVectorOriginal(orig).AddShape(AShape);
+  FShapeId := TVectorOriginal(orig).Shape[idxShapeAdd].Id;
+  TVectorOriginal(orig).MoveShapeToIndex(idxShapeAdd, FShapeIndex);
+  FShapeBounds := imgState.LayeredBitmap.RenderOriginalIfNecessary(orig.Guid);
+end;
+
+destructor TAddShapeToVectorOriginalDifference.Destroy;
+begin
+  FShapeData.Free;
+  inherited Destroy;
+end;
+
+procedure TAddShapeToVectorOriginalDifference.ApplyTo(AState: TState);
+var
+  imgState: TImageState;
+  layerIdx, idxShapeAdd: Integer;
+  orig: TBGRALayerCustomOriginal;
+  shape: TVectorShape;
+begin
+  inherited ApplyTo(AState);
+  imgState := AState as TImageState;
+  layerIdx := imgState.LayeredBitmap.GetLayerIndexFromId(FLayerId);
+  orig := imgState.LayerOriginal[layerIdx];
+  if not (orig is TVectorOriginal) then
+    raise exception.Create('Vector original expected');
+
+  shape := TVectorShape.CreateFromStorage(FShapeData,nil);
+  idxShapeAdd := TVectorOriginal(orig).AddShape(shape);
+  TVectorOriginal(orig).Shape[idxShapeAdd].Id := FShapeId;
+  TVectorOriginal(orig).MoveShapeToIndex(idxShapeAdd, FShapeIndex);
+  imgState.LayeredBitmap.RenderLayerFromOriginal(layerIdx);
+end;
+
+procedure TAddShapeToVectorOriginalDifference.UnapplyTo(AState: TState);
+var
+  imgState: TImageState;
+  layerIdx: Integer;
+  orig: TBGRALayerCustomOriginal;
+begin
+  inherited UnapplyTo(AState);
+  imgState := AState as TImageState;
+  layerIdx := imgState.LayeredBitmap.GetLayerIndexFromId(FLayerId);
+  orig := imgState.LayerOriginal[layerIdx];
+  if not (orig is TVectorOriginal) then
+    raise exception.Create('Vector original expected');
+  TVectorOriginal(orig).RemoveShape(TVectorOriginal(orig).Shape[FShapeIndex]);
+end;
+
+{ TReplaceLayerByVectorOriginalDifference }
+
+function TReplaceLayerByVectorOriginalDifference.CreateOriginal(AState: TState;
+  ALayerIndex: integer): TBGRALayerCustomOriginal;
+var
+  source: TBGRABitmap;
+  temp: TBGRABitmap;
+  imgState: TImageState;
+  orig: TVectorOriginal;
+  shape: TRectShape;
+begin
+  imgState := TImageState(AState);
+  orig := TVectorOriginal.Create;
+  source := imgState.LayeredBitmap.LayerBitmap[ALayerIndex];
+  if not source.Empty then
+  begin
+    shape := TRectShape.Create(orig);
+    shape.QuickDefine(PointF(0,0),PointF(FSourceBounds.Width,FSourceBounds.Height));
+    shape.PenStyle := ClearPenStyle;
+    temp := source.GetPart(FSourceBounds) as TBGRABitmap;
+    shape.BackFill.SetTexture(temp,AffineMatrixIdentity);
+    temp.FreeReference;
+    orig.AddShape(shape);
+  end;
+  result := orig;
+end;
+
 { TReplaceLayerByImageOriginalDifference }
 { TReplaceLayerByImageOriginalDifference }
 
 
-function TReplaceLayerByImageOriginalDifference.GetLayerId: integer;
+function TReplaceLayerByImageOriginalDifference.CreateOriginal(AState: TState; ALayerIndex: integer): TBGRALayerCustomOriginal;
+var
+  source: TBGRABitmap;
+  temp: TBGRACustomBitmap;
+  imgState: TImageState;
+  orig: TBGRALayerImageOriginal;
+begin
+  imgState := TImageState(AState);
+  orig := TBGRALayerImageOriginal.Create;
+  source := imgState.LayeredBitmap.LayerBitmap[ALayerIndex];
+  if (FSourceBounds.Width <> source.Width) or (FSourceBounds.Height <> source.Height) then
+  begin
+    temp := source.GetPart(FSourceBounds);
+    orig.AssignImage(temp);
+    temp.Free;
+  end else
+    orig.AssignImage(source);
+  result := orig;
+end;
+
+{ TSelectionTransformDifference }
+
+function TSelectionTransformDifference.GetImageDifferenceKind: TImageDifferenceKind;
+begin
+  if Assigned(FPrevSelectionMask) then
+  begin
+    if Assigned(FPrevSelectionLayer) then
+      Result:= idkChangeImageAndSelection
+    else
+      Result:= idkChangeSelection;
+  end else
+    if Assigned(FPrevSelectionLayer) then
+      Result:= idkChangeImage;
+end;
+
+function TSelectionTransformDifference.GetIsIdentity: boolean;
+begin
+  Result:= IsAffineMatrixIdentity(FPrevTransform);
+end;
+
+function TSelectionTransformDifference.TryCompress: boolean;
+begin
+  Result:= (Assigned(FPrevSelectionMask) and FPrevSelectionMask.Compress) or
+           (Assigned(FPrevSelectionLayer) and FPrevSelectionLayer.Compress);
+end;
+
+constructor TSelectionTransformDifference.Create(ADestination: TState;
+  AApplyNow: boolean);
+var
+  ImgState: TImageState;
+begin
+  inherited Create(ADestination);
+  ImgState := ADestination as TImageState;
+  FPrevTransform := ImgState.SelectionTransform;
+  if not ImgState.SelectionMaskEmpty then
+    FPrevSelectionMask := TStoredImage.Create(ImgState.SelectionMask)
+  else
+    FPrevSelectionMask := nil;
+  if not ImgState.SelectionLayerEmpty then
+    FPrevSelectionLayer := TStoredImage.Create(ImgState.SelectionLayer)
+  else
+    FPrevSelectionLayer := nil;
+  if AApplyNow then ApplyTo(ADestination);
+end;
+
+destructor TSelectionTransformDifference.Destroy;
+begin
+  FPrevSelectionMask.Free;
+  FPrevSelectionLayer.Free;
+  inherited Destroy;
+end;
+
+procedure TSelectionTransformDifference.ApplyTo(AState: TState);
+var
+  ImgState: TImageState;
+  newBmp: TBGRABitmap;
+  newLeft, newTop: integer;
+  r: TRect;
+begin
+  inherited ApplyTo(AState);
+  if not IsIdentity then
+  begin
+    ImgState := AState as TImageState;
+    if not ImgState.SelectionMaskEmpty then
+    begin
+      ImgState.ComputeTransformedSelectionMask(newBmp,newLeft,newTop);
+      r := ImgState.GetSelectionMaskBounds;
+      ImgState.SelectionMask.FillRect(r, BGRABlack, dmSet);
+      ImgState.SelectionMask.PutImage(newLeft,newTop,newBmp,dmSet);
+      newBmp.Free;
+    end;
+    if not ImgState.SelectionLayerEmpty then
+    begin
+      ImgState.ComputeTransformedSelectionLayer(newBmp,newLeft,newTop);
+      r := ImgState.GetSelectionLayerBounds;
+      ImgState.SelectionLayer.FillRect(r, BGRAPixelTransparent, dmSet);
+      ImgState.SelectionLayer.PutImage(newLeft,newTop,newBmp,dmSet);
+      newBmp.Free;
+    end;
+    ImgState.SelectionTransform := AffineMatrixIdentity;
+    ImgState.DiscardSelectionMaskBounds;
+    ImgState.DiscardSelectionLayerBounds;
+  end;
+end;
+
+procedure TSelectionTransformDifference.UnapplyTo(AState: TState);
+var
+  ImgState: TImageState;
+  prevMask, prevSelectionLayer: TBGRABitmap;
+begin
+  if not IsIdentity then
+  begin
+    ImgState := AState as TImageState;
+    if Assigned(FPrevSelectionMask) then prevMask := FPrevSelectionMask.GetBitmap else prevMask := nil;
+    if Assigned(FPrevSelectionLayer) then prevSelectionLayer := FPrevSelectionLayer.GetBitmap else prevSelectionLayer := nil;
+    ImgState.ReplaceSelection(prevMask, prevSelectionLayer);
+    ImgState.DiscardSelectionMaskBounds;
+    ImgState.DiscardSelectionLayerBounds;
+    ImgState.SelectionTransform := FPrevTransform;
+  end;
+  inherited UnapplyTo(AState);
+end;
+
+{ TReplaceLayerByOriginalDifference }
+
+function TReplaceLayerByOriginalDifference.GetLayerId: integer;
 begin
 begin
   result := FPreviousLayerContent.LayerId;
   result := FPreviousLayerContent.LayerId;
 end;
 end;
 
 
-function TReplaceLayerByImageOriginalDifference.GetImageDifferenceKind: TImageDifferenceKind;
+function TReplaceLayerByOriginalDifference.GetImageDifferenceKind: TImageDifferenceKind;
 begin
 begin
   Result:= idkChangeImage;
   Result:= idkChangeImage;
 end;
 end;
 
 
-constructor TReplaceLayerByImageOriginalDifference.Create(
-  AFromState: TState; AIndex: integer);
+constructor TReplaceLayerByOriginalDifference.Create(
+  AFromState: TState; AIndex: integer; AAlwaysStoreBitmap: boolean);
 var
 var
   imgState: TImageState;
   imgState: TImageState;
 begin
 begin
   inherited Create(AFromState);
   inherited Create(AFromState);
   imgState := AFromState as TImageState;
   imgState := AFromState as TImageState;
-  FPreviousLayerContent := TStoredLayer.Create(imgState.LayeredBitmap, AIndex);
+  FPreviousLayerContent := TStoredLayer.Create(imgState.LayeredBitmap, AIndex, AAlwaysStoreBitmap);
   FSourceBounds := imgState.LayeredBitmap.LayerBitmap[AIndex].GetImageBounds;
   FSourceBounds := imgState.LayeredBitmap.LayerBitmap[AIndex].GetImageBounds;
   with FPreviousLayerContent.Offset do FPrevMatrix := AffineMatrixTranslation(x+FSourceBounds.Left,y+FSourceBounds.Top);
   with FPreviousLayerContent.Offset do FPrevMatrix := AffineMatrixTranslation(x+FSourceBounds.Left,y+FSourceBounds.Top);
   FNextMatrix := FPrevMatrix;
   FNextMatrix := FPrevMatrix;
   ApplyTo(imgState);
   ApplyTo(imgState);
 end;
 end;
 
 
-function TReplaceLayerByImageOriginalDifference.UsedMemory: int64;
+function TReplaceLayerByOriginalDifference.UsedMemory: int64;
 begin
 begin
   Result:= FPreviousLayerContent.UsedMemory;
   Result:= FPreviousLayerContent.UsedMemory;
 end;
 end;
 
 
-function TReplaceLayerByImageOriginalDifference.TryCompress: boolean;
+function TReplaceLayerByOriginalDifference.TryCompress: boolean;
 begin
 begin
   Result:= FPreviousLayerContent.Compress;
   Result:= FPreviousLayerContent.Compress;
 end;
 end;
 
 
-procedure TReplaceLayerByImageOriginalDifference.ApplyTo(AState: TState);
+procedure TReplaceLayerByOriginalDifference.ApplyTo(AState: TState);
 var
 var
   imgState: TImageState;
   imgState: TImageState;
-  orig: TBGRALayerImageOriginal;
+  orig: TBGRALayerCustomOriginal;
   origIndex,layerIdx: Integer;
   origIndex,layerIdx: Integer;
-  source: TBGRABitmap;
-  temp: TBGRACustomBitmap;
 begin
 begin
+  inherited ApplyTo(AState);
   imgState := AState as TImageState;
   imgState := AState as TImageState;
   layerIdx := imgState.LayeredBitmap.GetLayerIndexFromId(FPreviousLayerContent.LayerId);
   layerIdx := imgState.LayeredBitmap.GetLayerIndexFromId(FPreviousLayerContent.LayerId);
-  orig := TBGRALayerImageOriginal.Create;
-  source := imgState.LayeredBitmap.LayerBitmap[layerIdx];
-  if (FSourceBounds.Width <> source.Width) or (FSourceBounds.Height <> source.Height) then
-  begin
-    temp := source.GetPart(FSourceBounds);
-    orig.AssignImage(temp);
-    temp.Free;
-  end else
-    orig.AssignImage(source);
+  orig := CreateOriginal(imgState, layerIdx);
   origIndex := imgState.LayeredBitmap.AddOriginal(orig, true);
   origIndex := imgState.LayeredBitmap.AddOriginal(orig, true);
   imgState.LayeredBitmap.LayerOriginalGuid[layerIdx] := imgState.LayeredBitmap.OriginalGuid[origIndex];
   imgState.LayeredBitmap.LayerOriginalGuid[layerIdx] := imgState.LayeredBitmap.OriginalGuid[origIndex];
   imgState.LayeredBitmap.LayerOriginalMatrix[layerIdx] := FNextMatrix;
   imgState.LayeredBitmap.LayerOriginalMatrix[layerIdx] := FNextMatrix;
@@ -581,15 +969,16 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TReplaceLayerByImageOriginalDifference.UnapplyTo(AState: TState);
+procedure TReplaceLayerByOriginalDifference.UnapplyTo(AState: TState);
 var
 var
   imgState: TImageState;
   imgState: TImageState;
 begin
 begin
+  inherited UnapplyTo(AState);
   imgState := AState as TImageState;
   imgState := AState as TImageState;
   FPreviousLayerContent.Replace(imgState.LayeredBitmap);
   FPreviousLayerContent.Replace(imgState.LayeredBitmap);
 end;
 end;
 
 
-destructor TReplaceLayerByImageOriginalDifference.Destroy;
+destructor TReplaceLayerByOriginalDifference.Destroy;
 begin
 begin
   FPreviousLayerContent.Free;
   FPreviousLayerContent.Free;
   inherited Destroy;
   inherited Destroy;
@@ -1541,8 +1930,8 @@ begin
   with imgDest.LayeredBitmap do
   with imgDest.LayeredBitmap do
   begin
   begin
     previousActiveLayerId:= LayerUniqueId[imgDest.SelectedImageLayerIndex];
     previousActiveLayerId:= LayerUniqueId[imgDest.SelectedImageLayerIndex];
-    layerOverCompressedBackup := TStoredLayer.Create(imgDest.LayeredBitmap, ALayerOverIndex);
-    layerUnderCompressedBackup := TStoredLayer.Create(imgDest.LayeredBitmap, ALayerOverIndex-1);
+    layerOverCompressedBackup := TStoredLayer.Create(imgDest.LayeredBitmap, ALayerOverIndex, true);
+    layerUnderCompressedBackup := TStoredLayer.Create(imgDest.LayeredBitmap, ALayerOverIndex-1, true);
   end;
   end;
 
 
   //select layer under and merge
   //select layer under and merge
@@ -1809,7 +2198,7 @@ end;
 
 
 function TImageLayerStateDifference.GetImageDifferenceKind: TImageDifferenceKind;
 function TImageLayerStateDifference.GetImageDifferenceKind: TImageDifferenceKind;
 begin
 begin
-  if ChangeImageLayer or ChangeSelectionLayer or (prevSelectionTransform <> nextSelectionTransform) then
+  if ChangeImageLayer or ChangeSelectionLayer then
   begin
   begin
     if ChangeSelectionMask then
     if ChangeSelectionMask then
       result := idkChangeImageAndSelection
       result := idkChangeImageAndSelection
@@ -1828,13 +2217,12 @@ function TImageLayerStateDifference.GetIsIdentity: boolean;
 begin
 begin
   Result:= not ChangeImageLayer and
   Result:= not ChangeImageLayer and
           not ChangeSelectionMask and
           not ChangeSelectionMask and
-          not ChangeSelectionLayer and
-          (prevSelectionTransform = nextSelectionTransform);
+          not ChangeSelectionLayer;
 end;
 end;
 
 
 function TImageLayerStateDifference.GetChangingBoundsDefined: boolean;
 function TImageLayerStateDifference.GetChangingBoundsDefined: boolean;
 begin
 begin
-  Result:= (prevSelectionTransform = nextSelectionTransform);
+  Result:= true;
 end;
 end;
 
 
 function TImageLayerStateDifference.GetChangingBounds: TRect;
 function TImageLayerStateDifference.GetChangingBounds: TRect;
@@ -1854,13 +2242,10 @@ end;
 
 
 procedure TImageLayerStateDifference.Init(AToState: TState; APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
 procedure TImageLayerStateDifference.Init(AToState: TState; APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
         APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
         APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
-        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect;
-        APreviousSelectionTransform: TAffineMatrix; APreviousLayerOriginalData: TStream;
-        APreviousLayerOriginalMatrix: TAffineMatrix);
+        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect);
 var
 var
   next: TImageState;
   next: TImageState;
   curIdx: integer;
   curIdx: integer;
-  nextOrig: TBGRALayerCustomOriginal;
 begin
 begin
   inherited Create((AToState as TImageState).saved,false);
   inherited Create((AToState as TImageState).saved,false);
   layerId := -1;
   layerId := -1;
@@ -1868,22 +2253,12 @@ begin
   imageOfs := Point(0,0);
   imageOfs := Point(0,0);
   selectionMaskDiff := nil;
   selectionMaskDiff := nil;
   selectionLayerDiff := nil;
   selectionLayerDiff := nil;
-  prevSelectionTransform := APreviousSelectionTransform;
-  nextSelectionTransform := (AToState as TImageState).SelectionTransform;
-  prevLayerOriginalData := nil;
-  nextLayerOriginalData := nil;
-  layerOriginalChange:= false;
 
 
   next := AToState as TImageState;
   next := AToState as TImageState;
   layerId := next.selectedLayerId;
   layerId := next.selectedLayerId;
   curIdx := next.LayeredBitmap.GetLayerIndexFromId(LayerId);
   curIdx := next.LayeredBitmap.GetLayerIndexFromId(LayerId);
   if curIdx = -1 then
   if curIdx = -1 then
-  begin
-    layerId:= -1;
-    prevLayerOriginalMatrix := AffineMatrixIdentity;
-    nextLayerOriginalMatrix := AffineMatrixIdentity;
-    APreviousLayerOriginalData.Free;
-  end
+    raise exception.Create('Layer not found')
   else
   else
   begin
   begin
     if not IsRectEmpty(APreviousImageChangeRect) then
     if not IsRectEmpty(APreviousImageChangeRect) then
@@ -1895,20 +2270,6 @@ begin
       selectionMaskDiff := TGrayscaleImageDiff.Create(APreviousSelection,next.SelectionMask,APreviousSelectionChangeRect);
       selectionMaskDiff := TGrayscaleImageDiff.Create(APreviousSelection,next.SelectionMask,APreviousSelectionChangeRect);
     if not IsRectEmpty(APreviousSelectionLayerChangeRect) then
     if not IsRectEmpty(APreviousSelectionLayerChangeRect) then
       selectionLayerDiff := TImageDiff.Create(APreviousSelectionLayer,next.SelectionLayer,APreviousSelectionLayerChangeRect);
       selectionLayerDiff := TImageDiff.Create(APreviousSelectionLayer,next.SelectionLayer,APreviousSelectionLayerChangeRect);
-    prevLayerOriginalMatrix := APreviousLayerOriginalMatrix;
-    nextLayerOriginalMatrix := next.LayerOriginalMatrix[curIdx];
-    nextOrig := next.LayerOriginal[curIdx];
-    //only case handled here: when going from original to raster bitmap
-    if APreviousLayerOriginalData <> nil then
-    begin
-      layerOriginalChange:= true;
-      prevLayerOriginalData := APreviousLayerOriginalData;
-      if Assigned(nextOrig) then
-      begin
-        nextLayerOriginalData := TMemoryStream.Create;
-        nextOrig.SaveToStream(nextLayerOriginalData);
-      end;
-    end;
   end;
   end;
 end;
 end;
 
 
@@ -1922,7 +2283,7 @@ end;
 
 
 procedure TImageLayerStateDifference.ApplyTo(AState: TState);
 procedure TImageLayerStateDifference.ApplyTo(AState: TState);
 var
 var
-  idx, origIdx: integer;
+  idx: integer;
   lState: TImageState;
   lState: TImageState;
   newSelectionMask, newSelectionLayer: TBGRABitmap;
   newSelectionMask, newSelectionLayer: TBGRABitmap;
 begin
 begin
@@ -1932,35 +2293,17 @@ begin
   begin
   begin
     idx := lState.LayeredBitmap.GetLayerIndexFromId(layerId);
     idx := lState.LayeredBitmap.GetLayerIndexFromId(layerId);
     if idx = -1 then raise exception.Create('Layer not found');
     if idx = -1 then raise exception.Create('Layer not found');
-    if ChangeImageLayer then
-    begin
-      lState.LayeredBitmap.SetLayerBitmap(idx, imageDiff.ApplyCanCreateNew(lState.LayerBitmap[idx],False), True);
-      lState.LayeredBitmap.LayerOriginalGuid[idx] := GUID_NULL;
-      lState.LayeredBitmap.RemoveUnusedOriginals;
-    end;
-    if nextLayerOriginalData <> nil then
-    begin
-      nextLayerOriginalData.Position := 0;
-      origIdx := lState.LayeredBitmap.AddOriginalFromStream(nextLayerOriginalData, true);
-      lState.LayeredBitmap.LayerOriginalGuid[idx] := lState.LayeredBitmap.OriginalGuid[origIdx];
-      lState.LayeredBitmap.LayerOriginalMatrix[idx] := nextLayerOriginalMatrix;
-      lState.LayeredBitmap.LayerOriginalRenderStatus[idx] := orsProof;
-    end else
-    if lState.LayeredBitmap.LayerOriginal[idx] <> nil then
-    begin
-      lState.LayeredBitmap.LayerOriginalMatrix[idx] := nextLayerOriginalMatrix;
-      lState.LayeredBitmap.LayerOriginalRenderStatus[idx] := orsProof;
-    end;
+    if ChangeImageLayer and (lState.LayeredBitmap.LayerOriginalGuid[idx] <> GUID_NULL) then raise exception.Create('Does not apply to originals');
+    if ChangeImageLayer then lState.LayeredBitmap.SetLayerBitmap(idx, imageDiff.ApplyCanCreateNew(lState.LayerBitmap[idx],False), True);
     if ChangeSelectionMask then newSelectionMask := selectionMaskDiff.ApplyCanCreateNew(lState.SelectionMask,False) else newSelectionMask := lState.SelectionMask;
     if ChangeSelectionMask then newSelectionMask := selectionMaskDiff.ApplyCanCreateNew(lState.SelectionMask,False) else newSelectionMask := lState.SelectionMask;
     if ChangeSelectionLayer then newSelectionLayer := selectionLayerDiff.ApplyCanCreateNew(lState.SelectionLayer,False) else newSelectionLayer := lState.SelectionLayer;
     if ChangeSelectionLayer then newSelectionLayer := selectionLayerDiff.ApplyCanCreateNew(lState.SelectionLayer,False) else newSelectionLayer := lState.SelectionLayer;
     lState.ReplaceSelection(newSelectionMask, newSelectionLayer);
     lState.ReplaceSelection(newSelectionMask, newSelectionLayer);
-    lState.SelectionTransform := nextSelectionTransform;
   end;
   end;
 end;
 end;
 
 
 procedure TImageLayerStateDifference.UnapplyTo(AState: TState);
 procedure TImageLayerStateDifference.UnapplyTo(AState: TState);
 var
 var
-  idx, origIdx: integer;
+  idx: integer;
   lState: TImageState;
   lState: TImageState;
   newSelectionMask, newSelectionLayer: TBGRABitmap;
   newSelectionMask, newSelectionLayer: TBGRABitmap;
 begin
 begin
@@ -1970,29 +2313,11 @@ begin
   begin
   begin
     idx := lState.LayeredBitmap.GetLayerIndexFromId(layerId);
     idx := lState.LayeredBitmap.GetLayerIndexFromId(layerId);
     if idx = -1 then raise exception.Create('Layer not found');
     if idx = -1 then raise exception.Create('Layer not found');
-    if ChangeImageLayer then
-    begin
-      lState.LayeredBitmap.SetLayerBitmap(idx, imageDiff.ApplyCanCreateNew(lState.LayerBitmap[idx],True), True);
-      lState.LayeredBitmap.LayerOriginalGuid[idx] := GUID_NULL;
-      lState.LayeredBitmap.RemoveUnusedOriginals;
-    end;
-    if prevLayerOriginalData <> nil then
-    begin
-      prevLayerOriginalData.Position:= 0;
-      origIdx := lState.LayeredBitmap.AddOriginalFromStream(prevLayerOriginalData, true);
-      lState.LayeredBitmap.LayerOriginalGuid[idx] := lState.LayeredBitmap.OriginalGuid[origIdx];
-      lState.LayeredBitmap.LayerOriginalMatrix[idx] := prevLayerOriginalMatrix;
-      lState.LayeredBitmap.LayerOriginalRenderStatus[idx] := orsProof;
-    end else
-    if lState.LayeredBitmap.LayerOriginal[idx] <> nil then
-    begin
-      lState.LayeredBitmap.LayerOriginalMatrix[idx] := prevLayerOriginalMatrix;
-      lState.LayeredBitmap.LayerOriginalRenderStatus[idx] := orsProof;
-    end;
+    if ChangeImageLayer and (lState.LayeredBitmap.LayerOriginalGuid[idx] <> GUID_NULL) then raise exception.Create('Does not apply to originals');
+    if ChangeImageLayer then lState.LayeredBitmap.SetLayerBitmap(idx, imageDiff.ApplyCanCreateNew(lState.LayerBitmap[idx],True), True);
     if ChangeSelectionMask then newSelectionMask := selectionMaskDiff.ApplyCanCreateNew(lState.SelectionMask,True) else newSelectionMask := lState.SelectionMask;
     if ChangeSelectionMask then newSelectionMask := selectionMaskDiff.ApplyCanCreateNew(lState.SelectionMask,True) else newSelectionMask := lState.SelectionMask;
     if ChangeSelectionLayer then newSelectionLayer := selectionLayerDiff.ApplyCanCreateNew(lState.SelectionLayer,True) else newSelectionLayer := lState.SelectionLayer;
     if ChangeSelectionLayer then newSelectionLayer := selectionLayerDiff.ApplyCanCreateNew(lState.SelectionLayer,True) else newSelectionLayer := lState.SelectionLayer;
     lState.ReplaceSelection(newSelectionMask, newSelectionLayer);
     lState.ReplaceSelection(newSelectionMask, newSelectionLayer);
-    lState.SelectionTransform := prevSelectionTransform;
   end;
   end;
 end;
 end;
 
 
@@ -2008,7 +2333,6 @@ constructor TImageLayerStateDifference.Create(AFromState, AToState: TState);
 var
 var
   prev,next: TImageState;
   prev,next: TImageState;
   prevIdx,curIdx: integer;
   prevIdx,curIdx: integer;
-  prevOrig,nextOrig: TBGRALayerCustomOriginal;
 begin
 begin
   inherited Create(AFromState,AToState);
   inherited Create(AFromState,AToState);
   layerId := -1;
   layerId := -1;
@@ -2016,9 +2340,6 @@ begin
   imageOfs := Point(0,0);
   imageOfs := Point(0,0);
   selectionMaskDiff := nil;
   selectionMaskDiff := nil;
   selectionLayerDiff := nil;
   selectionLayerDiff := nil;
-  prevLayerOriginalData := nil;
-  nextLayerOriginalData := nil;
-  layerOriginalChange := false;
 
 
   prev := AFromState as TImageState;
   prev := AFromState as TImageState;
   next := AToState as TImageState;
   next := AToState as TImageState;
@@ -2028,45 +2349,20 @@ begin
   prevIdx := prev.LayeredBitmap.GetLayerIndexFromId(LayerId);
   prevIdx := prev.LayeredBitmap.GetLayerIndexFromId(LayerId);
   curIdx := next.LayeredBitmap.GetLayerIndexFromId(LayerId);
   curIdx := next.LayeredBitmap.GetLayerIndexFromId(LayerId);
   if (curIdx = -1) or (prevIdx = -1) then
   if (curIdx = -1) or (prevIdx = -1) then
-  begin
-    layerId:= -1;
-    prevLayerOriginalMatrix := AffineMatrixIdentity;
-    nextLayerOriginalMatrix := AffineMatrixIdentity;
-  end
+    raise exception.Create('Layer not found')
   else
   else
   begin
   begin
     imageDiff := TImageDiff.Create(prev.LayerBitmap[prevIdx],next.LayerBitmap[curIdx]);
     imageDiff := TImageDiff.Create(prev.LayerBitmap[prevIdx],next.LayerBitmap[curIdx]);
     imageOfs := next.LayerOffset[curIdx];
     imageOfs := next.LayerOffset[curIdx];
     selectionMaskDiff := TGrayscaleImageDiff.Create(prev.SelectionMask,next.SelectionMask);
     selectionMaskDiff := TGrayscaleImageDiff.Create(prev.SelectionMask,next.SelectionMask);
     selectionLayerDiff := TImageDiff.Create(prev.SelectionLayer,next.SelectionLayer);
     selectionLayerDiff := TImageDiff.Create(prev.SelectionLayer,next.SelectionLayer);
-    prevOrig := prev.LayerOriginal[prevIdx];
-    prevLayerOriginalMatrix := prev.LayerOriginalMatrix[prevIdx];
-    nextOrig := next.LayerOriginal[curIdx];
-    nextLayerOriginalMatrix := next.LayerOriginalMatrix[curIdx];
-    if prevOrig <> nextOrig then
-    begin
-      layerOriginalChange := true;
-      if Assigned(prevOrig) then
-      begin
-        prevLayerOriginalData := TMemoryStream.Create;
-        prevOrig.SaveToStream(prevLayerOriginalData);
-      end;
-      if Assigned(nextOrig) then
-      begin
-        nextLayerOriginalData := TMemoryStream.Create;
-        nextOrig.SaveToStream(nextLayerOriginalData);
-      end;
-    end;
   end;
   end;
 end;
 end;
 
 
 constructor TImageLayerStateDifference.Create(AToState: TState;
 constructor TImageLayerStateDifference.Create(AToState: TState;
   APreviousImage: TBGRABitmap; APreviousImageDefined: boolean;
   APreviousImage: TBGRABitmap; APreviousImageDefined: boolean;
   APreviousSelection: TBGRABitmap; APreviousSelectionDefined: boolean;
   APreviousSelection: TBGRABitmap; APreviousSelectionDefined: boolean;
-  APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerDefined: boolean;
-  APreviousSelectionTransform: TAffineMatrix;
-  APreviousLayerOriginalData: TStream;
-  APreviousLayerOriginalMatrix: TAffineMatrix);
+  APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerDefined: boolean);
 var
 var
   r1,r2,r3: TRect;
   r1,r2,r3: TRect;
   w,h: integer;
   w,h: integer;
@@ -2076,21 +2372,16 @@ begin
   if APreviousImageDefined then r1 := rect(0,0,w,h) else r1 := EmptyRect;
   if APreviousImageDefined then r1 := rect(0,0,w,h) else r1 := EmptyRect;
   if APreviousSelectionDefined then r2 := rect(0,0,w,h) else r2 := EmptyRect;
   if APreviousSelectionDefined then r2 := rect(0,0,w,h) else r2 := EmptyRect;
   if APreviousSelectionLayerDefined then r3 := rect(0,0,w,h) else r3 := EmptyRect;
   if APreviousSelectionLayerDefined then r3 := rect(0,0,w,h) else r3 := EmptyRect;
-  Init(AToState,APreviousImage,r1,APreviousSelection,r2,APreviousSelectionLayer,r3,
-       APreviousSelectionTransform, APreviousLayerOriginalData, APreviousLayerOriginalMatrix);
+  Init(AToState,APreviousImage,r1,APreviousSelection,r2,APreviousSelectionLayer,r3);
 end;
 end;
 
 
 constructor TImageLayerStateDifference.Create(AToState: TState;
 constructor TImageLayerStateDifference.Create(AToState: TState;
   APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
   APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
   APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
   APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
-  APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect;
-  APreviousSelectionTransform: TAffineMatrix;
-  APreviousLayerOriginalData: TStream;
-  APreviousLayerOriginalMatrix: TAffineMatrix);
+  APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect);
 begin
 begin
   Init(AToState, APreviousImage, APreviousImageChangeRect, APreviousSelection,
   Init(AToState, APreviousImage, APreviousImageChangeRect, APreviousSelection,
-    APreviousSelectionChangeRect, APreviousSelectionLayer, APreviousSelectionLayerChangeRect,
-    APreviousSelectionTransform, APreviousLayerOriginalData, APreviousLayerOriginalMatrix);
+    APreviousSelectionChangeRect, APreviousSelectionLayer, APreviousSelectionLayerChangeRect);
 end;
 end;
 
 
 function TImageLayerStateDifference.ToString: ansistring;
 function TImageLayerStateDifference.ToString: ansistring;
@@ -2132,7 +2423,6 @@ begin
 
 
     result += 'SelectionLayer ';
     result += 'SelectionLayer ';
   end;
   end;
-  if nextSelectionTransform<>prevSelectionTransform then result += 'SelectionTransform ';
   result := trim(Result)+')';
   result := trim(Result)+')';
 end;
 end;
 
 
@@ -2141,8 +2431,6 @@ begin
   imageDiff.Free;
   imageDiff.Free;
   selectionMaskDiff.Free;
   selectionMaskDiff.Free;
   selectionLayerDiff.Free;
   selectionLayerDiff.Free;
-  prevLayerOriginalData.Free;
-  nextLayerOriginalData.Free;
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 

+ 21 - 37
lazpaint/uimagestate.pas

@@ -118,19 +118,14 @@ type
     function LinearNegative: TCustomImageDifference;
     function LinearNegative: TCustomImageDifference;
     function Negative: TCustomImageDifference;
     function Negative: TCustomImageDifference;
     function ComputeLayerOffsetDifference(AOffsetX, AOffsetY: integer): TCustomImageDifference;
     function ComputeLayerOffsetDifference(AOffsetX, AOffsetY: integer): TCustomImageDifference;
+    function ComputeSelectionTransformDifference: TCustomImageDifference;
     function ComputeLayerMatrixDifference(AIndex: integer; APrevMatrix, ANewMatrix: TAffineMatrix): TCustomImageDifference;
     function ComputeLayerMatrixDifference(AIndex: integer; APrevMatrix, ANewMatrix: TAffineMatrix): TCustomImageDifference;
     function ComputeLayerDifference(APreviousImage: TBGRABitmap; APreviousImageDefined: boolean;
     function ComputeLayerDifference(APreviousImage: TBGRABitmap; APreviousImageDefined: boolean;
         APreviousSelection: TBGRABitmap; APreviousSelectionDefined: boolean;
         APreviousSelection: TBGRABitmap; APreviousSelectionDefined: boolean;
-        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerDefined: boolean;
-        APreviousSelectionTransform: TAffineMatrix;
-        APreviousLayerOriginalData: TStream;
-        APreviousLayerOriginalMatrix: TAffineMatrix): TCustomImageDifference; overload;
+        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerDefined: boolean): TCustomImageDifference; overload;
     function ComputeLayerDifference(APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
     function ComputeLayerDifference(APreviousImage: TBGRABitmap; APreviousImageChangeRect: TRect;
         APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
         APreviousSelection: TBGRABitmap; APreviousSelectionChangeRect: TRect;
-        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect;
-        APreviousSelectionTransform: TAffineMatrix;
-        APreviousLayerOriginalData: TStream;
-        APreviousLayerOriginalMatrix: TAffineMatrix): TCustomImageDifference; overload;
+        APreviousSelectionLayer: TBGRABitmap; APreviousSelectionLayerChangeRect: TRect): TCustomImageDifference; overload;
     function GetLayeredBitmapCopy: TBGRALayeredBitmap;
     function GetLayeredBitmapCopy: TBGRALayeredBitmap;
     function ComputeFlatImage(AFromLayer, AToLayer: integer; ASeparateXorMask: boolean): TBGRABitmap;
     function ComputeFlatImage(AFromLayer, AToLayer: integer; ASeparateXorMask: boolean): TBGRABitmap;
     function ComputeFlatImage(ARect: TRect; AFromLayer, AToLayer: integer; ASeparateXorMask: boolean): TBGRABitmap;
     function ComputeFlatImage(ARect: TRect; AFromLayer, AToLayer: integer; ASeparateXorMask: boolean): TBGRABitmap;
@@ -524,7 +519,7 @@ begin
   begin
   begin
     r := SelectionLayer.GetImageAffineBounds(FSelectionTransform, GetSelectionLayerBounds);
     r := SelectionLayer.GetImageAffineBounds(FSelectionTransform, GetSelectionLayerBounds);
     ANewLayer := TBGRABitmap.Create(r.Width,r.Height);
     ANewLayer := TBGRABitmap.Create(r.Width,r.Height);
-    ANewLayer.PutImageAffine(AffineMatrixTranslation(-r.Left,-r.Top)*FSelectionTransform, SelectionLayer);
+    ANewLayer.PutImageAffine(AffineMatrixTranslation(-r.Left,-r.Top)*FSelectionTransform, SelectionLayer, rfHalfCosine);
     ALeft := r.Left;
     ALeft := r.Left;
     ATop := r.Top;
     ATop := r.Top;
   end;
   end;
@@ -808,27 +803,15 @@ begin
 end;
 end;
 
 
 function TImageState.DiscardOriginal(ACreateUndo: boolean): TCustomImageDifference;
 function TImageState.DiscardOriginal(ACreateUndo: boolean): TCustomImageDifference;
-var
-  prevOriginal: TBGRALayerCustomOriginal;
-  prevOriginalMatrix: TAffineMatrix;
-  prevOriginalData: TStream;
-  prevOriginalGuid: TGuid;
-begin
-  prevOriginalGuid := LayeredBitmap.LayerOriginalGuid[SelectedImageLayerIndex];
-  if prevOriginalGuid=GUID_NULL then exit;
-  prevOriginalMatrix:= LayeredBitmap.LayerOriginalMatrix[SelectedImageLayerIndex];
-  LayeredBitmap.LayerOriginalGuid[SelectedImageLayerIndex] := GUID_NULL;
-  LayeredBitmap.LayerOriginalMatrix[SelectedImageLayerIndex] := AffineMatrixIdentity;
+begin
   if ACreateUndo then
   if ACreateUndo then
-  begin
-    prevOriginalData:= TMemoryStream.Create;
-    prevOriginal := LayeredBitmap.Original[LayeredBitmap.IndexOfOriginal(prevOriginalGuid)];
-    prevOriginal.SaveToStream(prevOriginalData);
-    result := TImageLayerStateDifference.Create(self, nil,false,nil,false,nil,false,SelectionTransform,prevOriginalData,prevOriginalMatrix);
-  end
+    result := TDiscardOriginalDifference.Create(self, SelectedImageLayerIndex, true)
   else
   else
-    result := nil;
-  LayeredBitmap.RemoveUnusedOriginals;
+  begin
+    LayeredBitmap.LayerOriginalGuid[SelectedImageLayerIndex] := GUID_NULL;
+    LayeredBitmap.LayerOriginalMatrix[SelectedImageLayerIndex] := AffineMatrixIdentity;
+    LayeredBitmap.RemoveUnusedOriginals;
+  end;
 end;
 end;
 
 
 function TImageState.HorizontalFlip: TCustomImageDifference;
 function TImageState.HorizontalFlip: TCustomImageDifference;
@@ -929,7 +912,7 @@ begin
   begin
   begin
     r := SelectionMask.GetImageAffineBounds(FSelectionTransform, GetSelectionMaskBounds);
     r := SelectionMask.GetImageAffineBounds(FSelectionTransform, GetSelectionMaskBounds);
     ANewMask := TBGRABitmap.Create(r.Width,r.Height,BGRABlack);
     ANewMask := TBGRABitmap.Create(r.Width,r.Height,BGRABlack);
-    ANewMask.PutImageAffine(AffineMatrixTranslation(-r.Left,-r.Top)*FSelectionTransform, SelectionMask);
+    ANewMask.PutImageAffine(AffineMatrixTranslation(-r.Left,-r.Top)*FSelectionTransform, SelectionMask, rfHalfCosine, dmLinearBlend);
     ALeft := r.Left;
     ALeft := r.Left;
     ATop := r.Top;
     ATop := r.Top;
   end;
   end;
@@ -1028,6 +1011,11 @@ begin
   result := TApplyLayerOffsetStateDifference.Create(self, LayeredBitmap.LayerUniqueId[SelectedImageLayerIndex], AOffsetX,AOffsetY, false);
   result := TApplyLayerOffsetStateDifference.Create(self, LayeredBitmap.LayerUniqueId[SelectedImageLayerIndex], AOffsetX,AOffsetY, false);
 end;
 end;
 
 
+function TImageState.ComputeSelectionTransformDifference: TCustomImageDifference;
+begin
+  result := TSelectionTransformDifference.Create(self, false);
+end;
+
 function TImageState.ComputeLayerMatrixDifference(AIndex: integer; APrevMatrix,
 function TImageState.ComputeLayerMatrixDifference(AIndex: integer; APrevMatrix,
   ANewMatrix: TAffineMatrix): TCustomImageDifference;
   ANewMatrix: TAffineMatrix): TCustomImageDifference;
 begin
 begin
@@ -1037,29 +1025,25 @@ end;
 function TImageState.ComputeLayerDifference(APreviousImage: TBGRABitmap;
 function TImageState.ComputeLayerDifference(APreviousImage: TBGRABitmap;
   APreviousImageDefined: boolean; APreviousSelection: TBGRABitmap;
   APreviousImageDefined: boolean; APreviousSelection: TBGRABitmap;
   APreviousSelectionDefined: boolean; APreviousSelectionLayer: TBGRABitmap;
   APreviousSelectionDefined: boolean; APreviousSelectionLayer: TBGRABitmap;
-  APreviousSelectionLayerDefined: boolean; APreviousSelectionTransform: TAffineMatrix;
-  APreviousLayerOriginalData: TStream; APreviousLayerOriginalMatrix: TAffineMatrix): TCustomImageDifference;
+  APreviousSelectionLayerDefined: boolean): TCustomImageDifference;
 begin
 begin
   if LayeredBitmap = nil then
   if LayeredBitmap = nil then
     result := nil
     result := nil
   else
   else
     result := TImageLayerStateDifference.Create(self, APreviousImage, APreviousImageDefined,
     result := TImageLayerStateDifference.Create(self, APreviousImage, APreviousImageDefined,
-      APreviousSelection, APreviousSelectionDefined, APreviousSelectionLayer, APreviousSelectionLayerDefined,
-      APreviousSelectionTransform, APreviousLayerOriginalData, APreviousLayerOriginalMatrix);
+      APreviousSelection, APreviousSelectionDefined, APreviousSelectionLayer, APreviousSelectionLayerDefined);
 end;
 end;
 
 
 function TImageState.ComputeLayerDifference(APreviousImage: TBGRABitmap;
 function TImageState.ComputeLayerDifference(APreviousImage: TBGRABitmap;
   APreviousImageChangeRect: TRect; APreviousSelection: TBGRABitmap;
   APreviousImageChangeRect: TRect; APreviousSelection: TBGRABitmap;
   APreviousSelectionChangeRect: TRect; APreviousSelectionLayer: TBGRABitmap;
   APreviousSelectionChangeRect: TRect; APreviousSelectionLayer: TBGRABitmap;
-  APreviousSelectionLayerChangeRect: TRect; APreviousSelectionTransform: TAffineMatrix;
-  APreviousLayerOriginalData: TStream; APreviousLayerOriginalMatrix: TAffineMatrix): TCustomImageDifference;
+  APreviousSelectionLayerChangeRect: TRect): TCustomImageDifference;
 begin
 begin
   if LayeredBitmap = nil then
   if LayeredBitmap = nil then
     result := nil
     result := nil
   else
   else
     result := TImageLayerStateDifference.Create(self, APreviousImage, APreviousImageChangeRect,
     result := TImageLayerStateDifference.Create(self, APreviousImage, APreviousImageChangeRect,
-      APreviousSelection, APreviousSelectionChangeRect, APreviousSelectionLayer, APreviousSelectionLayerChangeRect,
-      APreviousSelectionTransform, APreviousLayerOriginalData, APreviousLayerOriginalMatrix);
+      APreviousSelection, APreviousSelectionChangeRect, APreviousSelectionLayer, APreviousSelectionLayerChangeRect);
 end;
 end;
 
 
 function TImageState.GetLayeredBitmapCopy: TBGRALayeredBitmap;
 function TImageState.GetLayeredBitmapCopy: TBGRALayeredBitmap;

+ 5 - 4
lazpaint/uimageview.pas

@@ -55,7 +55,7 @@ type
     procedure OnZoomChanged({%H-}sender: TZoom; {%H-}ANewZoom: single; AWorkArea: TRect);
     procedure OnZoomChanged({%H-}sender: TZoom; {%H-}ANewZoom: single; AWorkArea: TRect);
     procedure UpdateCursor(X,Y: integer; ACanvasOfs: TPoint; AWorkArea: TRect; AControl: TControl;
     procedure UpdateCursor(X,Y: integer; ACanvasOfs: TPoint; AWorkArea: TRect; AControl: TControl;
                           AWinControlOfs: TPoint; AWinControl: TWinControl);
                           AWinControlOfs: TPoint; AWinControl: TWinControl);
-    procedure UpdatePicture(ACanvasOfs: TPoint; AWorkArea: TRect; {%H-}AControl: TControl);
+    procedure UpdatePicture(ACanvasOfs: TPoint; AWorkArea: TRect; {%H-}AWinControl: TWinControl);
     function BitmapToForm(pt: TPointF): TPointF;
     function BitmapToForm(pt: TPointF): TPointF;
     function BitmapToForm(X, Y: Single): TPointF;
     function BitmapToForm(X, Y: Single): TPointF;
     function BitmapToVirtualScreen(ptF: TPointF): TPointF;
     function BitmapToVirtualScreen(ptF: TPointF): TPointF;
@@ -530,7 +530,7 @@ begin
     PaintVirtualScreenCursor(ACanvasOfs, AWorkArea, AWinControlOfs, AWinControl);
     PaintVirtualScreenCursor(ACanvasOfs, AWorkArea, AWinControlOfs, AWinControl);
 end;
 end;
 
 
-procedure TImageView.UpdatePicture(ACanvasOfs: TPoint; AWorkArea: TRect; AControl: TControl);
+procedure TImageView.UpdatePicture(ACanvasOfs: TPoint; AWorkArea: TRect; AWinControl: TWinControl);
 var
 var
   updateArea: TRect;
   updateArea: TRect;
   {$IFDEF IMAGEVIEW_DIRECTUPDATE}prevVSArea: TRect;{$ENDIF}
   {$IFDEF IMAGEVIEW_DIRECTUPDATE}prevVSArea: TRect;{$ENDIF}
@@ -542,13 +542,14 @@ begin
   FPenCursorPos := GetPenCursorPosition;
   FPenCursorPos := GetPenCursorPosition;
   updateArea := GetRectToInvalidate(false, AWorkArea);
   updateArea := GetRectToInvalidate(false, AWorkArea);
   FPenCursorPosBefore.bounds := EmptyRect;
   FPenCursorPosBefore.bounds := EmptyRect;
-  OffsetRect(updateArea, -FLastPictureParameters.virtualScreenArea.Left,-FLastPictureParameters.virtualScreenArea.Top);
   {$IFDEF IMAGEVIEW_DIRECTUPDATE}
   {$IFDEF IMAGEVIEW_DIRECTUPDATE}
+  OffsetRect(updateArea, -FLastPictureParameters.virtualScreenArea.Left,-FLastPictureParameters.virtualScreenArea.Top);
   PaintPictureImplementation(ACanvasOfs, AWorkArea, updateArea);
   PaintPictureImplementation(ACanvasOfs, AWorkArea, updateArea);
   if prevVSArea <> FLastPictureParameters.virtualScreenArea then
   if prevVSArea <> FLastPictureParameters.virtualScreenArea then
     PaintBlueAreaImplementation(ACanvasOfs, AWorkArea);
     PaintBlueAreaImplementation(ACanvasOfs, AWorkArea);
   {$ELSE}
   {$ELSE}
-  AControl.Update;
+  InvalidateRect(AWinControl.Handle, @updateArea, false);
+  AWinControl.Update;
   {$ENDIF}
   {$ENDIF}
 end;
 end;
 
 

+ 53 - 114
lazpaint/ulayeraction.pas

@@ -24,7 +24,6 @@ type
     FPrediff: TComposedImageDifference;
     FPrediff: TComposedImageDifference;
     FBackupSelectedLayer, FBackupSelectionLayer, FBackupSelection: TBGRABitmap;
     FBackupSelectedLayer, FBackupSelectionLayer, FBackupSelection: TBGRABitmap;
     FBackupSelectedLayerDefined, FBackupSelectionLayerDefined, FBackupSelectionMaskDefined: boolean;
     FBackupSelectedLayerDefined, FBackupSelectionLayerDefined, FBackupSelectionMaskDefined: boolean;
-    FBackupSelectionTransform: TAffineMatrix;
     FSelectedImageLayerChangedArea, FSelectionLayerChangedArea, FSelectionMaskChangedArea: TRect;
     FSelectedImageLayerChangedArea, FSelectionLayerChangedArea, FSelectionMaskChangedArea: TRect;
     FDone: boolean;
     FDone: boolean;
     FOnTryStop: TOnTryStopEventHandler;
     FOnTryStop: TOnTryStopEventHandler;
@@ -38,7 +37,6 @@ type
     function GetDrawingLayer: TBGRABitmap;
     function GetDrawingLayer: TBGRABitmap;
     function GetSelectedImageLayerOffset: TPoint;
     function GetSelectedImageLayerOffset: TPoint;
     function GetSelectionLayerBounds: TRect;
     function GetSelectionLayerBounds: TRect;
-    function GetSelectionTransform: TAffineMatrix;
     procedure SetOnDestroy(AValue: TNotifyEvent);
     procedure SetOnDestroy(AValue: TNotifyEvent);
     procedure SetOnNotifyChange(AValue: TNotifyChangeEvent);
     procedure SetOnNotifyChange(AValue: TNotifyChangeEvent);
     procedure SetOnNotifyUndo(AValue: TNotifyUndoEvent);
     procedure SetOnNotifyUndo(AValue: TNotifyUndoEvent);
@@ -49,7 +47,7 @@ type
     procedure NeedSelectionLayerBackup;
     procedure NeedSelectionLayerBackup;
     property CurrentState: TImageState read GetCurrentState;
     property CurrentState: TImageState read GetCurrentState;
   public
   public
-    constructor Create(AState: TImageState; AApplyOfsBefore: boolean = false);
+    constructor Create(AState: TImageState; AApplyOfsBefore: boolean = false; AApplySelectionTransformBefore: boolean = false);
     procedure Validate;
     procedure Validate;
     procedure PartialValidate(ADiscardBackup: boolean = false);
     procedure PartialValidate(ADiscardBackup: boolean = false);
     procedure PartialCancel;
     procedure PartialCancel;
@@ -62,7 +60,6 @@ type
     procedure ReleaseSelection;
     procedure ReleaseSelection;
     procedure RetrieveSelection;
     procedure RetrieveSelection;
     function RetrieveSelectionIfLayerEmpty(removeFromBitmap: boolean = false): boolean;
     function RetrieveSelectionIfLayerEmpty(removeFromBitmap: boolean = false): boolean;
-    procedure ApplySelectionTransform(ApplyToMask: boolean= true);
     procedure ApplySelectionMask;
     procedure ApplySelectionMask;
 
 
     procedure ReplaceSelectionLayer(bmp: TBGRABitmap; AOwned: boolean);
     procedure ReplaceSelectionLayer(bmp: TBGRABitmap; AOwned: boolean);
@@ -88,11 +85,11 @@ type
     property OnTryStop: TOnTryStopEventHandler read FOnTryStop write FOnTryStop;
     property OnTryStop: TOnTryStopEventHandler read FOnTryStop write FOnTryStop;
     property Done: boolean read FDone;
     property Done: boolean read FDone;
     property ChangeBoundsNotified: boolean read FChangeBoundsNotified write FChangeBoundsNotified;
     property ChangeBoundsNotified: boolean read FChangeBoundsNotified write FChangeBoundsNotified;
-    property SelectionTransform: TAffineMatrix read GetSelectionTransform;
     property SelectionLayerBounds: TRect read GetSelectionLayerBounds;
     property SelectionLayerBounds: TRect read GetSelectionLayerBounds;
     property OnNotifyChange: TNotifyChangeEvent read FOnNotifyChange write SetOnNotifyChange;
     property OnNotifyChange: TNotifyChangeEvent read FOnNotifyChange write SetOnNotifyChange;
     property OnNotifyUndo: TNotifyUndoEvent read FOnNotifyUndo write SetOnNotifyUndo;
     property OnNotifyUndo: TNotifyUndoEvent read FOnNotifyUndo write SetOnNotifyUndo;
     property OnDestroy: TNotifyEvent read FOnDestroy write SetOnDestroy;
     property OnDestroy: TNotifyEvent read FOnDestroy write SetOnDestroy;
+    property Prediff: TComposedImageDifference read FPrediff;
   end;
   end;
 
 
 implementation
 implementation
@@ -160,11 +157,6 @@ begin
   result := CurrentState.GetSelectionLayerBounds;
   result := CurrentState.GetSelectionLayerBounds;
 end;
 end;
 
 
-function TLayerAction.GetSelectionTransform: TAffineMatrix;
-begin
-  result:= CurrentState.SelectionTransform;
-end;
-
 procedure TLayerAction.SetOnDestroy(AValue: TNotifyEvent);
 procedure TLayerAction.SetOnDestroy(AValue: TNotifyEvent);
 begin
 begin
   if FOnDestroy=AValue then Exit;
   if FOnDestroy=AValue then Exit;
@@ -189,7 +181,6 @@ begin
   RestoreSelectedLayer;
   RestoreSelectedLayer;
   RestoreSelectionLayer;
   RestoreSelectionLayer;
   RestoreSelectionMask;
   RestoreSelectionMask;
-  CurrentState.SelectionTransform := FBackupSelectionTransform;
   if Assigned(FPrediff) then
   if Assigned(FPrediff) then
   begin
   begin
     FPrediff.UnapplyTo(CurrentState);
     FPrediff.UnapplyTo(CurrentState);
@@ -225,9 +216,10 @@ begin
   end;
   end;
 end;
 end;
 
 
-constructor TLayerAction.Create(AState: TImageState; AApplyOfsBefore: boolean);
+constructor TLayerAction.Create(AState: TImageState; AApplyOfsBefore: boolean;
+  AApplySelectionTransformBefore: boolean);
 var
 var
-  layerOfsDiff: TCustomImageDifference;
+  layerOfsDiff,selTransfDiff: TCustomImageDifference;
 begin
 begin
   FImageState := AState;
   FImageState := AState;
   FBackupSelectedLayer := nil;
   FBackupSelectedLayer := nil;
@@ -236,7 +228,6 @@ begin
   FBackupSelectedLayerDefined := false;
   FBackupSelectedLayerDefined := false;
   FBackupSelectionMaskDefined := false;
   FBackupSelectionMaskDefined := false;
   FBackupSelectionLayerDefined := false;
   FBackupSelectionLayerDefined := false;
-  FBackupSelectionTransform := CurrentState.SelectionTransform;
   FSelectedImageLayerChangedArea := EmptyRect;
   FSelectedImageLayerChangedArea := EmptyRect;
   FSelectionLayerChangedArea := EmptyRect;
   FSelectionLayerChangedArea := EmptyRect;
   FSelectionMaskChangedArea := EmptyRect;
   FSelectionMaskChangedArea := EmptyRect;
@@ -253,12 +244,23 @@ begin
       FPrediff.Add(layerOfsDiff);
       FPrediff.Add(layerOfsDiff);
     end;
     end;
   end;
   end;
+  if AApplySelectionTransformBefore then
+  begin
+    selTransfDiff := CurrentState.ComputeSelectionTransformDifference;
+    if selTransfDiff.IsIdentity then FreeAndNil(selTransfDiff)
+    else
+    begin
+      selTransfDiff.ApplyTo(CurrentState);
+      FPrediff.Add(selTransfDiff);
+    end;
+  end;
   if FPrediff.Count = 0 then FreeAndNil(FPrediff);
   if FPrediff.Count = 0 then FreeAndNil(FPrediff);
 end;
 end;
 
 
 destructor TLayerAction.Destroy;
 destructor TLayerAction.Destroy;
 begin
 begin
   if not FDone then Cancel;
   if not FDone then Cancel;
+  FPrediff.Free;
   FBackupSelectedLayer.Free;
   FBackupSelectedLayer.Free;
   FBackupSelection.Free;
   FBackupSelection.Free;
   FBackupSelectionLayer.Free;
   FBackupSelectionLayer.Free;
@@ -409,6 +411,7 @@ procedure TLayerAction.MergeWithSelection(AApplyMask: boolean);
 var offs: TPoint;
 var offs: TPoint;
   sourceRect,destRect: TRect;
   sourceRect,destRect: TRect;
 begin
 begin
+  if not IsAffineMatrixIdentity(CurrentState.SelectionTransform) then raise exception.Create('Unexpected selection transform');
   if not CurrentState.SelectionLayerEmpty and not (AApplyMask and CurrentState.SelectionMaskEmpty) then
   if not CurrentState.SelectionLayerEmpty and not (AApplyMask and CurrentState.SelectionMaskEmpty) then
   begin
   begin
     sourceRect := CurrentState.GetSelectionLayerBounds;
     sourceRect := CurrentState.GetSelectionLayerBounds;
@@ -430,6 +433,7 @@ end;
 procedure TLayerAction.ReleaseSelection;
 procedure TLayerAction.ReleaseSelection;
 var bounds: TRect;
 var bounds: TRect;
 begin
 begin
+  if not IsAffineMatrixIdentity(CurrentState.SelectionTransform) then raise exception.Create('Unexpected selection transform');
   if not CurrentState.SelectionMaskEmpty then
   if not CurrentState.SelectionMaskEmpty then
   begin
   begin
     bounds := CurrentState.GetSelectionMaskBounds;
     bounds := CurrentState.GetSelectionMaskBounds;
@@ -446,7 +450,6 @@ begin
     ApplySelectionMask;
     ApplySelectionMask;
     CurrentState.SelectionMask.Free;
     CurrentState.SelectionMask.Free;
     CurrentState.SelectionMask := nil;
     CurrentState.SelectionMask := nil;
-    ApplySelectionTransform(False);
     MergeWithSelection(False);
     MergeWithSelection(False);
   end;
   end;
 end;
 end;
@@ -456,11 +459,11 @@ var temp : TBGRABitmap;
   offs: TPoint;
   offs: TPoint;
   r, maskBounds: TRect;
   r, maskBounds: TRect;
 begin
 begin
+  if not IsAffineMatrixIdentity(CurrentState.SelectionTransform) then raise exception.Create('Unexpected selection transform');
   if not CurrentState.SelectionMaskEmpty then
   if not CurrentState.SelectionMaskEmpty then
   begin
   begin
     NeedSelectedLayerBackup;
     NeedSelectedLayerBackup;
     NeedSelectionLayerBackup;
     NeedSelectionLayerBackup;
-    ApplySelectionTransform;
     MergeWithSelection;
     MergeWithSelection;
     offs := CurrentState.LayerOffset[CurrentState.SelectedImageLayerIndex];
     offs := CurrentState.LayerOffset[CurrentState.SelectedImageLayerIndex];
     maskBounds := CurrentState.GetSelectionMaskBounds;
     maskBounds := CurrentState.GetSelectionMaskBounds;
@@ -477,6 +480,7 @@ end;
 
 
 function TLayerAction.RetrieveSelectionIfLayerEmpty(removeFromBitmap: boolean): boolean;
 function TLayerAction.RetrieveSelectionIfLayerEmpty(removeFromBitmap: boolean): boolean;
 begin
 begin
+  if not IsAffineMatrixIdentity(CurrentState.SelectionTransform) then raise exception.Create('Unexpected selection transform');
   NeedSelectedLayerBackup;
   NeedSelectedLayerBackup;
   NeedSelectionLayerBackup;
   NeedSelectionLayerBackup;
   if CurrentState.SelectionLayerEmpty then
   if CurrentState.SelectionLayerEmpty then
@@ -516,42 +520,6 @@ begin
   CurrentState.ReplaceSelectionLayer(bmp,AOwned);
   CurrentState.ReplaceSelectionLayer(bmp,AOwned);
 end;
 end;
 
 
-procedure TLayerAction.ApplySelectionTransform(ApplyToMask: boolean);
-var
-  newBmp: TBGRABitmap;
-  newLeft, newTop: integer;
-  r: TRect;
-begin
-  if not IsAffineMatrixIdentity(CurrentState.SelectionTransform) then
-  begin
-    if ApplyToMask and not CurrentState.SelectionMaskEmpty then
-    begin
-      NeedSelectionMaskBackup;
-      CurrentState.ComputeTransformedSelectionMask(newBmp,newLeft,newTop);
-      r := CurrentState.GetSelectionMaskBounds;
-      CurrentState.SelectionMask.FillRect(r, BGRABlack, dmSet);
-      NotifyChange(CurrentState.SelectionMask, r);
-      CurrentState.SelectionMask.PutImage(newLeft,newTop,newBmp,dmSet);
-      newBmp.Free;
-      CurrentState.DiscardSelectionMaskBounds;
-    end;
-    if not CurrentState.SelectionLayerEmpty then
-    begin
-      NeedSelectionLayerBackup;
-      CurrentState.ComputeTransformedSelectionLayer(newBmp,newLeft,newTop);
-      r := CurrentState.GetSelectionLayerBounds;
-      CurrentState.SelectionLayer.FillRect(r, BGRAPixelTransparent, dmSet);
-      NotifyChange(CurrentState.SelectionLayer, r);
-      CurrentState.SelectionLayer.PutImage(newLeft,newTop,newBmp,dmSet);
-      newBmp.Free;
-      CurrentState.DiscardSelectionLayerBounds;
-    end;
-    CurrentState.SelectionTransform := AffineMatrixIdentity;
-    NotifyChange(CurrentState.SelectionMask, CurrentState.GetSelectionMaskBounds);
-    NotifyChange(CurrentState.SelectionLayer, CurrentState.GetSelectionLayerBounds);
-  end;
-end;
-
 procedure TLayerAction.ApplySelectionMask;
 procedure TLayerAction.ApplySelectionMask;
 var r: TRect;
 var r: TRect;
 begin
 begin
@@ -583,19 +551,30 @@ end;
 
 
 procedure TLayerAction.PartialValidate(ADiscardBackup: boolean = false);
 procedure TLayerAction.PartialValidate(ADiscardBackup: boolean = false);
 var
 var
-  prevLayerOriginalMatrix: TAffineMatrix;
-  prevLayerOriginaData: TStream;
   imgDiff: TImageLayerStateDifference;
   imgDiff: TImageLayerStateDifference;
   composedDiff: TComposedImageDifference;
   composedDiff: TComposedImageDifference;
-  ofs: TPoint;
-  applyOfs: TCustomImageDifference;
-  appendOfs, owned: boolean;
+  owned, rasterizeOriginal: boolean;
+
+  procedure NotifyPrediff;
+  begin
+    if Assigned(FPrediff) then
+    begin
+      if Assigned(FOnNotifyUndo) then
+      begin
+        owned := false;
+        FOnNotifyUndo(self, FPrediff, owned);
+        if not owned then FPrediff.Free;
+      end else
+        FPrediff.Free;
+      FPrediff := nil;
+    end;
+  end;
+
 begin
 begin
-  if FBackupSelectedLayerDefined or FBackupSelectionMaskDefined or FBackupSelectionLayerDefined then
+  if (FBackupSelectedLayerDefined or FBackupSelectionMaskDefined or FBackupSelectionLayerDefined) and
+     not (ChangeBoundsNotified and IsRectEmpty(FSelectedImageLayerChangedArea) and IsRectEmpty(FSelectionMaskChangedArea) and
+         IsRectEmpty(FSelectionLayerChangedArea)) then
   begin
   begin
-    if ChangeBoundsNotified then
-      if IsRectEmpty(FSelectedImageLayerChangedArea) and IsRectEmpty(FSelectionMaskChangedArea) and
-         IsRectEmpty(FSelectionLayerChangedArea) then exit;
     if FBackupSelectionLayerDefined then
     if FBackupSelectionLayerDefined then
     begin
     begin
       CurrentState.DiscardSelectionLayerBounds;
       CurrentState.DiscardSelectionLayerBounds;
@@ -608,32 +587,15 @@ begin
       if CurrentState.SelectionMaskEmpty then
       if CurrentState.SelectionMaskEmpty then
         CurrentState.RemoveSelection;
         CurrentState.RemoveSelection;
     end;
     end;
-    //original will be backed up if there are changes in the raster image of the selected layer
-    if CurrentState.LayerOriginalDefined[CurrentState.SelectedImageLayerIndex] and
-       (FBackupSelectedLayerDefined or not IsRectEmpty(FSelectedImageLayerChangedArea)) then
-    begin
-      prevLayerOriginaData:= TMemoryStream.Create;
-      CurrentState.SaveOriginalToStream(prevLayerOriginaData);
-      prevLayerOriginalMatrix:= CurrentState.LayerOriginalMatrix[CurrentState.SelectedImageLayerIndex];
-      CurrentState.DiscardOriginal(false);
-    end else
-    begin
-      prevLayerOriginaData := nil;
-      prevLayerOriginalMatrix:= AffineMatrixIdentity;
-    end;
 
 
     if ChangeBoundsNotified then
     if ChangeBoundsNotified then
       imgDiff := CurrentState.ComputeLayerDifference(FBackupSelectedLayer, FSelectedImageLayerChangedArea,
       imgDiff := CurrentState.ComputeLayerDifference(FBackupSelectedLayer, FSelectedImageLayerChangedArea,
         FBackupSelection, FSelectionMaskChangedArea,
         FBackupSelection, FSelectionMaskChangedArea,
-        FBackupSelectionLayer, FSelectionLayerChangedArea,
-        FBackupSelectionTransform,
-        prevLayerOriginaData, prevLayerOriginalMatrix) as TImageLayerStateDifference
+        FBackupSelectionLayer, FSelectionLayerChangedArea) as TImageLayerStateDifference
     else
     else
       imgDiff := CurrentState.ComputeLayerDifference(FBackupSelectedLayer, FBackupSelectedLayerDefined,
       imgDiff := CurrentState.ComputeLayerDifference(FBackupSelectedLayer, FBackupSelectedLayerDefined,
         FBackupSelection, FBackupSelectionMaskDefined,
         FBackupSelection, FBackupSelectionMaskDefined,
-        FBackupSelectionLayer, FBackupSelectionLayerDefined,
-        FBackupSelectionTransform,
-        prevLayerOriginaData, prevLayerOriginalMatrix) as TImageLayerStateDifference;
+        FBackupSelectionLayer, FBackupSelectionLayerDefined) as TImageLayerStateDifference;
     if imgDiff.IsIdentity then FreeAndNil(imgDiff);
     if imgDiff.IsIdentity then FreeAndNil(imgDiff);
 
 
     if ADiscardBackup then
     if ADiscardBackup then
@@ -644,8 +606,6 @@ begin
       FBackupSelectedLayerDefined := false;
       FBackupSelectedLayerDefined := false;
       FBackupSelectedLayerDefined := false;
       FBackupSelectedLayerDefined := false;
       FBackupSelectionMaskDefined := false;
       FBackupSelectionMaskDefined := false;
-
-      appendOfs:= Assigned(imgDiff) and imgDiff.ChangeImageLayer;
     end else
     end else
     begin
     begin
       if FBackupSelectionLayerDefined then
       if FBackupSelectionLayerDefined then
@@ -694,13 +654,12 @@ begin
         end;
         end;
         FSelectionMaskChangedArea := EmptyRect;
         FSelectionMaskChangedArea := EmptyRect;
       end;
       end;
-
-      appendOfs := false;
     end;
     end;
 
 
     if assigned(imgDiff) then
     if assigned(imgDiff) then
     begin
     begin
-      if appendOfs or Assigned(FPrediff) then
+      rasterizeOriginal := CurrentState.LayerOriginalDefined[CurrentState.SelectedImageLayerIndex] and imgDiff.ChangeImageLayer;
+      if Assigned(FPrediff) or rasterizeOriginal then
       begin
       begin
         composedDiff := TComposedImageDifference.Create;
         composedDiff := TComposedImageDifference.Create;
         if Assigned(FPrediff) then
         if Assigned(FPrediff) then
@@ -708,24 +667,17 @@ begin
           composedDiff.AddRange(FPrediff);
           composedDiff.AddRange(FPrediff);
           FPrediff := nil;
           FPrediff := nil;
         end;
         end;
+        if rasterizeOriginal then
+          composedDiff.Add(TDiscardOriginalDifference.Create(CurrentState,
+            CurrentState.SelectedImageLayerIndex, true));
         composedDiff.Add(imgDiff);
         composedDiff.Add(imgDiff);
-        if appendOfs then
-        begin
-          ofs := CurrentState.LayerOffset[CurrentState.SelectedImageLayerIndex];
-          applyOfs:= CurrentState.ComputeLayerOffsetDifference(ofs.x, ofs.y);
-          if not applyOfs.IsIdentity then
-          begin
-            composedDiff.Add(applyOfs);
-            applyOfs.ApplyTo(CurrentState);
-          end else
-            applyOfs.Free;
-        end;
         if Assigned(FOnNotifyUndo) then
         if Assigned(FOnNotifyUndo) then
         begin
         begin
           owned := false;
           owned := false;
           FOnNotifyUndo(self, composedDiff, owned);
           FOnNotifyUndo(self, composedDiff, owned);
           if not owned then composedDiff.Free;
           if not owned then composedDiff.Free;
-        end;
+        end else
+          composedDiff.Free;
       end else
       end else
       begin
       begin
         if Assigned(FOnNotifyUndo) then
         if Assigned(FOnNotifyUndo) then
@@ -733,24 +685,11 @@ begin
           owned := false;
           owned := false;
           FOnNotifyUndo(self, imgDiff, owned);
           FOnNotifyUndo(self, imgDiff, owned);
           if not owned then imgDiff.Free;
           if not owned then imgDiff.Free;
-        end;
-      end;
-    end;
-
-    FBackupSelectionTransform := CurrentState.SelectionTransform;
-  end else
-  begin
-    if Assigned(FPrediff) then
-    begin
-      if Assigned(FOnNotifyUndo) then
-      begin
-        owned := false;
-        FOnNotifyUndo(self, FPrediff, owned);
-        if not owned then FPrediff.Free;
+        end else
+          imgDiff.Free;
       end;
       end;
-      FPrediff := nil;
-    end;
-  end;
+    end else NotifyPrediff;
+  end else NotifyPrediff;
 end;
 end;
 
 
 
 

+ 10 - 3
lazpaint/ulayerstack.lfm

@@ -18,7 +18,7 @@ object FLayerStack: TFLayerStack
   OnHide = FormHide
   OnHide = FormHide
   OnShow = FormShow
   OnShow = FormShow
   ShowInTaskBar = stNever
   ShowInTaskBar = stNever
-  LCLVersion = '2.0.0.4'
+  LCLVersion = '2.0.2.0'
   object BGRALayerStack: TBGRAVirtualScreen
   object BGRALayerStack: TBGRAVirtualScreen
     Left = 0
     Left = 0
     Height = 37
     Height = 37
@@ -33,6 +33,7 @@ object FLayerStack: TFLayerStack
     OnMouseDown = BGRALayerStackMouseDown
     OnMouseDown = BGRALayerStackMouseDown
     OnMouseMove = BGRALayerStackMouseMove
     OnMouseMove = BGRALayerStackMouseMove
     OnMouseUp = BGRALayerStackMouseUp
     OnMouseUp = BGRALayerStackMouseUp
+    OnMouseWheel = BGRALayerStackMouseWheel
     OnResize = BGRALayerStackResize
     OnResize = BGRALayerStackResize
   end
   end
   object Panel1: TPanel
   object Panel1: TPanel
@@ -51,6 +52,8 @@ object FLayerStack: TFLayerStack
       Width = 71
       Width = 71
       Align = alNone
       Align = alNone
       Anchors = [akTop, akRight]
       Anchors = [akTop, akRight]
+      ButtonHeight = 20
+      ButtonWidth = 20
       EdgeBorders = []
       EdgeBorders = []
       EdgeInner = esNone
       EdgeInner = esNone
       EdgeOuter = esNone
       EdgeOuter = esNone
@@ -59,7 +62,7 @@ object FLayerStack: TFLayerStack
       ShowHint = True
       ShowHint = True
       TabOrder = 0
       TabOrder = 0
       object ToolZoomLayerStackIn: TToolButton
       object ToolZoomLayerStackIn: TToolButton
-        Left = 24
+        Left = 21
         Hint = 'Zoom layer stack in'
         Hint = 'Zoom layer stack in'
         Top = 0
         Top = 0
         ImageIndex = 6
         ImageIndex = 6
@@ -73,7 +76,7 @@ object FLayerStack: TFLayerStack
         OnClick = ToolZoomLayerStackOutClick
         OnClick = ToolZoomLayerStackOutClick
       end
       end
       object ToolButton1: TToolButton
       object ToolButton1: TToolButton
-        Left = 47
+        Left = 41
         Top = 0
         Top = 0
         Action = FMain.LayerRemoveCurrent
         Action = FMain.LayerRemoveCurrent
       end
       end
@@ -98,6 +101,8 @@ object FLayerStack: TFLayerStack
       Width = 243
       Width = 243
       Align = alNone
       Align = alNone
       Anchors = [akTop, akLeft, akRight]
       Anchors = [akTop, akLeft, akRight]
+      ButtonHeight = 20
+      ButtonWidth = 20
       EdgeBorders = []
       EdgeBorders = []
       EdgeInner = esNone
       EdgeInner = esNone
       EdgeOuter = esNone
       EdgeOuter = esNone
@@ -112,6 +117,8 @@ object FLayerStack: TFLayerStack
       Top = 2
       Top = 2
       Width = 24
       Width = 24
       Align = alNone
       Align = alNone
+      ButtonHeight = 20
+      ButtonWidth = 20
       EdgeBorders = []
       EdgeBorders = []
       EdgeInner = esNone
       EdgeInner = esNone
       EdgeOuter = esNone
       EdgeOuter = esNone

+ 132 - 76
lazpaint/ulayerstack.pas

@@ -14,6 +14,12 @@ type
     PreviewPts: array of TPointF;
     PreviewPts: array of TPointF;
     NameRect,OpacityBar: TRect;
     NameRect,OpacityBar: TRect;
   end;
   end;
+  TLayerItemInfo = record
+    RightPart: TDrawLayerItemResult;
+    VisibleCheckbox: TRect;
+    KindIcon: TRect;
+    KindIconHint: string;
+  end;
 
 
   { TFLayerStack }
   { TFLayerStack }
 
 
@@ -36,6 +42,8 @@ type
       Y: Integer);
       Y: Integer);
     procedure BGRALayerStackMouseUp(Sender: TObject; Button: TMouseButton;
     procedure BGRALayerStackMouseUp(Sender: TObject; Button: TMouseButton;
       {%H-}Shift: TShiftState; X, Y: Integer);
       {%H-}Shift: TShiftState; X, Y: Integer);
+    procedure BGRALayerStackMouseWheel(Sender: TObject; Shift: TShiftState;
+      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
     procedure BGRALayerStackRedraw(Sender: TObject; Bitmap: TBGRABitmap);
     procedure BGRALayerStackRedraw(Sender: TObject; Bitmap: TBGRABitmap);
     procedure BGRALayerStackResize(Sender: TObject);
     procedure BGRALayerStackResize(Sender: TObject);
     procedure ComboBox_BlendOpChange(Sender: TObject);
     procedure ComboBox_BlendOpChange(Sender: TObject);
@@ -67,8 +75,7 @@ type
     VolatileHorzScrollBar, VolatileVertScrollBar: TVolatileScrollBar;
     VolatileHorzScrollBar, VolatileVertScrollBar: TVolatileScrollBar;
     ScrollButtonRect: TRect;
     ScrollButtonRect: TRect;
     InterruptorWidth,InterruptorHeight: integer;
     InterruptorWidth,InterruptorHeight: integer;
-    interruptors: array of TRect;
-    LayerInfo: array of TDrawLayerItemResult;
+    LayerInfo: array of TLayerItemInfo;
     movingItemStart: boolean;
     movingItemStart: boolean;
     movingItem: TBGRABitmap;
     movingItem: TBGRABitmap;
     movingItemSourceIndex: integer;
     movingItemSourceIndex: integer;
@@ -85,6 +92,7 @@ type
     procedure UpdateImage;
     procedure UpdateImage;
     procedure OnImageChangedHandler(AEvent: TLazPaintImageObservationEvent);
     procedure OnImageChangedHandler(AEvent: TLazPaintImageObservationEvent);
     procedure SelectBlendOp;
     procedure SelectBlendOp;
+    procedure DoScrollVertically(AAmount: integer);
   public
   public
     { public declarations }
     { public declarations }
     LazPaintInstance: TLazPaintCustomInstance;
     LazPaintInstance: TLazPaintCustomInstance;
@@ -95,6 +103,8 @@ type
     property CompletelyResizeable: boolean read FCompletelyResizeable write SetCompletelyResizeable;
     property CompletelyResizeable: boolean read FCompletelyResizeable write SetCompletelyResizeable;
   end;
   end;
 
 
+var TFLayerStack_CustomDPI: integer = 96;
+
 implementation
 implementation
 
 
 uses BGRAFillInfo,LCScaleDPI,uresourcestrings,ublendop, uimage, utool, BGRAText, BGRAThumbnail,
 uses BGRAFillInfo,LCScaleDPI,uresourcestrings,ublendop, uimage, utool, BGRAText, BGRAThumbnail,
@@ -179,10 +189,10 @@ end;
 
 
 procedure TFLayerStack.FormCreate(Sender: TObject);
 procedure TFLayerStack.FormCreate(Sender: TObject);
 begin
 begin
-  ScaleControl(Self,OriginalDPI);
+  ScaleControl(Self,OriginalDPI,TFLayerStack_CustomDPI,TFLayerStack_CustomDPI);
   FCompletelyResizeable:= true;
   FCompletelyResizeable:= true;
   Position := poDesigned;
   Position := poDesigned;
-  ZoomFactor := 1;
+  ZoomFactor := TFLayerStack_CustomDPI/96;
   ScrollPos := point(0,0);
   ScrollPos := point(0,0);
   VolatileHorzScrollBar := nil;
   VolatileHorzScrollBar := nil;
   VolatileVertScrollBar := nil;
   VolatileVertScrollBar := nil;
@@ -226,37 +236,36 @@ var iconSize: integer;
     images: TImageList;
     images: TImageList;
 begin
 begin
   LazPaintInstance.Image.OnImageChanged.AddObserver(@OnImageChangedHandler);
   LazPaintInstance.Image.OnImageChanged.AddObserver(@OnImageChangedHandler);
-  iconSize := LazPaintInstance.Config.DefaultIconSize(16);
-  if iconSize <> 16 then
-  begin
-    images := LazPaintInstance.Icons[iconSize];
-    ToolBar1.Images := images;
-    ToolBar1.ButtonWidth := images.Width+1;
-    ToolBar1.ButtonHeight := images.Height+1;
-    ToolBar1.Height := ToolBar1.ButtonHeight+1;
-    ToolBar2.Images := images;
-    ToolBar2.ButtonWidth := images.Width+1;
-    ToolBar2.ButtonHeight := images.Height+1;
-    ToolBar2.Height := ToolBar1.ButtonHeight+1;
-    ToolBar3.Images := images;
-    ToolBar3.ButtonWidth := images.Width+1;
-    ToolBar3.ButtonHeight := images.Height+1;
-    ToolBar3.Height := ToolBar1.ButtonHeight+1;
-
-    ClientWidth := ToolBar2.ButtonCount * (ToolBar2.ButtonWidth+1) + 5 + Toolbar2.Left;
-    Constraints.MinWidth := Width;
-
-    ToolBar1.Width := ToolBar1.ButtonCount * (ToolBar1.ButtonWidth+1) + 8;
-    ToolBar3.Width := ToolBar3.ButtonCount * (ToolBar3.ButtonWidth+1) + 5;
-
-    ComboBox_BlendOp.Left := Toolbar3.Left+Toolbar3.Width;
-    Toolbar1.Left := ClientWidth-Toolbar1.Width-6;
-    ComboBox_BlendOp.Width := Toolbar1.Left - ComboBox_BlendOp.Left;
-    Toolbar2.Top := Toolbar1.Top + Toolbar1.Height;
-    Panel1.Height := Toolbar2.Top+Toolbar2.Height+2;
+  iconSize := DoScaleX(16, 96, TFLayerStack_CustomDPI);
+
+  images := LazPaintInstance.Icons[iconSize];
+  ToolBar1.Images := images;
+  ToolBar1.ButtonWidth := images.Width+DoScaleX(4,96,TFLayerStack_CustomDPI);
+  ToolBar1.ButtonHeight := images.Height+DoScaleY(4,96,TFLayerStack_CustomDPI);
+  ToolBar1.Height := ToolBar1.ButtonHeight+1;
+  ToolBar2.Images := images;
+  ToolBar2.ButtonWidth := images.Width+DoScaleX(4,96,TFLayerStack_CustomDPI);
+  ToolBar2.ButtonHeight := images.Height+DoScaleY(4,96,TFLayerStack_CustomDPI);
+  ToolBar2.Height := ToolBar1.ButtonHeight+1;
+  ToolBar3.Images := images;
+  ToolBar3.ButtonWidth := images.Width+DoScaleX(4,96,TFLayerStack_CustomDPI);
+  ToolBar3.ButtonHeight := images.Height+DoScaleY(4,96,TFLayerStack_CustomDPI);
+  ToolBar3.Height := ToolBar1.ButtonHeight+1;
+
+  ClientWidth := ToolBar2.ButtonCount * (ToolBar2.ButtonWidth+1) + 5 + Toolbar2.Left;
+  Constraints.MinWidth := Width;
+
+  ToolBar1.Width := ToolBar1.ButtonCount * (ToolBar1.ButtonWidth+1) + 8;
+  ToolBar3.Width := ToolBar3.ButtonCount * (ToolBar3.ButtonWidth+1) + 5;
+
+  ComboBox_BlendOp.Left := Toolbar3.Left+Toolbar3.Width;
+  Toolbar1.Left := ClientWidth-Toolbar1.Width-6;
+  ComboBox_BlendOp.Width := Toolbar1.Left - ComboBox_BlendOp.Left;
+  Toolbar2.Top := Toolbar1.Top + Toolbar1.Height;
+  Panel1.Height := Toolbar2.Top+Toolbar2.Height+2;
+
+  ComboBox_BlendOp.Font.Height := -FontEmHeightSign * ((images.Height-2) * 6 div 10 + 2);
 
 
-    ComboBox_BlendOp.Font.Height := -FontEmHeightSign * ((images.Height-2) * 7 div 10);
-  end;
   if Toolbar2.Top < ComboBox_BlendOp.Top + ComboBox_BlendOp.Height then
   if Toolbar2.Top < ComboBox_BlendOp.Top + ComboBox_BlendOp.Height then
     Toolbar2.Top := ComboBox_BlendOp.Top + ComboBox_BlendOp.Height;
     Toolbar2.Top := ComboBox_BlendOp.Top + ComboBox_BlendOp.Height;
   if Toolbar2.Top+Toolbar2.Height+2 > Panel1.Height then
   if Toolbar2.Top+Toolbar2.Height+2 > Panel1.Height then
@@ -264,15 +273,9 @@ begin
 end;
 end;
 
 
 procedure TFLayerStack.TimerScrollTimer(Sender: TObject);
 procedure TFLayerStack.TimerScrollTimer(Sender: TObject);
-var prevY: integer;
 begin
 begin
-  prevY := scrollPos.Y;
-  ScrollPos.Y += TimerScrollDeltaY;
-  if ScrollPos.Y < 0 then ScrollPos.Y := 0;
-  if ScrollPos.Y > MaxScrollPos.Y then ScrollPos.Y := MaxScrollPos.Y;
-  movingItemMouseOrigin.Y -= ScrollPos.Y-prevY;
   TimerScroll.Enabled := False;
   TimerScroll.Enabled := False;
-  BGRALayerStack.RedrawBitmap;
+  DoScrollVertically(TimerScrollDeltaY);
 end;
 end;
 
 
 procedure TFLayerStack.ToolBlendOpClick(Sender: TObject);
 procedure TFLayerStack.ToolBlendOpClick(Sender: TObject);
@@ -304,7 +307,7 @@ procedure TFLayerStack.HandleChangeLayerOpacity(X, Y: integer);
 var newOpacity: integer;
 var newOpacity: integer;
 begin
 begin
   if (changingLayerOpacity <> -1) and (changingLayerOpacity <= high(LayerInfo)) then
   if (changingLayerOpacity <> -1) and (changingLayerOpacity <= high(LayerInfo)) then
-  with LayerInfo[changingLayerOpacity] do
+  with LayerInfo[changingLayerOpacity].RightPart do
   begin
   begin
     if changingLayerOpacity >= LazPaintInstance.Image.NbLayers then exit;
     if changingLayerOpacity >= LazPaintInstance.Image.NbLayers then exit;
     newOpacity := round((X-(OpacityBar.left+1))/(OpacityBar.right-OpacityBar.left-2)*255);
     newOpacity := round((X-(OpacityBar.left+1))/(OpacityBar.right-OpacityBar.left-2)*255);
@@ -398,7 +401,6 @@ end;
 procedure TFLayerStack.ComputeLayout(ABitmap: TBGRABitmap);
 procedure TFLayerStack.ComputeLayout(ABitmap: TBGRABitmap);
 var i,temp,h: integer;
 var i,temp,h: integer;
 begin
 begin
-  interruptors:= nil;
   LayerInfo := nil;
   LayerInfo := nil;
   LayerRectWidth := round(100*zoomFactor);
   LayerRectWidth := round(100*zoomFactor);
   LayerRectHeight := round(50*zoomFactor);
   LayerRectHeight := round(50*zoomFactor);
@@ -547,21 +549,56 @@ var i: integer;
   layerPos: TPoint;
   layerPos: TPoint;
   lSelected: boolean;
   lSelected: boolean;
   y: integer;
   y: integer;
-  clipping, rKind: TRect;
+  clipping: TRect;
   lColor, lColorTrans: TBGRAPixel;
   lColor, lColorTrans: TBGRAPixel;
 
 
-  procedure DrawKind(AClass: TBGRALayerOriginalAny);
+  procedure DrawKindUnknown(rKind: TRect; out HintText: string);
   var
   var
     eb: TEasyBezierCurve;
     eb: TEasyBezierCurve;
     w: single;
     w: single;
     i: integer;
     i: integer;
     m: TAffineMatrix;
     m: TAffineMatrix;
   begin
   begin
-    if AClass = TBGRALayerImageOriginal then
+    eb := EasyBezierCurve([PointF(0.25,0.25),PointF(0.32,0.07),PointF(0.5,0),PointF(0.68,0.07),PointF(0.75,0.20),
+                           PointF(0.75,0.30),PointF(0.70,0.40),PointF(0.5,0.5),PointF(0.5,0.70)],False,cmCurve);
+    m := AffineMatrixTranslation(rKind.Left,rKind.Top)*AffineMatrixScale(rKind.Width,rKind.Height);
+    for i := 0 to eb.PointCount-1 do eb.Point[i] := m*eb.Point[i];
+    w := max(1,rKind.Height/10);
+    Bitmap.DrawPolyLineAntialias(eb.ToPoints, lColor, w, true);
+    Bitmap.FillEllipseAntialias((rKind.Left+rKind.Right)/2, rKind.Bottom - 1 - (w-1)/2, w*0.6,w*0.6, lColor);
+    HintText := rsUnknownOriginal;
+  end;
+
+  procedure DrawKind(AClass: TBGRALayerOriginalAny; rKind: TRect; out HintText: string);
+  var
+    eb: TEasyBezierCurve;
+    w: single;
+    i: integer;
+    m: TAffineMatrix;
+    r: TRect;
+  begin
+    if AClass = nil then
     begin
     begin
       Bitmap.Rectangle(rKind, lColor,lColorTrans, dmDrawWithTransparency);
       Bitmap.Rectangle(rKind, lColor,lColorTrans, dmDrawWithTransparency);
       Bitmap.HorizLine(rKind.Left+1,rKind.Top+(rKind.Height-1) div 2,rKind.Right-2, lColor, dmDrawWithTransparency);
       Bitmap.HorizLine(rKind.Left+1,rKind.Top+(rKind.Height-1) div 2,rKind.Right-2, lColor, dmDrawWithTransparency);
       Bitmap.VertLine(rKind.Left+(rKind.Width-1) div 2,rKind.Top+1,rKind.Bottom-2, lColor, dmDrawWithTransparency);
       Bitmap.VertLine(rKind.Left+(rKind.Width-1) div 2,rKind.Top+1,rKind.Bottom-2, lColor, dmDrawWithTransparency);
+      HintText := rsRasterLayer;
+    end else
+    if AClass = TBGRALayerImageOriginal then
+    begin
+      r := rect(rKind.Left,(rKind.Top+rKind.Bottom) div 2, (rKind.Left+rKind.Right) div 2, rKind.Bottom);
+      w := max(1,rKind.Height/10);
+      Bitmap.Rectangle(r, lColor,lColorTrans, dmDrawWithTransparency);
+      eb := EasyBezierCurve([PointF(rKind.Left,rKind.Top+rKind.Height/4),
+                             PointF(rKind.Left+rKind.Width/2,rKind.Top+rKind.Height/4),
+                             PointF(rKind.Left+rKind.Width*3/4,rKind.Top+rKind.Height/2),
+                             PointF(rKind.Left+rKind.Width*3/4,rKind.Bottom)],False,cmCurve);
+      Bitmap.Arrow.StartAsClassic;
+      Bitmap.Arrow.EndAsClassic;
+      Bitmap.DrawPolyLineAntialias(eb.ToPoints, lColor, w);
+      Bitmap.Arrow.StartAsNone;
+      Bitmap.Arrow.EndAsNone;
+      HintText := rsTransformedRasterLayer;
     end else
     end else
     if AClass = TBGRALayerSVGOriginal then
     if AClass = TBGRALayerSVGOriginal then
     begin
     begin
@@ -577,16 +614,7 @@ var i: integer;
       eb.CurveMode[eb.PointCount-2] := cmAngle;
       eb.CurveMode[eb.PointCount-2] := cmAngle;
       for i := 0 to eb.PointCount-1 do eb.Point[i] := m*eb.Point[i];
       for i := 0 to eb.PointCount-1 do eb.Point[i] := m*eb.Point[i];
       Bitmap.DrawPolyLineAntialias(eb.ToPoints, lColor, w, true);
       Bitmap.DrawPolyLineAntialias(eb.ToPoints, lColor, w, true);
-    end else
-    if AClass = nil then
-    begin
-      eb := EasyBezierCurve([PointF(0.25,0.25),PointF(0.32,0.07),PointF(0.5,0),PointF(0.68,0.07),PointF(0.75,0.20),
-                             PointF(0.75,0.30),PointF(0.70,0.40),PointF(0.5,0.5),PointF(0.5,0.70)],False,cmCurve);
-      m := AffineMatrixTranslation(rKind.Left,rKind.Top)*AffineMatrixScale(rKind.Width,rKind.Height);
-      for i := 0 to eb.PointCount-1 do eb.Point[i] := m*eb.Point[i];
-      w := max(1,rKind.Height/10);
-      Bitmap.DrawPolyLineAntialias(eb.ToPoints, lColor, w, true);
-      Bitmap.FillEllipseAntialias((rKind.Left+rKind.Right)/2, rKind.Bottom - 1 - (w-1)/2, w*0.6,w*0.6, lColor);
+      HintText := rsVectorialLayer;
     end else
     end else
     begin
     begin
       Bitmap.EllipseAntialias(rKind.Left+rKind.Width / 3, rKind.Top+rKind.Height / 3,rKind.Width / 3,rKind.Height / 3,
       Bitmap.EllipseAntialias(rKind.Left+rKind.Width / 3, rKind.Top+rKind.Height / 3,rKind.Width / 3,rKind.Height / 3,
@@ -594,6 +622,7 @@ var i: integer;
       Bitmap.DrawPolygonAntialias([PointF(rKind.Left+rKind.Width/4,rKind.Bottom),
       Bitmap.DrawPolygonAntialias([PointF(rKind.Left+rKind.Width/4,rKind.Bottom),
                                    PointF(rKind.Left+rKind.Width/2,rKind.Top+rKind.Height/4),
                                    PointF(rKind.Left+rKind.Width/2,rKind.Top+rKind.Height/4),
                                    PointF(rKind.Right,rKind.Bottom)],lColor,1, lColorTrans);
                                    PointF(rKind.Right,rKind.Bottom)],lColor,1, lColorTrans);
+      HintText := rsVectorialLayer;
     end;
     end;
   end;
   end;
 
 
@@ -605,7 +634,6 @@ begin
   end;
   end;
   layerPos.x := -Offset.X;
   layerPos.x := -Offset.X;
   layerPos.y := -Offset.Y;
   layerPos.y := -Offset.Y;
-  SetLength(interruptors,LazPaintInstance.Image.NbLayers);
   SetLength(LayerInfo,LazPaintInstance.Image.NbLayers);
   SetLength(LayerInfo,LazPaintInstance.Image.NbLayers);
   clipping := EmptyRect;
   clipping := EmptyRect;
   for i := LazPaintInstance.Image.NbLayers-1 downto 0 do
   for i := LazPaintInstance.Image.NbLayers-1 downto 0 do
@@ -626,7 +654,7 @@ begin
         end;
         end;
         if UpdateItem <> -1 then clipping := rect(layerPos.X,layerPos.Y,layerPos.X+StackWidth,layerPos.Y+LayerRectHeight);
         if UpdateItem <> -1 then clipping := rect(layerPos.X,layerPos.Y,layerPos.X+StackWidth,layerPos.Y+LayerRectHeight);
 
 
-        interruptors[i] := RectWithSize(layerPos.X+InterruptorWidth div 5,layerpos.Y+(LayerRectHeight-5*InterruptorHeight div 2) div 2,
+        LayerInfo[i].VisibleCheckbox := RectWithSize(layerPos.X+InterruptorWidth div 5,layerpos.Y+(LayerRectHeight-5*InterruptorHeight div 2) div 2,
                                         InterruptorWidth, InterruptorHeight);
                                         InterruptorWidth, InterruptorHeight);
 
 
         if (layerpos.Y+LayerRectHeight > 0) and (layerpos.Y < Bitmap.Height) then
         if (layerpos.Y+LayerRectHeight > 0) and (layerpos.Y < Bitmap.Height) then
@@ -639,9 +667,9 @@ begin
           lColorTrans := lColor;
           lColorTrans := lColor;
           lColorTrans.alpha := lColorTrans.alpha div 3;
           lColorTrans.alpha := lColorTrans.alpha div 3;
 
 
-          Bitmap.Rectangle(interruptors[i],lColor,dmDrawWithTransparency);
+          Bitmap.Rectangle(LayerInfo[i].VisibleCheckbox,lColor,dmDrawWithTransparency);
           if LayerVisible[i] then
           if LayerVisible[i] then
-          with interruptors[i] do
+          with LayerInfo[i].VisibleCheckbox do
           begin
           begin
             Bitmap.DrawPolyLineAntialias(Bitmap.ComputeBezierSpline([
             Bitmap.DrawPolyLineAntialias(Bitmap.ComputeBezierSpline([
 
 
@@ -652,17 +680,17 @@ begin
                   PointF(right-2,top-2))]),lColor,1.5);
                   PointF(right-2,top-2))]),lColor,1.5);
           end;
           end;
 
 
-          rKind := interruptors[i];
-          rKind.Offset(0, InterruptorHeight*3 div 2);
+          LayerInfo[i].KindIcon := LayerInfo[i].VisibleCheckbox;
+          LayerInfo[i].KindIcon.Offset(0, InterruptorHeight*3 div 2);
           if LayerOriginalDefined[i] then
           if LayerOriginalDefined[i] then
           begin
           begin
             if LayerOriginalKnown[i] then
             if LayerOriginalKnown[i] then
-              DrawKind(LayerOriginalClass[i])
+              DrawKind(LayerOriginalClass[i], LayerInfo[i].KindIcon, LayerInfo[i].KindIconHint)
             else
             else
-              DrawKind(nil);
+              DrawKindUnknown(LayerInfo[i].KindIcon, LayerInfo[i].KindIconHint);
           end
           end
           else
           else
-            DrawKind(TBGRALayerImageOriginal);
+            DrawKind(nil, LayerInfo[i].KindIcon, LayerInfo[i].KindIconHint);
 
 
           inc(layerPos.X,InterruptorWidth);
           inc(layerPos.X,InterruptorWidth);
           if movingItemStart and (i= movingItemSourceIndex) then
           if movingItemStart and (i= movingItemSourceIndex) then
@@ -677,7 +705,7 @@ begin
             movingItemStart:= false;
             movingItemStart:= false;
           end;
           end;
 
 
-          LayerInfo[i] := DrawLayerItem(Bitmap,layerPos,i,lSelected);
+          LayerInfo[i].RightPart := DrawLayerItem(Bitmap,layerPos,i,lSelected);
           dec(layerPos.X,InterruptorWidth);
           dec(layerPos.X,InterruptorWidth);
         end;
         end;
       end;
       end;
@@ -699,12 +727,12 @@ begin
       y := movingItemOrigin.Y + movingItemMousePos.Y - movingItemMouseOrigin.Y - Offset.Y;
       y := movingItemOrigin.Y + movingItemMousePos.Y - movingItemMouseOrigin.Y - Offset.Y;
       if y < 0 then
       if y < 0 then
       begin
       begin
-        timerScrollDeltaY := -movingItem.Height div 10;
+        timerScrollDeltaY := -movingItem.Height div 3;
         TimerScroll.Enabled := true;
         TimerScroll.Enabled := true;
       end else
       end else
       if y + movingItem.Height > Bitmap.Height then
       if y + movingItem.Height > Bitmap.Height then
       begin
       begin
-        timerScrollDeltaY := +movingItem.Height div 10;
+        timerScrollDeltaY := +movingItem.Height div 3;
         TimerScroll.Enabled := true;
         TimerScroll.Enabled := true;
       end;
       end;
       Bitmap.PutImage(movingItemOrigin.X + movingItemMousePos.X - movingItemMouseOrigin.X - Offset.X,
       Bitmap.PutImage(movingItemOrigin.X + movingItemMousePos.X - movingItemMouseOrigin.X - Offset.X,
@@ -777,6 +805,17 @@ begin
     LazPaintInstance.ToolManager.ToolPopup(tpmBlendOpBackground);
     LazPaintInstance.ToolManager.ToolPopup(tpmBlendOpBackground);
 end;
 end;
 
 
+procedure TFLayerStack.DoScrollVertically(AAmount: integer);
+var prevY: integer;
+begin
+  prevY := scrollPos.Y;
+  ScrollPos.Y += AAmount;
+  if ScrollPos.Y < 0 then ScrollPos.Y := 0;
+  if ScrollPos.Y > MaxScrollPos.Y then ScrollPos.Y := MaxScrollPos.Y;
+  movingItemMouseOrigin.Y -= ScrollPos.Y-prevY;
+  BGRALayerStack.DiscardBitmap;
+end;
+
 procedure TFLayerStack.ComboBox_BlendOpChange(Sender: TObject);
 procedure TFLayerStack.ComboBox_BlendOpChange(Sender: TObject);
 var blendOp: TBlendOperation;
 var blendOp: TBlendOperation;
   itemStr: string;
   itemStr: string;
@@ -825,8 +864,8 @@ begin
       BGRALayerStack.RedrawBitmap;
       BGRALayerStack.RedrawBitmap;
       exit;
       exit;
     end;
     end;
-    for i := 0 to high(interruptors) do
-      if PtInRect(Point(x,Y),interruptors[i]) then
+    for i := 0 to high(LayerInfo) do
+      if PtInRect(Point(x,Y),LayerInfo[i].VisibleCheckbox) then
       begin
       begin
         if i < LazPaintInstance.Image.NbLayers then
         if i < LazPaintInstance.Image.NbLayers then
         begin
         begin
@@ -838,13 +877,13 @@ begin
         exit;
         exit;
       end;
       end;
     for i := 0 to high(LayerInfo) do
     for i := 0 to high(LayerInfo) do
-      if IsPointInPolygon(LayerInfo[i].PreviewPts,pointF(x,y),true) then
+      if IsPointInPolygon(LayerInfo[i].RightPart.PreviewPts,pointF(x,y),true) then
       begin
       begin
         HandleSelectLayer(i,x,y);
         HandleSelectLayer(i,x,y);
         exit;
         exit;
       end;
       end;
     for i := 0 to high(LayerInfo) do
     for i := 0 to high(LayerInfo) do
-      if PtInRect(Point(x,Y),LayerInfo[i].NameRect) then
+      if PtInRect(Point(x,Y),LayerInfo[i].RightPart.NameRect) then
       begin
       begin
         if i < LazPaintInstance.Image.NbLayers then
         if i < LazPaintInstance.Image.NbLayers then
         begin
         begin
@@ -865,8 +904,8 @@ begin
         exit;
         exit;
       end;
       end;
     for i := 0 to high(LayerInfo) do
     for i := 0 to high(LayerInfo) do
-      if PtInRect(Point(x,Y),LayerInfo[i].OpacityBar) or PtInRect(Point(x+4,Y),LayerInfo[i].OpacityBar) or
-        PtInRect(Point(x-4,Y),LayerInfo[i].OpacityBar) then
+      if PtInRect(Point(x,Y),LayerInfo[i].RightPart.OpacityBar) or PtInRect(Point(x+4,Y),LayerInfo[i].RightPart.OpacityBar) or
+        PtInRect(Point(x-4,Y),LayerInfo[i].RightPart.OpacityBar) then
       begin
       begin
         if i < LazPaintInstance.Image.NbLayers then
         if i < LazPaintInstance.Image.NbLayers then
         begin
         begin
@@ -880,11 +919,13 @@ end;
 
 
 procedure TFLayerStack.BGRALayerStackMouseMove(Sender: TObject;
 procedure TFLayerStack.BGRALayerStackMouseMove(Sender: TObject;
   Shift: TShiftState; X, Y: Integer);
   Shift: TShiftState; X, Y: Integer);
+var
+  i: Integer;
 begin
 begin
   if movingItem <> nil then
   if movingItem <> nil then
   begin
   begin
     movingItemMousePos := point(X,Y);
     movingItemMousePos := point(X,Y);
-    BGRALayerStack.RedrawBitmap;
+    BGRALayerStack.DiscardBitmap;
     exit;
     exit;
   end;
   end;
   if ((VolatileVertScrollBar <> nil) and VolatileVertScrollBar.MouseMove(X,Y)) or
   if ((VolatileVertScrollBar <> nil) and VolatileVertScrollBar.MouseMove(X,Y)) or
@@ -892,7 +933,7 @@ begin
   begin
   begin
     if VolatileHorzScrollBar <> nil then ScrollPos.X := VolatileHorzScrollBar.Position;
     if VolatileHorzScrollBar <> nil then ScrollPos.X := VolatileHorzScrollBar.Position;
     if VolatileVertScrollBar <> nil then ScrollPos.Y := VolatileVertScrollBar.Position;
     if VolatileVertScrollBar <> nil then ScrollPos.Y := VolatileVertScrollBar.Position;
-    BGRALayerStack.RedrawBitmap;
+    BGRALayerStack.DiscardBitmap;
     exit;
     exit;
   end;
   end;
   if changingLayerOpacity <> -1 then
   if changingLayerOpacity <> -1 then
@@ -900,6 +941,14 @@ begin
     HandleChangeLayerOpacity(X,Y);
     HandleChangeLayerOpacity(X,Y);
     exit;
     exit;
   end;
   end;
+  for i := 0 to high(LayerInfo) do
+    if LayerInfo[i].KindIcon.Contains(Point(X,Y)) then
+    begin
+      BGRALayerStack.Hint := LayerInfo[i].KindIconHint;
+      BGRALayerStack.ShowHint:= true;
+      exit;
+    end;
+  BGRALayerStack.ShowHint:= false;
 end;
 end;
 
 
 procedure TFLayerStack.BGRALayerStackMouseUp(Sender: TObject;
 procedure TFLayerStack.BGRALayerStackMouseUp(Sender: TObject;
@@ -938,6 +987,13 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TFLayerStack.BGRALayerStackMouseWheel(Sender: TObject;
+  Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
+  var Handled: Boolean);
+begin
+  DoScrollVertically(round(-WheelDelta*ZoomFactor*50/120));
+end;
+
 {$R *.lfm}
 {$R *.lfm}
 
 
 end.
 end.

+ 14 - 3
lazpaint/umenu.pas

@@ -5,7 +5,8 @@ unit UMenu;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, ActnList, Forms, Menus, UTool, LCLType, ExtCtrls, UConfig;
+  Classes, SysUtils, ActnList, Forms, Menus, UTool, LCLType, ExtCtrls, UConfig,
+  Controls;
 
 
 type
 type
 
 
@@ -19,6 +20,7 @@ type
     FToolbars: array of TPanel;
     FToolbars: array of TPanel;
     FToolbarsHeight : integer;
     FToolbarsHeight : integer;
     FToolbarBackground: TPanel;
     FToolbarBackground: TPanel;
+    FImageList: TImageList;
   protected
   protected
     procedure AddMenus(AMenu: TMenuItem; AActionList: TActionList; AActionsCommaText: string; AIndex: integer = -1); overload;
     procedure AddMenus(AMenu: TMenuItem; AActionList: TActionList; AActionsCommaText: string; AIndex: integer = -1); overload;
     procedure AddMenus(AMenuName: string; AActionsCommaText: string); overload;
     procedure AddMenus(AMenuName: string; AActionsCommaText: string); overload;
@@ -33,12 +35,13 @@ type
     procedure ArrangeToolbars(ClientWidth: integer);
     procedure ArrangeToolbars(ClientWidth: integer);
     procedure RepaintToolbar;
     procedure RepaintToolbar;
     property ToolbarsHeight: integer read FToolbarsHeight;
     property ToolbarsHeight: integer read FToolbarsHeight;
+    property ImageList: TImageList read FImageList write FImageList;
   end;
   end;
 
 
 implementation
 implementation
 
 
 uses UResourceStrings, BGRAUTF8, LazPaintType, LCScaleDPI, ComCtrls, Graphics,
 uses UResourceStrings, BGRAUTF8, LazPaintType, LCScaleDPI, ComCtrls, Graphics,
-  Spin, StdCtrls, BGRAText, Controls;
+  Spin, StdCtrls, BGRAText;
 
 
 { TMainFormMenu }
 { TMainFormMenu }
 
 
@@ -216,7 +219,7 @@ begin
   AddMenus('MenuFilter', 'MenuRadialBlur,FilterBlurMotion,FilterBlurCustom,FilterPixelate,-,FilterSharpen,FilterSmooth,FilterNoise,FilterMedian,FilterClearType,FilterClearTypeInverse,FilterFunction,-,FilterContour,FilterEmboss,FilterPhong,-,FilterSphere,FilterTwirl,FilterCylinder');
   AddMenus('MenuFilter', 'MenuRadialBlur,FilterBlurMotion,FilterBlurCustom,FilterPixelate,-,FilterSharpen,FilterSmooth,FilterNoise,FilterMedian,FilterClearType,FilterClearTypeInverse,FilterFunction,-,FilterContour,FilterEmboss,FilterPhong,-,FilterSphere,FilterTwirl,FilterCylinder');
   AddMenus('MenuRadialBlur',  'FilterBlurBox,FilterBlurFast,FilterBlurRadial,FilterBlurCorona,FilterBlurDisk');
   AddMenus('MenuRadialBlur',  'FilterBlurBox,FilterBlurFast,FilterBlurRadial,FilterBlurCorona,FilterBlurDisk');
   AddMenus('MenuColors', 'ColorCurves,ColorPosterize,ColorColorize,ColorShiftColors,FilterComplementaryColor,ColorIntensity,-,ColorLightness,FilterNegative,FilterLinearNegative,FilterNormalize,FilterGrayscale');
   AddMenus('MenuColors', 'ColorCurves,ColorPosterize,ColorColorize,ColorShiftColors,FilterComplementaryColor,ColorIntensity,-,ColorLightness,FilterNegative,FilterLinearNegative,FilterNormalize,FilterGrayscale');
-  AddMenus('MenuTool',   'ToolHand,ToolHotSpot,ToolColorPicker,-,ToolPen,ToolBrush,ToolEraser,-,ToolRect,ToolEllipse,ToolPolygon,ToolSpline,-,ToolFloodFill,ToolGradient,ToolPhong,-,ToolText,ToolDeformation,ToolTextureMapping,ToolClone');
+  AddMenus('MenuTool',   'ToolHand,ToolHotSpot,ToolColorPicker,-,ToolPen,ToolBrush,ToolEraser,ToolFloodFill,ToolClone,-,ToolRect,ToolEllipse,ToolPolygon,ToolSpline,ToolGradient,ToolPhong,ToolText,-,ToolDeformation,ToolTextureMapping');
   AddMenus('MenuRender', 'RenderPerlinNoise,RenderCyclicPerlinNoise,-,RenderWater,RenderCustomWater,RenderSnowPrint,RenderWood,RenderWoodVertical,RenderMetalFloor,RenderPlastik,RenderStone,RenderRoundStone,RenderMarble,RenderCamouflage,-,RenderClouds,FilterRain');
   AddMenus('MenuRender', 'RenderPerlinNoise,RenderCyclicPerlinNoise,-,RenderWater,RenderCustomWater,RenderSnowPrint,RenderWood,RenderWoodVertical,RenderMetalFloor,RenderPlastik,RenderStone,RenderRoundStone,RenderMarble,RenderCamouflage,-,RenderClouds,FilterRain');
   AddMenus('MenuHelp',   'HelpIndex,-,HelpAbout');
   AddMenus('MenuHelp',   'HelpIndex,-,HelpAbout');
   for i := 0 to high(FMainMenus) do
   for i := 0 to high(FMainMenus) do
@@ -224,6 +227,9 @@ begin
 
 
   ApplyShortcuts;
   ApplyShortcuts;
 
 
+  if Assigned(FImageList) then
+    FActionList.Images := FImageList;
+
   tbHeightOrig := DoScaleY(26,OriginalDPI);
   tbHeightOrig := DoScaleY(26,OriginalDPI);
   tbHeight := tbHeightOrig;
   tbHeight := tbHeightOrig;
   for i := 0 to high(FToolbars) do
   for i := 0 to high(FToolbars) do
@@ -235,7 +241,12 @@ begin
     for j := 0 to ControlCount-1 do
     for j := 0 to ControlCount-1 do
     begin
     begin
       if Controls[j] is TToolBar then
       if Controls[j] is TToolBar then
+      begin
         Controls[j].Color := clBtnFace;
         Controls[j].Color := clBtnFace;
+        if assigned(FImageList) then TToolbar(Controls[j]).Images := FImageList;
+        TToolbar(Controls[j]).ButtonWidth := TToolbar(Controls[j]).Images.Width+ScaleX(6, 96);
+        TToolbar(Controls[j]).ButtonHeight := TToolbar(Controls[j]).Images.Height+ScaleY(6, 96);
+      end;
       if Controls[j] is TSpinEdit then
       if Controls[j] is TSpinEdit then
       begin
       begin
         if Controls[j].Top + Controls[j].Height+4 > tbHeight then
         if Controls[j].Top + Controls[j].Height+4 > tbHeight then

+ 6 - 6
lazpaint/uphongfilter.pas

@@ -51,12 +51,12 @@ type
     FInitializing: boolean;
     FInitializing: boolean;
     FCenter: TPointF;
     FCenter: TPointF;
     FHeightMap: TBGRABitmap;
     FHeightMap: TBGRABitmap;
-    function GetCurrentLightPos: TPoint;
+    function GetCurrentLightPos: TPointF;
     procedure PreviewNeeded;
     procedure PreviewNeeded;
     function ComputeFilteredLayer: TBGRABitmap;
     function ComputeFilteredLayer: TBGRABitmap;
   public
   public
     FilterConnector: TFilterConnector;
     FilterConnector: TFilterConnector;
-    property CurrentLightPos: TPoint read GetCurrentLightPos;
+    property CurrentLightPos: TPointF read GetCurrentLightPos;
   end;
   end;
 
 
 function ShowPhongFilterDlg(AFilterConnector: TObject):boolean;
 function ShowPhongFilterDlg(AFilterConnector: TObject):boolean;
@@ -196,10 +196,10 @@ begin
   Button_OK.Enabled := false;
   Button_OK.Enabled := false;
 end;
 end;
 
 
-function TFPhongFilter.GetCurrentLightPos: TPoint;
+function TFPhongFilter.GetCurrentLightPos: TPointF;
 begin
 begin
-  result := Point(round(FCenter.X*FilterConnector.ActiveLayer.Width),
-    round(FCenter.Y*FilterConnector.ActiveLayer.Height));
+  result := PointF(FCenter.X*FilterConnector.ActiveLayer.Width,
+    FCenter.Y*FilterConnector.ActiveLayer.Height);
 end;
 end;
 
 
 procedure ScanLineMapLightness(psrc,pdest: PBGRAPixel; count: integer);
 procedure ScanLineMapLightness(psrc,pdest: PBGRAPixel; count: integer);
@@ -293,7 +293,7 @@ begin
   shader := TPhongShading.Create;
   shader := TPhongShading.Create;
   shader.AmbientFactor := 0.5;
   shader.AmbientFactor := 0.5;
   shader.NegativeDiffusionFactor := 0.15;
   shader.NegativeDiffusionFactor := 0.15;
-  shader.LightPosition := CurrentLightPos;
+  shader.LightPositionF := CurrentLightPos;
   shader.LightPositionZ := FilterConnector.LazPaintInstance.ToolManager.ToolLightAltitude;
   shader.LightPositionZ := FilterConnector.LazPaintInstance.ToolManager.ToolLightAltitude;
   if FHeightMap = nil then
   if FHeightMap = nil then
   begin
   begin

+ 6 - 0
lazpaint/uresourcestrings.pas

@@ -30,6 +30,11 @@ resourcestring
   rsEnterLayerName='Enter layer name:';
   rsEnterLayerName='Enter layer name:';
   rsFileExtensionNotSupported='This file extension is not supported.';
   rsFileExtensionNotSupported='This file extension is not supported.';
   rsFileFormatNotRecognized='The file format has not been recognized.';
   rsFileFormatNotRecognized='The file format has not been recognized.';
+  rsErrorLoadingOriginal='Error while loading original however layer can be rasterized.';
+  rsRasterLayer = 'Raster layer';
+  rsTransformedRasterLayer = 'Transformed raster layer';
+  rsVectorialLayer = 'Vectorial layer';
+  rsUnknownOriginal = 'Unknown original';
   rsFileName = 'Filename';
   rsFileName = 'Filename';
   rsFileSize = 'Size';
   rsFileSize = 'Size';
   rsFileType = 'Type';
   rsFileType = 'Type';
@@ -167,6 +172,7 @@ resourcestring
   rsMoreThanOneFile='You are trying to open more than one file. How would you like these files to be opened?';
   rsMoreThanOneFile='You are trying to open more than one file. How would you like these files to be opened?';
   rsOpenFilesAsLayers='Open files as layers in a single image';
   rsOpenFilesAsLayers='Open files as layers in a single image';
   rsTooManyLayers='Too many layers';
   rsTooManyLayers='Too many layers';
+  rsTooManyShapesInLayer='Too many shapes in layer';
   rsAddToImageList='Add files to the image processing list';
   rsAddToImageList='Add files to the image processing list';
   rsOpenFirstFileOnly='Open the first file only';
   rsOpenFirstFileOnly='Open the first file only';
   rsLayeredImage = 'Layered image';
   rsLayeredImage = 'Layered image';

+ 55 - 10
lazpaint/ustatetype.pas

@@ -5,7 +5,8 @@ unit UStateType;
 interface
 interface
 
 
 uses
 uses
-  Types, Classes, SysUtils, BGRABitmap, BGRABitmapTypes, BGRALayers, fgl;
+  Types, Classes, SysUtils, BGRABitmap, BGRABitmapTypes, BGRALayers,
+  BGRALayerOriginal, fgl;
 
 
 const MinSizeToCompress = 512; //set to 1 if you want always compression
 const MinSizeToCompress = 512; //set to 1 if you want always compression
 const MinSerializedSize = 16384;
 const MinSerializedSize = 16384;
@@ -120,6 +121,8 @@ type
     procedure Init(Image1,Image2: TBGRABitmap; {%H-}AChangeRect: TRect); virtual;
     procedure Init(Image1,Image2: TBGRABitmap; {%H-}AChangeRect: TRect); virtual;
     function SerializeCompressedData: boolean;
     function SerializeCompressedData: boolean;
     procedure UnserializeCompressedData;
     procedure UnserializeCompressedData;
+  protected
+    function CreateNew(AWidth,AHeight: integer): TBGRABitmap; virtual; abstract;
   public
   public
     SizeBefore, SizeAfter: TSize;
     SizeBefore, SizeAfter: TSize;
     constructor Create(Image1,Image2: TBGRABitmap; AChangeRect: TRect); overload;
     constructor Create(Image1,Image2: TBGRABitmap; AChangeRect: TRect); overload;
@@ -145,6 +148,8 @@ type
     function GetIsIdentity: boolean; override;
     function GetIsIdentity: boolean; override;
     procedure Decompress;
     procedure Decompress;
     procedure Init(Image1,Image2: TBGRABitmap; AChangeRect: TRect); override;
     procedure Init(Image1,Image2: TBGRABitmap; AChangeRect: TRect); override;
+  protected
+    function CreateNew(AWidth, AHeight: integer): TBGRABitmap; override;
   public
   public
     procedure ApplyInPlace(ADest: TBGRABitmap; {%H-}AReverse: boolean); override;
     procedure ApplyInPlace(ADest: TBGRABitmap; {%H-}AReverse: boolean); override;
     function Compress: boolean; override;
     function Compress: boolean; override;
@@ -166,6 +171,8 @@ type
     function GetIsIdentity: boolean; override;
     function GetIsIdentity: boolean; override;
     procedure Decompress;
     procedure Decompress;
     procedure Init(Image1,Image2: TBGRABitmap; AChangeRect: TRect); override;
     procedure Init(Image1,Image2: TBGRABitmap; AChangeRect: TRect); override;
+  protected
+    function CreateNew(AWidth, AHeight: integer): TBGRABitmap; override;
   public
   public
     procedure ApplyInPlace(ADest: TBGRABitmap; {%H-}AReverse: boolean); override;
     procedure ApplyInPlace(ADest: TBGRABitmap; {%H-}AReverse: boolean); override;
     function Compress: boolean; override;
     function Compress: boolean; override;
@@ -193,12 +200,14 @@ type
     FInfo: TLayerInfo;
     FInfo: TLayerInfo;
     FIndex: integer;
     FIndex: integer;
     FOriginalData: TMemoryStream;
     FOriginalData: TMemoryStream;
-    FOriginalKnown: boolean;
+    FOriginalBitmapStored: boolean;
     FOriginalRenderStatus: TOriginalRenderStatus;
     FOriginalRenderStatus: TOriginalRenderStatus;
     FOriginalMatrix: TAffineMatrix;
     FOriginalMatrix: TAffineMatrix;
     FOriginalDraft: boolean;
     FOriginalDraft: boolean;
   public
   public
     constructor Create(ALayeredImage: TBGRALayeredBitmap; AIndex: integer);
     constructor Create(ALayeredImage: TBGRALayeredBitmap; AIndex: integer);
+    constructor Create(ALayeredImage: TBGRALayeredBitmap; AIndex: integer;
+                       AAlwaysStoreBitmap: boolean);
     procedure Restore(ALayeredImage: TBGRALayeredBitmap);
     procedure Restore(ALayeredImage: TBGRALayeredBitmap);
     procedure Replace(ALayeredImage: TBGRALayeredBitmap);
     procedure Replace(ALayeredImage: TBGRALayeredBitmap);
     property LayerIndex: integer read FIndex;
     property LayerIndex: integer read FIndex;
@@ -322,7 +331,12 @@ var
   DestSize: TSize;
   DestSize: TSize;
 begin
 begin
   if (self = nil) or IsIdentity then
   if (self = nil) or IsIdentity then
-    result := ASource.Duplicate as TBGRABitmap
+  begin
+    if ASource = nil then
+      result := nil
+    else
+      result := ASource.Duplicate as TBGRABitmap
+  end
   else
   else
   begin
   begin
     if AReverse then DestSize := SizeBefore else
     if AReverse then DestSize := SizeBefore else
@@ -332,7 +346,7 @@ begin
       result := nil
       result := nil
     else
     else
     begin
     begin
-      result := TBGRABitmap.Create(Destsize.cx,Destsize.cy);
+      result := CreateNew(Destsize.cx,Destsize.cy);
       if ASource <> nil then
       if ASource <> nil then
         result.PutImage(0,0,ASource,dmSet);
         result.PutImage(0,0,ASource,dmSet);
       ApplyInPlace(result, AReverse);
       ApplyInPlace(result, AReverse);
@@ -345,8 +359,9 @@ function TCustomImageDiff.ApplyCanCreateNew(ASource: TBGRABitmap;
 begin
 begin
   if (self = nil) or IsIdentity then exit(ASource); //keep
   if (self = nil) or IsIdentity then exit(ASource); //keep
 
 
-  if (SizeAfter.cx <> SizeBefore.cx) or
-     (SizeAfter.cy <> SizeBefore.cy) then
+  if (ASource = nil) or
+     ((SizeAfter.cx <> SizeBefore.cx) or
+     (SizeAfter.cy <> SizeBefore.cy)) then
      exit(ApplyInNew(ASource, AReverse))
      exit(ApplyInNew(ASource, AReverse))
   else
   else
   begin
   begin
@@ -581,6 +596,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TGrayscaleImageDiff.CreateNew(AWidth, AHeight: integer): TBGRABitmap;
+begin
+  result := TBGRABitmap.Create(AWidth,AHeight, BGRABlack);
+end;
+
 procedure TGrayscaleImageDiff.ApplyInPlace(ADest: TBGRABitmap; AReverse: boolean);
 procedure TGrayscaleImageDiff.ApplyInPlace(ADest: TBGRABitmap; AReverse: boolean);
 var
 var
   pdest: PBGRAPixel;
   pdest: PBGRAPixel;
@@ -884,6 +904,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TImageDiff.CreateNew(AWidth, AHeight: integer): TBGRABitmap;
+begin
+  result := TBGRABitmap.Create(AWidth,AHeight);
+end;
+
 procedure TImageDiff.ApplyInPlace(ADest: TBGRABitmap; AReverse: boolean);
 procedure TImageDiff.ApplyInPlace(ADest: TBGRABitmap; AReverse: boolean);
 var
 var
   pdest: PDWord;
   pdest: PDWord;
@@ -1001,15 +1026,35 @@ end;
 
 
 constructor TStoredLayer.Create(ALayeredImage: TBGRALayeredBitmap;
 constructor TStoredLayer.Create(ALayeredImage: TBGRALayeredBitmap;
   AIndex: integer);
   AIndex: integer);
+var
+  {%H-}orig: TBGRALayerCustomOriginal;
+  alwaysStoreBitmap: Boolean;
+begin
+  alwaysStoreBitmap := false;
+  if (ALayeredImage.LayerOriginalGuid[AIndex]<>GUID_NULL) and
+    ALayeredImage.LayerOriginalKnown[AIndex] then
+  begin
+    try
+      orig := ALayeredImage.LayerOriginal[AIndex];
+    except
+      on ex:exception do
+        alwaysStoreBitmap:= true;
+    end;
+  end;
+  Create(ALayeredImage, AIndex, alwaysStoreBitmap);
+end;
+
+constructor TStoredLayer.Create(ALayeredImage: TBGRALayeredBitmap;
+  AIndex: integer; AAlwaysStoreBitmap: boolean);
 begin
 begin
   FIndex := AIndex;
   FIndex := AIndex;
   FInfo := GetLayerInfo(ALayeredImage, AIndex);
   FInfo := GetLayerInfo(ALayeredImage, AIndex);
   if ALayeredImage.LayerOriginalGuid[AIndex]<>GUID_NULL then
   if ALayeredImage.LayerOriginalGuid[AIndex]<>GUID_NULL then
   begin
   begin
-    FOriginalKnown := ALayeredImage.LayerOriginalKnown[AIndex];
+    FOriginalBitmapStored := AAlwaysStoreBitmap or not ALayeredImage.LayerOriginalKnown[AIndex];
     FOriginalRenderStatus:= ALayeredImage.LayerOriginalRenderStatus[AIndex];
     FOriginalRenderStatus:= ALayeredImage.LayerOriginalRenderStatus[AIndex];
 
 
-    if FOriginalKnown then
+    if not FOriginalBitmapStored then
       inherited Create(nil)
       inherited Create(nil)
     else
     else
       inherited Create(ALayeredImage.LayerBitmap[AIndex]);
       inherited Create(ALayeredImage.LayerBitmap[AIndex]);
@@ -1034,7 +1079,7 @@ begin
     FOriginalData.Position:= 0;
     FOriginalData.Position:= 0;
     idxOrig := ALayeredImage.AddOriginalFromStream(FOriginalData, true);
     idxOrig := ALayeredImage.AddOriginalFromStream(FOriginalData, true);
 
 
-    if FOriginalKnown then
+    if not FOriginalBitmapStored then
     begin
     begin
       tempIdx := ALayeredImage.AddLayerFromOriginal(ALayeredImage.Original[idxOrig].Guid, FOriginalMatrix);
       tempIdx := ALayeredImage.AddLayerFromOriginal(ALayeredImage.Original[idxOrig].Guid, FOriginalMatrix);
       ALayeredImage.RenderLayerFromOriginal(tempIdx, FOriginalDraft);
       ALayeredImage.RenderLayerFromOriginal(tempIdx, FOriginalDraft);
@@ -1060,7 +1105,7 @@ begin
   begin
   begin
     FOriginalData.Position:= 0;
     FOriginalData.Position:= 0;
     idxOrig := ALayeredImage.AddOriginalFromStream(FOriginalData, true);
     idxOrig := ALayeredImage.AddOriginalFromStream(FOriginalData, true);
-    if FOriginalKnown then
+    if not FOriginalBitmapStored then
     begin
     begin
       ALayeredImage.LayerOriginalGuid[FIndex] := ALayeredImage.OriginalGuid[idxOrig];
       ALayeredImage.LayerOriginalGuid[FIndex] := ALayeredImage.OriginalGuid[idxOrig];
       ALayeredImage.LayerOriginalMatrix[FIndex] := FOriginalMatrix;
       ALayeredImage.LayerOriginalMatrix[FIndex] := FOriginalMatrix;

+ 54 - 59
lazpaint/utool.pas

@@ -46,12 +46,12 @@ type
   protected
   protected
     FManager: TToolManager;
     FManager: TToolManager;
     FLastToolDrawingLayer: TBGRABitmap;
     FLastToolDrawingLayer: TBGRABitmap;
-    FBackupDrawingLayerBounds: TRect;
-    FBackupDrawingLayer: TBGRABitmap;
+    FValidating, FCanceling: boolean;
     function GetAction: TLayerAction; virtual;
     function GetAction: TLayerAction; virtual;
     function GetIdleAction: TLayerAction; virtual;
     function GetIdleAction: TLayerAction; virtual;
     function GetIsSelectingTool: boolean; virtual; abstract;
     function GetIsSelectingTool: boolean; virtual; abstract;
     function FixSelectionTransform: boolean; virtual;
     function FixSelectionTransform: boolean; virtual;
+    function FixLayerOffset: boolean; virtual;
     function DoToolDown(toolDest: TBGRABitmap; pt: TPoint; ptF: TPointF; rightBtn: boolean): TRect; virtual;
     function DoToolDown(toolDest: TBGRABitmap; pt: TPoint; ptF: TPointF; rightBtn: boolean): TRect; virtual;
     function DoToolMove(toolDest: TBGRABitmap; pt: TPoint; ptF: TPointF): TRect; virtual;
     function DoToolMove(toolDest: TBGRABitmap; pt: TPoint; ptF: TPointF): TRect; virtual;
     procedure DoToolMoveAfter(pt: TPoint; ptF: TPointF); virtual;
     procedure DoToolMoveAfter(pt: TPoint; ptF: TPointF); virtual;
@@ -95,6 +95,8 @@ type
     property LayerOffset : TPoint read GetLayerOffset;
     property LayerOffset : TPoint read GetLayerOffset;
     property LastToolDrawingLayer: TBGRABitmap read FLastToolDrawingLayer;
     property LastToolDrawingLayer: TBGRABitmap read FLastToolDrawingLayer;
     property StatusText: string read GetStatusText;
     property StatusText: string read GetStatusText;
+    property Validating: boolean read FValidating;
+    property Canceling: boolean read FCanceling;
   end;
   end;
 
 
   { TReadonlyTool }
   { TReadonlyTool }
@@ -185,7 +187,6 @@ type
     ToolArrowSize: TPointF;
     ToolArrowSize: TPointF;
     ToolJoinStyle: TPenJoinStyle;
     ToolJoinStyle: TPenJoinStyle;
     ToolSplineStyle: TSplineStyle;
     ToolSplineStyle: TSplineStyle;
-    ToolSplineEasyBezier: boolean;
     ToolPenStyle: TPenStyle;
     ToolPenStyle: TPenStyle;
     ToolPerspectiveRepeat,ToolPerspectiveTwoPlanes: boolean;
     ToolPerspectiveRepeat,ToolPerspectiveTwoPlanes: boolean;
     ToolDeformationGridMoveWithoutDeformation: boolean;
     ToolDeformationGridMoveWithoutDeformation: boolean;
@@ -193,7 +194,7 @@ type
     ToolTextFont: TFont;
     ToolTextFont: TFont;
     ToolTextBlur: single;
     ToolTextBlur: single;
     ToolTextShadowOffset: TPoint;
     ToolTextShadowOffset: TPoint;
-    ToolLightPosition: TPoint;
+    ToolLightPosition: TPointF;
     ToolLightAltitude: integer;
     ToolLightAltitude: integer;
     ToolShapeAltitude: integer;
     ToolShapeAltitude: integer;
     ToolShapeBorderSize: integer;
     ToolShapeBorderSize: integer;
@@ -411,27 +412,13 @@ begin
 end;
 end;
 
 
 function TGenericTool.GetAction: TLayerAction;
 function TGenericTool.GetAction: TLayerAction;
-var
-  layer: TBGRABitmap;
 begin
 begin
   if not Assigned(FAction) then
   if not Assigned(FAction) then
   begin
   begin
-    FAction := Manager.Image.CreateAction(not IsSelectingTool And Manager.Image.SelectionMaskEmpty);
+    FAction := Manager.Image.CreateAction(not IsSelectingTool And Manager.Image.SelectionMaskEmpty,
+                                          IsSelectingTool or not Manager.Image.SelectionMaskEmpty);
     FAction.OnTryStop := @OnTryStop;
     FAction.OnTryStop := @OnTryStop;
     FAction.ChangeBoundsNotified:= true;
     FAction.ChangeBoundsNotified:= true;
-    if IsSelectingTool or not Manager.Image.SelectionMaskEmpty then
-    begin
-      FAction.ApplySelectionTransform;
-      layer := GetToolDrawingLayer;
-      if Assigned(layer) then
-      begin
-        if layer = Manager.Image.SelectionMaskReadonly then
-          FBackupDrawingLayerBounds:= layer.GetImageBounds(cGreen)
-        else
-          FBackupDrawingLayerBounds:= layer.GetImageBounds;
-        FBackupDrawingLayer := layer.GetPart(FBackupDrawingLayerBounds) as TBGRABitmap;
-      end;
-    end;
   end;
   end;
   result := FAction;
   result := FAction;
 end;
 end;
@@ -452,6 +439,11 @@ begin
   result:= true;
   result:= true;
 end;
 end;
 
 
+function TGenericTool.FixLayerOffset: boolean;
+begin
+  result:= true;
+end;
+
 function TGenericTool.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
 function TGenericTool.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
   ptF: TPointF; rightBtn: boolean): TRect;
   ptF: TPointF; rightBtn: boolean): TRect;
 begin
 begin
@@ -485,7 +477,6 @@ end;
 destructor TGenericTool.Destroy;
 destructor TGenericTool.Destroy;
 begin
 begin
   FAction.Free;
   FAction.Free;
-  FBackupDrawingLayer.Free;
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
@@ -493,26 +484,41 @@ procedure TGenericTool.ValidateAction;
 begin
 begin
   if Assigned(FAction) then
   if Assigned(FAction) then
   begin
   begin
+    FValidating := true;
     FAction.Validate;
     FAction.Validate;
+    FValidating := false;
     FreeAndNil(FAction);
     FreeAndNil(FAction);
-    FreeAndNil(FBackupDrawingLayer);
   end;
   end;
 end;
 end;
 
 
 procedure TGenericTool.ValidateActionPartially;
 procedure TGenericTool.ValidateActionPartially;
 begin
 begin
-  if Assigned(FAction) then FAction.PartialValidate;
+  if Assigned(FAction) then
+  begin
+    FValidating := true;
+    FAction.PartialValidate;
+    FValidating := false;
+  end;
 end;
 end;
 
 
 procedure TGenericTool.CancelAction;
 procedure TGenericTool.CancelAction;
 begin
 begin
   if FAction <> nil then
   if FAction <> nil then
+  begin
+    FCanceling := true;
     FreeAndNil(FAction);
     FreeAndNil(FAction);
+    FCanceling := false;
+  end;
 end;
 end;
 
 
 procedure TGenericTool.CancelActionPartially;
 procedure TGenericTool.CancelActionPartially;
 begin
 begin
-  if Assigned(FAction) then FAction.PartialCancel;
+  if Assigned(FAction) then
+  begin
+    FCanceling := true;
+    FAction.PartialCancel;
+    FCanceling := false;
+  end;
 end;
 end;
 
 
 procedure TGenericTool.BeforeGridSizeChange;
 procedure TGenericTool.BeforeGridSizeChange;
@@ -574,8 +580,11 @@ begin
   ptF := PointF(x,y);
   ptF := PointF(x,y);
   if toolDest = Manager.Image.CurrentLayerReadOnly then
   if toolDest = Manager.Image.CurrentLayerReadOnly then
   begin
   begin
-    ptF.x -= LayerOffset.x;
-    ptF.y -= LayerOffset.y;
+    if FixLayerOffset then
+    begin
+      ptF.x -= LayerOffset.x;
+      ptF.y -= LayerOffset.y;
+    end;
   end else if FixSelectionTransform and ((toolDest = Manager.Image.SelectionMaskReadonly)
   end else if FixSelectionTransform and ((toolDest = Manager.Image.SelectionMaskReadonly)
     or (toolDest = Manager.Image.SelectionLayerReadonly)) and
     or (toolDest = Manager.Image.SelectionLayerReadonly)) and
       IsAffineMatrixInversible(Manager.Image.SelectionTransform) then
       IsAffineMatrixInversible(Manager.Image.SelectionTransform) then
@@ -599,8 +608,11 @@ begin
   toolDest.PenStyle := Manager.ToolPenStyle;
   toolDest.PenStyle := Manager.ToolPenStyle;
   if toolDest = Manager.Image.CurrentLayerReadOnly then
   if toolDest = Manager.Image.CurrentLayerReadOnly then
   begin
   begin
-    ptF.x -= LayerOffset.x;
-    ptF.y -= LayerOffset.y;
+    if FixLayerOffset then
+    begin
+      ptF.x -= LayerOffset.x;
+      ptF.y -= LayerOffset.y;
+    end;
   end else if FixSelectionTransform and ((toolDest = Manager.Image.SelectionMaskReadonly)
   end else if FixSelectionTransform and ((toolDest = Manager.Image.SelectionMaskReadonly)
     or (toolDest = Manager.Image.SelectionLayerReadonly)) and
     or (toolDest = Manager.Image.SelectionLayerReadonly)) and
       IsAffineMatrixInversible(Manager.Image.SelectionTransform) then
       IsAffineMatrixInversible(Manager.Image.SelectionTransform) then
@@ -614,8 +626,11 @@ var
   pt: TPoint;
   pt: TPoint;
   ptF: TPointF;
   ptF: TPointF;
 begin
 begin
-  x -= LayerOffset.x;
-  y -= LayerOffset.y;
+  if FixLayerOffset then
+  begin
+    x -= LayerOffset.x;
+    y -= LayerOffset.y;
+  end;
   pt := Point(round(x),round(y));
   pt := Point(round(x),round(y));
   ptF := PointF(x,y);
   ptF := PointF(x,y);
   DoToolMoveAfter(pt,ptF);
   DoToolMoveAfter(pt,ptF);
@@ -685,30 +700,13 @@ begin
 end;
 end;
 
 
 procedure TGenericTool.RestoreBackupDrawingLayer;
 procedure TGenericTool.RestoreBackupDrawingLayer;
-var
-  layer: TBGRABitmap;
 begin
 begin
   if Assigned(FAction) then
   if Assigned(FAction) then
   begin
   begin
-    if Assigned(FBackupDrawingLayer) then
-    begin
-      layer:= GetToolDrawingLayer;
-      if Assigned(layer) then
-      begin
-        if layer = Manager.Image.SelectionMaskReadonly then
-          layer.Fill(BGRABlack)
-        else
-          layer.FillTransparent;
-        layer.PutImage(FBackupDrawingLayerBounds.Left,FBackupDrawingLayerBounds.Top, FBackupDrawingLayer, dmSet);
-        Action.NotifyChange(layer, rect(0,0,layer.Width,layer.Height));
-      end;
-    end else
-    begin
-      if IsSelectingTool then
-        Action.RestoreSelectionMask
-      else
-        Action.RestoreDrawingLayer;
-    end;
+    if IsSelectingTool then
+      Action.RestoreSelectionMask
+    else
+      Action.RestoreDrawingLayer;
   end;
   end;
 end;
 end;
 
 
@@ -918,13 +916,12 @@ begin
   ToolFloodFillOptionProgressive := true;
   ToolFloodFillOptionProgressive := true;
   ToolLineCap := pecRound;
   ToolLineCap := pecRound;
   ToolJoinStyle := pjsRound;
   ToolJoinStyle := pjsRound;
-  ToolArrowStart := 'None';
-  ToolArrowEnd := 'None';
+  ToolArrowStart := 'none';
+  ToolArrowEnd := 'none';
   ToolArrowSize := PointF(2,2);
   ToolArrowSize := PointF(2,2);
   ToolPenStyle := psSolid;
   ToolPenStyle := psSolid;
   ToolEraserAlpha := 255;
   ToolEraserAlpha := 255;
-  ToolSplineStyle := ssRoundOutside;
-  ToolSplineEasyBezier := true;
+  ToolSplineStyle := ssEasyBezier;
   ToolTextOutline := False;
   ToolTextOutline := False;
   ToolTextShadow := false;
   ToolTextShadow := false;
   ToolTextFont := TFont.Create;
   ToolTextFont := TFont.Create;
@@ -935,7 +932,7 @@ begin
   ToolTextBlur := 4;
   ToolTextBlur := 4;
   ToolTextShadowOffset := Point(5,5);
   ToolTextShadowOffset := Point(5,5);
   ToolTextOutlineWidth := 2;
   ToolTextOutlineWidth := 2;
-  ToolLightPosition := Point(0,0);
+  ToolLightPosition := PointF(0,0);
   ToolLightAltitude := 100;
   ToolLightAltitude := 100;
   ToolShapeAltitude := 50;
   ToolShapeAltitude := 50;
   ToolShapeBorderSize := 20;
   ToolShapeBorderSize := 20;
@@ -1299,7 +1296,6 @@ function TToolManager.ToolDown(X, Y: single; ARightBtn: boolean;
 var changed: TRect;
 var changed: TRect;
 begin
 begin
   SetPressure(APressure);
   SetPressure(APressure);
-  Image.DraftOriginal := true;
   if ToolCanBeUsed then
   if ToolCanBeUsed then
     changed := currentTool.ToolDown(X,Y,ARightBtn)
     changed := currentTool.ToolDown(X,Y,ARightBtn)
   else
   else
@@ -1425,7 +1421,6 @@ end;
 function TToolManager.ToolUp: boolean;
 function TToolManager.ToolUp: boolean;
 var changed: TRect;
 var changed: TRect;
 begin
 begin
-  Image.DraftOriginal := false;
   if ToolCanBeUsed then
   if ToolCanBeUsed then
     changed := currentTool.ToolUp
     changed := currentTool.ToolUp
   else
   else
@@ -1514,7 +1509,7 @@ end;
 
 
 function TToolManager.GetRenderBounds(VirtualScreenWidth, VirtualScreenHeight: integer): TRect;
 function TToolManager.GetRenderBounds(VirtualScreenWidth, VirtualScreenHeight: integer): TRect;
 begin
 begin
-  if ToolCanBeUsed then
+  if ToolCanBeUsed and not currentTool.Validating and not currentTool.Canceling then
     result := currentTool.Render(nil,VirtualScreenWidth,VirtualScreenHeight, @InternalBitmapToVirtualScreen)
     result := currentTool.Render(nil,VirtualScreenWidth,VirtualScreenHeight, @InternalBitmapToVirtualScreen)
   else
   else
     result := EmptyRect;
     result := EmptyRect;

+ 196 - 58
lazpaint/utoolbasic.pas

@@ -73,26 +73,35 @@ type
   { TVectorialTool }
   { TVectorialTool }
 
 
   TVectorialTool = class(TGenericTool)
   TVectorialTool = class(TGenericTool)
+  private
+    function GetIsHandDrawing: boolean;
+    function GetIsIdle: boolean;
   protected
   protected
     FShape: TVectorShape;
     FShape: TVectorShape;
     FSwapColor: boolean;
     FSwapColor: boolean;
     FQuickDefine: Boolean;
     FQuickDefine: Boolean;
-    FQuickDefineStartPoint: TPointF;
+    FQuickDefineStartPoint, FQuickDefineEndPoint: TPointF;
     FQuickSquare: boolean;
     FQuickSquare: boolean;
     FPreviousUpdateBounds, FPreviousEditorBounds: TRect;
     FPreviousUpdateBounds, FPreviousEditorBounds: TRect;
     FEditor: TBGRAOriginalEditor;
     FEditor: TBGRAOriginalEditor;
     FShiftState: TShiftState;
     FShiftState: TShiftState;
     FRightDown, FLeftDown: boolean;
     FRightDown, FLeftDown: boolean;
     FLastPos: TPointF;
     FLastPos: TPointF;
+    FLastShapeTransform: TAffineMatrix;
+    FUseOriginal: boolean;
+    function AlwaysRasterizeShape: boolean; virtual;
     function CreateShape: TVectorShape; virtual; abstract;
     function CreateShape: TVectorShape; virtual; abstract;
+    function UseOriginal: boolean; virtual;
     function GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; {%H-}ADraft: boolean): TRect; virtual;
     function GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; {%H-}ADraft: boolean): TRect; virtual;
     procedure DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); virtual;
     procedure DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); virtual;
-    procedure AssignShapeStyle; virtual;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); virtual;
     procedure QuickDefineShape(AStart,AEnd: TPointF); virtual;
     procedure QuickDefineShape(AStart,AEnd: TPointF); virtual;
     function RoundCoordinate(ptF: TPointF): TPointF; virtual;
     function RoundCoordinate(ptF: TPointF): TPointF; virtual;
     function GetIsSelectingTool: boolean; override;
     function GetIsSelectingTool: boolean; override;
     function UpdateShape(toolDest: TBGRABitmap): TRect; virtual;
     function UpdateShape(toolDest: TBGRABitmap): TRect; virtual;
+    function VectorTransform: TAffineMatrix;
     procedure UpdateCursor(ACursor: TOriginalEditorCursor);
     procedure UpdateCursor(ACursor: TOriginalEditorCursor);
+    function FixLayerOffset: boolean; override;
     function DoToolDown({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; {%H-}ptF: TPointF; rightBtn: boolean): TRect; override;
     function DoToolDown({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; {%H-}ptF: TPointF; rightBtn: boolean): TRect; override;
     function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; {%H-}ptF: TPointF): TRect; override;
     function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; {%H-}ptF: TPointF): TRect; override;
     function DoToolUpdate({%H-}toolDest: TBGRABitmap): TRect; override;
     function DoToolUpdate({%H-}toolDest: TBGRABitmap): TRect; override;
@@ -102,6 +111,7 @@ type
     function SlowShape: boolean; virtual;
     function SlowShape: boolean; virtual;
     procedure QuickDefineEnd; virtual;
     procedure QuickDefineEnd; virtual;
     procedure OnTryStop({%H-}sender: TCustomLayerAction); override;
     procedure OnTryStop({%H-}sender: TCustomLayerAction); override;
+    procedure UpdateUseOriginal;
   public
   public
     function ValidateShape: TRect;
     function ValidateShape: TRect;
     function CancelShape: TRect;
     function CancelShape: TRect;
@@ -111,6 +121,8 @@ type
     function ToolKeyPress(var key: TUTF8Char): TRect; override;
     function ToolKeyPress(var key: TUTF8Char): TRect; override;
     function ToolKeyUp(var key: Word): TRect; override;
     function ToolKeyUp(var key: Word): TRect; override;
     function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth, {%H-}VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction):TRect; override;
     function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth, {%H-}VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction):TRect; override;
+    property IsIdle: boolean read GetIsIdle;
+    property IsHandDrawing: boolean read GetIsHandDrawing;
     destructor Destroy; override;
     destructor Destroy; override;
   end;
   end;
 
 
@@ -131,7 +143,8 @@ type
 implementation
 implementation
 
 
 uses Types, Graphics, ugraph, Controls, LazPaintType,
 uses Types, Graphics, ugraph, Controls, LazPaintType,
-  UResourceStrings, BGRATransform, Math, BGRAPen, LCVectorRectShapes;
+  UResourceStrings, BGRATransform, Math, BGRAPen, LCVectorRectShapes,
+  uimagediff, UStateType, ULoading;
 
 
 { TVectorialTool }
 { TVectorialTool }
 
 
@@ -139,13 +152,14 @@ procedure TVectorialTool.ShapeChange(ASender: TObject; ABounds: TRectF);
 var
 var
   toolDest: TBGRABitmap;
   toolDest: TBGRABitmap;
   r: TRect;
   r: TRect;
+  matrix: TAffineMatrix;
 begin
 begin
   toolDest := GetToolDrawingLayer;
   toolDest := GetToolDrawingLayer;
-  with ABounds do r := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
+  matrix := VectorTransform;
+  r := (matrix*TAffineBox.AffineBox(ABounds)).RectBounds;
   UpdateShape(toolDest);
   UpdateShape(toolDest);
   Action.NotifyChange(toolDest, r);
   Action.NotifyChange(toolDest, r);
-  with FShape.GetRenderBounds(rect(0,0,toolDest.Width,toolDest.Height),
-       AffineMatrixIdentity,[]) do
+  with FShape.GetRenderBounds(rect(0,0,toolDest.Width,toolDest.Height),matrix,[]) do
     FPreviousUpdateBounds := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
     FPreviousUpdateBounds := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
   if IsRectEmpty(r) then ShapeEditingChange(ASender);
   if IsRectEmpty(r) then ShapeEditingChange(ASender);
 end;
 end;
@@ -206,22 +220,103 @@ begin
   ValidateShape;
   ValidateShape;
 end;
 end;
 
 
+procedure TVectorialTool.UpdateUseOriginal;
+begin
+  if not IsSelectingTool and Manager.Image.SelectionMaskEmpty and
+     Manager.Image.LayerOriginalDefined[Manager.Image.CurrentLayerIndex] and
+     Manager.Image.LayerOriginalKnown[Manager.Image.CurrentLayerIndex] and
+    (Manager.Image.LayerOriginalClass[Manager.Image.CurrentLayerIndex] = TVectorOriginal) then
+    FUseOriginal:= Assigned(Manager.Image.LayerOriginal[Manager.Image.CurrentLayerIndex])
+  else
+    FUseOriginal:= false;
+end;
+
 function TVectorialTool.ValidateShape: TRect;
 function TVectorialTool.ValidateShape: TRect;
+var
+  diff: TComposedImageDifference;
+  layerId: LongInt;
+  replaceDiff: TReplaceLayerByVectorOriginalDifference;
+  transf: TAffineMatrix;
+  addDiff: TAddShapeToVectorOriginalDifference;
+  rF: TRectF;
 begin
 begin
-  ValidateActionPartially;
-  FreeAndNil(FShape);
-  Cursor := crDefault;
-  result := OnlyRenderChange;
+  if Assigned(FShape) then
+  begin
+    FShape.OnChange:= nil;
+    FShape.OnEditingChange:= nil;
+    if not AlwaysRasterizeShape and Manager.Image.SelectionMaskEmpty then
+    begin
+      CancelAction;
+      if FShape.Usermode = vsuCreate then FShape.Usermode:= vsuEdit;
+      rF := FShape.GetRenderBounds(rect(0,0,Manager.Image.Width,Manager.Image.Height), VectorTransform);
+      if rF.IntersectsWith(rectF(0,0,Manager.Image.Width,Manager.Image.Height)) then
+      begin
+        layerId := Manager.Image.LayerId[Manager.Image.CurrentLayerIndex];
+        if UseOriginal then
+        begin
+          addDiff := TAddShapeToVectorOriginalDifference.Create(Manager.Image.CurrentState,layerId,FShape);
+          Manager.Image.AddUndo(addDiff);
+        end
+        else
+        begin
+          transf := VectorTransform;
+          diff := TComposedImageDifference.Create;
+          replaceDiff := TReplaceLayerByVectorOriginalDifference.Create(Manager.Image.CurrentState,Manager.Image.CurrentLayerIndex,
+                           Manager.Image.LayerOriginalClass[Manager.Image.CurrentLayerIndex]=TVectorOriginal);
+          diff.Add(replaceDiff);
+          transf := AffineMatrixInverse(Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex])*transf;
+          FShape.Transform(transf);
+          addDiff := TAddShapeToVectorOriginalDifference.Create(Manager.Image.CurrentState,layerId,FShape);
+          diff.Add(addDiff);
+          Manager.Image.AddUndo(diff);
+        end;
+        Manager.Image.ImageMayChange(addDiff.ChangingBounds);
+      end else
+        FShape.Free;
+      FShape := nil;
+      FEditor.Clear;
+    end else
+    begin
+      ValidateActionPartially;
+      FreeAndNil(FShape);
+      FEditor.Clear;
+    end;
+    Cursor := crDefault;
+    result := OnlyRenderChange;
+    UpdateUseOriginal;
+  end else
+    result := EmptyRect;
 end;
 end;
 
 
 function TVectorialTool.CancelShape: TRect;
 function TVectorialTool.CancelShape: TRect;
 begin
 begin
   CancelActionPartially;
   CancelActionPartially;
   FreeAndNil(FShape);
   FreeAndNil(FShape);
+  FEditor.Clear;
   Cursor := crDefault;
   Cursor := crDefault;
   result := OnlyRenderChange;
   result := OnlyRenderChange;
 end;
 end;
 
 
+function TVectorialTool.GetIsHandDrawing: boolean;
+begin
+  result := Assigned(FShape) and (FQuickDefine or (FShape.Usermode = vsuCreate));
+end;
+
+function TVectorialTool.GetIsIdle: boolean;
+begin
+  result := FShape = nil;
+end;
+
+function TVectorialTool.AlwaysRasterizeShape: boolean;
+begin
+  result := false;
+end;
+
+function TVectorialTool.UseOriginal: boolean;
+begin
+  result := FUseOriginal;
+end;
+
 function TVectorialTool.GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; ADraft: boolean): TRect;
 function TVectorialTool.GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; ADraft: boolean): TRect;
 begin
 begin
   with FShape.GetRenderBounds(ADestBounds,AMatrix,[]) do
   with FShape.GetRenderBounds(ADestBounds,AMatrix,[]) do
@@ -233,17 +328,19 @@ begin
   FShape.Render(ADest,AMatrix,ADraft);
   FShape.Render(ADest,AMatrix,ADraft);
 end;
 end;
 
 
-procedure TVectorialTool.AssignShapeStyle;
+procedure TVectorialTool.AssignShapeStyle(AMatrix: TAffineMatrix);
 var
 var
   f: TVectorShapeFields;
   f: TVectorShapeFields;
+  zoom: Single;
 begin
 begin
+  zoom := (VectLen(AMatrix[1,1],AMatrix[2,1])+VectLen(AMatrix[1,2],AMatrix[2,2]))/2;
   f:= FShape.Fields;
   f:= FShape.Fields;
   if vsfPenFill in f then
   if vsfPenFill in f then
   begin
   begin
     if Manager.ToolOptionDrawShape then
     if Manager.ToolOptionDrawShape then
     begin
     begin
       if (not (vsfBackFill in f) or not Manager.ToolOptionFillShape) and (Manager.GetToolTexture <> nil) then
       if (not (vsfBackFill in f) or not Manager.ToolOptionFillShape) and (Manager.GetToolTexture <> nil) then
-        FShape.PenFill.SetTexture(Manager.GetToolTexture,AffineMatrixIdentity,Manager.ToolTextureOpacity)
+        FShape.PenFill.SetTexture(Manager.GetToolTexture,AMatrix,Manager.ToolTextureOpacity)
       else
       else
       begin
       begin
         if FSwapColor then
         if FSwapColor then
@@ -254,7 +351,7 @@ begin
     end else
     end else
       FShape.PenFill.Clear;
       FShape.PenFill.Clear;
   end;
   end;
-  if vsfPenWidth in f then FShape.PenWidth := Manager.ToolPenWidth;
+  if vsfPenWidth in f then FShape.PenWidth := zoom*Manager.ToolPenWidth;
   if vsfPenStyle in f Then FShape.PenStyle := PenStyleToBGRA(Manager.ToolPenStyle);
   if vsfPenStyle in f Then FShape.PenStyle := PenStyleToBGRA(Manager.ToolPenStyle);
   if vsfJoinStyle in f then FShape.JoinStyle:= Manager.ToolJoinStyle;
   if vsfJoinStyle in f then FShape.JoinStyle:= Manager.ToolJoinStyle;
   if vsfBackFill in f then
   if vsfBackFill in f then
@@ -270,7 +367,8 @@ begin
         else
         else
           FShape.BackFill.SetSolid(Manager.ToolBackColor);
           FShape.BackFill.SetSolid(Manager.ToolBackColor);
       end;
       end;
-    end;
+    end else
+      FShape.BackFill.Clear;
   end;
   end;
 end;
 end;
 
 
@@ -302,7 +400,7 @@ var
 begin
 begin
   result := FPreviousUpdateBounds;
   result := FPreviousUpdateBounds;
   RestoreBackupDrawingLayer;
   RestoreBackupDrawingLayer;
-  matrix := AffineMatrixIdentity;
+  matrix := VectorTransform;
   draft := (FRightDown or FLeftDown) and SlowShape;
   draft := (FRightDown or FLeftDown) and SlowShape;
   newBounds := GetCustomShapeBounds(toolDest.ClipRect,matrix,draft);
   newBounds := GetCustomShapeBounds(toolDest.ClipRect,matrix,draft);
   result := RectUnion(result, newBounds);
   result := RectUnion(result, newBounds);
@@ -312,6 +410,14 @@ begin
   FPreviousUpdateBounds := newBounds;
   FPreviousUpdateBounds := newBounds;
 end;
 end;
 
 
+function TVectorialTool.VectorTransform: TAffineMatrix;
+begin
+  if not UseOriginal then
+    result := AffineMatrixIdentity
+  else
+    result := Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex];
+end;
+
 procedure TVectorialTool.UpdateCursor(ACursor: TOriginalEditorCursor);
 procedure TVectorialTool.UpdateCursor(ACursor: TOriginalEditorCursor);
 begin
 begin
   case ACursor of
   case ACursor of
@@ -330,6 +436,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TVectorialTool.FixLayerOffset: boolean;
+begin
+  Result:= false;
+end;
+
 function TVectorialTool.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
 function TVectorialTool.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
   ptF: TPointF; rightBtn: boolean): TRect;
   ptF: TPointF; rightBtn: boolean): TRect;
 var
 var
@@ -337,43 +448,54 @@ var
   cur: TOriginalEditorCursor;
   cur: TOriginalEditorCursor;
   handled: boolean;
   handled: boolean;
 begin
 begin
+  result := EmptyRect;
   FRightDown := rightBtn;
   FRightDown := rightBtn;
   FLeftDown := not rightBtn;
   FLeftDown := not rightBtn;
   FLastPos := ptF;
   FLastPos := ptF;
   if Assigned(FShape) then
   if Assigned(FShape) then
   begin
   begin
-    viewPt := FEditor.Matrix*ptF;
+    with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+      viewPt := FEditor.Matrix*AffineMatrixInverse(VectorTransform)*AffineMatrixTranslation(X,Y)*ptF;
     FEditor.MouseDown(rightBtn, FShiftState, viewPt.X,viewPt.Y, cur, handled);
     FEditor.MouseDown(rightBtn, FShiftState, viewPt.X,viewPt.Y, cur, handled);
     if not handled and Assigned(FShape) then
     if not handled and Assigned(FShape) then
       FShape.MouseDown(rightBtn, FShiftState, ptF.X,ptF.Y, cur, handled);
       FShape.MouseDown(rightBtn, FShiftState, ptF.X,ptF.Y, cur, handled);
     UpdateCursor(cur);
     UpdateCursor(cur);
-    result := EmptyRect;
     if handled then exit
     if handled then exit
-    else
-    begin
-      ValidateAction;
-      FreeAndNil(FShape);
-    end;
+    else result := RectUnion(result, ValidateShape);
   end;
   end;
 
 
   if FShape=nil then
   if FShape=nil then
   begin
   begin
-    FSwapColor:= rightBtn;
-    FShape := CreateShape;
-    FQuickDefine := true;
-    FQuickDefineStartPoint := RoundCoordinate(ptF);
-    AssignShapeStyle;
-    QuickDefineShape(FQuickDefineStartPoint,FQuickDefineStartPoint);
-    FShape.OnChange:= @ShapeChange;
-    FShape.OnEditingChange:=@ShapeEditingChange;
-    result := UpdateShape(toolDest);
+    if UseOriginal and
+      ((Manager.Image.LayerOriginal[Manager.Image.CurrentLayerIndex] as TVectorOriginal).ShapeCount >= 10) then
+    begin
+      MessagePopup(rsTooManyShapesInLayer, 3000);
+    end
+    else
+    begin
+      toolDest := GetToolDrawingLayer;
+      FSwapColor:= rightBtn;
+      FShape := CreateShape;
+      FQuickDefine := true;
+      FQuickDefineStartPoint := RoundCoordinate(ptF);
+      FQuickDefineEndPoint := FQuickDefineStartPoint;
+      FShape.BeginUpdate;
+        QuickDefineShape(FQuickDefineStartPoint,FQuickDefineEndPoint);
+        FLastShapeTransform := AffineMatrixInverse(VectorTransform);
+        FShape.Transform(FLastShapeTransform);
+        AssignShapeStyle(FLastShapeTransform);
+      FShape.EndUpdate;
+      FShape.OnChange:= @ShapeChange;
+      FShape.OnEditingChange:=@ShapeEditingChange;
+      result := RectUnion(result, UpdateShape(toolDest));
+    end;
   end;
   end;
 end;
 end;
 
 
 function TVectorialTool.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
 function TVectorialTool.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
   ptF: TPointF): TRect;
   ptF: TPointF): TRect;
 var
 var
-  secondCoord, s: TPointF;
+  s: TPointF;
   avg: single;
   avg: single;
   viewPt: TPointF;
   viewPt: TPointF;
   handled: boolean;
   handled: boolean;
@@ -382,42 +504,55 @@ begin
   FLastPos := ptF;
   FLastPos := ptF;
   if FQuickDefine then
   if FQuickDefine then
   begin
   begin
-    secondCoord := RoundCoordinate(ptF);
+    FQuickDefineEndPoint := RoundCoordinate(ptF);
     if FQuickSquare then
     if FQuickSquare then
     begin
     begin
-      s := secondCoord-FQuickDefineStartPoint;
+      s := FQuickDefineEndPoint-FQuickDefineStartPoint;
       avg := sqrt(abs(s.x*s.y));
       avg := sqrt(abs(s.x*s.y));
-      if s.x > 0 then secondCoord.x := FQuickDefineStartPoint.x + avg else secondCoord.x := FQuickDefineStartPoint.x - avg;
-      if s.y > 0 then secondCoord.y := FQuickDefineStartPoint.y + avg else secondCoord.y := FQuickDefineStartPoint.y - avg;
+      if s.x > 0 then FQuickDefineEndPoint.x := FQuickDefineStartPoint.x + avg else FQuickDefineEndPoint.x := FQuickDefineStartPoint.x - avg;
+      if s.y > 0 then FQuickDefineEndPoint.y := FQuickDefineStartPoint.y + avg else FQuickDefineEndPoint.y := FQuickDefineStartPoint.y - avg;
     end;
     end;
-    QuickDefineShape(FQuickDefineStartPoint, secondCoord);
+    FShape.BeginUpdate;
+      QuickDefineShape(FQuickDefineStartPoint, FQuickDefineEndPoint);
+      FLastShapeTransform := AffineMatrixInverse(VectorTransform);
+      FShape.Transform(FLastShapeTransform);
+      AssignShapeStyle(FLastShapeTransform);
+    FShape.EndUpdate;
     result := OnlyRenderChange;
     result := OnlyRenderChange;
   end else
   end else
   begin
   begin
-    viewPt := FEditor.Matrix*ptF;
+    with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+      viewPt := FEditor.Matrix*AffineMatrixInverse(VectorTransform)*AffineMatrixTranslation(X,Y)*ptF;
     FEditor.MouseMove(FShiftState, viewPt.X,viewPt.Y, cur, handled);
     FEditor.MouseMove(FShiftState, viewPt.X,viewPt.Y, cur, handled);
     if not handled and Assigned(FShape) then
     if not handled and Assigned(FShape) then
       FShape.MouseMove(FShiftState, ptF.X,ptF.Y, cur, handled);
       FShape.MouseMove(FShiftState, ptF.X,ptF.Y, cur, handled);
     UpdateCursor(cur);
     UpdateCursor(cur);
-    result := EmptyRect;
+    if handled then result := OnlyRenderChange
+    else result := EmptyRect;
   end;
   end;
 end;
 end;
 
 
 function TVectorialTool.DoToolUpdate(toolDest: TBGRABitmap): TRect;
 function TVectorialTool.DoToolUpdate(toolDest: TBGRABitmap): TRect;
 begin
 begin
-  if Assigned(FShape) then AssignShapeStyle;
+  if Assigned(FShape) then
+  begin
+    FShape.BeginUpdate;
+    AssignShapeStyle(FLastShapeTransform);
+    FShape.EndUpdate;
+  end;
   result := EmptyRect;
   result := EmptyRect;
 end;
 end;
 
 
 constructor TVectorialTool.Create(AManager: TToolManager);
 constructor TVectorialTool.Create(AManager: TToolManager);
 begin
 begin
   inherited Create(AManager);
   inherited Create(AManager);
-  Action.ChangeBoundsNotified:= true;
+  UpdateUseOriginal;
   FPreviousUpdateBounds := EmptyRect;
   FPreviousUpdateBounds := EmptyRect;
   FEditor := TVectorOriginalEditor.Create(nil);
   FEditor := TVectorOriginalEditor.Create(nil);
   FEditor.GridMatrix := AffineMatrixScale(0.5,0.5);
   FEditor.GridMatrix := AffineMatrixScale(0.5,0.5);
   FEditor.Focused := true;
   FEditor.Focused := true;
   FPreviousEditorBounds := EmptyRect;
   FPreviousEditorBounds := EmptyRect;
+  FLastShapeTransform := AffineMatrixIdentity;
 end;
 end;
 
 
 function TVectorialTool.ToolUp: TRect;
 function TVectorialTool.ToolUp: TRect;
@@ -443,7 +578,7 @@ begin
     UpdateCursor(cur);
     UpdateCursor(cur);
     result := EmptyRect;
     result := EmptyRect;
   end;
   end;
-  if SlowShape then
+  if SlowShape and Assigned(FShape) then
     result := UpdateShape(GetToolDrawingLayer);
     result := UpdateShape(GetToolDrawingLayer);
 end;
 end;
 
 
@@ -545,26 +680,29 @@ function TVectorialTool.Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth,
 var
 var
   orig, xAxis, yAxis: TPointF;
   orig, xAxis, yAxis: TPointF;
 begin
 begin
-  orig := BitmapToVirtualScreen(PointF(0,0));
-  xAxis := BitmapToVirtualScreen(PointF(1,0));
-  yAxis := BitmapToVirtualScreen(PointF(0,1));
-  FEditor.Matrix := AffineMatrix(xAxis-orig,yAxis-orig,orig);
-  FEditor.Clear;
-  if Assigned(FShape) then FShape.ConfigureEditor(FEditor);
-  if Assigned(VirtualScreen) then
-    Result:= FEditor.Render(VirtualScreen, rect(0,0,VirtualScreen.Width,VirtualScreen.Height))
-  else
-    Result:= FEditor.GetRenderBounds(rect(0,0,VirtualScreenWidth,VirtualScreenHeight));
-  FPreviousEditorBounds := result
+  if Assigned(FShape) then
+  begin
+    orig := BitmapToVirtualScreen(PointF(0,0));
+    xAxis := BitmapToVirtualScreen(PointF(1,0));
+    yAxis := BitmapToVirtualScreen(PointF(0,1));
+    FEditor.Matrix := AffineMatrix(xAxis-orig,yAxis-orig,orig)*VectorTransform;
+    FEditor.Clear;
+    if Assigned(FShape) then FShape.ConfigureEditor(FEditor);
+    if Assigned(VirtualScreen) then
+      Result:= FEditor.Render(VirtualScreen, rect(0,0,VirtualScreen.Width,VirtualScreen.Height))
+    else
+      Result:= FEditor.GetRenderBounds(rect(0,0,VirtualScreenWidth,VirtualScreenHeight));
+  end else
+  begin
+    result := EmptyRect;
+    FEditor.Clear;
+  end;
+  FPreviousEditorBounds := result;
 end;
 end;
 
 
 destructor TVectorialTool.Destroy;
 destructor TVectorialTool.Destroy;
 begin
 begin
-  if Assigned(FShape) then
-  begin
-    ValidateAction;
-    FShape.Free;
-  end;
+  if Assigned(FShape) then ValidateShape;
   FEditor.Free;
   FEditor.Free;
   inherited Destroy;
   inherited Destroy;
 end;
 end;

+ 24 - 4
lazpaint/utoolfloodfill.pas

@@ -26,7 +26,8 @@ type
   TToolGradient = class(TVectorialTool)
   TToolGradient = class(TVectorialTool)
   protected
   protected
     function CreateShape: TVectorShape; override;
     function CreateShape: TVectorShape; override;
-    procedure AssignShapeStyle; override;
+    procedure DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
     procedure QuickDefineShape(AStart,AEnd: TPointF); override;
     procedure QuickDefineShape(AStart,AEnd: TPointF); override;
     function SlowShape: boolean; override;
     function SlowShape: boolean; override;
     function GetStatusText: string; override;
     function GetStatusText: string; override;
@@ -34,20 +35,38 @@ type
 
 
 implementation
 implementation
 
 
-uses ugraph, LazPaintType, BGRAGradientScanner, LCVectorRectShapes;
+uses ugraph, LazPaintType, BGRAGradientScanner, LCVectorRectShapes,
+  math, BGRATransform;
 
 
 { TToolGradient }
 { TToolGradient }
 
 
 function TToolGradient.CreateShape: TVectorShape;
 function TToolGradient.CreateShape: TVectorShape;
 begin
 begin
   result := TRectShape.Create(nil);
   result := TRectShape.Create(nil);
-  result.QuickDefine(PointF(-0.5,-0.5),PointF(Manager.Image.Width-0.5,Manager.Image.Height-0.5));
   result.PenFill.Clear;
   result.PenFill.Clear;
   result.BackFill.SetGradient(TBGRALayerGradientOriginal.Create,true);
   result.BackFill.SetGradient(TBGRALayerGradientOriginal.Create,true);
   result.Usermode := vsuEditBackFill;
   result.Usermode := vsuEditBackFill;
 end;
 end;
 
 
-procedure TToolGradient.AssignShapeStyle;
+procedure TToolGradient.DrawCustomShape(ADest: TBGRABitmap;
+  AMatrix: TAffineMatrix; ADraft: boolean);
+var
+  temp: TBGRABitmap;
+begin
+  if ADraft and (ADest.NbPixels > 384*384) then
+  begin
+    temp := TBGRABitmap.Create(0,0);
+    temp.SetSize(min(384,ADest.Width),min(384,ADest.Height));
+    FShape.BackFill.Gradient.Render(temp,
+      AffineMatrixScale(temp.Width/ADest.Width,
+                        temp.Height/ADest.Height)*AMatrix, ADraft);
+    ADest.StretchPutImage(rect(0,0,ADest.Width,Adest.Height),temp,dmSet);
+    temp.Free;
+  end else
+    FShape.BackFill.Gradient.Render(ADest,AMatrix,ADraft);
+end;
+
+procedure TToolGradient.AssignShapeStyle(AMatrix: TAffineMatrix);
 begin
 begin
   with FShape.BackFill.Gradient do
   with FShape.BackFill.Gradient do
   begin
   begin
@@ -72,6 +91,7 @@ end;
 
 
 procedure TToolGradient.QuickDefineShape(AStart, AEnd: TPointF);
 procedure TToolGradient.QuickDefineShape(AStart, AEnd: TPointF);
 begin
 begin
+  FShape.QuickDefine(PointF(-0.5,-0.5),PointF(Manager.Image.Width-0.5,Manager.Image.Height-0.5));
   FShape.BackFill.Gradient.Origin := AStart;
   FShape.BackFill.Gradient.Origin := AStart;
   FShape.BackFill.Gradient.XAxis := AEnd;
   FShape.BackFill.Gradient.XAxis := AEnd;
 end;
 end;

+ 367 - 455
lazpaint/utoollayer.pas

@@ -37,12 +37,11 @@ type
       BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect; override;
       BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect; override;
   end;
   end;
 
 
-  { TToolRotateLayer }
+  { TToolTransformLayer }
 
 
-  TToolRotateLayer = class(TGenericTool)
+  TToolTransformLayer = class(TGenericTool)
   private
   private
-    function GetActualAngle: single;
-    function GetOriginalLayerBounds: TRect;
+    function GetInitialLayerBounds: TRect;
     function GetTransformCenter: TPointF;
     function GetTransformCenter: TPointF;
     procedure SetTransformCenter(AValue: TPointF);
     procedure SetTransformCenter(AValue: TPointF);
     procedure NeedOriginal;
     procedure NeedOriginal;
@@ -56,21 +55,26 @@ type
     FTransformCenter: TPointF;
     FTransformCenter: TPointF;
     FTransformCenterDefined: boolean;
     FTransformCenterDefined: boolean;
     FPreviousTransformCenter: TPointF;
     FPreviousTransformCenter: TPointF;
-    FAngle,FActualAngle,FPreviousActualAngle: single;
     FPreviousFilter: TResampleFilter;
     FPreviousFilter: TResampleFilter;
     FTransforming: boolean;
     FTransforming: boolean;
     FPreviousMousePos: TPointF;
     FPreviousMousePos: TPointF;
     FCtrlDown: boolean;
     FCtrlDown: boolean;
     FLastUpdateRect: TRect;
     FLastUpdateRect: TRect;
     FLastUpdateRectDefined: boolean;
     FLastUpdateRectDefined: boolean;
+    FOriginalBounds: TRect;
+    FOriginalBoundsDefined: boolean;
     function GetIsSelectingTool: boolean; override;
     function GetIsSelectingTool: boolean; override;
     function DoToolDown({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF;
     function DoToolDown({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF;
       rightBtn: boolean): TRect; override;
       rightBtn: boolean): TRect; override;
     function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF): TRect;
     function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF): TRect;
       override;
       override;
-    function UpdateTransform: TRect;
     procedure CancelTransform;
     procedure CancelTransform;
     procedure ValidateTransform;
     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;
     property TransformCenter: TPointF read GetTransformCenter write SetTransformCenter;
     function GetAction: TLayerAction; override;
     function GetAction: TLayerAction; override;
     function DoGetToolDrawingLayer: TBGRABitmap; override;
     function DoGetToolDrawingLayer: TBGRABitmap; override;
@@ -87,102 +91,248 @@ type
 
 
   { TToolZoomLayer }
   { TToolZoomLayer }
 
 
-  TToolZoomLayer = class(TGenericTool)
+  TToolZoomLayer = class(TToolTransformLayer)
   private
   private
+    FZoom,FActualZoom,FPreviousActualZoom: single;
     function GetActualZoom: single;
     function GetActualZoom: single;
-    function GetOriginalLayerBounds: TRect;
-    function GetTransformCenter: TPointF;
-    procedure SetTransformCenter(AValue: TPointF);
-    procedure NeedOriginal;
   protected
   protected
-    FOriginalInit: boolean;
-    FBackupLayer: TReplaceLayerByImageOriginalDifference;
-    FInitialOriginalMatrix: TAffineMatrix;
-    FInitialLayerBounds: TRect;
-    FInitialLayerBoundsDefined: boolean;
+    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;
 
 
-    FTransformCenter: TPointF;
-    FTransformCenterDefined: boolean;
-    FPreviousTransformCenter: TPointF;
-    FZoom,FActualZoom,FPreviousActualZoom: single;
-    FPreviousFilter: TResampleFilter;
-    FTransforming: boolean;
-    FPreviousMousePos: TPointF;
-    FCtrlDown: boolean;
-    FLastUpdateRect: TRect;
-    FLastUpdateRectDefined: 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;
-    function UpdateTransform: TRect;
-    procedure CancelTransform;
-    procedure ValidateTransform;
-    property TransformCenter: TPointF read GetTransformCenter write SetTransformCenter;
-    function GetAction: TLayerAction; override;
-    function DoGetToolDrawingLayer: TBGRABitmap; override;
+  { 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
   public
     constructor Create(AManager: TToolManager); override;
     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;
   end;
 
 
 implementation
 implementation
 
 
 uses LazPaintType, ugraph, LCLType, Types, BGRALayerOriginal;
 uses LazPaintType, ugraph, LCLType, Types, BGRALayerOriginal;
 
 
-{ TToolRotateLayer }
+const
+  VeryBigValue = maxLongInt div 2;
 
 
-function TToolRotateLayer.GetActualAngle: single;
+{ TToolMoveLayer }
+
+function TToolMoveLayer.GetIsSelectingTool: boolean;
 begin
 begin
-  if FCtrlDown then
-    result := round(FAngle/15)*15
-  else
-    result := FAngle;
+  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;
 end;
 
 
-function TToolRotateLayer.GetOriginalLayerBounds: TRect;
+{ TToolTransformLayer }
+
+function TToolTransformLayer.GetInitialLayerBounds: TRect;
 begin
 begin
   if not FInitialLayerBoundsDefined then
   if not FInitialLayerBoundsDefined then
   begin
   begin
     FInitialLayerBounds := GetToolDrawingLayer.GetImageBounds;
     FInitialLayerBounds := GetToolDrawingLayer.GetImageBounds;
+    with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+      FInitialLayerBounds.Offset(X,Y);
     FInitialLayerBoundsDefined := true;
     FInitialLayerBoundsDefined := true;
   end;
   end;
   result := FInitialLayerBounds;
   result := FInitialLayerBounds;
 end;
 end;
 
 
-function TToolRotateLayer.GetTransformCenter: TPointF;
+function TToolTransformLayer.GetTransformCenter: TPointF;
 var bounds: TRect;
 var bounds: TRect;
 begin
 begin
   if not FTransformCenterDefined then
   if not FTransformCenterDefined then
   begin
   begin
-    bounds := GetOriginalLayerBounds;
+    bounds := GetInitialLayerBounds;
     if IsRectEmpty(bounds) then
     if IsRectEmpty(bounds) then
       FTransformCenter := PointF(Manager.Image.Width/2 - 0.5,Manager.Image.Height/2 - 0.5)
       FTransformCenter := PointF(Manager.Image.Width/2 - 0.5,Manager.Image.Height/2 - 0.5)
     else
     else
     begin
     begin
       with bounds do
       with bounds do
         FTransformCenter := PointF((Left+Right)/2 - 0.5, (Top+Bottom)/2 - 0.5);
         FTransformCenter := PointF((Left+Right)/2 - 0.5, (Top+Bottom)/2 - 0.5);
-      with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
-        FTransformCenter += PointF(X,Y);
     end;
     end;
     FTransformCenterDefined := true;
     FTransformCenterDefined := true;
   end;
   end;
   result := FTransformCenter;
   result := FTransformCenter;
 end;
 end;
 
 
-procedure TToolRotateLayer.SetTransformCenter(AValue: TPointF);
+procedure TToolTransformLayer.SetTransformCenter(AValue: TPointF);
 begin
 begin
   FTransformCenter := AValue;
   FTransformCenter := AValue;
 end;
 end;
 
 
-procedure TToolRotateLayer.NeedOriginal;
+procedure TToolTransformLayer.NeedOriginal;
 var
 var
   layered: TBGRALayeredBitmap;
   layered: TBGRALayeredBitmap;
   layerIdx: Integer;
   layerIdx: Integer;
@@ -195,13 +345,13 @@ begin
      Manager.Image.LayerOriginalKnown[layerIdx]) then
      Manager.Image.LayerOriginalKnown[layerIdx]) then
   begin
   begin
     if Assigned(FBackupLayer) then raise exception.Create('Backup layer already assigned');
     if Assigned(FBackupLayer) then raise exception.Create('Backup layer already assigned');
-    FBackupLayer:= TReplaceLayerByImageOriginalDifference.Create(Manager.Image.CurrentState, layerIdx);
+    FBackupLayer:= TReplaceLayerByImageOriginalDifference.Create(Manager.Image.CurrentState, layerIdx, true);
   end;
   end;
   FInitialOriginalMatrix := layered.LayerOriginalMatrix[layerIdx];
   FInitialOriginalMatrix := layered.LayerOriginalMatrix[layerIdx];
   FOriginalInit := true;
   FOriginalInit := true;
 end;
 end;
 
 
-function TToolRotateLayer.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
+function TToolTransformLayer.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
   ptF: TPointF; rightBtn: boolean): TRect;
   ptF: TPointF; rightBtn: boolean): TRect;
 begin
 begin
   with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
   with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
@@ -211,57 +361,42 @@ begin
   begin
   begin
     FTransforming := true;
     FTransforming := true;
     FPreviousMousePos := ptF;
     FPreviousMousePos := ptF;
-    if FCtrlDown then result := UpdateTransform
-     else result := EmptyRect;
+    if FCtrlDown then
+    begin
+      result := UpdateTransform;
+      if IsRectEmpty(result) then result := OnlyRenderChange;
+    end else result := EmptyRect;
+    Manager.Image.DraftOriginal := true;
   end else
   end else
   if rightBtn then
   if rightBtn then
   begin
   begin
     FTransformCenter := ptF;
     FTransformCenter := ptF;
-    FAngle := 0;
-    FActualAngle:= GetActualAngle;
+    TransformCenterChanged;
     result := UpdateTransform;
     result := UpdateTransform;
     if IsRectEmpty(result) then result := OnlyRenderChange;
     if IsRectEmpty(result) then result := OnlyRenderChange;
   end else
   end else
     result := EmptyRect;
     result := EmptyRect;
 end;
 end;
 
 
-function TToolRotateLayer.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
+function TToolTransformLayer.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
   ptF: TPointF): TRect;
   ptF: TPointF): TRect;
-var angleDiff: single;
 begin
 begin
   with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
   with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
     ptF += PointF(X,Y);
     ptF += PointF(X,Y);
   if FTransforming then
   if FTransforming then
   begin
   begin
-    angleDiff := ComputeAngle(ptF.X-TransformCenter.X,ptF.Y-TransformCenter.Y)-
-               ComputeAngle(FPreviousMousePos.X-TransformCenter.X,FPreviousMousePos.Y-TransformCenter.Y);
-    FAngle += angleDiff;
-    FActualAngle:= GetActualAngle;
-    result := UpdateTransform;
+    If MouseChangesTransform(FPreviousMousePos, ptF) then
+    begin
+      result := UpdateTransform;
+      if result.IsEmpty then result := OnlyRenderChange;
+    end
+    else result := EmptyRect;
     FPreviousMousePos := ptF;
     FPreviousMousePos := ptF;
   end else
   end else
     result := EmptyRect;
     result := EmptyRect;
 end;
 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;
-
-procedure TToolRotateLayer.CancelTransform;
+procedure TToolTransformLayer.CancelTransform;
 begin
 begin
   if FOriginalInit then
   if FOriginalInit then
   begin
   begin
@@ -276,7 +411,7 @@ begin
   Manager.QueryExitTool;
   Manager.QueryExitTool;
 end;
 end;
 
 
-procedure TToolRotateLayer.ValidateTransform;
+procedure TToolTransformLayer.ValidateTransform;
 var
 var
   transform: TAffineMatrix;
   transform: TAffineMatrix;
 begin
 begin
@@ -297,50 +432,48 @@ begin
   Manager.QueryExitTool;
   Manager.QueryExitTool;
 end;
 end;
 
 
-function TToolRotateLayer.GetAction: TLayerAction;
+function TToolTransformLayer.GetAction: TLayerAction;
 begin
 begin
   result := GetIdleAction;
   result := GetIdleAction;
 end;
 end;
 
 
-function TToolRotateLayer.DoGetToolDrawingLayer: TBGRABitmap;
+function TToolTransformLayer.DoGetToolDrawingLayer: TBGRABitmap;
 begin
 begin
   Result:= Manager.Image.CurrentLayerReadOnly   //do not modify layer data directly and ignore selection
   Result:= Manager.Image.CurrentLayerReadOnly   //do not modify layer data directly and ignore selection
 end;
 end;
 
 
-constructor TToolRotateLayer.Create(AManager: TToolManager);
+constructor TToolTransformLayer.Create(AManager: TToolManager);
 begin
 begin
   inherited Create(AManager);
   inherited Create(AManager);
   FCtrlDown:= false;
   FCtrlDown:= false;
   FTransformCenterDefined := false;
   FTransformCenterDefined := false;
   FLastUpdateRectDefined:= false;
   FLastUpdateRectDefined:= false;
-
-  FAngle:= 0;
-  FPreviousActualAngle := 0;
 end;
 end;
 
 
-destructor TToolRotateLayer.Destroy;
+destructor TToolTransformLayer.Destroy;
 begin
 begin
-  ValidateTransform;
+  if TransformOk then ValidateTransform
+  else CancelTransform;
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
-function TToolRotateLayer.ToolKeyDown(var key: Word): TRect;
+function TToolTransformLayer.ToolKeyDown(var key: Word): TRect;
 begin
 begin
   if key = VK_CONTROL then
   if key = VK_CONTROL then
   begin
   begin
     FCtrlDown:= true;
     FCtrlDown:= true;
-    if FTransforming then
+    if FTransforming and CtrlChangesTransform then
     begin
     begin
-      FActualAngle := GetActualAngle;
       result := UpdateTransform;
       result := UpdateTransform;
+      if result.IsEmpty then result := OnlyRenderChange;
     end
     end
-     else result := EmptyRect;
+      else result := EmptyRect;
     Key := 0;
     Key := 0;
   end else
   end else
   if Key = VK_RETURN then
   if Key = VK_RETURN then
   begin
   begin
-    if FActualAngle = 0 then CancelTransform
-    else ValidateTransform;
+    if TransformOk then ValidateTransform
+    else CancelTransform;
     result := OnlyRenderChange;
     result := OnlyRenderChange;
     key := 0;
     key := 0;
   end else
   end else
@@ -353,35 +486,85 @@ begin
     result := EmptyRect;
     result := EmptyRect;
 end;
 end;
 
 
-function TToolRotateLayer.ToolKeyUp(var key: Word): TRect;
+function TToolTransformLayer.ToolKeyUp(var key: Word): TRect;
 begin
 begin
   if key = VK_CONTROL then
   if key = VK_CONTROL then
   begin
   begin
     FCtrlDown := false;
     FCtrlDown := false;
+    if FTransforming and CtrlChangesTransform then
+    begin
+      result := UpdateTransform;
+      if result.IsEmpty then result := OnlyRenderChange;
+    end
+      else result := EmptyRect;
     Key := 0;
     Key := 0;
-  end;
-  result := EmptyRect;
+  end else
+    result := EmptyRect;
 end;
 end;
 
 
-function TToolRotateLayer.ToolUp: TRect;
+function TToolTransformLayer.ToolUp: TRect;
 begin
 begin
   if FTransforming then
   if FTransforming then
   begin
   begin
     FTransforming := false;
     FTransforming := false;
     result := UpdateTransform;
     result := UpdateTransform;
+    if result.IsEmpty then result := OnlyRenderChange;
+    Manager.Image.DraftOriginal := false;
   end else
   end else
     Result:=EmptyRect;
     Result:=EmptyRect;
 end;
 end;
 
 
-function TToolRotateLayer.Render(VirtualScreen: TBGRABitmap;
+function TToolTransformLayer.Render(VirtualScreen: TBGRABitmap;
   VirtualScreenWidth, VirtualScreenHeight: integer;
   VirtualScreenWidth, VirtualScreenHeight: integer;
   BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
   BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
-begin
-  with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+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)));
     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;
 end;
 
 
-function TToolRotateLayer.GetIsSelectingTool: boolean;
+function TToolTransformLayer.GetIsSelectingTool: boolean;
 begin
 begin
   result := false;
   result := false;
 end;
 end;
@@ -418,104 +601,9 @@ begin
     result := FZoom;
     result := FZoom;
 end;
 end;
 
 
-function TToolZoomLayer.GetOriginalLayerBounds: TRect;
-begin
-  if not FInitialLayerBoundsDefined then
-  begin
-    FInitialLayerBounds := GetToolDrawingLayer.GetImageBounds;
-    FInitialLayerBoundsDefined := true;
-  end;
-  result := FInitialLayerBounds;
-end;
-
-function TToolZoomLayer.GetTransformCenter: TPointF;
-var bounds: TRect;
-begin
-  if not FTransformCenterDefined then
-  begin
-    bounds := GetOriginalLayerBounds;
-    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);
-      with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
-        FTransformCenter += PointF(X,Y);
-    end;
-    FTransformCenterDefined := true;
-  end;
-  result := FTransformCenter;
-end;
-
-procedure TToolZoomLayer.SetTransformCenter(AValue: TPointF);
-begin
-  FTransformCenter := AValue;
-end;
-
-procedure TToolZoomLayer.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);
-  end;
-  FInitialOriginalMatrix := layered.LayerOriginalMatrix[layerIdx];
-  FOriginalInit := true;
-end;
-
-function TToolZoomLayer.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 result := UpdateTransform
-     else result := EmptyRect;
-  end else
-  if rightBtn then
-  begin
-    FTransformCenter := ptF;
-    FZoom := 1;
-    FActualZoom:= GetActualZoom;
-    result := UpdateTransform;
-    if IsRectEmpty(result) then result := OnlyRenderChange;
-  end else
-    result := EmptyRect;
-end;
-
-function TToolZoomLayer.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
-  ptF: TPointF): TRect;
-var dist, prevDist: single;
+function TToolZoomLayer.TransformOk: boolean;
 begin
 begin
-  with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
-    ptF += PointF(X,Y);
-  if FTransforming then
-  begin
-    dist := VectLen(ptF-TransformCenter);
-    prevDist := VectLen(FPreviousMousePos-TransformCenter);
-    if (prevDist <> 0) and (dist <> 0) then
-    begin
-      FZoom *= dist/prevDist;
-      FActualZoom:= GetActualZoom;
-      result := UpdateTransform;
-    end
-    else result := EmptyRect;
-    FPreviousMousePos := ptF;
-  end else
-    result := EmptyRect;
+  result := FActualZoom <> 0;
 end;
 end;
 
 
 function TToolZoomLayer.UpdateTransform: TRect;
 function TToolZoomLayer.UpdateTransform: TRect;
@@ -536,296 +624,120 @@ begin
     FInitialOriginalMatrix;
     FInitialOriginalMatrix;
 end;
 end;
 
 
-procedure TToolZoomLayer.CancelTransform;
+procedure TToolZoomLayer.TransformCenterChanged;
 begin
 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;
+  FZoom := 1;
+  FActualZoom:= GetActualZoom;
 end;
 end;
 
 
-procedure TToolZoomLayer.ValidateTransform;
+function TToolZoomLayer.MouseChangesTransform(APrevPos, ANewPos: TPointF): boolean;
 var
 var
-  transform: TAffineMatrix;
+  dist, prevDist: Single;
 begin
 begin
-  if FOriginalInit then
+  dist := VectLen(ANewPos-TransformCenter);
+  prevDist := VectLen(APrevPos-TransformCenter);
+  if (prevDist <> 0) and (dist <> 0) then
   begin
   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 TToolZoomLayer.GetAction: TLayerAction;
-begin
-  result := GetIdleAction;
+    FZoom *= dist/prevDist;
+    FActualZoom:= GetActualZoom;
+    result := true;
+  end
+  else result := false;
 end;
 end;
 
 
-function TToolZoomLayer.DoGetToolDrawingLayer: TBGRABitmap;
+function TToolZoomLayer.CtrlChangesTransform: boolean;
+var
+  newActualZoom: Single;
 begin
 begin
-  Result:= Manager.Image.CurrentLayerReadOnly   //do not modify layer data directly and ignore selection
+  newActualZoom := GetActualZoom;
+  if FActualZoom<>newActualZoom then
+  begin
+    FActualZoom := newActualZoom;
+    result := true;
+  end else
+    result := false;
 end;
 end;
 
 
 constructor TToolZoomLayer.Create(AManager: TToolManager);
 constructor TToolZoomLayer.Create(AManager: TToolManager);
 begin
 begin
   inherited Create(AManager);
   inherited Create(AManager);
-  FCtrlDown:= false;
-  FTransformCenterDefined := false;
-  FLastUpdateRectDefined:= false;
-
   FZoom:= 1;
   FZoom:= 1;
   FPreviousActualZoom := 1;
   FPreviousActualZoom := 1;
 end;
 end;
 
 
-destructor TToolZoomLayer.Destroy;
-begin
-  ValidateTransform;
-  inherited Destroy;
-end;
-
-function TToolZoomLayer.ToolKeyDown(var key: Word): TRect;
-begin
-  if key = VK_CONTROL then
-  begin
-    FCtrlDown:= true;
-    if FTransforming then
-    begin
-      FActualZoom := GetActualZoom;
-      result := UpdateTransform;
-    end
-     else result := EmptyRect;
-    Key := 0;
-  end else
-  if Key = VK_RETURN then
-  begin
-    if FActualZoom = 0 then CancelTransform
-    else ValidateTransform;
-    result := OnlyRenderChange;
-    key := 0;
-  end else
-  if Key = VK_ESCAPE then
-  begin
-    CancelTransform;
-    result := OnlyRenderChange;
-    key := 0;
-  end else
-    result := EmptyRect;
-end;
-
-function TToolZoomLayer.ToolKeyUp(var key: Word): TRect;
-begin
-  if key = VK_CONTROL then
-  begin
-    FCtrlDown := false;
-    Key := 0;
-  end;
-  result := EmptyRect;
-end;
-
-function TToolZoomLayer.ToolUp: TRect;
-begin
-  if FTransforming then
-  begin
-    FTransforming := false;
-    result := UpdateTransform;
-  end else
-    Result:=EmptyRect;
-end;
+{ TToolRotateLayer }
 
 
-function TToolZoomLayer.Render(VirtualScreen: TBGRABitmap;
-  VirtualScreenWidth, VirtualScreenHeight: integer;
-  BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
+function TToolRotateLayer.GetActualAngle: single;
 begin
 begin
-  with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
-    Result:= NicePoint(VirtualScreen,BitmapToVirtualScreen(TransformCenter-PointF(X,Y)));
+  if FCtrlDown then
+    result := round(FAngle/15)*15
+  else
+    result := FAngle;
 end;
 end;
 
 
-function TToolZoomLayer.GetIsSelectingTool: boolean;
+function TToolRotateLayer.TransformOk: boolean;
 begin
 begin
-  result := false;
+  result := true;
 end;
 end;
 
 
-{ TToolMoveLayer }
-
-function TToolMoveLayer.GetIsSelectingTool: boolean;
+procedure TToolRotateLayer.TransformCenterChanged;
 begin
 begin
-  result := false;
+  FAngle := 0;
+  FActualAngle:= GetActualAngle;
 end;
 end;
 
 
-function TToolMoveLayer.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
-  ptF: TPointF; rightBtn: boolean): TRect;
-var idx: integer;
+function TToolRotateLayer.MouseChangesTransform(APrevPos, ANewPos: TPointF): boolean;
+var
+  angleDiff, newActualAngle: Single;
 begin
 begin
-  result := EmptyRect;
-  if not handMoving then
+  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
   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;
-  end;
+    FActualAngle:= newActualAngle;
+    result := true;
+  end
+  else result := false;
 end;
 end;
 
 
-function TToolMoveLayer.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
-  ptF: TPointF): TRect;
-var idx: integer;
-  prev: TPoint;
+function TToolRotateLayer.CtrlChangesTransform: boolean;
+var
+  newActualAngle: Single;
 begin
 begin
-  if handMoving and ((handOrigin.X <> pt.X) or (handOrigin.Y <> pt.Y)) then
+  newActualAngle := GetActualAngle;
+  if newActualAngle<>FActualAngle then
   begin
   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;
+    FActualAngle := newActualAngle;
+    result := true;
   end else
   end else
-    result := EmptyRect;
-end;
-
-procedure TToolMoveLayer.DoToolMoveAfter(pt: TPoint; ptF: TPointF);
-begin
-  if handMoving then handOrigin := pt;
+    result := false;
 end;
 end;
 
 
-function TToolMoveLayer.UseOriginal: boolean;
-begin
-  with Manager.Image do
-    result := LayerOriginalDefined[CurrentLayerIndex] and
-              LayerOriginalKnown[CurrentLayerIndex];
-end;
-
-procedure TToolMoveLayer.NeedLayerBounds;
-const
-  VeryBigValue = maxLongInt div 2;
-var
-  idx: Integer;
+function TToolRotateLayer.UpdateTransform: TRect;
 begin
 begin
-  GetAction;
-  idx := Manager.Image.CurrentLayerIndex;
-  if not FLayerBoundsDefined then
+  if (FActualAngle = FPreviousActualAngle) and ((FActualAngle = 0) or (TransformCenter = FPreviousTransformCenter)) then
   begin
   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;
+    result := EmptyRect;
+    exit;
   end;
   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;
+  FPreviousActualAngle := FActualAngle;
+  FPreviousTransformCenter := TransformCenter;
   result := EmptyRect;
   result := EmptyRect;
+  NeedOriginal;
+  Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex] :=
+    AffineMatrixTranslation(TransformCenter.X,TransformCenter.Y)*
+    AffineMatrixRotationDeg(FActualAngle)*
+    AffineMatrixTranslation(-TransformCenter.X,-TransformCenter.Y)*
+    FInitialOriginalMatrix;
 end;
 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;
+constructor TToolRotateLayer.Create(AManager: TToolManager);
 begin
 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);
+  inherited Create(AManager);
+  FAngle:= 0;
+  FPreviousActualAngle := 0;
 end;
 end;
 
 
 initialization
 initialization

+ 18 - 7
lazpaint/utoolphong.pas

@@ -13,28 +13,39 @@ type
 
 
   TToolPhong = class(TVectorialTool)
   TToolPhong = class(TVectorialTool)
   protected
   protected
+    FMatrix: TAffineMatrix;
+    constructor Create(AManager: TToolManager); override;
     procedure ShapeChange({%H-}ASender: TObject; ABounds: TRectF); override;
     procedure ShapeChange({%H-}ASender: TObject; ABounds: TRectF); override;
-    procedure AssignShapeStyle; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
     function CreateShape: TVectorShape; override;
     function CreateShape: TVectorShape; override;
     function SlowShape: boolean; override;
     function SlowShape: boolean; override;
   end;
   end;
 
 
 implementation
 implementation
 
 
-uses ugraph, Graphics, LazPaintType, LCVectorRectShapes;
+uses ugraph, Graphics, LazPaintType, LCVectorRectShapes, BGRATransform;
 
 
 { TToolPhong }
 { TToolPhong }
 
 
+constructor TToolPhong.Create(AManager: TToolManager);
+begin
+  inherited Create(AManager);
+  FMatrix := AffineMatrixIdentity;
+end;
+
 procedure TToolPhong.ShapeChange(ASender: TObject; ABounds: TRectF);
 procedure TToolPhong.ShapeChange(ASender: TObject; ABounds: TRectF);
+var
+  posF: TPointF;
 begin
 begin
-  with (FShape as TPhongShape) do
-    Manager.ToolLightPosition := Point(round(LightPosition.X),round(LightPosition.Y));
+  posF := AffineMatrixInverse(FMatrix)*(FShape as TPhongShape).LightPosition;
+  Manager.ToolLightPosition := posF;
   inherited ShapeChange(ASender, ABounds);
   inherited ShapeChange(ASender, ABounds);
 end;
 end;
 
 
-procedure TToolPhong.AssignShapeStyle;
+procedure TToolPhong.AssignShapeStyle(AMatrix: TAffineMatrix);
 begin
 begin
-  inherited AssignShapeStyle;
+  inherited AssignShapeStyle(AMatrix);
+  FMatrix := AMatrix;
   with (FShape as TPhongShape) do
   with (FShape as TPhongShape) do
   begin
   begin
     if Manager.ToolShapeType = 'RoundRectangle' then ShapeKind:= pskRoundRectangle else
     if Manager.ToolShapeType = 'RoundRectangle' then ShapeKind:= pskRoundRectangle else
@@ -44,7 +55,7 @@ begin
     if Manager.ToolShapeType = 'VerticalCylinder' then ShapeKind := pskVertCylinder else
     if Manager.ToolShapeType = 'VerticalCylinder' then ShapeKind := pskVertCylinder else
     if Manager.ToolShapeType = 'HorizontalCylinder' then ShapeKind := pskHorizCylinder
     if Manager.ToolShapeType = 'HorizontalCylinder' then ShapeKind := pskHorizCylinder
     else ShapeKind := pskRectangle;
     else ShapeKind := pskRectangle;
-    LightPosition := PointF(Manager.ToolLightPosition.X,Manager.ToolLightPosition.Y);
+    LightPosition := AMatrix*Manager.ToolLightPosition;
     ShapeAltitudePercent := Manager.ToolShapeAltitude;
     ShapeAltitudePercent := Manager.ToolShapeAltitude;
     BorderSizePercent:= Manager.ToolShapeBorderSize;
     BorderSizePercent:= Manager.ToolShapeBorderSize;
   end;
   end;

+ 146 - 8
lazpaint/utoolpolygon.pas

@@ -5,13 +5,44 @@ unit UToolPolygon;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, utool, BGRABitmap, BGRABitmapTypes, ULayerAction;
+  Classes, SysUtils, utool, utoolbasic, BGRABitmap, BGRABitmapTypes,
+  LCVectorOriginal, LCLType;
 
 
 const
 const
   EasyBezierMinimumDotProduct = 0.5;
   EasyBezierMinimumDotProduct = 0.5;
 
 
 type
 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;
 
 
+{
   { TToolGenericPolygon }
   { TToolGenericPolygon }
 
 
   TToolGenericPolygon = class(TGenericTool)
   TToolGenericPolygon = class(TGenericTool)
@@ -80,8 +111,6 @@ type
     function FinalPolygonView(toolDest: TBGRABitmap): TRect; override;
     function FinalPolygonView(toolDest: TBGRABitmap): TRect; override;
   end;
   end;
 
 
-  TToolSplineMode = (tsmMovePoint, tsmCurveModeAuto, tsmCurveModeAngle, tsmCurveModeSpline);
-
   { TToolGenericSpline }
   { TToolGenericSpline }
 
 
   TToolGenericSpline = class(TToolGenericPolygon)
   TToolGenericSpline = class(TToolGenericPolygon)
@@ -125,14 +154,123 @@ type
     function GetIsSelectingTool: boolean; override;
     function GetIsSelectingTool: boolean; override;
     function HandDrawingPolygonView(toolDest: TBGRABitmap): TRect; override;
     function HandDrawingPolygonView(toolDest: TBGRABitmap): TRect; override;
     function FinalPolygonView({%H-}toolDest: TBGRABitmap):TRect; override;
     function FinalPolygonView({%H-}toolDest: TBGRABitmap):TRect; override;
-  end;
+  end;}
 
 
 implementation
 implementation
 
 
-uses Types, Graphics, LCLType, ugraph, Dialogs, Controls, LazPaintType,
-  BGRAFillInfo, BGRAPath;
+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;
 
 
-{ TToolGenericSpline }
+{ 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;
+
+{{ TToolGenericSpline }
 
 
 function TToolGenericSpline.GetCurrentMode: TToolSplineMode;
 function TToolGenericSpline.GetCurrentMode: TToolSplineMode;
 begin
 begin
@@ -962,7 +1100,7 @@ begin
   if length(polygonPoints)<>0 then
   if length(polygonPoints)<>0 then
     ValidatePolygon(GetToolDrawingLayer);
     ValidatePolygon(GetToolDrawingLayer);
   inherited Destroy;
   inherited Destroy;
-end;
+end;}
 
 
 initialization
 initialization
 
 

+ 60 - 103
lazpaint/utoolselect.pas

@@ -14,7 +14,7 @@ type
   TVectorialSelectTool = class(TVectorialTool)
   TVectorialSelectTool = class(TVectorialTool)
   protected
   protected
     function GetIsSelectingTool: boolean; override;
     function GetIsSelectingTool: boolean; override;
-    procedure AssignShapeStyle; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
     function RoundCoordinate(ptF: TPointF): TPointF; override;
     function RoundCoordinate(ptF: TPointF): TPointF; override;
     function UpdateShape(toolDest: TBGRABitmap): TRect; override;
     function UpdateShape(toolDest: TBGRABitmap): TRect; override;
     procedure QuickDefineEnd; override;
     procedure QuickDefineEnd; override;
@@ -41,22 +41,18 @@ type
 
 
   { TToolSelectPoly }
   { TToolSelectPoly }
 
 
-  TToolSelectPoly = class(TToolGenericPolygon)
+  TToolSelectPoly = class(TToolPolygon)
   protected
   protected
-    function HandDrawingPolygonView({%H-}toolDest: TBGRABitmap): TRect; override;
-    function FinalPolygonView(toolDest: TBGRABitmap): TRect; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
     function GetIsSelectingTool: boolean; override;
     function GetIsSelectingTool: boolean; override;
-    function GetFillColor: TBGRAPixel; override;
   end;
   end;
 
 
   { TToolSelectSpline }
   { TToolSelectSpline }
 
 
-  TToolSelectSpline = class(TToolGenericSpline)
+  TToolSelectSpline = class(TToolSpline)
   protected
   protected
-    function HandDrawingPolygonView(toolDest: TBGRABitmap): TRect; override;
-    function FinalPolygonView({%H-}toolDest: TBGRABitmap): TRect; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
     function GetIsSelectingTool: boolean; override;
     function GetIsSelectingTool: boolean; override;
-    function GetFillColor: TBGRAPixel; override;
   end;
   end;
 
 
   { TToolMagicWand }
   { TToolMagicWand }
@@ -133,6 +129,52 @@ implementation
 uses types, ugraph, LCLType, LazPaintType, Math, BGRATransform, BGRAPath,
 uses types, ugraph, LCLType, LazPaintType, Math, BGRATransform, BGRAPath,
   BGRAPen, LCVectorRectShapes;
   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 }
 { TVectorialSelectTool }
 
 
 function TVectorialSelectTool.GetIsSelectingTool: boolean;
 function TVectorialSelectTool.GetIsSelectingTool: boolean;
@@ -140,20 +182,9 @@ begin
   Result:= true;
   Result:= true;
 end;
 end;
 
 
-procedure TVectorialSelectTool.AssignShapeStyle;
-var
-  f: TVectorShapeFields;
+procedure TVectorialSelectTool.AssignShapeStyle(AMatrix: TAffineMatrix);
 begin
 begin
-  f:= FShape.Fields;
-  if vsfPenFill in f then FShape.PenFill.Clear;
-  if vsfPenStyle in f Then FShape.PenStyle := ClearPenStyle;
-  if vsfBackFill in f then
-  begin
-    if FSwapColor then
-      FShape.BackFill.SetSolid(BGRABlack)
-    else
-      FShape.BackFill.SetSolid(BGRAWhite);
-  end;
+  AssignSelectShapeStyle(FShape, FSwapColor);
   if FShape is TCustomRectShape then
   if FShape is TCustomRectShape then
   begin
   begin
     if Manager.ToolRatio = 0 then
     if Manager.ToolRatio = 0 then
@@ -177,13 +208,18 @@ begin
 end;
 end;
 
 
 procedure TVectorialSelectTool.QuickDefineEnd;
 procedure TVectorialSelectTool.QuickDefineEnd;
+var
+  toolDest: TBGRABitmap;
+  r: TRect;
 begin
 begin
-  UpdateShape(GetToolDrawingLayer);
+  toolDest := GetToolDrawingLayer;
+  r := UpdateShape(toolDest);
+  Action.NotifyChange(toolDest, r);
 end;
 end;
 
 
 function TVectorialSelectTool.BigImage: boolean;
 function TVectorialSelectTool.BigImage: boolean;
 begin
 begin
-  result := GetToolDrawingLayer.NbPixels > 480000;
+  result := Manager.Image.Width*Manager.Image.Height > 480000;
 end;
 end;
 
 
 { TToolSelectRect }
 { TToolSelectRect }
@@ -465,49 +501,6 @@ begin
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
-{ TToolSelectSpline }
-
-function TToolSelectSpline.HandDrawingPolygonView(toolDest: TBGRABitmap): TRect;
-var
-  splinePoints: ArrayOfTPointF;
-begin
-  if Manager.ToolSplineEasyBezier then
-  begin
-    NeedCurveMode;
-    splinePoints := EasyBezierCurve(polygonPoints,True,FCurveMode,EasyBezierMinimumDotProduct).ToPoints;
-  end else
-    splinePoints := toolDest.ComputeClosedSpline(polygonPoints,Manager.ToolSplineStyle);
-  FRenderedPolygonPoints := splinePoints;
-
-  if length(splinePoints) > 2 then
-  begin
-    toolDest.FillPolyAntialias(splinePoints, fillColor);
-    result := GetShapeBounds(splinePoints,1);
-  end else
-    result := EmptyRect;
-end;
-
-function TToolSelectSpline.FinalPolygonView(toolDest: TBGRABitmap): TRect;
-begin
-  if FAfterHandDrawing then
-    result := HandDrawingPolygonView(toolDest)
-  else
-    result := EmptyRect;
-end;
-
-function TToolSelectSpline.GetIsSelectingTool: boolean;
-begin
-  Result:= true;
-end;
-
-function TToolSelectSpline.GetFillColor: TBGRAPixel;
-begin
-  if swapedColor then
-    result := BGRABlack
-  else
-    result := BGRAWhite;
-end;
-
 { TToolSelectionPen }
 { TToolSelectionPen }
 
 
 function TToolSelectionPen.GetIsSelectingTool: boolean;
 function TToolSelectionPen.GetIsSelectingTool: boolean;
@@ -553,42 +546,6 @@ begin
   ValidateAction;
   ValidateAction;
 end;
 end;
 
 
-{ TToolSelectPoly }
-
-function TToolSelectPoly.HandDrawingPolygonView(toolDest: TBGRABitmap): TRect;
-begin
-  result := EmptyRect;
-  //nothing
-end;
-
-function TToolSelectPoly.FinalPolygonView(toolDest: TBGRABitmap): TRect;
-var
-  i: Integer;
-begin
-  if length(polygonPoints) > 2 then
-  begin
-    toolDest.FillPolyAntialias(polygonPoints, fillColor);
-    result := GetShapeBounds(polygonPoints,1);
-  end else
-    result := EmptyRect;
-  setlength(FRenderedPolygonPoints, length(polygonPoints));
-  for i := 0 to high(polygonPoints) do
-    FRenderedPolygonPoints[i] := polygonPoints[i];
-end;
-
-function TToolSelectPoly.GetIsSelectingTool: boolean;
-begin
-  result := true;
-end;
-
-function TToolSelectPoly.GetFillColor: TBGRAPixel;
-begin
-  if swapedColor then
-    result := BGRABlack
-  else
-    result := BGRAWhite;
-end;
-
 initialization
 initialization
 
 
   RegisterTool(ptMagicWand,TToolMagicWand);
   RegisterTool(ptMagicWand,TToolMagicWand);

+ 30 - 6
lazpaint/utooltext.pas

@@ -14,19 +14,23 @@ type
 
 
   TToolText = class(TVectorialTool)
   TToolText = class(TVectorialTool)
   protected
   protected
+    FMatrix: TAffineMatrix;
     FPrevShadow: boolean;
     FPrevShadow: boolean;
     FPrevShadowOffset: TPoint;
     FPrevShadowOffset: TPoint;
     FPrevShadowRadius: single;
     FPrevShadowRadius: single;
     function CreateShape: TVectorShape; override;
     function CreateShape: TVectorShape; override;
+    function AlwaysRasterizeShape: boolean; override;
     procedure IncludeShadowBounds(var ARect: TRect);
     procedure IncludeShadowBounds(var ARect: TRect);
     function GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; ADraft: boolean): TRect; override;
     function GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; ADraft: boolean): TRect; override;
     procedure DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); override;
     procedure DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); override;
     procedure ShapeChange(ASender: TObject; ABounds: TRectF); override;
     procedure ShapeChange(ASender: TObject; ABounds: TRectF); override;
     procedure ShapeEditingChange(ASender: TObject); override;
     procedure ShapeEditingChange(ASender: TObject); override;
-    procedure AssignShapeStyle; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
     function SlowShape: boolean; override;
     function SlowShape: boolean; override;
     procedure QuickDefineEnd; override;
     procedure QuickDefineEnd; override;
+    function RoundCoordinate(ptF: TPointF): TPointF; override;
   public
   public
+    constructor Create(AManager: TToolManager); override;
     function ToolKeyDown(var key: Word): TRect; override;
     function ToolKeyDown(var key: Word): TRect; override;
     function ToolCopy: boolean; override;
     function ToolCopy: boolean; override;
     function ToolCut: boolean; override;
     function ToolCut: boolean; override;
@@ -48,6 +52,11 @@ begin
   result := TTextShape.Create(nil);
   result := TTextShape.Create(nil);
 end;
 end;
 
 
+function TToolText.AlwaysRasterizeShape: boolean;
+begin
+  Result:= Manager.ToolTextShadow;
+end;
+
 procedure TToolText.IncludeShadowBounds(var ARect: TRect);
 procedure TToolText.IncludeShadowBounds(var ARect: TRect);
 var
 var
   shadowRect: TRect;
   shadowRect: TRect;
@@ -120,9 +129,10 @@ end;
 procedure TToolText.ShapeChange(ASender: TObject; ABounds: TRectF);
 procedure TToolText.ShapeChange(ASender: TObject; ABounds: TRectF);
 var
 var
   r: TRect;
   r: TRect;
+  posF: TPointF;
 begin
 begin
-  with (FShape as TTextShape) do
-    Manager.ToolLightPosition := Point(round(LightPosition.X),round(LightPosition.Y));
+  posF := AffineMatrixInverse(FMatrix)*(FShape as TTextShape).LightPosition;
+  Manager.ToolLightPosition := posF;
   with ABounds do r := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
   with ABounds do r := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
   IncludeShadowBounds(r);
   IncludeShadowBounds(r);
   inherited ShapeChange(ASender, RectF(r.Left,r.Top,r.Right,r.Bottom));
   inherited ShapeChange(ASender, RectF(r.Left,r.Top,r.Right,r.Bottom));
@@ -135,14 +145,17 @@ begin
   inherited ShapeEditingChange(ASender);
   inherited ShapeEditingChange(ASender);
 end;
 end;
 
 
-procedure TToolText.AssignShapeStyle;
+procedure TToolText.AssignShapeStyle(AMatrix: TAffineMatrix);
 var
 var
   r: TRect;
   r: TRect;
   toolDest: TBGRABitmap;
   toolDest: TBGRABitmap;
+  zoom: Single;
 begin
 begin
+  FMatrix := AMatrix;
   with TTextShape(FShape) do
   with TTextShape(FShape) do
   begin
   begin
-    FontEmHeight:= Manager.ToolTextFont.Size*ScreenInfo.PixelsPerInchY/72;
+    zoom := (VectLen(AMatrix[1,1],AMatrix[2,1])+VectLen(AMatrix[1,2],AMatrix[2,2]))/2;
+    FontEmHeight:= zoom*Manager.ToolTextFont.Size*ScreenInfo.PixelsPerInchY/72;
     FontName:= Manager.ToolTextFont.Name;
     FontName:= Manager.ToolTextFont.Name;
     FontStyle:= Manager.ToolTextFont.Style;
     FontStyle:= Manager.ToolTextFont.Style;
 
 
@@ -168,7 +181,7 @@ begin
     else
     else
       OutlineFill.Clear;
       OutlineFill.Clear;
 
 
-    LightPosition := PointF(Manager.ToolLightPosition.X,Manager.ToolLightPosition.Y);
+    LightPosition := AMatrix*Manager.ToolLightPosition;
     AltitudePercent:= Manager.ToolShapeAltitude;
     AltitudePercent:= Manager.ToolShapeAltitude;
     ParagraphAlignment:= Manager.ToolTextAlign;
     ParagraphAlignment:= Manager.ToolTextAlign;
     PenPhong := Manager.ToolTextPhong;
     PenPhong := Manager.ToolTextPhong;
@@ -193,6 +206,17 @@ begin
   FShape.Usermode := vsuEditText;
   FShape.Usermode := vsuEditText;
 end;
 end;
 
 
+function TToolText.RoundCoordinate(ptF: TPointF): TPointF;
+begin
+  result := PointF(floor(ptF.x)+0.5,floor(ptF.y)+0.5);
+end;
+
+constructor TToolText.Create(AManager: TToolManager);
+begin
+  inherited Create(AManager);
+  FMatrix := AffineMatrixIdentity;
+end;
+
 function TToolText.ToolKeyDown(var key: Word): TRect;
 function TToolText.ToolKeyDown(var key: Word): TRect;
 var
 var
   keyUtf8: TUTF8Char;
   keyUtf8: TUTF8Char;

+ 52 - 17
lazpaintcontrols/lcvectororiginal.pas

@@ -57,8 +57,6 @@ type
     procedure SetId(AValue: integer);
     procedure SetId(AValue: integer);
     procedure SetOutlineWidth(AValue: single);
     procedure SetOutlineWidth(AValue: single);
   protected
   protected
-    procedure BeginUpdate;
-    procedure EndUpdate;
     procedure BeginEditingUpdate;
     procedure BeginEditingUpdate;
     procedure EndEditingUpdate;
     procedure EndEditingUpdate;
     procedure DoOnChange(ABoundsBefore: TRectF); virtual;
     procedure DoOnChange(ABoundsBefore: TRectF); virtual;
@@ -79,7 +77,7 @@ type
     procedure SetUsermode(AValue: TVectorShapeUsermode); virtual;
     procedure SetUsermode(AValue: TVectorShapeUsermode); virtual;
     procedure LoadFill(AStorage: TBGRACustomOriginalStorage; AObjectName: string; var AValue: TVectorialFill);
     procedure LoadFill(AStorage: TBGRACustomOriginalStorage; AObjectName: string; var AValue: TVectorialFill);
     procedure SaveFill(AStorage: TBGRACustomOriginalStorage; AObjectName: string; AValue: TVectorialFill);
     procedure SaveFill(AStorage: TBGRACustomOriginalStorage; AObjectName: string; AValue: TVectorialFill);
-    function ComputeStroke(APoints: ArrayOfTPointF; AClosed: boolean; AStrokeMatrix: TAffineMatrix): ArrayOfTPointF;
+    function ComputeStroke(APoints: ArrayOfTPointF; AClosed: boolean; AStrokeMatrix: TAffineMatrix): ArrayOfTPointF; virtual;
     function GetStroker: TBGRAPenStroker;
     function GetStroker: TBGRAPenStroker;
     property Stroker: TBGRAPenStroker read GetStroker;
     property Stroker: TBGRAPenStroker read GetStroker;
     procedure FillChange({%H-}ASender: TObject); virtual;
     procedure FillChange({%H-}ASender: TObject); virtual;
@@ -89,7 +87,10 @@ type
     function CanHaveRenderStorage: boolean;
     function CanHaveRenderStorage: boolean;
   public
   public
     constructor Create(AContainer: TVectorOriginal); virtual;
     constructor Create(AContainer: TVectorOriginal); virtual;
+    class function CreateFromStorage(AStorage: TBGRACustomOriginalStorage; AContainer: TVectorOriginal): TVectorShape;
     destructor Destroy; override;
     destructor Destroy; override;
+    procedure BeginUpdate;
+    procedure EndUpdate;
     procedure QuickDefine(const APoint1,APoint2: TPointF); virtual; abstract;
     procedure QuickDefine(const APoint1,APoint2: TPointF); virtual; abstract;
     //one of the two Render functions must be overriden
     //one of the two Render functions must be overriden
     procedure Render(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); virtual;
     procedure Render(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); virtual;
@@ -116,6 +117,7 @@ type
     class function StorageClassName: RawByteString; virtual; abstract;
     class function StorageClassName: RawByteString; virtual; abstract;
     function GetIsSlow({%H-}AMatrix: TAffineMatrix): boolean; virtual;
     function GetIsSlow({%H-}AMatrix: TAffineMatrix): boolean; virtual;
     function GetUsedTextures: ArrayOfBGRABitmap;
     function GetUsedTextures: ArrayOfBGRABitmap;
+    procedure Transform(AMatrix: TAffineMatrix); virtual;
     class function Fields: TVectorShapeFields; virtual;
     class function Fields: TVectorShapeFields; virtual;
     class function Usermodes: TVectorShapeUsermodes; virtual;
     class function Usermodes: TVectorShapeUsermodes; virtual;
     class function PreferPixelCentered: boolean; virtual;
     class function PreferPixelCentered: boolean; virtual;
@@ -531,6 +533,20 @@ begin
   setlength(result, nb);
   setlength(result, nb);
 end;
 end;
 
 
+procedure TVectorShape.Transform(AMatrix: TAffineMatrix);
+var
+  zoom: Single;
+begin
+  if IsAffineMatrixIdentity(AMatrix) then exit;
+  BeginUpdate;
+  if vsfBackFill in Fields then BackFill.Transform(AMatrix);
+  if vsfPenFill in Fields then PenFill.Transform(AMatrix);
+  zoom := (VectLen(AMatrix[1,1],AMatrix[2,1])+VectLen(AMatrix[1,2],AMatrix[2,2]))/2;
+  if vsfPenWidth in Fields then PenWidth := zoom*PenWidth;
+  if vsfOutlineFill in Fields then OutlineWidth := zoom*OutlineWidth;
+  EndUpdate;
+end;
+
 class function TVectorShape.Fields: TVectorShapeFields;
 class function TVectorShape.Fields: TVectorShapeFields;
 begin
 begin
   result := [];
   result := [];
@@ -855,7 +871,7 @@ begin
   if FStroker = nil then
   if FStroker = nil then
   begin
   begin
     FStroker := TBGRAPenStroker.Create;
     FStroker := TBGRAPenStroker.Create;
-    FStroker.MiterLimit:= sqrt(2);
+    FStroker.MiterLimit:= 2;
   end;
   end;
   result := FStroker;
   result := FStroker;
 end;
 end;
@@ -983,6 +999,20 @@ begin
   FRenderIteration:= 0;
   FRenderIteration:= 0;
 end;
 end;
 
 
+class function TVectorShape.CreateFromStorage(
+  AStorage: TBGRACustomOriginalStorage; AContainer: TVectorOriginal): TVectorShape;
+var
+  objClassName: RawByteString;
+  shapeClass: TVectorShapeAny;
+begin
+  objClassName := AStorage.RawString['class'];
+  if objClassName = '' then raise exception.Create('Shape class not defined');
+  shapeClass:= GetVectorShapeByStorageClassName(objClassName);
+  if shapeClass = nil then raise exception.Create('Unknown shape class "'+objClassName+'"');
+  result := shapeClass.Create(AContainer);
+  result.LoadFromStorage(AStorage);
+end;
+
 destructor TVectorShape.Destroy;
 destructor TVectorShape.Destroy;
 begin
 begin
   FreeAndNil(FStroker);
   FreeAndNil(FStroker);
@@ -1536,6 +1566,8 @@ procedure TVectorOriginal.Render(ADest: TBGRABitmap; ARenderOffset: TPoint; AMat
 var
 var
   i: Integer;
   i: Integer;
   idxSelected: LongInt;
   idxSelected: LongInt;
+  clipRectF,allRectF: TRectF;
+  mOfs: TAffineMatrix;
 begin
 begin
   if AMatrix <> FFrozenShapeMatrix then DiscardFrozenShapes;
   if AMatrix <> FFrozenShapeMatrix then DiscardFrozenShapes;
   idxSelected := FShapes.IndexOf(FSelectedShape);
   idxSelected := FShapes.IndexOf(FSelectedShape);
@@ -1544,12 +1576,16 @@ begin
     FSelectedShape := nil;
     FSelectedShape := nil;
     DiscardFrozenShapes;
     DiscardFrozenShapes;
   end;
   end;
+  with ADest.ClipRect do
+    clipRectF := RectF(Left,Top,Right,Bottom);
+  mOfs := AffineMatrixTranslation(ARenderOffset.X,ARenderOffset.Y)*AMatrix;
   if FFrozenShapesComputed then
   if FFrozenShapesComputed then
   begin
   begin
     ADest.PutImage(ARenderOffset.X-FFrozenShapesRenderOffset.X,
     ADest.PutImage(ARenderOffset.X-FFrozenShapesRenderOffset.X,
                    ARenderOffset.Y-FFrozenShapesRenderOffset.Y,
                    ARenderOffset.Y-FFrozenShapesRenderOffset.Y,
                    FFrozenShapesUnderSelection, dmSet);
                    FFrozenShapesUnderSelection, dmSet);
-    FSelectedShape.Render(ADest, ARenderOffset, AMatrix, ADraft);
+    if FSelectedShape.GetRenderBounds(ADest.ClipRect, mOfs, []).IntersectsWith(clipRectF) then
+      FSelectedShape.Render(ADest, ARenderOffset, AMatrix, ADraft);
     ADest.PutImage(ARenderOffset.X-FFrozenShapesRenderOffset.X,
     ADest.PutImage(ARenderOffset.X-FFrozenShapesRenderOffset.X,
                    ARenderOffset.Y-FFrozenShapesRenderOffset.Y,
                    ARenderOffset.Y-FFrozenShapesRenderOffset.Y,
                    FFrozenShapesOverSelection, dmDrawWithTransparency);
                    FFrozenShapesOverSelection, dmDrawWithTransparency);
@@ -1557,21 +1593,25 @@ begin
   begin
   begin
     if idxSelected <> -1 then
     if idxSelected <> -1 then
     begin
     begin
+      allRectF := rectF(0,0,ADest.Width,ADest.Height);
       if idxSelected > 0 then
       if idxSelected > 0 then
       begin
       begin
         FreeAndNil(FFrozenShapesUnderSelection);
         FreeAndNil(FFrozenShapesUnderSelection);
         FFrozenShapesUnderSelection := TBGRABitmap.Create(ADest.Width,ADest.Height);
         FFrozenShapesUnderSelection := TBGRABitmap.Create(ADest.Width,ADest.Height);
         for i:= 0 to idxSelected-1 do
         for i:= 0 to idxSelected-1 do
-          FShapes[i].Render(FFrozenShapesUnderSelection, ARenderOffset, AMatrix, false);
+          if FShapes[i].GetRenderBounds(rect(0,0,ADest.Width,ADest.Height), mOfs, []).IntersectsWith(allRectF) then
+            FShapes[i].Render(FFrozenShapesUnderSelection, ARenderOffset, AMatrix, false);
         ADest.PutImage(0,0,FFrozenShapesUnderSelection, dmSet);
         ADest.PutImage(0,0,FFrozenShapesUnderSelection, dmSet);
       end;
       end;
-      FSelectedShape.Render(ADest, ARenderOffset, AMatrix, ADraft);
+      if FSelectedShape.GetRenderBounds(ADest.ClipRect, mOfs, []).IntersectsWith(clipRectF) then
+        FSelectedShape.Render(ADest, ARenderOffset, AMatrix, ADraft);
       if idxSelected < FShapes.Count-1 then
       if idxSelected < FShapes.Count-1 then
       begin
       begin
         FreeAndNil(FFrozenShapesOverSelection);
         FreeAndNil(FFrozenShapesOverSelection);
         FFrozenShapesOverSelection := TBGRABitmap.Create(ADest.Width,ADest.Height);
         FFrozenShapesOverSelection := TBGRABitmap.Create(ADest.Width,ADest.Height);
         for i:= idxSelected+1 to FShapes.Count-1 do
         for i:= idxSelected+1 to FShapes.Count-1 do
-          FShapes[i].Render(FFrozenShapesOverSelection, ARenderOffset, AMatrix, false);
+          if FShapes[i].GetRenderBounds(rect(0,0,ADest.Width,ADest.Height), mOfs, []).IntersectsWith(allRectF) then
+            FShapes[i].Render(FFrozenShapesOverSelection, ARenderOffset, AMatrix, false);
         ADest.PutImage(0,0,FFrozenShapesOverSelection, dmDrawWithTransparency);
         ADest.PutImage(0,0,FFrozenShapesOverSelection, dmDrawWithTransparency);
       end;
       end;
       FFrozenShapesRenderOffset := ARenderOffset;
       FFrozenShapesRenderOffset := ARenderOffset;
@@ -1580,7 +1620,8 @@ begin
     end else
     end else
     begin
     begin
       for i:= 0 to FShapes.Count-1 do
       for i:= 0 to FShapes.Count-1 do
-        FShapes[i].Render(ADest, ARenderOffset, AMatrix, ADraft);
+        if FShapes[i].GetRenderBounds(ADest.ClipRect, mOfs, []).IntersectsWith(clipRectF) then
+          FShapes[i].Render(ADest, ARenderOffset, AMatrix, ADraft);
     end;
     end;
   end;
   end;
   DiscardUnusedRenderStorage;
   DiscardUnusedRenderStorage;
@@ -1651,8 +1692,7 @@ var
   nb: LongInt;
   nb: LongInt;
   i: Integer;
   i: Integer;
   shapeObj, texObj: TBGRACustomOriginalStorage;
   shapeObj, texObj: TBGRACustomOriginalStorage;
-  objClassName, texName: String;
-  shapeClass: TVectorShapeAny;
+  texName: String;
   loadedShape: TVectorShape;
   loadedShape: TVectorShape;
   idList: array of single;
   idList: array of single;
   mem: TMemoryStream;
   mem: TMemoryStream;
@@ -1694,12 +1734,7 @@ begin
     shapeObj := AStorage.OpenObject('shape'+inttostr(i+1));
     shapeObj := AStorage.OpenObject('shape'+inttostr(i+1));
     if shapeObj <> nil then
     if shapeObj <> nil then
     try
     try
-      objClassName := shapeObj.RawString['class'];
-      if objClassName = '' then raise exception.Create('Shape class not defined');
-      shapeClass:= GetVectorShapeByStorageClassName(objClassName);
-      if shapeClass = nil then raise exception.Create('Unknown shape class "'+objClassName+'"');
-      loadedShape := shapeClass.Create(self);
-      loadedShape.LoadFromStorage(shapeObj);
+      loadedShape := TVectorShape.CreateFromStorage(shapeObj, self);
       loadedShape.OnChange := @OnShapeChange;
       loadedShape.OnChange := @OnShapeChange;
       loadedShape.OnEditingChange := @OnShapeEditingChange;
       loadedShape.OnEditingChange := @OnShapeEditingChange;
       if loadedShape.Id > FLastShapeId then FLastShapeId := loadedShape.Id;
       if loadedShape.Id > FLastShapeId then FLastShapeId := loadedShape.Id;

+ 174 - 10
lazpaintcontrols/lcvectorpolyshapes.pas

@@ -8,6 +8,19 @@ uses
   Classes, SysUtils, Types, LCVectorOriginal, BGRABitmapTypes, BGRALayerOriginal,
   Classes, SysUtils, Types, LCVectorOriginal, BGRABitmapTypes, BGRALayerOriginal,
   BGRABitmap, BGRATransform, BGRAGradients;
   BGRABitmap, BGRATransform, BGRAGradients;
 
 
+type
+  TArrowKind = (akNone, akTail, akTip, akNormal, akCut, akFlipped, akFlippedCut,
+                akTriangle, akTriangleBack1, akTriangleBack2,
+                akHollowTriangle, akHollowTriangleBack1, akHollowTriangleBack2);
+
+const
+  ArrowKindToStr: array[TArrowKind] of string =
+    ('none', 'tail', 'tip', 'normal', 'cut', 'flipped', 'flipped-cut',
+     'triangle', 'triangle-back1', 'triangle-back2',
+     'hollow-triangle', 'hollow-triangle-back1', 'hollow-triangle-back2');
+
+function StrToArrowKind(AStr: string): TArrowKind;
+
 type
 type
   { TCustomPolypointShape }
   { TCustomPolypointShape }
 
 
@@ -16,6 +29,9 @@ type
     FClosed: boolean;
     FClosed: boolean;
     function GetPoint(AIndex: integer): TPointF;
     function GetPoint(AIndex: integer): TPointF;
     function GetPointCount: integer;
     function GetPointCount: integer;
+    procedure SetArrowEndKind(AValue: TArrowKind);
+    procedure SetArrowSize(AValue: TPointF);
+    procedure SetArrowStartKind(AValue: TArrowKind);
     procedure SetPoint(AIndex: integer; AValue: TPointF);
     procedure SetPoint(AIndex: integer; AValue: TPointF);
   protected
   protected
     FPoints: array of record
     FPoints: array of record
@@ -29,6 +45,8 @@ type
     FAddingPoint: boolean;
     FAddingPoint: boolean;
     FMousePos: TPointF;
     FMousePos: TPointF;
     FHoverPoint: integer;
     FHoverPoint: integer;
+    FArrowStartKind,FArrowEndKind: TArrowKind;
+    FArrowSize: TPointF;
     procedure OnMovePoint({%H-}ASender: TObject; {%H-}APrevCoord, ANewCoord: TPointF; {%H-}AShift: TShiftState);
     procedure OnMovePoint({%H-}ASender: TObject; {%H-}APrevCoord, ANewCoord: TPointF; {%H-}AShift: TShiftState);
     procedure OnMoveCenterPoint({%H-}ASender: TObject; {%H-}APrevCoord, ANewCoord: TPointF; {%H-}AShift: TShiftState);
     procedure OnMoveCenterPoint({%H-}ASender: TObject; {%H-}APrevCoord, ANewCoord: TPointF; {%H-}AShift: TShiftState);
     procedure OnStartMove({%H-}ASender: TObject; APointIndex: integer; {%H-}AShift: TShiftState);
     procedure OnStartMove({%H-}ASender: TObject; APointIndex: integer; {%H-}AShift: TShiftState);
@@ -42,11 +60,13 @@ type
     procedure DoClickPoint({%H-}APointIndex: integer; {%H-}AShift: TShiftState); virtual;
     procedure DoClickPoint({%H-}APointIndex: integer; {%H-}AShift: TShiftState); virtual;
     function CanMovePoints: boolean; virtual;
     function CanMovePoints: boolean; virtual;
     procedure InsertPointAuto;
     procedure InsertPointAuto;
+    function ComputeStroke(APoints: ArrayOfTPointF; AClosed: boolean;
+      AStrokeMatrix: TAffineMatrix): ArrayOfTPointF; override;
   public
   public
     constructor Create(AContainer: TVectorOriginal); override;
     constructor Create(AContainer: TVectorOriginal); override;
     procedure Clear;
     procedure Clear;
     destructor Destroy; override;
     destructor Destroy; override;
-    function AddPoint(const APoint: TPointF): integer;
+    function AddPoint(const APoint: TPointF): integer; virtual;
     function RemovePoint(AIndex: integer): boolean;
     function RemovePoint(AIndex: integer): boolean;
     procedure RemovePointRange(AFromIndex, AToIndexPlus1: integer);
     procedure RemovePointRange(AFromIndex, AToIndexPlus1: integer);
     procedure InsertPoint(AIndex: integer; APoint: TPointF);
     procedure InsertPoint(AIndex: integer; APoint: TPointF);
@@ -57,11 +77,16 @@ type
     procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure ConfigureCustomEditor(AEditor: TBGRAOriginalEditor); override;
     procedure ConfigureCustomEditor(AEditor: TBGRAOriginalEditor); override;
+    procedure Transform(AMatrix: TAffineMatrix); override;
     class function Usermodes: TVectorShapeUsermodes; override;
     class function Usermodes: TVectorShapeUsermodes; override;
+    class function DefaultArrowSize: TPointF;
     property Points[AIndex:integer]: TPointF read GetPoint write SetPoint;
     property Points[AIndex:integer]: TPointF read GetPoint write SetPoint;
     property PointCount: integer read GetPointCount;
     property PointCount: integer read GetPointCount;
     property Closed: boolean read GetClosed write SetClosed;
     property Closed: boolean read GetClosed write SetClosed;
     property HoverPoint: integer read FHoverPoint;
     property HoverPoint: integer read FHoverPoint;
+    property ArrowStartKind: TArrowKind read FArrowStartKind write SetArrowStartKind;
+    property ArrowEndKind: TArrowKind read FArrowEndKind write SetArrowEndKind;
+    property ArrowSize: TPointF read FArrowSize write SetArrowSize;
   end;
   end;
 
 
   { TPolylineShape }
   { TPolylineShape }
@@ -83,8 +108,10 @@ type
 
 
   TCurveShape = class(TPolylineShape)
   TCurveShape = class(TPolylineShape)
   private
   private
+    FCosineAngle: single;
     FSplineStyle: TSplineStyle;
     FSplineStyle: TSplineStyle;
     function GetCurveMode(AIndex: integer): TEasyBezierCurveMode;
     function GetCurveMode(AIndex: integer): TEasyBezierCurveMode;
+    procedure SetCosineAngle(AValue: single);
     procedure SetCurveMode(AIndex: integer; AValue: TEasyBezierCurveMode);
     procedure SetCurveMode(AIndex: integer; AValue: TEasyBezierCurveMode);
     procedure SetSplineStyle(AValue: TSplineStyle);
     procedure SetSplineStyle(AValue: TSplineStyle);
   protected
   protected
@@ -94,17 +121,55 @@ type
   public
   public
     class function Usermodes: TVectorShapeUsermodes; override;
     class function Usermodes: TVectorShapeUsermodes; override;
     constructor Create(AContainer: TVectorOriginal); override;
     constructor Create(AContainer: TVectorOriginal); override;
+    function AddPoint(const APoint: TPointF): integer; override;
     procedure KeyPress(UTF8Key: string; var AHandled: boolean); override;
     procedure KeyPress(UTF8Key: string; var AHandled: boolean); override;
     procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); override;
     class function StorageClassName: RawByteString; override;
     class function StorageClassName: RawByteString; override;
     property SplineStyle: TSplineStyle read FSplineStyle write SetSplineStyle;
     property SplineStyle: TSplineStyle read FSplineStyle write SetSplineStyle;
     property CurveMode[AIndex: integer]: TEasyBezierCurveMode read GetCurveMode write SetCurveMode;
     property CurveMode[AIndex: integer]: TEasyBezierCurveMode read GetCurveMode write SetCurveMode;
+    property CosineAngle: single read FCosineAngle write SetCosineAngle;
   end;
   end;
 
 
+procedure ApplyArrowStyle(AArrow: TBGRACustomArrow; AStart: boolean; AKind: TArrowKind; ASize: TPointF);
+
 implementation
 implementation
 
 
-uses BGRAPen, BGRAGraphics, BGRAFillInfo, BGRAPath, math, LCVectorialFill;
+uses BGRAPen, BGRAGraphics, BGRAFillInfo, BGRAPath, math, LCVectorialFill,
+  BGRAArrow;
+
+function StrToArrowKind(AStr: string): TArrowKind;
+var
+  ak: TArrowKind;
+begin
+  for ak := low(TArrowKind) to high(TArrowKind) do
+    if CompareText(AStr, ArrowKindToStr[ak])=0 then exit(ak);
+  result := akNone;
+end;
+
+procedure ApplyArrowStyle(AArrow: TBGRACustomArrow; AStart: boolean; AKind: TArrowKind; ASize: TPointF);
+var backOfs: single;
+begin
+  backOfs := 0;
+  if (ASize.x = 0) or (ASize.y = 0) then AKind := akNone;
+  if AKind in[akTriangleBack1,akHollowTriangleBack1] then backOfs := 0.25;
+  if AKind in[akTriangleBack2,akHollowTriangleBack2] then backOfs := 0.50;
+  case AKind of
+  akTail: if AStart then AArrow.StartAsTail else AArrow.EndAsTail;
+  akTip: if AStart then AArrow.StartAsTriangle else AArrow.EndAsTriangle;
+  akNormal,akCut,akFlipped,akFlippedCut:
+    if AStart then AArrow.StartAsClassic(AKind in[akFlipped,akFlippedCut], AKind in[akCut,akFlippedCut])
+    else AArrow.EndAsClassic(AKind in[akFlipped,akFlippedCut], AKind in[akCut,akFlippedCut]);
+  akTriangle,akTriangleBack1,akTriangleBack2:
+    if AStart then AArrow.StartAsTriangle(backOfs) else AArrow.EndAsTriangle(backOfs);
+  akHollowTriangle,akHollowTriangleBack1,akHollowTriangleBack2:
+    if AStart then AArrow.StartAsTriangle(backOfs,False,True) else AArrow.EndAsTriangle(backOfs,False,True);
+  else if AStart then AArrow.StartAsNone else AArrow.EndAsNone;
+  end;
+  if (AKind = akTip) and not ((ASize.x = 0) or (ASize.y = 0)) then
+    ASize := ASize*(0.5/ASize.y);
+  if AStart then AArrow.StartSize := ASize else AArrow.EndSize := ASize;
+end;
 
 
 procedure IncludePointF(var ARectF: TRectF; APointF: TPointF);
 procedure IncludePointF(var ARectF: TRectF; APointF: TPointF);
 begin
 begin
@@ -153,6 +218,30 @@ begin
   result:= length(FPoints);
   result:= length(FPoints);
 end;
 end;
 
 
+procedure TCustomPolypointShape.SetArrowEndKind(AValue: TArrowKind);
+begin
+  if FArrowEndKind=AValue then Exit;
+  BeginUpdate;
+  FArrowEndKind:=AValue;
+  EndUpdate;
+end;
+
+procedure TCustomPolypointShape.SetArrowSize(AValue: TPointF);
+begin
+  if FArrowSize=AValue then Exit;
+  BeginUpdate;
+  FArrowSize:=AValue;
+  EndUpdate;
+end;
+
+procedure TCustomPolypointShape.SetArrowStartKind(AValue: TArrowKind);
+begin
+  if FArrowStartKind=AValue then Exit;
+  BeginUpdate;
+  FArrowStartKind:=AValue;
+  EndUpdate;
+end;
+
 procedure TCustomPolypointShape.SetClosed(AValue: boolean);
 procedure TCustomPolypointShape.SetClosed(AValue: boolean);
 begin
 begin
   if AValue = FClosed then exit;
   if AValue = FClosed then exit;
@@ -234,6 +323,11 @@ begin
   Result:= inherited Usermodes + [vsuCreate];
   Result:= inherited Usermodes + [vsuCreate];
 end;
 end;
 
 
+class function TCustomPolypointShape.DefaultArrowSize: TPointF;
+begin
+  result := PointF(2,2);
+end;
+
 procedure TCustomPolypointShape.SetUsermode(AValue: TVectorShapeUsermode);
 procedure TCustomPolypointShape.SetUsermode(AValue: TVectorShapeUsermode);
 var
 var
   add: Boolean;
   add: Boolean;
@@ -355,6 +449,21 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TCustomPolypointShape.ComputeStroke(APoints: ArrayOfTPointF;
+  AClosed: boolean; AStrokeMatrix: TAffineMatrix): ArrayOfTPointF;
+begin
+  if Stroker.Arrow = nil then
+  begin
+    Stroker.Arrow := TBGRAArrow.Create;
+    Stroker.ArrowOwned:= true;
+  end;
+  ApplyArrowStyle(Stroker.Arrow, true, ArrowStartKind, ArrowSize);
+  ApplyArrowStyle(Stroker.Arrow, false, ArrowEndKind, ArrowSize);
+  Result:=inherited ComputeStroke(APoints, AClosed, AStrokeMatrix);
+  Stroker.Arrow.StartAsNone;
+  Stroker.Arrow.EndAsNone;
+end;
+
 constructor TCustomPolypointShape.Create(AContainer: TVectorOriginal);
 constructor TCustomPolypointShape.Create(AContainer: TVectorOriginal);
 begin
 begin
   inherited Create(AContainer);
   inherited Create(AContainer);
@@ -434,7 +543,10 @@ begin
   FMousePos := PointF(X,Y);
   FMousePos := PointF(X,Y);
   if FAddingPoint then
   if FAddingPoint then
   begin
   begin
-    Points[PointCount-1] := FMousePos;
+    if (PointCount = 1) and (FMousePos <> Points[PointCount-1]) then
+      Points[PointCount] := FMousePos
+    else
+      Points[PointCount-1] := FMousePos;
     AHandled:= true;
     AHandled:= true;
   end;
   end;
 end;
 end;
@@ -513,6 +625,11 @@ begin
     FPoints[i].data := nil;
     FPoints[i].data := nil;
   end;
   end;
   FClosed:= AStorage.Bool['closed'];
   FClosed:= AStorage.Bool['closed'];
+  if AStorage.HasAttribute('arrow-size') then
+    FArrowSize := AStorage.PointF['arrow-size']
+  else FArrowSize := DefaultArrowSize;
+  FArrowStartKind:= StrToArrowKind(AStorage.RawString['arrow-start-kind']);
+  FArrowEndKind:= StrToArrowKind(AStorage.RawString['arrow-end-kind']);
   EndUpdate;
   EndUpdate;
 end;
 end;
 
 
@@ -532,6 +649,12 @@ begin
   AStorage.FloatArray['x'] := x;
   AStorage.FloatArray['x'] := x;
   AStorage.FloatArray['y'] := y;
   AStorage.FloatArray['y'] := y;
   AStorage.Bool['closed'] := Closed;
   AStorage.Bool['closed'] := Closed;
+  if ArrowStartKind=akNone then AStorage.RemoveAttribute('arrow-start-kind')
+  else AStorage.RawString['arrow-start-kind'] := ArrowKindToStr[ArrowStartKind];
+  if ArrowEndKind=akNone then AStorage.RemoveAttribute('arrow-end-kind')
+  else AStorage.RawString['arrow-end-kind'] := ArrowKindToStr[ArrowEndKind];
+  if (ArrowStartKind=akNone) and (ArrowEndKind=akNone) then AStorage.RemoveAttribute('arrow-size')
+  else AStorage.PointF['arrow-size'] := FArrowSize;
 end;
 end;
 
 
 procedure TCustomPolypointShape.ConfigureCustomEditor(AEditor: TBGRAOriginalEditor);
 procedure TCustomPolypointShape.ConfigureCustomEditor(AEditor: TBGRAOriginalEditor);
@@ -546,7 +669,7 @@ begin
   for i:= 0 to PointCount-1 do
   for i:= 0 to PointCount-1 do
     if isEmptyPointF(Points[i]) then
     if isEmptyPointF(Points[i]) then
       FPoints[i].editorIndex := -1
       FPoints[i].editorIndex := -1
-    else if (FAddingPoint and ((i = 0) or (i = PointCount-1))) then
+    else if (FAddingPoint and (i = PointCount-1)) then
     begin
     begin
       FPoints[i].editorIndex := -1;
       FPoints[i].editorIndex := -1;
       FCenterPoint += Points[i];
       FCenterPoint += Points[i];
@@ -569,6 +692,17 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TCustomPolypointShape.Transform(AMatrix: TAffineMatrix);
+var
+  i: Integer;
+begin
+  BeginUpdate;
+  inherited Transform(AMatrix);
+  for i := 0 to PointCount-1 do
+    FPoints[i].coord := AMatrix*FPoints[i].coord;
+  EndUpdate;
+end;
+
 { TPolylineShape }
 { TPolylineShape }
 
 
 function TPolylineShape.PenVisible(AAssumePenFill: boolean): boolean;
 function TPolylineShape.PenVisible(AAssumePenFill: boolean): boolean;
@@ -648,7 +782,7 @@ begin
     pts := GetCurve(AMatrix);
     pts := GetCurve(AMatrix);
     if PenVisible(rboAssumePenFill in AOptions) then
     if PenVisible(rboAssumePenFill in AOptions) then
     begin
     begin
-      if JoinStyle = pjsRound then
+      if (JoinStyle = pjsRound) and (ArrowStartKind = akNone) and (ArrowEndKind = akNone) then
       begin
       begin
         xMargin := (abs(AMatrix[1,1])+abs(AMatrix[1,2]))*PenWidth*0.5;
         xMargin := (abs(AMatrix[1,1])+abs(AMatrix[1,2]))*PenWidth*0.5;
         yMargin := (abs(AMatrix[2,1])+abs(AMatrix[2,2]))*PenWidth*0.5;
         yMargin := (abs(AMatrix[2,1])+abs(AMatrix[2,2]))*PenWidth*0.5;
@@ -716,6 +850,14 @@ begin
     result := cmAuto;
     result := cmAuto;
 end;
 end;
 
 
+procedure TCurveShape.SetCosineAngle(AValue: single);
+begin
+  if FCosineAngle=AValue then Exit;
+  BeginUpdate;
+  FCosineAngle:=AValue;
+  EndUpdate;
+end;
+
 procedure TCurveShape.SetCurveMode(AIndex: integer; AValue: TEasyBezierCurveMode);
 procedure TCurveShape.SetCurveMode(AIndex: integer; AValue: TEasyBezierCurveMode);
 begin
 begin
   if (AIndex < 0) or (AIndex >= PointCount) then exit;
   if (AIndex < 0) or (AIndex >= PointCount) then exit;
@@ -739,7 +881,7 @@ begin
     setlength(cm, PointCount);
     setlength(cm, PointCount);
     for i := 0 to PointCount-1 do
     for i := 0 to PointCount-1 do
       cm[i] := CurveMode[i];
       cm[i] := CurveMode[i];
-    eb := EasyBezierCurve(pts, Closed, cm);
+    eb := EasyBezierCurve(pts, Closed, cm, CosineAngle);
     result := eb.ToPoints;
     result := eb.ToPoints;
   end else
   end else
   begin
   begin
@@ -775,23 +917,43 @@ begin
   FSplineStyle:= ssEasyBezier;
   FSplineStyle:= ssEasyBezier;
 end;
 end;
 
 
+function TCurveShape.AddPoint(const APoint: TPointF): integer;
+begin
+  if (PointCount > 1) and (APoint = Points[PointCount-1]) then
+  begin
+    BeginUpdate;
+    CurveMode[PointCount-1] := CurveMode[PointCount-2];
+    Result:=inherited AddPoint(APoint);
+    EndUpdate;
+  end
+  else Result:=inherited AddPoint(APoint);
+end;
+
 procedure TCurveShape.KeyPress(UTF8Key: string; var AHandled: boolean);
 procedure TCurveShape.KeyPress(UTF8Key: string; var AHandled: boolean);
+var
+  targetPoint: Integer;
 begin
 begin
-  if (FHoverPoint >= 0) and (FHoverPoint < PointCount) then
+  if FHoverPoint<>-1 then
+    targetPoint := FHoverPoint
+  else if FAddingPoint and (PointCount > 1) then
+    targetPoint := PointCount-2
+  else
+    targetPoint := -1;
+  if (targetPoint >= 0) and (targetPoint < PointCount) then
   begin
   begin
     if (UTF8Key = 'A') or (UTF8Key = 'a') then
     if (UTF8Key = 'A') or (UTF8Key = 'a') then
     begin
     begin
-      CurveMode[FHoverPoint] := cmAuto;
+      CurveMode[targetPoint] := cmAuto;
       AHandled := true;
       AHandled := true;
     end else
     end else
     if (UTF8Key = 'S') or (UTF8Key = 's') then
     if (UTF8Key = 'S') or (UTF8Key = 's') then
     begin
     begin
-      CurveMode[FHoverPoint] := cmCurve;
+      CurveMode[targetPoint] := cmCurve;
       AHandled:= true;
       AHandled:= true;
     end else
     end else
     if (UTF8Key = 'X') or (UTF8Key = 'x') then
     if (UTF8Key = 'X') or (UTF8Key = 'x') then
     begin
     begin
-      CurveMode[FHoverPoint] := cmAngle;
+      CurveMode[targetPoint] := cmAngle;
       AHandled:= true;
       AHandled:= true;
     end;
     end;
   end;
   end;
@@ -829,6 +991,7 @@ begin
       for i:= length(cm) to PointCount-1 do
       for i:= length(cm) to PointCount-1 do
         CurveMode[i] := cmCurve;
         CurveMode[i] := cmCurve;
   end;
   end;
+  CosineAngle := AStorage.FloatDef['cosine-angle', EasyBezierDefaultMinimumDotProduct];
   EndUpdate;
   EndUpdate;
 end;
 end;
 
 
@@ -857,6 +1020,7 @@ begin
       cm[i] := ord(CurveMode[i]);
       cm[i] := ord(CurveMode[i]);
     AStorage.FloatArray['curve-mode'] := cm;
     AStorage.FloatArray['curve-mode'] := cm;
   end;
   end;
+  AStorage.Float['cosine-angle'] := CosineAngle;
 end;
 end;
 
 
 class function TCurveShape.StorageClassName: RawByteString;
 class function TCurveShape.StorageClassName: RawByteString;

+ 61 - 35
lazpaintcontrols/lcvectorrectshapes.pas

@@ -50,6 +50,7 @@ type
     function GetRenderBounds({%H-}ADestRect: TRect; AMatrix: TAffineMatrix; {%H-}AOptions: TRenderBoundsOptions = []): TRectF; override;
     function GetRenderBounds({%H-}ADestRect: TRect; AMatrix: TAffineMatrix; {%H-}AOptions: TRenderBoundsOptions = []): TRectF; override;
     procedure ConfigureCustomEditor(AEditor: TBGRAOriginalEditor); override;
     procedure ConfigureCustomEditor(AEditor: TBGRAOriginalEditor); override;
     function GetAffineBox(AMatrix: TAffineMatrix; APixelCentered: boolean): TAffineBox;
     function GetAffineBox(AMatrix: TAffineMatrix; APixelCentered: boolean): TAffineBox;
+    procedure Transform(AMatrix: TAffineMatrix); override;
     property Origin: TPointF read FOrigin write SetOrigin;
     property Origin: TPointF read FOrigin write SetOrigin;
     property XAxis: TPointF read FXAxis;
     property XAxis: TPointF read FXAxis;
     property YAxis: TPointF read FYAxis;
     property YAxis: TPointF read FYAxis;
@@ -130,6 +131,7 @@ type
     function GetRenderBounds({%H-}ADestRect: TRect; AMatrix: TAffineMatrix; AOptions: TRenderBoundsOptions = []): TRectF; override;
     function GetRenderBounds({%H-}ADestRect: TRect; AMatrix: TAffineMatrix; AOptions: TRenderBoundsOptions = []): TRectF; override;
     function PointInShape(APoint: TPointF): boolean; override;
     function PointInShape(APoint: TPointF): boolean; override;
     function GetIsSlow(AMatrix: TAffineMatrix): boolean; override;
     function GetIsSlow(AMatrix: TAffineMatrix): boolean; override;
+    procedure Transform(AMatrix: TAffineMatrix); override;
     class function StorageClassName: RawByteString; override;
     class function StorageClassName: RawByteString; override;
     property ShapeKind: TPhongShapeKind read FShapeKind write SetShapeKind;
     property ShapeKind: TPhongShapeKind read FShapeKind write SetShapeKind;
     property LightPosition: TPointF read FLightPosition write SetLightPosition;
     property LightPosition: TPointF read FLightPosition write SetLightPosition;
@@ -146,17 +148,17 @@ uses BGRAPen, BGRAGraphics, BGRAFillInfo, BGRAPath, math, LCVectorialFill;
 procedure TCustomRectShape.SetOrigin(AValue: TPointF);
 procedure TCustomRectShape.SetOrigin(AValue: TPointF);
 var
 var
   delta: TPointF;
   delta: TPointF;
+  t: TAffineMatrix;
 begin
 begin
   if FOrigin=AValue then Exit;
   if FOrigin=AValue then Exit;
   BeginUpdate;
   BeginUpdate;
   delta := AValue - FOrigin;
   delta := AValue - FOrigin;
+  t := AffineMatrixTranslation(delta.x, delta.y);
   FOrigin := AValue;
   FOrigin := AValue;
-  FXAxis += delta;
-  FYAxis += delta;
-  if vsfBackFill in Fields then
-    BackFill.Transform(AffineMatrixTranslation(delta.x, delta.y));
-  if vsfPenFill in Fields then
-    PenFill.Transform(AffineMatrixTranslation(delta.x, delta.y));
+  FXAxis := t*FXAxis;
+  FYAxis := t*FYAxis;
+  if vsfBackFill in Fields then BackFill.Transform(t);
+  if vsfPenFill in Fields then PenFill.Transform(t);
   EndUpdate;
   EndUpdate;
 end;
 end;
 
 
@@ -346,18 +348,22 @@ begin
   end else
   end else
   begin
   begin
     d := GetCornerPositition;
     d := GetCornerPositition;
-    m := AffineMatrixInverse(AffineMatrix(AFactorX*FXUnitBackup*d,AFactorY*FYUnitBackup*d,FOriginBackup));
-    newSize := m*ANewCoord;
-    if (ssShift in AShift) and (FXSizeBackup <> 0) and (FYSizeBackup <> 0) then
+    m := AffineMatrix(AFactorX*FXUnitBackup*d,AFactorY*FYUnitBackup*d,FOriginBackup);
+    if IsAffineMatrixInversible(m) then
     begin
     begin
-      ratio := (newSize.X/FXSizeBackup + newSize.Y/FYSizeBackup)/2;
-      newSize.X := ratio*FXSizeBackup;
-      newSize.Y := ratio*FYSizeBackup;
+      m := AffineMatrixInverse(m);
+      newSize := m*ANewCoord;
+      if (ssShift in AShift) and (FXSizeBackup <> 0) and (FYSizeBackup <> 0) then
+      begin
+        ratio := (newSize.X/FXSizeBackup + newSize.Y/FYSizeBackup)/2;
+        newSize.X := ratio*FXSizeBackup;
+        newSize.Y := ratio*FYSizeBackup;
+      end;
+      FXAxis := FXAxisBackup + (AFactorX+1)*0.5*sqrt(d)*(newSize.X-FXSizeBackup)*FXUnitBackup + AFactorY*(newSize.Y-FYSizeBackup)*0.5*sqrt(d)*FYUnitBackup;
+      FYAxis := FYAxisBackup + (AFactorY+1)*0.5*sqrt(d)*(newSize.Y-FYSizeBackup)*FYUnitBackup + AFactorX*(newSize.X-FXSizeBackup)*0.5*sqrt(d)*FXUnitBackup;
+      FOrigin := FOriginBackup + AFactorX*(newSize.X-FXSizeBackup)*0.5*sqrt(d)*FXUnitBackup
+                               + AFactorY*(newSize.Y-FYSizeBackup)*0.5*sqrt(d)*FYUnitBackup;
     end;
     end;
-    FXAxis := FXAxisBackup + (AFactorX+1)*0.5*sqrt(d)*(newSize.X-FXSizeBackup)*FXUnitBackup + AFactorY*(newSize.Y-FYSizeBackup)*0.5*sqrt(d)*FYUnitBackup;
-    FYAxis := FYAxisBackup + (AFactorY+1)*0.5*sqrt(d)*(newSize.Y-FYSizeBackup)*FYUnitBackup + AFactorX*(newSize.X-FXSizeBackup)*0.5*sqrt(d)*FXUnitBackup;
-    FOrigin := FOriginBackup + AFactorX*(newSize.X-FXSizeBackup)*0.5*sqrt(d)*FXUnitBackup
-                             + AFactorY*(newSize.Y-FYSizeBackup)*0.5*sqrt(d)*FYUnitBackup;
   end;
   end;
   EnsureRatio(-AFactorX,-AFactorY);
   EnsureRatio(-AFactorX,-AFactorY);
   EndUpdate;
   EndUpdate;
@@ -443,6 +449,16 @@ begin
       FXAxis - (FYAxis - FOrigin), FYAxis - (FXAxis - FOrigin));
       FXAxis - (FYAxis - FOrigin), FYAxis - (FXAxis - FOrigin));
 end;
 end;
 
 
+procedure TCustomRectShape.Transform(AMatrix: TAffineMatrix);
+begin
+  BeginUpdate;
+  FOrigin := AMatrix*FOrigin;
+  FXAxis := AMatrix*FXAxis;
+  FYAxis := AMatrix*FYAxis;
+  inherited Transform(AMatrix);
+  EndUpdate;
+end;
+
 function TCustomRectShape.GetOrthoRect(AMatrix: TAffineMatrix; out ARect: TRectF): boolean;
 function TCustomRectShape.GetOrthoRect(AMatrix: TAffineMatrix; out ARect: TRectF): boolean;
 var
 var
   sx,sy: single;
   sx,sy: single;
@@ -525,6 +541,14 @@ begin
   u := FXAxis - FOrigin;
   u := FXAxis - FOrigin;
   v := FYAxis - FOrigin;
   v := FYAxis - FOrigin;
   AEditor.AddStartMoveHandler(@OnStartMove);
   AEditor.AddStartMoveHandler(@OnStartMove);
+  d := GetCornerPositition;
+  if d <> 0 then
+  begin
+    AEditor.AddPoint(FOrigin + (u+v)*d, @OnMoveXYCorner, false);
+    AEditor.AddPoint(FOrigin + (-u+v)*d, @OnMoveXNegYCorner, false);
+    AEditor.AddPoint(FOrigin + (u-v)*d, @OnMoveXYNegCorner, false);
+    AEditor.AddPoint(FOrigin + (-u-v)*d, @OnMoveXNegYNegCorner, false);
+  end;
   if ShowArrows then
   if ShowArrows then
   begin
   begin
     idxX := AEditor.AddArrow(FOrigin, FXAxis, @OnMoveXAxis);
     idxX := AEditor.AddArrow(FOrigin, FXAxis, @OnMoveXAxis);
@@ -538,14 +562,6 @@ begin
     idxXNeg := AEditor.AddPoint(FOrigin - u, @OnMoveXAxisNeg);
     idxXNeg := AEditor.AddPoint(FOrigin - u, @OnMoveXAxisNeg);
     idxYNeg := AEditor.AddPoint(FOrigin - v, @OnMoveYAxisNeg);
     idxYNeg := AEditor.AddPoint(FOrigin - v, @OnMoveYAxisNeg);
   end;
   end;
-  d := GetCornerPositition;
-  if d <> 0 then
-  begin
-    AEditor.AddPoint(FOrigin + (u+v)*d, @OnMoveXYCorner, false);
-    AEditor.AddPoint(FOrigin + (-u+v)*d, @OnMoveXNegYCorner, false);
-    AEditor.AddPoint(FOrigin + (u-v)*d, @OnMoveXYNegCorner, false);
-    AEditor.AddPoint(FOrigin + (-u-v)*d, @OnMoveXNegYNegCorner, false);
-  end;
   idxOrig := AEditor.AddPoint(FOrigin, @OnMoveOrigin, true);
   idxOrig := AEditor.AddPoint(FOrigin, @OnMoveOrigin, true);
   if ShowArrows then
   if ShowArrows then
   begin
   begin
@@ -1144,7 +1160,7 @@ var
   shader: TPhongShading;
   shader: TPhongShading;
   approxFactor,borderSize: single;
   approxFactor,borderSize: single;
   m: TAffineMatrix;
   m: TAffineMatrix;
-  h: single;
+  h, lightPosZ: single;
   map,raster: TBGRABitmap;
   map,raster: TBGRABitmap;
   u,v,lightPosF: TPointF;
   u,v,lightPosF: TPointF;
   scan: TBGRACustomScanner;
   scan: TBGRACustomScanner;
@@ -1176,8 +1192,12 @@ begin
   approxFactor := 1;
   approxFactor := 1;
   if ADraft then
   if ADraft then
   begin
   begin
-    if mapWidth > 300 then approxFactor:= min(approxFactor, 300/mapWidth);
-    if mapHeight > 300 then approxFactor:= min(approxFactor, 300/mapHeight);
+    if mapWidth > 100 then approxFactor:= min(approxFactor, 100/mapWidth);
+    if mapHeight > 100 then approxFactor:= min(approxFactor, 100/mapHeight);
+  end else
+  begin
+    if mapWidth > 800 then approxFactor:= min(approxFactor, 800/mapWidth);
+    if mapHeight > 800 then approxFactor:= min(approxFactor, 800/mapHeight);
   end;
   end;
   mapWidth:= ceil(mapWidth*approxFactor);
   mapWidth:= ceil(mapWidth*approxFactor);
   mapHeight:= ceil(mapHeight*approxFactor);
   mapHeight:= ceil(mapHeight*approxFactor);
@@ -1240,20 +1260,18 @@ begin
       shader.AmbientFactor := 0.5;
       shader.AmbientFactor := 0.5;
       shader.NegativeDiffusionFactor := 0.15;
       shader.NegativeDiffusionFactor := 0.15;
       lightPosF := AffineMatrixTranslation(-rectRaster.Left,-rectRaster.Top)
       lightPosF := AffineMatrixTranslation(-rectRaster.Left,-rectRaster.Top)
-                    *AffineMatrixInverse(m)*AMatrix
-                    *PointF(FLightPosition.x,FLightPosition.y);
-      shader.LightPosition := Point(round(lightPosF.x),round(lightPosF.y));
-      shader.LightPositionZ := round(100*power(approxFactor,1.18));
-      if h*3/2 > shader.LightPositionZ then
-       shader.LightPositionZ := round(h*3/2);
+                    *AffineMatrixInverse(m)*AMatrix*FLightPosition;
+      lightPosZ := 100*Power(approxFactor,1.1);
+      if h*3/2 > lightPosZ then lightposZ := h*3/2;
+      shader.LightPosition3D := Point3D(lightPosF.x,lightPosF.y,lightPosZ);
 
 
       raster := TBGRABitmap.Create(rectRaster.Width,rectRaster.Height);
       raster := TBGRABitmap.Create(rectRaster.Width,rectRaster.Height);
       if BackFill.FillType = vftSolid then
       if BackFill.FillType = vftSolid then
-        shader.Draw(raster,map,round(h),-rectRaster.Left,-rectRaster.Top,BackFill.SolidColor)
+        shader.Draw(raster,map,h,-rectRaster.Left,-rectRaster.Top,BackFill.SolidColor)
       else
       else
       begin
       begin
         scan := BackFill.CreateScanner(AffineMatrixTranslation(-rectRaster.left,-rectRaster.top)*AffineMatrixInverse(m)*AMatrix,ADraft);
         scan := BackFill.CreateScanner(AffineMatrixTranslation(-rectRaster.left,-rectRaster.top)*AffineMatrixInverse(m)*AMatrix,ADraft);
-        shader.DrawScan(raster,map,round(h),-rectRaster.Left,-rectRaster.Top,scan);
+        shader.DrawScan(raster,map,h,-rectRaster.Left,-rectRaster.Top,scan);
         scan.Free;
         scan.Free;
       end;
       end;
 
 
@@ -1314,6 +1332,14 @@ begin
   result := ab.Surface > 320*240;
   result := ab.Surface > 320*240;
 end;
 end;
 
 
+procedure TPhongShape.Transform(AMatrix: TAffineMatrix);
+begin
+  BeginUpdate;
+  inherited Transform(AMatrix);
+  LightPosition := AMatrix*LightPosition;
+  EndUpdate;
+end;
+
 class function TPhongShape.StorageClassName: RawByteString;
 class function TPhongShape.StorageClassName: RawByteString;
 begin
 begin
   result := 'phong';
   result := 'phong';

+ 87 - 11
lazpaintcontrols/lcvectortextshapes.pas

@@ -8,6 +8,9 @@ uses
   Classes, SysUtils, LCVectorRectShapes, BGRATextBidi, BGRABitmapTypes, LCVectorOriginal, BGRAGraphics,
   Classes, SysUtils, LCVectorRectShapes, BGRATextBidi, BGRABitmapTypes, LCVectorOriginal, BGRAGraphics,
   BGRABitmap, BGRALayerOriginal, BGRACanvas2D;
   BGRABitmap, BGRALayerOriginal, BGRACanvas2D;
 
 
+const
+  AlwaysVectorialText = true;
+
 type
 type
 
 
   { TTextShape }
   { TTextShape }
@@ -23,6 +26,9 @@ type
     FLightPosition: TPointF;
     FLightPosition: TPointF;
     FText: string;
     FText: string;
     FSelStart,FSelEnd: integer;
     FSelStart,FSelEnd: integer;
+    FEnteringUnicode: boolean;
+    FUnicodeValue: cardinal;
+    FUnicodeDigitCount: integer;
     FMouseSelecting: boolean;
     FMouseSelecting: boolean;
     FVertAlign: TTextLayout;
     FVertAlign: TTextLayout;
     function GetBidiParagraphAlignment: TBidiTextAlignment;
     function GetBidiParagraphAlignment: TBidiTextAlignment;
@@ -53,6 +59,7 @@ type
     function ShowArrows: boolean; override;
     function ShowArrows: boolean; override;
     function GetTextLayout: TBidiTextLayout;
     function GetTextLayout: TBidiTextLayout;
     function GetFontRenderer: TBGRACustomFontRenderer;
     function GetFontRenderer: TBGRACustomFontRenderer;
+    function UseVectorialTextRenderer: boolean;
     function UpdateFontRenderer: boolean;
     function UpdateFontRenderer: boolean;
     function GetTextRenderZoom: single;
     function GetTextRenderZoom: single;
     function GetUntransformedMatrix: TAffineMatrix; //matrix before render transform
     function GetUntransformedMatrix: TAffineMatrix; //matrix before render transform
@@ -65,6 +72,7 @@ type
     procedure InsertText(ATextUTF8: string);
     procedure InsertText(ATextUTF8: string);
     procedure SelectWithMouse(X,Y: single; AExtend: boolean);
     procedure SelectWithMouse(X,Y: single; AExtend: boolean);
     function HasOutline: boolean;
     function HasOutline: boolean;
+    procedure InsertUnicodeValue;
   public
   public
     constructor Create(AContainer: TVectorOriginal); override;
     constructor Create(AContainer: TVectorOriginal); override;
     procedure QuickDefine(const APoint1,APoint2: TPointF); override;
     procedure QuickDefine(const APoint1,APoint2: TPointF); override;
@@ -89,10 +97,12 @@ type
     procedure MouseUp({%H-}RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); override;
     procedure MouseUp({%H-}RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); override;
     procedure KeyDown({%H-}Shift: TShiftState; {%H-}Key: TSpecialKey; var {%H-}AHandled: boolean); override;
     procedure KeyDown({%H-}Shift: TShiftState; {%H-}Key: TSpecialKey; var {%H-}AHandled: boolean); override;
     procedure KeyPress({%H-}UTF8Key: string; var {%H-}AHandled: boolean); override;
     procedure KeyPress({%H-}UTF8Key: string; var {%H-}AHandled: boolean); override;
+    procedure KeyUp({%H-}Shift: TShiftState; {%H-}Key: TSpecialKey; var {%H-}AHandled: boolean); override;
     procedure SetFontNameAndStyle(AFontName: string; AFontStyle: TFontStyles);
     procedure SetFontNameAndStyle(AFontName: string; AFontStyle: TFontStyles);
     function CopySelection: boolean;
     function CopySelection: boolean;
     function CutSelection: boolean;
     function CutSelection: boolean;
     function PasteSelection: boolean;
     function PasteSelection: boolean;
+    procedure Transform(AMatrix: TAffineMatrix); override;
     property HasSelection: boolean read GetHasSelection;
     property HasSelection: boolean read GetHasSelection;
     property CanPasteSelection: boolean read GetCanPasteSelection;
     property CanPasteSelection: boolean read GetCanPasteSelection;
     property Text: string read FText write SetText;
     property Text: string read FText write SetText;
@@ -364,7 +374,7 @@ begin
   if Assigned(FFontRenderer) then
   if Assigned(FFontRenderer) then
   begin
   begin
     freeRenderer := false;
     freeRenderer := false;
-    if OutlineFill.FillType <> vftNone then
+    if UseVectorialTextRenderer then
     begin
     begin
       if not (FFontRenderer is TBGRAVectorizedFontRenderer) then
       if not (FFontRenderer is TBGRAVectorizedFontRenderer) then
         freeRenderer:= true;
         freeRenderer:= true;
@@ -428,27 +438,37 @@ begin
   result := FFontRenderer;
   result := FFontRenderer;
 end;
 end;
 
 
+function TTextShape.UseVectorialTextRenderer: boolean;
+begin
+  result := AlwaysVectorialText or HasOutline;
+end;
+
 function TTextShape.UpdateFontRenderer: boolean;
 function TTextShape.UpdateFontRenderer: boolean;
 var
 var
-  newEmHeight: integer;
+  newEmHeight: single;
 begin
 begin
   if FFontRenderer = nil then
   if FFontRenderer = nil then
   begin
   begin
-    if OutlineFill.FillType <> vftNone then
-      FFontRenderer := TBGRAVectorizedFontRenderer.Create
+    if UseVectorialTextRenderer then
+    begin
+      FFontRenderer := TBGRAVectorizedFontRenderer.Create;
+      TBGRAVectorizedFontRenderer(FFontRenderer).QuadraticCurves := true;
+      TBGRAVectorizedFontRenderer(FFontRenderer).MinFontResolution := 300;
+      TBGRAVectorizedFontRenderer(FFontRenderer).MaxFontResolution := 300;
+    end
     else
     else
     begin
     begin
       FFontRenderer := TLCLFontRenderer.Create;
       FFontRenderer := TLCLFontRenderer.Create;
       TLCLFontRenderer(FFontRenderer).OverrideUnderlineDecoration:= true;
       TLCLFontRenderer(FFontRenderer).OverrideUnderlineDecoration:= true;
     end;
     end;
   end;
   end;
-  newEmHeight := Round(FontEmHeight*GetTextRenderZoom);
+  newEmHeight := FontEmHeight*GetTextRenderZoom;
   if (newEmHeight <> FFontRenderer.FontEmHeight) or
   if (newEmHeight <> FFontRenderer.FontEmHeight) or
      (FFontRenderer.FontName <> FontName) or
      (FFontRenderer.FontName <> FontName) or
      (FFontRenderer.FontStyle <> FontStyle) or
      (FFontRenderer.FontStyle <> FontStyle) or
      (FFontRenderer.FontQuality <> fqFineAntialiasing) then
      (FFontRenderer.FontQuality <> fqFineAntialiasing) then
   begin
   begin
-    FFontRenderer.FontEmHeight := newEmHeight;
+    FFontRenderer.FontEmHeightF := newEmHeight;
     FFontRenderer.FontName:= FontName;
     FFontRenderer.FontName:= FontName;
     FFontRenderer.FontStyle:= FontStyle;
     FFontRenderer.FontStyle:= FontStyle;
     FFontRenderer.FontQuality:= fqFineAntialiasing;
     FFontRenderer.FontQuality:= fqFineAntialiasing;
@@ -597,6 +617,15 @@ begin
   result := not OutlineFill.IsFullyTransparent and (OutlineWidth > 0);
   result := not OutlineFill.IsFullyTransparent and (OutlineWidth > 0);
 end;
 end;
 
 
+procedure TTextShape.InsertUnicodeValue;
+begin
+  if FEnteringUnicode then
+  begin
+    InsertText(UnicodeCharToUTF8(FUnicodeValue));
+    FEnteringUnicode:= false;
+  end;
+end;
+
 constructor TTextShape.Create(AContainer: TVectorOriginal);
 constructor TTextShape.Create(AContainer: TVectorOriginal);
 begin
 begin
   inherited Create(AContainer);
   inherited Create(AContainer);
@@ -835,13 +864,16 @@ procedure TTextShape.Render(ADest: TBGRABitmap; ARenderOffset: TPoint; AMatrix:
   end;
   end;
 
 
   function CreateShader(AOfsX,AOfsY: integer): TPhongShading;
   function CreateShader(AOfsX,AOfsY: integer): TPhongShading;
+  var
+    lightPosF: TPointF;
+    lightPosZ: Single;
   begin
   begin
     result := TPhongShading.Create;
     result := TPhongShading.Create;
     result.AmbientFactor := 0.6;
     result.AmbientFactor := 0.6;
     result.NegativeDiffusionFactor := 0.15;
     result.NegativeDiffusionFactor := 0.15;
-    result.LightPosition := Point(round(LightPosition.x)+AOfsX+ARenderOffset.X,
-                                  round(LightPosition.y)+AOfsY+ARenderOffset.Y);
-    result.LightPositionZ := round(max(AltitudePercent, 1.2*GetTextPhongHeight));
+    lightPosF := FGlobalMatrix*LightPosition+PointF(AOfsX,AOfsY);
+    lightPosZ := max(AltitudePercent, 1.2*GetTextPhongHeight);
+    result.LightPosition3D := Point3D(lightPosF.x,lightPosF.y,lightPosZ);
   end;
   end;
 
 
 var
 var
@@ -923,7 +955,7 @@ begin
   with transfRectF do
   with transfRectF do
     transfRect := Rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
     transfRect := Rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
 
 
-  if HasOutline then
+  if UseVectorialTextRenderer then
   begin
   begin
     tmpTransf := TBGRABitmap.Create(transfRect.Width,transfRect.Height);
     tmpTransf := TBGRABitmap.Create(transfRect.Width,transfRect.Height);
     ctx := tmpTransf.Canvas2D;
     ctx := tmpTransf.Canvas2D;
@@ -952,7 +984,7 @@ begin
     end else
     end else
       textFx := nil;
       textFx := nil;
 
 
-    if OutLineFill.FillType <> vftNone then
+    if HasOutline then
     begin
     begin
       ctx := tmpTransf.Canvas2D;
       ctx := tmpTransf.Canvas2D;
       ctx.lineWidth := OutlineWidth;
       ctx.lineWidth := OutlineWidth;
@@ -1243,6 +1275,11 @@ begin
     EndEditingUpdate;
     EndEditingUpdate;
     AHandled := true;
     AHandled := true;
   end else
   end else
+  if (Key = skReturn) and ([ssCtrl,ssShift] <= Shift) and FEnteringUnicode then
+  begin
+    InsertUnicodeValue;
+    AHandled:= true;
+  end else
   if Key = skReturn then
   if Key = skReturn then
   begin
   begin
     if ssShift in Shift then
     if ssShift in Shift then
@@ -1256,6 +1293,26 @@ begin
     InsertText(#9);
     InsertText(#9);
     AHandled := true;
     AHandled := true;
   end else
   end else
+  if (Key = skU) and ([ssCtrl,ssShift] <= Shift) then
+  begin
+    if FEnteringUnicode then InsertUnicodeValue;
+    FEnteringUnicode:= true;
+    FUnicodeValue:= 0;
+    FUnicodeDigitCount:= 0;
+    AHandled := true;
+  end else
+  if (Key in[sk0..sk9,skNum0..skNum9,skA..skF]) and ([ssCtrl,ssShift] <= Shift) and FEnteringUnicode then
+  begin
+    if FUnicodeDigitCount >= 8 then FEnteringUnicode:= false else
+    begin
+      FUnicodeValue := (FUnicodeValue shl 4);
+      case Key of
+      sk0..sk9: inc(FUnicodeValue, ord(Key)-ord(sk0));
+      skNum0..skNum9: inc(FUnicodeValue, ord(Key)-ord(sk0));
+      skA..skF: inc(FUnicodeValue, ord(Key)-ord(skA)+10);
+      end;
+    end;
+  end else
   if (Key = skC) and (ssCtrl in Shift) then
   if (Key = skC) and (ssCtrl in Shift) then
   begin
   begin
     if CopySelection then AHandled:= true;
     if CopySelection then AHandled:= true;
@@ -1274,6 +1331,7 @@ begin
     FSelStart:= 0;
     FSelStart:= 0;
     FSelEnd:= GetTextLayout.CharCount;
     FSelEnd:= GetTextLayout.CharCount;
     EndEditingUpdate;
     EndEditingUpdate;
+    AHandled := true;
   end;
   end;
 end;
 end;
 
 
@@ -1300,6 +1358,12 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TTextShape.KeyUp(Shift: TShiftState; Key: TSpecialKey;
+  var AHandled: boolean);
+begin
+  if (Key in[skCtrl,skShift]) and FEnteringUnicode then InsertUnicodeValue;
+end;
+
 procedure TTextShape.SetFontNameAndStyle(AFontName: string;
 procedure TTextShape.SetFontNameAndStyle(AFontName: string;
   AFontStyle: TFontStyles);
   AFontStyle: TFontStyles);
 begin
 begin
@@ -1355,6 +1419,18 @@ begin
     result := false;
     result := false;
 end;
 end;
 
 
+procedure TTextShape.Transform(AMatrix: TAffineMatrix);
+var
+  zoom: Single;
+begin
+  BeginUpdate;
+  inherited Transform(AMatrix);
+  zoom := (VectLen(AMatrix[1,1],AMatrix[2,1])+VectLen(AMatrix[1,2],AMatrix[2,2]))/2;
+  FontEmHeight:= zoom*FontEmHeight;
+  LightPosition := AMatrix*LightPosition;
+  EndUpdate;
+end;
+
 class function TTextShape.StorageClassName: RawByteString;
 class function TTextShape.StorageClassName: RawByteString;
 begin
 begin
   result := 'text';
   result := 'text';

+ 8 - 5
vectoredit/umain.pas

@@ -900,12 +900,15 @@ begin
   if Assigned(img) and img.EditorFocused then
   if Assigned(img) and img.EditorFocused then
   begin
   begin
     sk := LCLKeyToSpecialKey(Key, Shift);
     sk := LCLKeyToSpecialKey(Key, Shift);
-    FSpecialKeyPressed[sk] := true;
-    img.KeyDown(Shift, sk, AHandled);
-    if AHandled then
+    if sk<>skUnknown then
     begin
     begin
-      Key := 0;
-      UpdateTextAlignment;
+      FSpecialKeyPressed[sk] := true;
+      img.KeyDown(Shift, sk, AHandled);
+      if AHandled then
+      begin
+        Key := 0;
+        UpdateTextAlignment;
+      end;
     end;
     end;
   end;
   end;