ソースを参照

first draft for shape edit tool

Johann 6 年 前
コミット
e7df82d839

+ 26 - 0
lazpaint/image/uimage.pas

@@ -94,6 +94,10 @@ type
     function GetWidth: integer;
     function GetZoomFactor: single;
     procedure InvalidateImageDifference(ADiff: TCustomImageDifference);
+    procedure OriginalChange({%H-}ASender: TObject;
+      AOriginal: TBGRALayerCustomOriginal; var ADiff: TBGRAOriginalDiff);
+    procedure OriginalEditingChange({%H-}ASender: TObject;
+      AOriginal: TBGRALayerCustomOriginal);
     procedure SetBlendOperation(AIndex: integer; AValue: TBlendOperation);
     procedure SetCurrentFilenameUTF8(AValue: string);
     procedure LayeredBitmapReplaced;
@@ -963,6 +967,26 @@ begin
   end;
 end;
 
+procedure TLazPaintImage.OriginalChange(ASender: TObject;
+  AOriginal: TBGRALayerCustomOriginal; var ADiff: TBGRAOriginalDiff);
+var
+  r: TRect;
+begin
+  r := FCurrentState.LayeredBitmap.RenderOriginalIfNecessary(AOriginal.Guid, FDraftOriginal);
+  ImageMayChange(r, false);
+  if Assigned(ADiff) then
+  begin
+    AddUndo(TVectorOriginalEmbeddedDifference.Create(CurrentState,AOriginal.Guid,ADiff,r));
+    ADiff := nil;
+  end;
+end;
+
+procedure TLazPaintImage.OriginalEditingChange(ASender: TObject;
+  AOriginal: TBGRALayerCustomOriginal);
+begin
+  OnImageChanged.NotifyObservers;
+end;
+
 procedure TLazPaintImage.Redo;
 var diff: TCustomImageDifference;
 begin
@@ -2050,6 +2074,8 @@ end;
 constructor TLazPaintImage.Create;
 begin
   FCurrentState := TImageState.Create;
+  FCurrentState.OnOriginalChange:=@OriginalChange;
+  FCurrentState.OnOriginalEditingChange:=@OriginalEditingChange;
   FRenderUpdateRectInPicCoord := rect(0,0,0,0);
   FRenderUpdateRectInVSCoord := rect(0,0,0,0);
   FOnSelectionMaskChanged := nil;

+ 100 - 8
lazpaint/image/uimagediff.pas

@@ -292,6 +292,7 @@ type
     FPreviousLayerContent: TStoredLayer;
     FPrevMatrix,FNextMatrix: TAffineMatrix;
     FSourceBounds: TRect;
+    FOriginalGuid: TGUID;
     function GetImageDifferenceKind: TImageDifferenceKind; override;
     function CreateOriginal(AState: TState; ALayerIndex: integer): TBGRALayerCustomOriginal; virtual; abstract;
   public
@@ -362,6 +363,25 @@ type
     procedure UnapplyTo(AState: TState); override;
   end;
 
+  { TVectorOriginalEmbeddedDifference }
+
+  TVectorOriginalEmbeddedDifference = class(TCustomImageDifference)
+  private
+    FDate: TDateTime;
+    FOriginalGuid: TGuid;
+    FDiff: TBGRAOriginalDiff;
+    FBounds: TRect;
+  protected
+    function GetImageDifferenceKind: TImageDifferenceKind; override;
+    function GetChangingBounds: TRect; override;
+    function GetChangingBoundsDefined: boolean; override;
+  public
+    constructor Create({%H-}ADestination: TState; AOriginalGuid: TGuid; ADiff: TBGRAOriginalDiff; ABounds: TRect);
+    destructor Destroy; override;
+    procedure ApplyTo(AState: TState); override;
+    procedure UnapplyTo(AState: TState); override;
+  end;
+
   { TDiscardOriginalStateDifference }
 
   TDiscardOriginalStateDifference = class(TCustomImageDifference)
@@ -488,6 +508,7 @@ begin
 end;
 
 function TryCombineImageDiff(ANewDiff, APrevDiff: TCustomImageDifference): boolean;
+const VectorDiffMinTime = 2000/(1000*60*60*24);
 var
   combined: TInversibleAction;
 begin
@@ -572,9 +593,78 @@ begin
     else result := false;
   end
   else
+  if (APrevDiff is TVectorOriginalEmbeddedDifference) and (ANewDiff is TVectorOriginalEmbeddedDifference) then
+  begin
+    if (TVectorOriginalEmbeddedDifference(ANewDiff).FDate <
+       TVectorOriginalEmbeddedDifference(APrevDiff).FDate+VectorDiffMinTime) and
+      TVectorOriginalEmbeddedDifference(APrevDiff).FDiff.CanAppend(
+      TVectorOriginalEmbeddedDifference(ANewDiff).FDiff) then
+    begin
+      TVectorOriginalEmbeddedDifference(APrevDiff).FDiff.Append(
+        TVectorOriginalEmbeddedDifference(ANewDiff).FDiff);
+      result := true;
+    end else
+      result := false;
+  end else
     result := false;
 end;
 
+{ TVectorOriginalEmbeddedDifference }
+
+function TVectorOriginalEmbeddedDifference.GetImageDifferenceKind: TImageDifferenceKind;
+begin
+  Result:= idkChangeImage;
+end;
+
+function TVectorOriginalEmbeddedDifference.GetChangingBounds: TRect;
+begin
+  Result:= FBounds;
+end;
+
+function TVectorOriginalEmbeddedDifference.GetChangingBoundsDefined: boolean;
+begin
+  Result:= true;
+end;
+
+constructor TVectorOriginalEmbeddedDifference.Create(ADestination: TState;
+  AOriginalGuid: TGuid; ADiff: TBGRAOriginalDiff; ABounds: TRect);
+begin
+  FDate := Now;
+  FOriginalGuid:= AOriginalGuid;
+  FDiff := ADiff;
+  FBounds := ABounds;
+end;
+
+destructor TVectorOriginalEmbeddedDifference.Destroy;
+begin
+  FDiff.Free;
+  inherited Destroy;
+end;
+
+procedure TVectorOriginalEmbeddedDifference.ApplyTo(AState: TState);
+var
+  img: TImageState;
+  idxOrig: Integer;
+begin
+  inherited ApplyTo(AState);
+  img := AState as TImageState;
+  idxOrig := img.LayeredBitmap.IndexOfOriginal(FOriginalGuid);
+  if idxOrig<>-1 then
+    FDiff.Apply(img.LayeredBitmap.Original[idxOrig]);
+end;
+
+procedure TVectorOriginalEmbeddedDifference.UnapplyTo(AState: TState);
+var
+  img: TImageState;
+  idxOrig: Integer;
+begin
+  inherited UnapplyTo(AState);
+  img := AState as TImageState;
+  idxOrig := img.LayeredBitmap.IndexOfOriginal(FOriginalGuid);
+  if idxOrig<>-1 then
+    FDiff.Unapply(img.LayeredBitmap.Original[idxOrig]);
+end;
+
 { TDiscardOriginalDifference }
 
 function TDiscardOriginalDifference.GetLayerId: integer;
@@ -692,7 +782,7 @@ constructor TAddShapeToVectorOriginalDifference.Create(ADestination: TState;
   ALayerId: integer; AShape: TVectorShape; AShapeIndex: integer);
 var
   imgState: TImageState;
-  layerIdx, idxShapeAdd: Integer;
+  layerIdx: Integer;
   orig: TBGRALayerCustomOriginal;
 begin
   FLayerId := ALayerId;
@@ -709,9 +799,9 @@ begin
   FShapeCopy := AShape.Duplicate;
 
   inherited ApplyTo(ADestination);
-  idxShapeAdd := TVectorOriginal(orig).AddShape(AShape);
-  FShapeId := TVectorOriginal(orig).Shape[idxShapeAdd].Id;
-  TVectorOriginal(orig).MoveShapeToIndex(idxShapeAdd, FShapeIndex);
+  TVectorOriginal(orig).InsertShape(AShape, FShapeIndex);
+  FShapeId := TVectorOriginal(orig).Shape[FShapeIndex].Id;
+  TVectorOriginal(orig).SelectShape(FShapeIndex);
   FShapeBounds := imgState.LayeredBitmap.RenderOriginalIfNecessary(orig.Guid);
 end;
 
@@ -724,7 +814,7 @@ end;
 procedure TAddShapeToVectorOriginalDifference.ApplyTo(AState: TState);
 var
   imgState: TImageState;
-  layerIdx, idxShapeAdd: Integer;
+  layerIdx: Integer;
   orig: TBGRALayerCustomOriginal;
   shape: TVectorShape;
 begin
@@ -736,9 +826,9 @@ begin
     raise exception.Create('Vector original expected');
 
   shape := FShapeCopy.Duplicate;
-  idxShapeAdd := TVectorOriginal(orig).AddShape(shape);
-  TVectorOriginal(orig).Shape[idxShapeAdd].Id := FShapeId;
-  TVectorOriginal(orig).MoveShapeToIndex(idxShapeAdd, FShapeIndex);
+  TVectorOriginal(orig).InsertShape(shape, FShapeIndex);
+  TVectorOriginal(orig).Shape[FShapeIndex].Id := FShapeId;
+  TVectorOriginal(orig).SelectShape(FShapeIndex);
   imgState.LayeredBitmap.RenderLayerFromOriginal(layerIdx);
 end;
 
@@ -955,7 +1045,9 @@ begin
   imgState := AState as TImageState;
   layerIdx := imgState.LayeredBitmap.GetLayerIndexFromId(FPreviousLayerContent.LayerId);
   orig := CreateOriginal(imgState, layerIdx);
+  if FOriginalGuid <> GUID_NULL then orig.Guid := FOriginalGuid;
   origIndex := imgState.LayeredBitmap.AddOriginal(orig, true);
+  if FOriginalGuid = GUID_NULL then FOriginalGuid := orig.Guid;
   imgState.LayeredBitmap.LayerOriginalGuid[layerIdx] := imgState.LayeredBitmap.OriginalGuid[origIndex];
   imgState.LayeredBitmap.LayerOriginalMatrix[layerIdx] := FNextMatrix;
   if FNextMatrix = FPrevMatrix then

+ 38 - 0
lazpaint/image/uimagestate.pas

@@ -14,6 +14,8 @@ type
   TImageState = class(TState)
   private
     FLayeredBitmap: TBGRALayeredBitmap;
+    FOnOriginalChange: TEmbeddedOriginalChangeEvent;
+    FOnOriginalEditingChange: TEmbeddedOriginalEditingChangeEvent;
     FSelectionMask: TBGRABitmap;
     FLastSelectionMaskBoundsIsDefined,
     FLastSelectionLayerBoundsIsDefined: boolean;
@@ -40,6 +42,10 @@ type
     function GetLinearBlend: boolean;
     function GetNbLayers: integer;
     function GetWidth: integer;
+    procedure OriginalChange({%H-}ASender: TObject;
+      AOriginal: TBGRALayerCustomOriginal; var ADiff: TBGRAOriginalDiff);
+    procedure OriginalEditingChange({%H-}ASender: TObject;
+      AOriginal: TBGRALayerCustomOriginal);
     procedure SelectImageLayer(AValue: TBGRABitmap);
     procedure SelectImageLayerByIndex(AValue: integer);
     procedure SetLayeredBitmap(AValue: TBGRALayeredBitmap);
@@ -49,6 +55,7 @@ type
     SelectionLayer: TBGRABitmap;
     selectedLayerId: integer;
     filenameUTF8: string;
+    DiscardOriginalDiff: boolean;
 
     // generic state functions
     constructor Create;
@@ -158,6 +165,8 @@ type
     property SelectionMask: TBGRABitmap read GetSelectionMask write SetSelectionMask;
     property LayeredBitmap: TBGRALayeredBitmap read FLayeredBitmap;
     property SelectionTransform: TAffineMatrix read FSelectionTransform write FSelectionTransform;
+    property OnOriginalChange: TEmbeddedOriginalChangeEvent read FOnOriginalChange write FOnOriginalChange;
+    property OnOriginalEditingChange: TEmbeddedOriginalEditingChangeEvent read FOnOriginalEditingChange write FOnOriginalEditingChange;
   end;
 
 implementation
@@ -347,6 +356,23 @@ begin
     result := LayeredBitmap.Width;
 end;
 
+procedure TImageState.OriginalChange(ASender: TObject;
+  AOriginal: TBGRALayerCustomOriginal; var ADiff: TBGRAOriginalDiff);
+begin
+  If Assigned(FOnOriginalChange) then
+  begin
+    if DiscardOriginalDiff then FreeAndNil(ADiff);
+    FOnOriginalChange(self, AOriginal, ADiff);
+  end;
+end;
+
+procedure TImageState.OriginalEditingChange(ASender: TObject;
+  AOriginal: TBGRALayerCustomOriginal);
+begin
+  If Assigned(FOnOriginalEditingChange) then
+    FOnOriginalEditingChange(self, AOriginal);
+end;
+
 procedure TImageState.SelectImageLayer(AValue: TBGRABitmap);
 var
   i: Integer;
@@ -377,7 +403,18 @@ end;
 procedure TImageState.SetLayeredBitmap(AValue: TBGRALayeredBitmap);
 begin
   if FLayeredBitmap=AValue then Exit;
+
+  if Assigned(FLayeredBitmap) then
+  begin
+    FLayeredBitmap.OnOriginalChange:= nil;
+    FLayeredBitmap.OnOriginalEditingChange:= nil;
+  end;
   FLayeredBitmap:=AValue;
+  if Assigned(FLayeredBitmap) then
+  begin
+    FLayeredBitmap.OnOriginalChange:=@OriginalChange;
+    FLayeredBitmap.OnOriginalEditingChange:=@OriginalEditingChange;
+  end;
 end;
 
 function TImageState.SetLayerName(Index: integer; AValue: string): TCustomImageDifference;
@@ -1077,6 +1114,7 @@ begin
   FLastSelectionMaskBoundsIsDefined := false;
   FLastSelectionLayerBoundsIsDefined := false;
   FSelectionTransform := AffineMatrixIdentity;
+  DiscardOriginalDiff := true;
 end;
 
 destructor TImageState.Destroy;

+ 9 - 2
lazpaint/lazpaintinstance.pas

@@ -40,6 +40,7 @@ type
     function ScriptFileNew(AVars: TVariableSet): TScriptResult;
     function ScriptImageResample(AParams: TVariableSet): TScriptResult;
     procedure SelectionInstanceOnRun(AInstance: TLazPaintCustomInstance);
+    procedure ToolColorChanged(Sender: TObject);
 
   protected
     InColorFromFChooseColor: boolean;
@@ -302,6 +303,7 @@ begin
   FToolManager := TToolManager.Create(FImage, self, nil, BlackAndWhite);
   UseConfig(TIniFile.Create(''));
   FToolManager.OnPopup := @OnToolPopup;
+  FToolManager.OnColorChanged:=@ToolColorChanged;
   FSelectionEditConfig := nil;
   FTextureEditConfig := nil;
 
@@ -863,6 +865,12 @@ begin
   AInstance.Config.SetDefaultImageHeight(Image.Height);
 end;
 
+procedure TLazPaintInstance.ToolColorChanged(Sender: TObject);
+begin
+  ColorToFChooseColor;
+  if Assigned(FMain) then FMain.UpdateToolbar;
+end;
+
 function TLazPaintInstance.GetIcons(ASize: integer): TImageList;
 var
   i: Integer;
@@ -1243,8 +1251,7 @@ begin
     ToolManager.ToolForeColor := FChooseColor.GetCurrentColor else
   if FChooseColor.colorTarget = ctBackColor then
     ToolManager.ToolBackColor := FChooseColor.GetCurrentColor;
-  FMain.UpdateToolbar;
-  FMain.UpdateEditPicture;
+  if Assigned(FMain) then FMain.UpdateEditPicture;
   InColorFromFChooseColor := false;
 end;
 

ファイルの差分が大きいため隠しています
+ 183 - 552
lazpaint/lazpaintmainform.lfm


+ 9 - 4
lazpaint/lazpaintmainform.pas

@@ -643,6 +643,7 @@ type
 
   private
     function GetImage: TLazPaintImage;
+    procedure OnTextureChanged(Sender: TObject);
   private
     { private declarations }
     FLayout: TMainFormLayout;
@@ -913,6 +914,8 @@ begin
   begin
     if ToolManager.OnToolChanged = @OnToolChanged then
       ToolManager.OnToolChanged := nil;
+    if ToolManager.OnTextureChanged = @OnTextureChanged then
+      ToolManager.OnTextureChanged := nil;
   end;
   FreeAndNil(Zoom);
   FreeAndNil(FOnlineUpdater);
@@ -972,6 +975,7 @@ begin
 
   ToolManager.SetCurrentToolType(ptHand);
   ToolManager.OnToolChanged := @OnToolChanged;
+  ToolManager.OnTextureChanged := @OnTextureChanged;
 
   InitToolbarElements;
 
@@ -2404,8 +2408,6 @@ procedure TFMain.ToolNoTextureExecute(Sender: TObject);
 begin
   try
     ToolManager.SetToolTexture(nil);
-
-    UpdateTextureIcon;
     UpdateEditPicture;
 
   except
@@ -2663,7 +2665,6 @@ begin
                       BGRAReplace(newTexture, newTexture.GetPart(newTexture.GetImageBounds));
                       ToolManager.SetToolTexture(newTexture);
                       newTexture.FreeReference;
-                      UpdateTextureIcon;
                     end;
                   end;
                 end;
@@ -3140,7 +3141,6 @@ begin
         newTex.FreeReference;
         newTex := nil;
         result := true;
-        UpdateTextureIcon;
         UpdateEditPicture;
         Config.SetDefaultTextureDirectory(ExtractFilePath(texFilename));
       except
@@ -3509,6 +3509,11 @@ begin
   result := LazPaintInstance.Image;
 end;
 
+procedure TFMain.OnTextureChanged(Sender: TObject);
+begin
+  UpdateTextureIcon;
+end;
+
 procedure TFMain.UpdateStatusText;
 var s: string;
 begin

+ 7 - 14
lazpaint/maintoolbar.inc

@@ -659,12 +659,8 @@ begin
 end;
 
 procedure TFMain.SwitchColors;
-var temp: TBGRAPixel;
 begin
-  temp := ToolManager.ToolForeColor;
-  ToolManager.ToolForeColor := ToolManager.ToolBackColor;
-  ToolManager.ToolBackColor := temp;
-  UpdateToolbar;
+  ToolManager.SwapToolColors;
   UpdateEditPicture;
 end;
 
@@ -682,10 +678,9 @@ begin
   ColorDialog1.Color := BGRAToColor(ToolManager.ToolForeColor);
   if ColorDialog1.Execute then
   begin
-       ToolManager.ToolForeColor := ColorToBGRA(ColorDialog1.Color,ToolManager.ToolForeColor.alpha);
-       Shape_PenColor.Brush.Color := BGRAToColor(ToolManager.ToolForeColor);
-       LazPaintInstance.ColorToFChooseColor;
-       UpdateEditPicture;
+    ToolManager.ToolForeColor := ColorToBGRA(ColorDialog1.Color,ToolManager.ToolForeColor.alpha);
+    LazPaintInstance.ColorToFChooseColor;
+    UpdateEditPicture;
   end;
 end;
 
@@ -715,10 +710,9 @@ begin
   ColorDialog1.Color := BGRAToColor(ToolManager.ToolBackColor);
   if ColorDialog1.Execute then
   begin
-       ToolManager.ToolBackColor := ColorToBGRA(ColorDialog1.Color,ToolManager.ToolBackColor.alpha);
-       Shape_BackColor.Brush.Color := BGRAToColor(ToolManager.ToolBackColor);
-       LazPaintInstance.ColorToFChooseColor;
-       UpdateEditPicture;
+    ToolManager.ToolBackColor := ColorToBGRA(ColorDialog1.Color,ToolManager.ToolBackColor.alpha);
+    LazPaintInstance.ColorToFChooseColor;
+    UpdateEditPicture;
   end;
 end;
 
@@ -753,7 +747,6 @@ procedure TFMain.Image_CurrentTextureMouseDown(Sender: TObject;
   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
 begin
   LazPaintInstance.EditTexture;
-  UpdateTextureIcon;
   UpdateEditPicture;
 end;
 

+ 47 - 3
lazpaint/tools/utool.pas

@@ -123,6 +123,8 @@ type
 
   TToolManager = class
   private
+    FOnColorChanged: TNotifyEvent;
+    FOnTextureChanged: TNotifyEvent;
     FShouldExitTool: boolean;
     FOnToolChangedHandler: TOnToolChangedHandler;
     FOnPopupToolHandler: TOnPopupToolHandler;
@@ -151,6 +153,8 @@ type
     function GetToolSleeping: boolean;
     function GetToolTextureOpacity: byte;
     procedure SetControlsVisible(Controls: TList; Visible: Boolean);
+    procedure SetToolBackColor(AValue: TBGRAPixel);
+    procedure SetToolForeColor(AValue: TBGRAPixel);
     procedure SetToolPenWidth(AValue: single);
     procedure SetToolTextureOpacity(AValue: byte);
     procedure ToolCloseAndReopenImmediatly;
@@ -255,10 +259,11 @@ type
 
     property ToolDeformationGridNbX: integer read FToolDeformationGridNbX;
     property ToolDeformationGridNbY: integer read FToolDeformationGridNbY;
-    property ToolForeColor: TBGRAPixel read GetToolForeColor write FToolForeColor;
-    property ToolBackColor: TBGRAPixel read GetToolBackColor write FToolBackColor;
+    property ToolForeColor: TBGRAPixel read GetToolForeColor write SetToolForeColor;
+    property ToolBackColor: TBGRAPixel read GetToolBackColor write SetToolBackColor;
 
     function SetToolDeformationGridSize(NbX,NbY: integer): boolean;
+    procedure SwapToolColors;
     procedure SetToolTexture(ATexture: TBGRABitmap);
     function GetToolTextureAfterAlpha: TBGRABitmap;
     function GetToolTexture: TBGRABitmap;
@@ -268,6 +273,8 @@ type
 
     property OnToolChanged: TOnToolChangedHandler read FOnToolChangedHandler write FOnToolChangedHandler;
     property OnPopup: TOnPopupToolHandler read FOnPopupToolHandler write FOnPopupToolHandler;
+    property OnTextureChanged: TNotifyEvent read FOnTextureChanged write FOnTextureChanged;
+    property OnColorChanged: TNotifyEvent read FOnColorChanged write FOnColorChanged;
     property Cursor: TCursor read GetCursor;
     property ToolSleeping: boolean read GetToolSleeping;
     property ToolTextureOpacity: byte read GetToolTextureOpacity write SetToolTextureOpacity;
@@ -763,6 +770,26 @@ begin
   end;
 end;
 
+procedure TToolManager.SetToolBackColor(AValue: TBGRAPixel);
+begin
+  if (AValue.red = FToolBackColor.red) and
+     (AValue.green = FToolBackColor.green) and
+     (AValue.blue = FToolBackColor.blue) and
+     (AValue.alpha = FToolBackColor.alpha) then exit;
+  FToolBackColor := AValue;
+  if Assigned(FOnColorChanged) then FOnColorChanged(self);
+end;
+
+procedure TToolManager.SetToolForeColor(AValue: TBGRAPixel);
+begin
+  if (AValue.red = FToolForeColor.red) and
+     (AValue.green = FToolForeColor.green) and
+     (AValue.blue = FToolForeColor.blue) and
+     (AValue.alpha = FToolForeColor.alpha) then exit;
+  FToolForeColor := AValue;
+  if Assigned(FOnColorChanged) then FOnColorChanged(self);
+end;
+
 procedure TToolManager.SetToolPenWidth(AValue: single);
 begin
   if GetCurrentToolType = ptEraser then
@@ -795,7 +822,7 @@ begin
       if not IsOnlyRenderChange(ARect) then
         CurrentTool.FAction.NotifyChange(ALayer, ARect);
 
-    if ALayer = nil then
+    if Assigned(ALayer) then
     begin
       if ALayer = Image.CurrentLayerReadOnly then
         Image.ImageMayChange(AddLayerOffset(ARect))
@@ -1123,6 +1150,7 @@ begin
       showPenwidth := true;
       showBrush:= FCurrentToolType in[ptBrush,ptClone];
     end;
+  ptEditShape: showTexture := true;
   ptSelectSpline: showSplineStyle := true;
   ptEraser: begin showPenwidth := true; showEraserOption := true; showColor := false; end;
   ptRect, ptEllipse, ptPolygon, ptSpline:
@@ -1237,12 +1265,27 @@ begin
   end;
 end;
 
+procedure TToolManager.SwapToolColors;
+var
+  tmp: TBGRAPixel;
+begin
+  if (FToolForeColor.red = FToolBackColor.red) and
+     (FToolForeColor.green = FToolBackColor.green) and
+     (FToolForeColor.blue = FToolBackColor.blue) and
+     (FToolForeColor.alpha = FToolBackColor.alpha) then exit;
+  tmp := FToolForeColor;
+  FToolForeColor := FToolBackColor;
+  FToolBackColor := tmp;
+  if Assigned(FOnColorChanged) then FOnColorChanged(self);
+end;
+
 procedure TToolManager.SetToolTexture(ATexture: TBGRABitmap);
 begin
   if ATexture = FToolTexture then exit;
   FToolTexture.FreeReference;
   FToolTexture := ATexture.NewReference as TBGRABitmap;
   FreeAndNil(FToolTextureAfterAlpha);
+  if Assigned(FOnTextureChanged) then FOnTextureChanged(self);
 end;
 
 function TToolManager.GetToolTextureAfterAlpha: TBGRABitmap;
@@ -1265,6 +1308,7 @@ begin
   result := FToolTexture;
   FToolTexture := nil;
   FreeAndNil(FToolTextureAfterAlpha);
+  if Assigned(FOnTextureChanged) then FOnTextureChanged(self);
 end;
 
 procedure TToolManager.AddBrush(brush: TLazPaintBrush);

+ 395 - 19
lazpaint/tools/utoolvectorial.pas

@@ -7,7 +7,7 @@ interface
 uses
   Classes, SysUtils, LCLType, BGRABitmap, BGRABitmapTypes,
   BGRALayerOriginal, LCVectorOriginal,
-  UTool, UImageType;
+  UTool, UImageType, ULayerAction;
 
 type
   { TVectorialTool }
@@ -68,10 +68,390 @@ type
     destructor Destroy; override;
   end;
 
+  { TEditShapeTool }
+
+  TEditShapeTool = class(TGenericTool)
+  private
+    procedure SelectShape({%H-}ASender: TObject; AShape: TVectorShape;
+      {%H-}APreviousShape: TVectorShape);
+  protected
+    FShiftState: TShiftState;
+    FLeftButton,FRightButton: boolean;
+    FLastPos: TPointF;
+    procedure BindOriginalEvent(ABind: boolean);
+    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 DoToolUpdate({%H-}toolDest: TBGRABitmap): TRect; override;
+    function GetAction: TLayerAction; override;
+    function DoGetToolDrawingLayer: TBGRABitmap; override;
+    procedure OnTryStop({%H-}sender: TCustomLayerAction); override;
+    procedure StopEdit;
+    function IsVectorOriginal: boolean;
+    function GetIsSelectingTool: boolean; override;
+    function GetVectorOriginal: TVectorOriginal;
+    function FixLayerOffset: boolean; override;
+  public
+    destructor Destroy; override;
+    function Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth, VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect; override;
+    function ToolKeyDown(var key: Word): TRect; override;
+    function ToolKeyPress(var key: TUTF8Char): TRect; override;
+    function ToolKeyUp(var key: Word): TRect; override;
+    function ToolUp: TRect; override;
+  end;
+
 implementation
 
 uses LazPaintType, LCVectorRectShapes, LCVectorTextShapes, LCVectorialFill, BGRASVGOriginal,
-  ULoading, BGRATransform, math, UStateType, UImageDiff, Controls, BGRAPen, UResourceStrings, ugraph;
+  ULoading, BGRATransform, math, UStateType, UImageDiff, Controls, BGRAPen, UResourceStrings, ugraph,
+  LCScaleDPI;
+
+const PointSize = 6;
+
+function OriginalCursorToCursor(ACursor: TOriginalEditorCursor): TCursor;
+begin
+  case ACursor of
+    oecMove: result := crSizeAll;
+    oecMoveN: result := crSizeN;
+    oecMoveS: result := crSizeS;
+    oecMoveE: result := crSizeE;
+    oecMoveW: result := crSizeW;
+    oecMoveNE: result := crSizeNE;
+    oecMoveSW: result := crSizeSW;
+    oecMoveNW: result := crSizeNW;
+    oecMoveSE: result := crSizeSE;
+    oecHandPoint: result := crHandPoint;
+    oecText: result := crIBeam;
+    else result := crDefault;
+  end;
+end;
+
+{ TEditShapeTool }
+
+procedure TEditShapeTool.SelectShape(ASender: TObject; AShape: TVectorShape;
+  APreviousShape: TVectorShape);
+begin
+  if Assigned(AShape) then
+  begin
+    if (vsfBackFill in AShape.Fields) and (AShape.BackFill.FillType = vftGradient) then
+    begin
+      Manager.ToolForeColor := AShape.BackFill.Gradient.StartColor;
+      Manager.ToolBackColor := AShape.BackFill.Gradient.EndColor;
+      Manager.SetToolTexture(nil);
+    end else
+    begin
+      if (vsfPenFill in AShape.Fields) and (AShape.PenFill.FillType = vftSolid) then
+        Manager.ToolForeColor := AShape.PenFill.SolidColor;
+      if (vsfBackFill in AShape.Fields) and (AShape.BackFill.FillType = vftSolid) then
+        Manager.ToolBackColor := AShape.BackFill.SolidColor;
+      if (vsfBackFill in AShape.Fields) and (AShape.BackFill.FillType = vftTexture) then
+        Manager.SetToolTexture(AShape.BackFill.Texture)
+      else if (vsfPenFill in AShape.Fields) and (AShape.PenFill.FillType = vftTexture) then
+        Manager.SetToolTexture(AShape.PenFill.Texture)
+      else
+        Manager.SetToolTexture(nil);
+    end;
+  end;
+end;
+
+procedure TEditShapeTool.BindOriginalEvent(ABind: boolean);
+begin
+  if IsVectorOriginal then
+  begin
+    if ABind then
+    begin
+      GetVectorOriginal.OnSelectShape:= @SelectShape;
+      Manager.Image.CurrentState.DiscardOriginalDiff := false;
+    end else
+    begin
+      GetVectorOriginal.OnSelectShape := nil;
+      Manager.Image.CurrentState.DiscardOriginalDiff := true;
+    end;
+  end;
+end;
+
+function TEditShapeTool.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF; rightBtn: boolean): TRect;
+var
+  cur: TOriginalEditorCursor;
+  handled: boolean;
+begin
+  Manager.Image.DraftOriginal := true;
+  FRightButton:= rightBtn;
+  FLeftButton:= not rightBtn;
+  FLastPos := ptF;
+  BindOriginalEvent(true);
+  Manager.Image.CurrentState.LayeredBitmap.MouseDown(rightBtn, FShiftState, ptF.X,ptF.Y, cur, handled);
+  BindOriginalEvent(false);
+  if handled then Cursor := OriginalCursorToCursor(cur);
+  Result:= EmptyRect;
+end;
+
+function TEditShapeTool.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
+  ptF: TPointF): TRect;
+var
+  cur: TOriginalEditorCursor;
+  handled: boolean;
+begin
+  FLastPos := ptF;
+  BindOriginalEvent(true);
+  Manager.Image.CurrentState.LayeredBitmap.MouseMove(FShiftState, ptF.X,ptF.Y, cur, handled);
+  BindOriginalEvent(false);
+  Cursor := OriginalCursorToCursor(cur);
+  Result:= EmptyRect;
+end;
+
+function TEditShapeTool.DoToolUpdate(toolDest: TBGRABitmap): TRect;
+begin
+  if IsVectorOriginal then
+  with GetVectorOriginal do
+  begin
+    if Assigned(SelectedShape) then
+    begin
+      if (vsfBackFill in SelectedShape.Fields) and (SelectedShape.BackFill.FillType = vftGradient) then
+      begin
+        if Assigned(Manager.GetToolTexture) then
+          SelectedShape.BackFill.SetTexture(Manager.GetToolTexture, AffineMatrixIdentity)
+        else
+        begin
+          SelectedShape.BackFill.Gradient.StartColor := Manager.ToolForeColor;
+          SelectedShape.BackFill.Gradient.EndColor := Manager.ToolBackColor;
+        end;
+      end else
+      begin
+        if Assigned(Manager.GetToolTexture) then
+        begin
+          case SelectedShape.BackFill.FillType of
+          vftTexture:
+            begin
+              SelectedShape.BackFill.SetTexture(Manager.GetToolTexture,
+                SelectedShape.BackFill.TextureMatrix,SelectedShape.BackFill.TextureOpacity,
+                SelectedShape.BackFill.TextureRepetition);
+              if (vsfPenFill in SelectedShape.Fields) and (SelectedShape.PenFill.FillType = vftSolid) then
+                SelectedShape.PenFill.SolidColor := Manager.ToolForeColor;
+            end;
+          vftGradient,vftSolid:
+            begin
+              SelectedShape.BackFill.SetTexture(Manager.GetToolTexture, AffineMatrixIdentity);
+              if (vsfPenFill in SelectedShape.Fields) and (SelectedShape.PenFill.FillType = vftSolid) then
+                SelectedShape.PenFill.SolidColor := Manager.ToolForeColor;
+            end;
+          vftNone: begin
+              case SelectedShape.PenFill.FillType of
+              vftTexture:
+                begin
+                  SelectedShape.PenFill.SetTexture(Manager.GetToolTexture,
+                    SelectedShape.PenFill.TextureMatrix,SelectedShape.PenFill.TextureOpacity,
+                    SelectedShape.PenFill.TextureRepetition);
+                  if (vsfBackFill in SelectedShape.Fields) and (SelectedShape.BackFill.FillType = vftSolid) then
+                    SelectedShape.BackFill.SolidColor := Manager.ToolBackColor;
+                end;
+              vftGradient,vftSolid:
+                begin
+                  SelectedShape.PenFill.SetTexture(Manager.GetToolTexture, AffineMatrixIdentity);
+                  if (vsfBackFill in SelectedShape.Fields) and (SelectedShape.BackFill.FillType = vftSolid) then
+                    SelectedShape.BackFill.SolidColor := Manager.ToolBackColor;
+                end;
+              end;
+            end;
+          end;
+        end else
+        begin
+          if (vsfPenFill in SelectedShape.Fields) and (SelectedShape.PenFill.FillType in [vftSolid,vftTexture]) then
+            SelectedShape.PenFill.SolidColor := Manager.ToolForeColor;
+          if (vsfBackFill in SelectedShape.Fields) and (SelectedShape.BackFill.FillType in [vftSolid,vftTexture]) then
+            SelectedShape.BackFill.SolidColor := Manager.ToolBackColor;
+        end;
+      end;
+    end;
+  end;
+  Result := EmptyRect;
+end;
+
+function TEditShapeTool.GetAction: TLayerAction;
+begin
+  result := nil;
+end;
+
+function TEditShapeTool.DoGetToolDrawingLayer: TBGRABitmap;
+begin
+  Result:= Manager.Image.LayerBitmap[Manager.Image.CurrentLayerIndex];
+end;
+
+procedure TEditShapeTool.OnTryStop(sender: TCustomLayerAction);
+begin
+  StopEdit;
+  inherited OnTryStop(sender);
+end;
+
+procedure TEditShapeTool.StopEdit;
+var
+  r: TRect;
+begin
+  if FLeftButton or FRightButton then
+  begin
+    r := ToolUp;
+    Manager.Image.LayerMayChange(GetToolDrawingLayer,r);
+  end;
+  if IsVectorOriginal then
+    GetVectorOriginal.DeselectShape;
+  Manager.Image.CurrentState.LayeredBitmap.ClearEditor;
+end;
+
+function TEditShapeTool.IsVectorOriginal: boolean;
+begin
+  result := Manager.Image.LayerOriginalClass[Manager.Image.CurrentLayerIndex]=TVectorOriginal;
+end;
+
+function TEditShapeTool.GetIsSelectingTool: boolean;
+begin
+  result := false;
+end;
+
+function TEditShapeTool.GetVectorOriginal: TVectorOriginal;
+begin
+  result := Manager.Image.LayerOriginal[Manager.Image.CurrentLayerIndex] as TVectorOriginal;
+end;
+
+function TEditShapeTool.FixLayerOffset: boolean;
+begin
+  Result:= false;
+end;
+
+destructor TEditShapeTool.Destroy;
+begin
+  StopEdit;
+  inherited Destroy;
+end;
+
+function TEditShapeTool.Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth,
+  VirtualScreenHeight: integer;
+  BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
+var
+  orig, xAxis, yAxis: TPointF;
+  viewMatrix: TAffineMatrix;
+begin
+  with LayerOffset do
+  begin
+    orig := BitmapToVirtualScreen(PointF(-X,-Y));
+    xAxis := BitmapToVirtualScreen(PointF(-X+1,-Y));
+    yAxis := BitmapToVirtualScreen(PointF(-X,-Y+1));
+  end;
+  viewMatrix := AffineMatrix(xAxis-orig,yAxis-orig,orig);
+
+  if IsVectorOriginal then
+  begin
+    if Assigned(VirtualScreen) then
+      result := Manager.Image.CurrentState.LayeredBitmap.DrawEditor(VirtualScreen,
+        Manager.Image.CurrentLayerIndex, viewMatrix, DoScaleX(PointSize,OriginalDPI))
+    else
+      result := Manager.Image.CurrentState.LayeredBitmap.GetEditorBounds(
+        rect(0,0,VirtualScreenWidth,VirtualScreenHeight),
+        Manager.Image.CurrentLayerIndex, viewMatrix, DoScaleX(PointSize,OriginalDPI));
+  end else
+  begin
+    Manager.Image.CurrentState.LayeredBitmap.ClearEditor;
+    result := EmptyRect;
+  end;
+end;
+
+function TEditShapeTool.ToolKeyDown(var key: Word): TRect;
+var
+  handled: boolean;
+begin
+  Result:= EmptyRect;
+  if key = VK_SHIFT then
+  begin
+    include(FShiftState, ssShift);
+    key := 0;
+  end else
+  if key = VK_CONTROL then
+  begin
+    include(FShiftState, ssCtrl);
+    key := 0;
+  end else
+  if key = VK_MENU then
+  begin
+    include(FShiftState, ssAlt);
+    key := 0;
+  end else
+  begin
+    BindOriginalEvent(true);
+    Manager.Image.CurrentState.LayeredBitmap.KeyDown(FShiftState, LCLKeyToSpecialKey(key, FShiftState), handled);
+    if not handled and IsVectorOriginal then
+    begin
+      if (key = VK_DELETE) and Assigned(GetVectorOriginal.SelectedShape) then
+        GetVectorOriginal.RemoveShape(GetVectorOriginal.SelectedShape);
+    end;
+    BindOriginalEvent(false);
+  end;
+end;
+
+function TEditShapeTool.ToolKeyPress(var key: TUTF8Char): TRect;
+var
+  handled: boolean;
+begin
+  Result:= EmptyRect;
+  BindOriginalEvent(true);
+  Manager.Image.CurrentState.LayeredBitmap.KeyPress(key, handled);
+  BindOriginalEvent(false);
+end;
+
+function TEditShapeTool.ToolKeyUp(var key: Word): TRect;
+var
+  handled: boolean;
+begin
+  Result:= EmptyRect;
+  if key = VK_SHIFT then
+  begin
+    exclude(FShiftState, ssShift);
+    key := 0;
+  end else
+  if key = VK_CONTROL then
+  begin
+    exclude(FShiftState, ssCtrl);
+    key := 0;
+  end else
+  if key = VK_MENU then
+  begin
+    exclude(FShiftState, ssAlt);
+    key := 0;
+  end else
+  begin
+    BindOriginalEvent(true);
+    Manager.Image.CurrentState.LayeredBitmap.KeyUp(FShiftState, LCLKeyToSpecialKey(key, FShiftState), handled);
+    BindOriginalEvent(false);
+  end;
+end;
+
+
+function TEditShapeTool.ToolUp: TRect;
+var
+  cur: TOriginalEditorCursor;
+  handled: boolean;
+  m: TAffineMatrix;
+begin
+  if FLeftButton or FRightButton then
+  begin
+    Manager.Image.DraftOriginal := false;
+    BindOriginalEvent(true);
+    Manager.Image.CurrentState.LayeredBitmap.MouseUp(FRightButton, FShiftState, FLastPos.X,FLastPos.Y, cur, handled);
+    if handled then
+    begin
+      Cursor := OriginalCursorToCursor(cur);
+      result := OnlyRenderChange;
+    end else
+      Result:= EmptyRect;
+    FLeftButton:= false;
+    FRightButton:= false;
+    if not handled and IsVectorOriginal then
+    begin
+      m := AffineMatrixInverse(Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex]);
+      GetVectorOriginal.MouseClick(m*FLastPos);
+    end;
+    BindOriginalEvent(false);
+  end
+  else result := EmptyRect;
+end;
 
 { TVectorialTool }
 
@@ -116,6 +496,7 @@ var
   toolDest: TBGRABitmap;
 begin
   if ASender <> FShape then exit;
+  AHandled := true;
   toolDest := GetToolDrawingLayer;
   r := CancelShape;
   Action.NotifyChange(toolDest, r);
@@ -377,20 +758,7 @@ end;
 
 procedure TVectorialTool.UpdateCursor(ACursor: TOriginalEditorCursor);
 begin
-  case ACursor of
-    oecMove: Cursor := crSizeAll;
-    oecMoveN: Cursor := crSizeN;
-    oecMoveS: Cursor := crSizeS;
-    oecMoveE: Cursor := crSizeE;
-    oecMoveW: Cursor := crSizeW;
-    oecMoveNE: Cursor := crSizeNE;
-    oecMoveSW: Cursor := crSizeSW;
-    oecMoveNW: Cursor := crSizeNW;
-    oecMoveSE: Cursor := crSizeSE;
-    oecHandPoint: Cursor := crHandPoint;
-    oecText: Cursor := crIBeam;
-    else Cursor := crDefault;
-  end;
+  Cursor := OriginalCursorToCursor(ACursor);
 end;
 
 function TVectorialTool.FixLayerOffset: boolean;
@@ -657,11 +1025,15 @@ var
 begin
   if Assigned(FShape) then
   begin
-    orig := BitmapToVirtualScreen(PointF(0,0));
-    xAxis := BitmapToVirtualScreen(PointF(1,0));
-    yAxis := BitmapToVirtualScreen(PointF(0,1));
+    with LayerOffset do
+    begin
+      orig := BitmapToVirtualScreen(PointF(0,0));
+      xAxis := BitmapToVirtualScreen(PointF(1,0));
+      yAxis := BitmapToVirtualScreen(PointF(0,1));
+    end;
     FEditor.Matrix := AffineMatrix(xAxis-orig,yAxis-orig,orig)*VectorTransform;
     FEditor.Clear;
+    FEditor.PointSize := DoScaleX(PointSize, OriginalDPI);
     if Assigned(FShape) then FShape.ConfigureEditor(FEditor);
     if Assigned(VirtualScreen) then
       Result:= FEditor.Render(VirtualScreen, rect(0,0,VirtualScreen.Width,VirtualScreen.Height))
@@ -682,5 +1054,9 @@ begin
   inherited Destroy;
 end;
 
+initialization
+
+  RegisterTool(ptEditShape, TEditShapeTool);
+
 end.
 

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません