1 // SPDX-License-Identifier: GPL-3.0-only
2 unit UToolVectorial;
3 
4 {$mode objfpc}{$H+}
5 
6 interface
7 
8 uses
9   Classes, SysUtils, LCLType, BGRABitmap, BGRABitmapTypes,
10   BGRALayerOriginal, BGRAGraphics, LCVectorOriginal, LCVectorialFill,
11   UTool, UImageType, ULayerAction, LCVectorRectShapes, LCVectorMultishape,
12   BGRAGradientOriginal, UStateType;
13 
14 type
15   TToolSplineMode = (tsmMovePoint, tsmCurveModeAuto, tsmCurveModeAngle, tsmCurveModeSpline);
16 
ToolSplineModeFromShapenull17 function ToolSplineModeFromShape(AShape: TVectorShape): TToolSplineMode;
18 
19 type
20   TFitMode = (fmNever, fmIfChange, fmAlways);
21 
22 type
23   { TVectorialTool }
24 
25   TVectorialTool = class(TGenericTool)
26   private
GetEditornull27     function GetEditor: TBGRAOriginalEditor;
GetIsHandDrawingnull28     function GetIsHandDrawing: boolean;
GetIsIdlenull29     function GetIsIdle: boolean;
30   protected
31     FLayerWasEmpty: boolean;
32     FShape: TVectorShape;
33     FTemporaryStorage: TBGRACustomOriginalStorage;
34     FLastDraftUpdate: Boolean;
35     FSwapColor: boolean;
36     FQuickDefine: Boolean;
37     FQuickDefineStartPoint, FQuickDefineEndPoint: TPointF;
38     FPreviousUpdateBounds, FPreviousEditorBounds: TRect;
39     FEditor: TBGRAOriginalEditor;
40     FRightDown, FLeftDown: boolean;
41     FLastPos: TPointF;
42     FLastShapeTransform: TAffineMatrix;
43     FUseOriginal: boolean;
AlwaysRasterizeShapenull44     function AlwaysRasterizeShape: boolean; virtual;
CreateShapenull45     function CreateShape: TVectorShape; virtual;
46     procedure ClearShape; virtual;
ShapeClassnull47     function ShapeClass: TVectorShapeAny; virtual; abstract;
UseOriginalnull48     function UseOriginal: boolean; virtual;
HasBrushnull49     function HasBrush: boolean; virtual;
GetCustomShapeBoundsnull50     function GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; {%H-}ADraft: boolean): TRect; virtual;
51     procedure DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); virtual;
52     procedure AssignShapeStyle(AMatrix: TAffineMatrix; AAlwaysFit: boolean); virtual;
GetManagerShapeOptionsnull53     function GetManagerShapeOptions: TShapeOptions; virtual;
54     procedure QuickDefineShape(AStart,AEnd: TPointF); virtual;
RoundCoordinatenull55     function RoundCoordinate(constref ptF: TPointF): TPointF; virtual;
GetIsSelectingToolnull56     function GetIsSelectingTool: boolean; override;
UpdateShapenull57     function UpdateShape(toolDest: TBGRABitmap): TRect; virtual;
PreferDraftUpdatenull58     function PreferDraftUpdate: boolean;
VectorTransformnull59     function VectorTransform(APixelCentered: boolean): TAffineMatrix;
60     procedure UpdateCursor(ACursor: TOriginalEditorCursor);
FixLayerOffsetnull61     function FixLayerOffset: boolean; override;
DoToolDownnull62     function DoToolDown({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; {%H-}ptF: TPointF; rightBtn: boolean): TRect; override;
DoToolMovenull63     function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; {%H-}ptF: TPointF): TRect; override;
DoToolUpdatenull64     function DoToolUpdate({%H-}toolDest: TBGRABitmap): TRect; override;
DoToolKeyDownnull65     function DoToolKeyDown(var key: Word): TRect; override;
DoToolKeyUpnull66     function DoToolKeyUp(var key: Word): TRect; override;
67     procedure ShapeChange({%H-}ASender: TObject; ABounds: TRectF; ADiff: TVectorShapeDiff); virtual;
68     procedure ShapeEditingChange({%H-}ASender: TObject); virtual;
69     procedure ShapeRemoveQuery({%H-}ASender: TObject; var AHandled: boolean);
GetStatusTextnull70     function GetStatusText: string; override;
SlowShapenull71     function SlowShape: boolean; virtual;
72     procedure QuickDefineEnd; virtual;
73     procedure OnTryStop({%H-}sender: TCustomLayerAction); override;
74     procedure UpdateUseOriginal;
ReplaceLayerAndAddShapenull75     function ReplaceLayerAndAddShape(out ARect: TRect): TCustomImageDifference; virtual;
76     procedure ShapeValidated; virtual;
ForeGradTexModenull77     function ForeGradTexMode: TVectorShapeUsermode; virtual;
BackGradTexModenull78     function BackGradTexMode: TVectorShapeUsermode; virtual;
OutlineGradTexModenull79     function OutlineGradTexMode: TVectorShapeUsermode; virtual;
ForeFitModenull80     function ForeFitMode: TFitMode;
BackFitModenull81     function BackFitMode: TFitMode;
OutlineFitModenull82     function OutlineFitMode: TFitMode;
ManagerForeFillnull83     function ManagerForeFill: TVectorialFill;
ManagerBackFillnull84     function ManagerBackFill: TVectorialFill;
ManagerOutlineFillnull85     function ManagerOutlineFill: TVectorialFill;
GetIsForeEditGradTexPointsnull86     function GetIsForeEditGradTexPoints: boolean; override;
GetIsBackEditGradTexPointsnull87     function GetIsBackEditGradTexPoints: boolean; override;
GetIsOutlineEditGradTexPointsnull88     function GetIsOutlineEditGradTexPoints: boolean; override;
GetGridMatrixnull89     function GetGridMatrix: TAffineMatrix; virtual;
90     property Editor: TBGRAOriginalEditor read GetEditor;
91   public
ValidateShapenull92     function ValidateShape: TRect;
CancelShapenull93     function CancelShape: TRect;
94     constructor Create(AManager: TToolManager); override;
ToolUpnull95     function ToolUp: TRect; override;
ToolKeyPressnull96     function ToolKeyPress(var key: TUTF8Char): TRect; override;
ToolCommandnull97     function ToolCommand(ACommand: TToolCommand): boolean; override;
ToolProvideCommandnull98     function ToolProvideCommand(ACommand: TToolCommand): boolean; override;
SuggestGradientBoxnull99     function SuggestGradientBox: TAffineBox; override;
GetContextualToolbarsnull100     function GetContextualToolbars: TContextualToolbars; override;
Rendernull101     function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth, {%H-}VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction):TRect; override;
102     property IsIdle: boolean read GetIsIdle;
103     property IsHandDrawing: boolean read GetIsHandDrawing;
104     destructor Destroy; override;
105   end;
106 
107   { TEditShapeTool }
108 
109   TEditShapeMode = (esmNone, esmSelection, esmGradient, esmOtherOriginal, esmShape, esmNoShape);
110   TEditShapeTool = class(TGenericTool)
111   private
GetNothingSelectednull112     function GetNothingSelected: boolean;
113   protected
114     FDownHandled,FRectEditorCapture,FLayerOriginalCapture,
115     FLeftButton,FRightButton: boolean;
116     FLastPos: TPointF;
117     FOriginalLayerId: integer;
118     FOriginalRect: TRectShape;
119     FOriginalRectUntransformed: TRectF;
120     FRectEditor: TBGRAOriginalEditor;
121     FSelectionRect: TRectShape;
122     FSelectionRectUntransformed: TRectF;
123     FIsEditingGradient: boolean;
124     procedure RetrieveLightPosition;
125     procedure UpdateToolManagerFromShape(AShape: TVectorShape);
126     procedure UpdateDraftMode;
127     procedure BindOriginalEvent(ABind: boolean);
128     procedure SelectShape({%H-}ASender: TObject; AShape: TVectorShape; {%H-}APreviousShape: TVectorShape);
DoToolDownnull129     function DoToolDown({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; {%H-}ptF: TPointF; rightBtn: boolean): TRect; override;
DoToolMovenull130     function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; {%H-}ptF: TPointF): TRect; override;
DoToolUpdatenull131     function DoToolUpdate({%H-}toolDest: TBGRABitmap): TRect; override;
DoToolKeyDownnull132     function DoToolKeyDown(var key: Word): TRect; override;
DoToolKeyUpnull133     function DoToolKeyUp(var key: Word): TRect; override;
134     procedure UpdateSnap(AEditor: TBGRAOriginalEditor);
GetActionnull135     function GetAction: TLayerAction; override;
DoGetToolDrawingLayernull136     function DoGetToolDrawingLayer: TBGRABitmap; override;
137     procedure OnTryStop({%H-}sender: TCustomLayerAction); override;
138     procedure StopEdit(AUpdateInterface, ARaiseToolUp: boolean);
IsEditingnull139     function IsEditing: boolean;
140     procedure MakeImageOriginal;
141     procedure MakeVectorOriginal;
142     procedure UpdateMatrixFromRect;
143     procedure DoEditSelection;
GetMatrixFromRectnull144     function GetMatrixFromRect(ARect: TRectShape; AUntransformedRect: TRectF): TAffineMatrix;
CreateRectnull145     function CreateRect(AUntransformedRect: TRectF; AMatrix: TAffineMatrix): TRectShape;
GetIsSelectingToolnull146     function GetIsSelectingTool: boolean; override;
GetVectorOriginalnull147     function GetVectorOriginal: TVectorOriginal;
GetGradientOriginalnull148     function GetGradientOriginal: TBGRALayerGradientOriginal;
GetImageOriginalnull149     function GetImageOriginal: TBGRALayerImageOriginal;
GetOriginalTransformnull150     function GetOriginalTransform: TAffineMatrix;
FixLayerOffsetnull151     function FixLayerOffset: boolean; override;
GetCurrentSplineModenull152     function GetCurrentSplineMode: TToolSplineMode;
153     procedure SetCurrentSplineMode(AMode: TToolSplineMode);
ConvertToSplinenull154     function ConvertToSpline: boolean;
GetEditModenull155     function GetEditMode: TEditShapeMode;
InvalidEditModenull156     function InvalidEditMode: boolean;
ForeGradTexModenull157     function ForeGradTexMode: TVectorShapeUsermode; virtual;
BackGradTexModenull158     function BackGradTexMode: TVectorShapeUsermode; virtual;
OutlineGradTexModenull159     function OutlineGradTexMode: TVectorShapeUsermode; virtual;
ForeFitModenull160     function ForeFitMode: TFitMode;
BackFitModenull161     function BackFitMode: TFitMode;
OutlineFitModenull162     function OutlineFitMode: TFitMode;
GetIsForeEditGradTexPointsnull163     function GetIsForeEditGradTexPoints: boolean; override;
GetIsBackEditGradTexPointsnull164     function GetIsBackEditGradTexPoints: boolean; override;
GetIsOutlineEditGradTexPointsnull165     function GetIsOutlineEditGradTexPoints: boolean; override;
GetAllowedBackFillTypesnull166     function GetAllowedBackFillTypes: TVectorialFillTypes; override;
GetStatusTextnull167     function GetStatusText: string; override;
168   public
169     constructor Create(AManager: TToolManager); override;
170     destructor Destroy; override;
GetContextualToolbarsnull171     function GetContextualToolbars: TContextualToolbars; override;
Rendernull172     function Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth, VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect; override;
ToolKeyPressnull173     function ToolKeyPress(var key: TUTF8Char): TRect; override;
ToolUpnull174     function ToolUp: TRect; override;
ToolCommandnull175     function ToolCommand(ACommand: TToolCommand): boolean; override;
ToolProvideCommandnull176     function ToolProvideCommand(ACommand: TToolCommand): boolean; override;
SuggestGradientBoxnull177     function SuggestGradientBox: TAffineBox; override;
178     property CurrentSplineMode: TToolSplineMode read GetCurrentSplineMode write SetCurrentSplineMode;
179     property NothingSelected: boolean read GetNothingSelected;
180   end;
181 
182 procedure AssignFill(ATarget, ASource: TVectorialFill; const ABox: TAffineBox; AFitMode: TFitMode);
GetShapeStatusTextnull183 function GetShapeStatusText(AShape: TVectorShape; const AMatrix: TAffineMatrix): string;
GetGradientStatusTextnull184 function GetGradientStatusText(AGradient: TBGRALayerGradientOriginal; const AMatrix: TAffineMatrix): string;
185 
186 implementation
187 
188 uses LazPaintType, LCVectorPolyShapes, LCVectorTextShapes, BGRASVGOriginal,
189   ULoading, BGRATransform, math, UImageDiff, Controls, BGRAPen, UResourceStrings, ugraph,
190   LCScaleDPI, LCVectorClipboard, BGRAGradientScanner, UClipboard, BGRAUTF8;
191 
192 const PointSize = 6;
193 
OriginalCursorToCursornull194 function OriginalCursorToCursor(ACursor: TOriginalEditorCursor): TCursor;
195 begin
196   case ACursor of
197     oecMove: result := crSizeAll;
198     oecMoveN: result := crSizeN;
199     oecMoveS: result := crSizeS;
200     oecMoveE: result := crSizeE;
201     oecMoveW: result := crSizeW;
202     oecMoveNE: result := crSizeNE;
203     oecMoveSW: result := crSizeSW;
204     oecMoveNW: result := crSizeNW;
205     oecMoveSE: result := crSizeSE;
206     oecHandPoint: result := crHandPoint;
207     oecText: result := crIBeam;
208     else result := crDefault;
209   end;
210 end;
211 
ToolSplineModeFromShapenull212 function ToolSplineModeFromShape(AShape: TVectorShape): TToolSplineMode;
213 var
214   c: TCurveShape;
215 begin
216   result := tsmMovePoint;
217   if not (AShape is TCurveShape) then exit;
218   c := TCurveShape(AShape);
219   case c.Usermode of
220   vsuEdit: result := tsmMovePoint;
221   vsuCreate: if c.PointCount > 1 then
222              begin
223                case c.CurveMode[c.PointCount-2] of
224                  cmAuto: result := tsmCurveModeAuto;
225                  cmAngle: result := tsmCurveModeAngle;
226                  cmCurve: result := tsmCurveModeSpline;
227                end;
228              end else
229                result := tsmCurveModeAuto;
230   vsuCurveSetAuto: result := tsmCurveModeAuto;
231   vsuCurveSetAngle: result := tsmCurveModeAngle;
232   vsuCurveSetCurve: result := tsmCurveModeSpline;
233   end;
234 end;
235 
ContextualToolbarsFromShapenull236 function ContextualToolbarsFromShape(AShapeClass: TVectorShapeAny; AShape: TVectorShape): TContextualToolbars;
237 var
238   f: TVectorShapeFields;
239 begin
240   result:= [ctPenFill, ctBackFill];
241   if Assigned(AShape) then
242     f := AShape.MultiFields
243     else f := AShapeClass.Fields;
244   if vsfPenWidth in f then result += [ctPenWidth];
245   if vsfPenStyle in f then result += [ctPenStyle];
246   if vsfJoinStyle in f then result += [ctJoinStyle];
247   if [vsfPenStyle,vsfPenFill,vsfBackFill] <= f then result += [ctShape];
248   if vsfOutlineFill in f then
249   begin
250     result += [ctOutlineFill];
251     if not (vsfBackFill in f) then result -= [ctBackFill];
252   end;
253   if vsfOutlineWidth in f then result += [ctOutlineWidth];
254 
255   if AShapeClass = TCurveShape then result := result + [ctShape,ctCloseShape,ctLineCap,ctSplineStyle]
256   else if AShapeClass = TPolylineShape then result := result + [ctShape,ctCloseShape,ctLineCap]
257   else if AShapeClass = TPhongShape then result := result + [ctPhong,ctAltitude]
258   else if AShapeClass = TTextShape then
259   begin
260     result := result + [ctText,ctAliasing];
261     if TTextShape(AShape).PenPhong then include(result, ctAltitude);
262   end;
263 end;
264 
265 procedure AlignShape(AShape: TVectorShape; ACommand: TToolCommand; const AMatrix: TAffineMatrix; const ARect: TRect);
266 begin
267   case ACommand of
268   tcAlignLeft: AShape.AlignHorizontally(taLeftJustify,AMatrix,ARect);
269   tcCenterHorizontally: AShape.AlignHorizontally(taCenter,AMatrix,ARect);
270   tcAlignRight: AShape.AlignHorizontally(taRightJustify,AMatrix,ARect);
271   tcAlignTop..tcAlignBottom:
272       AShape.AlignVertically(TTextLayout(ord(ACommand)-ord(tcAlignTop)+ord(tlTop)),AMatrix,ARect);
273   end;
274 end;
275 
276 procedure AssignFill(ATarget, ASource: TVectorialFill; const ABox: TAffineBox; AFitMode: TFitMode);
277 var
278   temp: TVectorialFill;
279   change: Boolean;
280 begin
281   if ASource.IsFullyTransparent then ATarget.Clear else
282   begin
283     change := ((ATarget.FillType = vftGradient) and (ASource.FillType = vftGradient) and
284        (ATarget.Gradient.GradientType <> ASource.Gradient.GradientType) and
285        not ([ATarget.Gradient.GradientType,ASource.Gradient.GradientType] <= [gtRadial,gtDiamond,gtAngular])) or
286       ((ATarget.FillType = vftTexture) and (ASource.FillType = vftTexture) and
287        (ATarget.TextureRepetition <> ASource.TextureRepetition));
288     if ((AFitMode = fmIfChange) and change) or (AFitMode = fmAlways)
289         or (ATarget.FillType <> ASource.FillType) then
290     begin
291       temp := ATarget.Duplicate;
292       temp.AssignExceptGeometry(ASource);
293       temp.FitGeometry(ABox);
294       ATarget.Assign(temp);
295       temp.Free;
296     end else
297       ATarget.AssignExceptGeometry(ASource);
298   end;
299 end;
300 
GetShapeStatusTextnull301 function GetShapeStatusText(AShape: TVectorShape; const AMatrix: TAffineMatrix): string;
302 var
303   orig, xa, ya, corner1, corner2: TPointF;
304   overline: string4;
305   i, nb: Integer;
306   rF: TRectF;
307 begin
308   if AShape is TEllipseShape then
309     with TEllipseShape(AShape) do
310     begin
311       orig := AMatrix*Origin;
312       xa := AMatrix*XAxis;
313       ya := AMatrix*YAxis;
314       result := 'x = '+FloatToStrF(orig.x,ffFixed,6,1)+'|y = '+FloatToStrF(orig.y,ffFixed,6,1)+'|'+
315       'rx = '+FloatToStrF(VectLen(xa-orig),ffFixed,6,1)+'|ry = '+FloatToStrF(VectLen(ya-orig),ffFixed,6,1)
316     end
317   else if AShape is TCustomRectShape then
318     with TCustomRectShape(AShape) do
319     begin
320       orig := AMatrix*Origin;
321       xa := AMatrix*XAxis;
322       ya := AMatrix*YAxis;
323       corner1 := orig-(xa-orig)-(ya-orig);
324       corner2 := xa + (ya-orig);
325       result := 'x1 = '+FloatToStrF(corner1.x,ffFixed,6,1)+'|y1 = '+FloatToStrF(corner1.y,ffFixed,6,1)+'|'+
326       'x2 = '+FloatToStrF(corner2.x,ffFixed,6,1)+'|y2 = '+FloatToStrF(corner2.y,ffFixed,6,1)+'|'+
327       'Δx = '+FloatToStrF(VectLen(xa-orig)*2,ffFixed,6,1)+'|Δy = '+FloatToStrF(VectLen(ya-orig)*2,ffFixed,6,1);
328     end
329   else if AShape is TCustomPolypointShape then
330     with TCustomPolypointShape(AShape) do
331     begin
332       result := 'count = ';
333       nb := 0;
334       for i := 0 to PointCount-1 do
335         if Points[i].IsEmpty then
336         begin
337           if nb > 0 then result += inttostr(nb)+', ';
338           nb := 0;
339         end else inc(nb);
340       result += inttostr(nb);
341       if not Center.IsEmpty then
342       begin
343         orig := AMatrix*Center;
344         overline := UnicodeCharToUTF8($0305);
345         result += '|x'+overline+' = '+FloatToStrF(orig.x,ffFixed,6,1);
346         result += '|y'+overline+' = '+FloatToStrF(orig.y,ffFixed,6,1);
347       end;
348       if (Usermode = vsuCreate) and (PointCount > 0) then
349       begin
350         xa := AMatrix*Points[PointCount-1];
351         result += '|x = '+FloatToStrF(xa.x,ffFixed,6,1);
352         result += '|y = '+FloatToStrF(xa.y,ffFixed,6,1);
353       end else
354       if HoverPoint <> -1 then
355       begin
356         xa := AMatrix*Points[HoverPoint];
357         result += '|x = '+FloatToStrF(xa.x,ffFixed,6,1);
358         result += '|y = '+FloatToStrF(xa.y,ffFixed,6,1);
359       end else
360       begin
361         rF := GetPointBounds(AMatrix);
362         result += '|Δx = '+FloatToStrF(rF.Width,ffFixed,6,1);
363         result += '|Δy = '+FloatToStrF(rF.Height,ffFixed,6,1);
364       end;
365     end else
366       result := '';
367 end;
368 
GetGradientStatusTextnull369 function GetGradientStatusText(AGradient: TBGRALayerGradientOriginal; const AMatrix: TAffineMatrix): string;
370 var
371   orig, xa: TPointF;
372 begin
373   with AGradient do
374   begin
375     orig := AMatrix*Origin;
376     xa := AMatrix*XAxis;
377     result := 'x1 = '+FloatToStrF(orig.x,ffFixed,6,1)+'|y1 = '+FloatToStrF(orig.y,ffFixed,6,1)+'|'+
378       'x2 = '+FloatToStrF(xa.x,ffFixed,6,1)+'|y2 = '+FloatToStrF(xa.y,ffFixed,6,1)+'|'+
379       'Δx = '+FloatToStrF(abs(xa.x-orig.x),ffFixed,6,1)+'|Δy = '+FloatToStrF(abs(xa.y-orig.y),ffFixed,6,1);
380   end;
381 end;
382 
383 { TEditShapeTool }
384 
385 procedure TEditShapeTool.SelectShape(ASender: TObject; AShape: TVectorShape;
386   APreviousShape: TVectorShape);
387 begin
388   if Assigned(AShape) and (GetCurrentLayerKind = lkVectorial) then
389   begin
390     UpdateToolManagerFromShape(AShape);
391     Manager.UpdateContextualToolbars;
392   end else
393   if Assigned(APreviousShape) then
394     Manager.UpdateContextualToolbars;
395 end;
396 
GetNothingSelectednull397 function TEditShapeTool.GetNothingSelected: boolean;
398 begin
399   result := GetEditMode in [esmNone, esmNoShape];
400 end;
401 
402 procedure TEditShapeTool.RetrieveLightPosition;
403 var
404   shape: TVectorShape;
405   m: TAffineMatrix;
406 begin
407   if GetCurrentLayerKind = lkVectorial then
408   begin
409     shape := GetVectorOriginal.SelectedShape;
410     if shape=nil then exit;
411     m := Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex];
412     if (shape is TTextShape) and TTextShape(shape).PenPhong then
413       Manager.LightPosition := m*TTextShape(shape).LightPosition
414     else if shape is TPhongShape then
415       Manager.LightPosition := m*TPhongShape(shape).LightPosition;
416   end;
417 end;
418 
419 procedure TEditShapeTool.UpdateToolManagerFromShape(AShape: TVectorShape);
420 var
421   opt: TShapeOptions;
422   zoom: single;
423   m: TAffineMatrix;
424   doFill, doDraw: Boolean;
425   f: TVectorShapeFields;
426 begin
427   m := Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex];
428   zoom := (VectLen(m[1,1],m[2,1])+VectLen(m[1,2],m[2,2]))/2;
429   if AShape.Usermode in [vsuEditBackFill, vsuEditPenFill] then
430     AShape.Usermode := vsuEdit;
431   opt := Manager.ShapeOptions;
432   f := AShape.MultiFields;
433   doDraw := vsfPenFill in f;
434   doFill := vsfBackFill in f;
435   if vsfPenStyle in f then
436   begin
437     doDraw := AShape.PenVisible;
438     if doDraw then doFill := AShape.BackVisible;
439 
440     if not doFill then
441       exclude(opt,toFillShape)
442       else include(opt,toFillShape);
443     if not doDraw then
444       exclude(opt,toDrawShape)
445       else
446       begin
447         include(opt,toDrawShape);
448         Manager.PenStyle := BGRAToPenStyle(AShape.PenStyle);
449       end;
450   end;
451   if doDraw then
452   begin
453     if not AShape.PenVisible then
454       Manager.ForeColor := BGRA(Manager.ForeColor.red,
455         Manager.ForeColor.green,Manager.ForeColor.blue,0)
456     else
457       Manager.ForeFill.Assign(AShape.PenFill);
458   end;
459   if doFill then
460   begin
461     if not AShape.BackVisible then
462       Manager.BackColor := BGRA(Manager.BackColor.red,
463         Manager.BackColor.green,Manager.BackColor.blue,0)
464     else
465       Manager.BackFill.Assign(AShape.BackFill);
466   end;
467   if not AShape.OutlineVisible then
468     Manager.SetTextOutline(false, Manager.TextOutlineWidth) else
469   begin
470     Manager.SetTextOutline(true, AShape.OutlineWidth*zoom);
471     Manager.OutlineFill.Assign(AShape.OutlineFill);
472   end;
473 
474   if toDrawShape in opt then
475   begin
476     if vsfPenWidth in f then Manager.PenWidth := AShape.PenWidth*zoom;
477     if vsfJoinStyle in f then Manager.JoinStyle:= AShape.JoinStyle;
478     if AShape is TCustomPolypointShape then
479     begin
480       if TCustomPolypointShape(AShape).Closed then
481         include(opt, toCloseShape)
482       else
483         exclude(opt, toCloseShape);
484       Manager.LineCap := TCustomPolypointShape(AShape).LineCap;
485       Manager.ArrowSize := TCustomPolypointShape(AShape).ArrowSize;
486       Manager.ArrowStart := TCustomPolypointShape(AShape).ArrowStartKind;
487       Manager.ArrowEnd := TCustomPolypointShape(AShape).ArrowEndKind;
488     end;
489     if AShape is TCurveShape then
490       Manager.SplineStyle := TCurveShape(AShape).SplineStyle;
491   end;
492 
493   if AShape is TTextShape then
494   with TTextShape(AShape) do
495   begin
496     Manager.TextPhong := PenPhong;
497     Manager.LightPosition := m*LightPosition;
498     Manager.PhongShapeAltitude := round(AltitudePercent);
499     Manager.TextAlign:= ParagraphAlignment;
500     Manager.SetTextFont(FontName, FontEmHeight*zoom*72/Manager.Image.DPI, FontStyle);
501     Manager.TextShadow:= false;
502     if Aliased then
503       include(opt,toAliasing)
504       else exclude(opt,toAliasing);
505   end;
506   Manager.ShapeOptions := opt;
507 
508   if AShape is TPhongShape then
509   with TPhongShape(AShape) do
510   begin
511     Manager.PhongShapeKind:= ShapeKind;
512     Manager.LightPosition:= LightPosition;
513     Manager.PhongShapeAltitude:= round(ShapeAltitudePercent);
514     Manager.PhongShapeBorderSize:= round(BorderSizePercent);
515   end;
516 end;
517 
518 procedure TEditShapeTool.UpdateDraftMode;
519 begin
520   case GetEditMode of
521   esmShape: Manager.Image.DraftOriginal:= GetVectorOriginal.PreferDraftMode(Manager.Image.CurrentState.LayeredBitmap.OriginalEditor, GetOriginalTransform);
522   esmNoShape: Manager.Image.DraftOriginal:= false;
523   else Manager.Image.DraftOriginal:= FLeftButton or FRightButton;
524   end;
525 end;
526 
527 procedure TEditShapeTool.BindOriginalEvent(ABind: boolean);
528 begin
529   case GetCurrentLayerKind of
530   lkVectorial:
531     begin
532       if ABind then
533       begin
534         GetVectorOriginal.OnSelectShape:= @SelectShape;
535         Manager.Image.CurrentState.DiscardOriginalDiff := false;
536       end else
537       begin
538         GetVectorOriginal.OnSelectShape := nil;
539         Manager.Image.CurrentState.DiscardOriginalDiff := true;
540       end;
541     end;
542   lkGradient:
543     begin
544       if ABind then
545       begin
546         Manager.Image.CurrentState.DiscardOriginalDiff := false;
547       end else
548       begin
549         Manager.Image.CurrentState.DiscardOriginalDiff := true;
550       end;
551     end;
552   end;
553 end;
554 
DoToolDownnull555 function TEditShapeTool.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
556   ptF: TPointF; rightBtn: boolean): TRect;
557 var
558   cur: TOriginalEditorCursor;
559   handled: boolean;
560   ptView: TPointF;
561 begin
562   Result:= EmptyRect;
563   FRightButton:= rightBtn;
564   FLeftButton:= not rightBtn;
565   FRectEditorCapture:= false;
566   FLayerOriginalCapture:= false;
567   FLastPos := ptF;
568   handled := false;
569   if not handled and (GetEditMode in [esmSelection,esmOtherOriginal]) and Assigned(FRectEditor) then
570   begin
571     ptView := FRectEditor.Matrix*ptF;
572     UpdateSnap(FRectEditor);
573     FRectEditor.MouseDown(rightBtn, ShiftState, ptView.X,ptView.Y, cur, handled);
574     Cursor := OriginalCursorToCursor(cur);
575     if handled then
576     begin
577       FRectEditorCapture:= true;
578       result := OnlyRenderChange;
579       UpdateMatrixFromRect;
580     end;
581   end;
582   if not handled and (GetEditMode in [esmShape,esmGradient,esmNoShape]) then
583   begin
584     BindOriginalEvent(true);
585     try
586       UpdateSnap(Manager.Image.CurrentState.LayeredBitmap.OriginalEditor);
587       Manager.Image.CurrentState.LayeredBitmap.MouseDown(rightBtn, ShiftState, ptF.X,ptF.Y, cur, handled);
588     finally
589       BindOriginalEvent(false);
590     end;
591     if handled then
592     begin
593       Cursor := OriginalCursorToCursor(cur);
594       FLayerOriginalCapture:= true;
595     end;
596   end;
597   FDownHandled:= handled;
598 end;
599 
DoToolMovenull600 function TEditShapeTool.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
601   ptF: TPointF): TRect;
602 var
603   cur: TOriginalEditorCursor;
604   handled: boolean;
605   ptView: TPointF;
606 begin
607   FLastPos := ptF;
608   Result:= EmptyRect;
609   UpdateDraftMode;
610 
611   case GetEditMode of
612   esmGradient, esmShape, esmNoShape:
613     begin
614       BindOriginalEvent(true);
615       try
616         UpdateSnap(Manager.Image.CurrentState.LayeredBitmap.OriginalEditor);
617         Manager.Image.CurrentState.LayeredBitmap.MouseMove(ShiftState, ptF.X,ptF.Y, cur, handled);
618       finally
619         BindOriginalEvent(false);
620       end;
621       Cursor := OriginalCursorToCursor(cur);
622     end;
623   esmSelection, esmOtherOriginal:
624     if Assigned(FRectEditor) then
625     begin
626       ptView := FRectEditor.Matrix*ptF;
627       UpdateSnap(FRectEditor);
628       FRectEditor.MouseMove(ShiftState, ptView.X,ptView.Y, cur, handled);
629       Cursor := OriginalCursorToCursor(cur);
630       if handled then
631       begin
632         result := OnlyRenderChange;
633         UpdateMatrixFromRect;
634       end;
635     end;
636   end;
637 end;
638 
TEditShapeTool.DoToolUpdatenull639 function TEditShapeTool.DoToolUpdate(toolDest: TBGRABitmap): TRect;
640 var
641   doDraw, doFill: Boolean;
642   m: TAffineMatrix;
643   zoom: Single;
644   gradBox: TAffineBox;
645   f: TVectorShapeFields;
646   shape: TVectorShape;
647 begin
648   shape := nil;
649   case GetEditMode of
650   esmShape:
651     try
652       BindOriginalEvent(true);
653       shape := GetVectorOriginal.SelectedShape;
654       shape.BeginUpdate;
655       gradBox := shape.SuggestGradientBox(AffineMatrixIdentity);
656       m := AffineMatrixInverse(Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex]);
657       zoom := (VectLen(m[1,1],m[2,1])+VectLen(m[1,2],m[2,2]))/2;
658       f := shape.MultiFields;
659       if f*[vsfPenFill,vsfBackFill,vsfPenStyle] = [vsfPenFill,vsfBackFill,vsfPenStyle] then
660       begin
661         doDraw := toDrawShape in Manager.ShapeOptions;
662         doFill := toFillShape in Manager.ShapeOptions;
663 
664         if doDraw then
665           shape.PenStyle := PenStyleToBGRA(Manager.PenStyle)
666         else
667           shape.PenStyle := ClearPenStyle;
668 
669         if doDraw and (vsfPenWidth in f) then shape.PenWidth := Manager.PenWidth*zoom;
670         if doDraw and (vsfJoinStyle in f) then shape.JoinStyle := Manager.JoinStyle;
671         if shape is TCustomPolypointShape then
672         begin
673           TCustomPolypointShape(shape).Closed := toCloseShape in Manager.ShapeOptions;
674           if not TCustomPolypointShape(shape).Closed then
675           begin
676             TCustomPolypointShape(shape).LineCap:= Manager.LineCap;
677             TCustomPolypointShape(shape).ArrowSize:= Manager.ArrowSize;
678             TCustomPolypointShape(shape).ArrowStartKind:= Manager.ArrowStart;
679             TCustomPolypointShape(shape).ArrowEndKind:= Manager.ArrowEnd;
680           end;
681         end;
682         if shape is TCurveShape then
683           TCurveShape(shape).SplineStyle:= Manager.SplineStyle;
684       end else
685       begin
686         doDraw := vsfPenFill in f;
687         doFill := vsfBackFill in f;
688       end;
689       if doFill then AssignFill(shape.BackFill, Manager.BackFill, gradBox, BackFitMode)
690       else if vsfBackFill in f then
691           shape.BackFill.Clear;
692       if doDraw then AssignFill(shape.PenFill, Manager.ForeFill, gradBox, ForeFitMode);
693       if (vsfOutlineWidth in f) and Manager.TextOutline then shape.OutlineWidth := Manager.TextOutlineWidth*zoom;
694       if vsfOutlineFill in f then
695       begin
696         if Manager.TextOutline then
697           AssignFill(shape.OutLineFill, Manager.OutLineFill, gradBox, OutlineFitMode)
698           else shape.OutlineFill.Clear;
699       end;
700 
701       if shape is TTextShape then
702       with TTextShape(shape) do
703       begin
704         PenPhong := Manager.TextPhong;
705         LightPosition := m*Manager.LightPosition;
706         AltitudePercent := Manager.PhongShapeAltitude;
707         ParagraphAlignment := Manager.TextAlign;
708         FontName:= Manager.TextFontName;
709         FontEmHeight:= Manager.TextFontSize*zoom*Manager.Image.DPI/72;
710         FontStyle := Manager.TextFontStyle;
711         Aliased := Manager.ShapeOptionAliasing;
712       end;
713       if shape is TPhongShape then
714       with TPhongShape(shape) do
715       begin
716         ShapeKind := Manager.PhongShapeKind;
717         LightPosition := Manager.LightPosition;
718         ShapeAltitudePercent := Manager.PhongShapeAltitude;
719         BorderSizePercent := Manager.PhongShapeBorderSize;
720       end;
721     finally
722       if Assigned(shape) then shape.EndUpdate;
723       BindOriginalEvent(false);
724     end;
725   esmGradient:
726     try
727       BindOriginalEvent(true);
728       case Manager.BackFill.FillType of
729       vftGradient: GetGradientOriginal.AssignExceptGeometry(Manager.BackFill.Gradient);
730       vftSolid: GetGradientOriginal.SetColors(Manager.BackFill.SolidColor, Manager.BackFill.SolidColor);
731       end;
732     finally
733       BindOriginalEvent(false);
734     end;
735   end;
736   Result := EmptyRect;
737 end;
738 
739 procedure TEditShapeTool.UpdateSnap(AEditor: TBGRAOriginalEditor);
740 begin
741   if Assigned(AEditor) then
742     AEditor.GridActive := ssSnap in ShiftState;
743 end;
744 
GetActionnull745 function TEditShapeTool.GetAction: TLayerAction;
746 begin
747   result := nil;
748 end;
749 
TEditShapeTool.DoGetToolDrawingLayernull750 function TEditShapeTool.DoGetToolDrawingLayer: TBGRABitmap;
751 begin
752   Result:= Manager.Image.LayerBitmap[Manager.Image.CurrentLayerIndex];
753 end;
754 
755 procedure TEditShapeTool.OnTryStop(sender: TCustomLayerAction);
756 begin
757   StopEdit(True, True);
758   inherited OnTryStop(sender);
759 end;
760 
761 procedure TEditShapeTool.StopEdit(AUpdateInterface, ARaiseToolUp: boolean);
762 var
763   r: TRect;
764 begin
765   if ARaiseToolUp and (FLeftButton or FRightButton) then
766   begin
767     r := ToolUp;
768     Manager.Image.LayerMayChange(GetToolDrawingLayer,r);
769   end;
770   case GetEditMode of
771   esmShape: GetVectorOriginal.DeselectShapes;
772   esmGradient: FIsEditingGradient:= false;
773   esmOtherOriginal: FreeAndNil(FOriginalRect);
774   esmSelection: FreeAndNil(FSelectionRect);
775   end;
776   Manager.Image.CurrentState.LayeredBitmap.ClearEditor;
777   FLayerOriginalCapture:= false;
778   FreeAndNil(FRectEditor);
779   FRectEditorCapture := false;
780   Cursor := crDefault;
781   if AUpdateInterface then
782   begin
783     Manager.Image.OnImageChanged.NotifyObservers;
784     Manager.UpdateContextualToolbars;
785   end;
786 end;
787 
IsEditingnull788 function TEditShapeTool.IsEditing: boolean;
789 begin
790   result := not (GetEditMode in[esmNone, esmNoShape]);
791 end;
792 
793 procedure TEditShapeTool.MakeImageOriginal;
794 var
795   diff: TReplaceLayerByImageOriginalDifference;
796 begin
797   if GetCurrentLayerKind = lkBitmap then
798   begin
799     diff := TReplaceLayerByImageOriginalDifference.Create(Manager.Image.CurrentState,
800               Manager.Image.CurrentLayerIndex, false);
801     Manager.Image.AddUndo(diff);
802     if Assigned(Manager.Image.OnStackChanged) then
803       Manager.Image.OnStackChanged(Manager.Image, False);
804   end;
805 end;
806 
807 procedure TEditShapeTool.MakeVectorOriginal;
808 var
809   diff: TReplaceLayerByVectorOriginalDifference;
810 begin
811   if GetCurrentLayerKind in [lkEmpty,lkBitmap,lkTransformedBitmap] then
812   begin
813     StopEdit(True, True);
814     diff := TReplaceLayerByVectorOriginalDifference.Create(Manager.Image.CurrentState,
815               Manager.Image.CurrentLayerIndex, false);
816     Manager.Image.AddUndo(diff);
817     if Assigned(Manager.Image.OnStackChanged) then
818       Manager.Image.OnStackChanged(Manager.Image, False);
819   end;
820 end;
821 
822 procedure TEditShapeTool.UpdateMatrixFromRect;
823 begin
824   if Assigned(FOriginalRect) then
825     Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex] :=
826       GetMatrixFromRect(FOriginalRect,FOriginalRectUntransformed);
827   if Assigned(FSelectionRect) then
828   begin
829     Manager.Image.SelectionTransform :=
830       GetMatrixFromRect(FSelectionRect,FSelectionRectUntransformed);
831     Manager.Image.OnImageChanged.NotifyObservers;
832   end;
833 end;
834 
835 procedure TEditShapeTool.DoEditSelection;
836 begin
837   if not IsEditing then
838   begin
839     with Manager.Image.SelectionMaskBounds do
840       FSelectionRectUntransformed := rectF(Left-0.5, Top-0.5, Right-0.5, Bottom-0.5);
841     FSelectionRect := CreateRect(FSelectionRectUntransformed, Manager.Image.SelectionTransform);
842   end;
843 end;
844 
GetMatrixFromRectnull845 function TEditShapeTool.GetMatrixFromRect(ARect: TRectShape; AUntransformedRect: TRectF): TAffineMatrix;
846 var
847   u, v: TPointF;
848   mAfter, mBefore: TAffineMatrix;
849 begin
850   u := (ARect.XAxis-ARect.Origin)*2;
851   v := (ARect.YAxis-ARect.Origin)*2;
852   mAfter := AffineMatrix(u,v,ARect.Origin-(u+v)*0.5);
853   mBefore := AffineMatrixTranslation(AUntransformedRect.Left,
854                AUntransformedRect.Top)
855     *AffineMatrixScale(AUntransformedRect.Width,AUntransformedRect.Height);
856   if IsAffineMatrixInversible(mBefore) then
857     result := mAfter*AffineMatrixInverse(mBefore)
858   else
859     result := AffineMatrixIdentity;
860 end;
861 
TEditShapeTool.CreateRectnull862 function TEditShapeTool.CreateRect(AUntransformedRect: TRectF; AMatrix: TAffineMatrix): TRectShape;
863 var
864   box: TAffineBox;
865 begin
866   if (AUntransformedRect.Width > 0) and (AUntransformedRect.Height > 0) then
867   begin
868     result := TRectShape.Create(nil);
869     result.PenStyle := ClearPenStyle;
870     result.BackFill.SetSolid(BGRAWhite);
871     box := AMatrix*TAffineBox.AffineBox(AUntransformedRect);
872     result.Origin := (box.TopLeft+box.BottomRight)*0.5;
873     result.XAxis := result.Origin+(box.TopRight-box.TopLeft)*0.5;
874     result.YAxis := result.Origin+(box.BottomLeft-box.TopLeft)*0.5;
875     Manager.UpdateContextualToolbars;
876   end else
877     result := nil;
878 end;
879 
TEditShapeTool.GetIsSelectingToolnull880 function TEditShapeTool.GetIsSelectingTool: boolean;
881 begin
882   result := false;
883 end;
884 
GetVectorOriginalnull885 function TEditShapeTool.GetVectorOriginal: TVectorOriginal;
886 begin
887   result := Manager.Image.LayerOriginal[Manager.Image.CurrentLayerIndex] as TVectorOriginal;
888 end;
889 
GetGradientOriginalnull890 function TEditShapeTool.GetGradientOriginal: TBGRALayerGradientOriginal;
891 begin
892   result := Manager.Image.LayerOriginal[Manager.Image.CurrentLayerIndex] as TBGRALayerGradientOriginal;
893 end;
894 
GetImageOriginalnull895 function TEditShapeTool.GetImageOriginal: TBGRALayerImageOriginal;
896 begin
897   result := Manager.Image.LayerOriginal[Manager.Image.CurrentLayerIndex] as TBGRALayerImageOriginal;
898 end;
899 
TEditShapeTool.GetOriginalTransformnull900 function TEditShapeTool.GetOriginalTransform: TAffineMatrix;
901 begin
902   result := Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex];
903 end;
904 
TEditShapeTool.FixLayerOffsetnull905 function TEditShapeTool.FixLayerOffset: boolean;
906 begin
907   Result:= false;
908 end;
909 
910 destructor TEditShapeTool.Destroy;
911 begin
912   FreeAndNil(FOriginalRect);
913   FreeAndNil(FSelectionRect);
914   Manager.Image.CurrentState.LayeredBitmap.ClearEditor;
915   FreeAndNil(FRectEditor);
916   inherited Destroy;
917 end;
918 
TEditShapeTool.GetContextualToolbarsnull919 function TEditShapeTool.GetContextualToolbars: TContextualToolbars;
920 var
921   shape: TVectorShape;
922 begin
923   case GetEditMode of
924   esmShape:
925     begin
926       shape := GetVectorOriginal.SelectedShape;
927       result := ContextualToolbarsFromShape(TVectorShapeAny(shape.ClassType), shape);
928     end;
929   esmGradient: result := [ctBackFill];
930   else
931     Result:= [ctPenFill, ctBackFill];
932   end;
933 end;
934 
TEditShapeTool.Rendernull935 function TEditShapeTool.Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth,
936   VirtualScreenHeight: integer;
937   BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
938 var
939   orig, xAxis, yAxis: TPointF;
940   viewMatrix, editMatrix: TAffineMatrix;
941 begin
942   if InvalidEditMode then StopEdit(false,false);
943   with LayerOffset do
944   begin
945     orig := BitmapToVirtualScreen(PointF(-X,-Y));
946     xAxis := BitmapToVirtualScreen(PointF(-X+1,-Y));
947     yAxis := BitmapToVirtualScreen(PointF(-X,-Y+1));
948   end;
949   viewMatrix := AffineMatrixTranslation(0.5,0.5)
950                 *AffineMatrix(xAxis-orig,yAxis-orig,orig)
951                 *AffineMatrixTranslation(-0.5,-0.5);
952 
953   case GetEditMode of
954   esmGradient, esmShape:
955     begin
956       FreeAndNil(FRectEditor);
957       FRectEditorCapture := false;
958       if Assigned(Manager.Image.CurrentState.LayeredBitmap.OriginalEditor) then
959         Manager.Image.CurrentState.LayeredBitmap.OriginalEditor.GridMatrix := AffineMatrixScale(0.5,0.5);
960       if Assigned(VirtualScreen) then
961         result := Manager.Image.CurrentState.LayeredBitmap.DrawEditor(VirtualScreen,
962           Manager.Image.CurrentLayerIndex, viewMatrix, DoScaleX(PointSize*Manager.CanvasScale,OriginalDPI))
963       else
964         result := Manager.Image.CurrentState.LayeredBitmap.GetEditorBounds(
965           rect(0,0,VirtualScreenWidth,VirtualScreenHeight),
966           Manager.Image.CurrentLayerIndex, viewMatrix, DoScaleX(PointSize*Manager.CanvasScale,OriginalDPI));
967       RetrieveLightPosition;
968     end;
969   esmSelection, esmOtherOriginal:
970     begin
971       result := EmptyRect;
972       Manager.Image.CurrentState.LayeredBitmap.ClearEditor;
973       FLayerOriginalCapture:= false;
974       if not Assigned(FRectEditor) then
975       begin
976         FRectEditor := TVectorOriginalEditor.Create(nil);
977         FRectEditor.GridMatrix := AffineMatrixScale(0.5,0.5);
978         FRectEditor.Focused := true;
979         FRectEditor.PointSize := DoScaleX(PointSize*Manager.CanvasScale,OriginalDPI);
980       end;
981       FRectEditor.Clear;
982       editMatrix := AffineMatrixTranslation(-0.5,-0.5)*viewMatrix*AffineMatrixTranslation(0.5,0.5);
983       if IsAffineMatrixInversible(editMatrix) then
984       begin
985         FRectEditor.Matrix := editMatrix;
986         if Assigned(FOriginalRect) then FOriginalRect.ConfigureEditor(FRectEditor);
987         if Assigned(FSelectionRect) then FSelectionRect.ConfigureEditor(FRectEditor);
988         if Assigned(VirtualScreen) then
989           result := FRectEditor.Render(VirtualScreen,
990             rect(0,0,VirtualScreenWidth,VirtualScreenHeight))
991         else
992           result := FRectEditor.GetRenderBounds(
993             rect(0,0,VirtualScreenWidth,VirtualScreenHeight));
994       end
995       else
996         result := EmptyRect;
997     end;
998   else
999     begin
1000       result := EmptyRect;
1001       Manager.Image.CurrentState.LayeredBitmap.ClearEditor;
1002       FLayerOriginalCapture := false;
1003       FreeAndNil(FRectEditor);
1004       FRectEditorCapture := false;
1005     end;
1006   end;
1007 end;
1008 
TEditShapeTool.GetCurrentSplineModenull1009 function TEditShapeTool.GetCurrentSplineMode: TToolSplineMode;
1010 var
1011   orig: TVectorOriginal;
1012 begin
1013   if GetEditMode = esmShape then
1014   begin
1015     orig := GetVectorOriginal;
1016     if Assigned(orig.SelectedShape) and
1017       (orig.SelectedShape is TCurveShape) then
1018       exit(ToolSplineModeFromShape(orig.SelectedShape));
1019   end;
1020   result := tsmMovePoint;
1021 end;
1022 
1023 procedure TEditShapeTool.SetCurrentSplineMode(AMode: TToolSplineMode);
1024 var
1025   c: TCurveShape;
1026 begin
1027   if (GetEditMode = esmShape) and
1028     (GetVectorOriginal.SelectedShape is TCurveShape) then
1029   begin
1030     c := TCurveShape(GetVectorOriginal.SelectedShape);
1031     case AMode of
1032     tsmMovePoint: if not (c.Usermode in [vsuEdit,vsuCreate]) then c.Usermode := vsuEdit;
1033     tsmCurveModeAuto: if c.Usermode <> vsuCreate then c.Usermode := vsuCurveSetAuto else
1034                       if c.PointCount > 1 then c.CurveMode[c.PointCount-2] := cmAuto;
1035     tsmCurveModeAngle: if c.Usermode <> vsuCreate then c.Usermode := vsuCurveSetAngle else
1036                        if c.PointCount > 1 then c.CurveMode[c.PointCount-2] := cmAngle;
1037     tsmCurveModeSpline: if c.Usermode <> vsuCreate then c.Usermode := vsuCurveSetCurve else
1038                         if c.PointCount > 1 then c.CurveMode[c.PointCount-2] := cmCurve;
1039     end;
1040   end;
1041 end;
1042 
ConvertToSplinenull1043 function TEditShapeTool.ConvertToSpline: boolean;
1044 var
1045   shapeBefore: TVectorShape;
1046   orig: TVectorOriginal;
1047   shapeAfter: TCurveShape;
1048 begin
1049   if (GetEditMode = esmShape) and
1050     TCurveShape.CanCreateFrom(GetVectorOriginal.SelectedShape) then
1051   begin
1052     orig := GetVectorOriginal;
1053     shapeBefore:= orig.SelectedShape;
1054     shapeAfter := TCurveShape.CreateFrom(orig, shapeBefore);
1055     shapeAfter.JoinStyle := pjsRound;
1056     orig.ReplaceShape(orig.IndexOfShape(shapeBefore), shapeAfter);
1057     orig.SelectShape(shapeAfter, False);
1058     result := true;
1059   end else
1060     result := false;
1061 end;
1062 
TEditShapeTool.GetEditModenull1063 function TEditShapeTool.GetEditMode: TEditShapeMode;
1064 begin
1065   if InvalidEditMode then exit(esmNone);
1066   if Assigned(FSelectionRect) then exit(esmSelection)
1067   else if Assigned(FOriginalRect) then exit(esmOtherOriginal)
1068   else
1069   case GetCurrentLayerKind of
1070   lkGradient: if FIsEditingGradient then exit(esmGradient) else exit(esmNone);
1071   lkVectorial: if Assigned(GetVectorOriginal.SelectedShape) then exit(esmShape) else exit(esmNoShape);
1072   else exit(esmNone);
1073   end;
1074 end;
1075 
InvalidEditModenull1076 function TEditShapeTool.InvalidEditMode: boolean;
1077 begin
1078   if Assigned(FOriginalRect) and
1079      ((FOriginalLayerId <> Manager.Image.LayerId[Manager.Image.CurrentLayerIndex])
1080       or not (GetCurrentLayerKind in[lkTransformedBitmap,lkSVG,lkOther])) then
1081       result := true
1082   else if Assigned(FSelectionRect) and
1083        Manager.Image.SelectionMaskEmpty then result := true
1084   else if FIsEditingGradient and (GetCurrentLayerKind <> lkGradient) then
1085       result := true
1086   else
1087     result := false;
1088 end;
1089 
ForeGradTexModenull1090 function TEditShapeTool.ForeGradTexMode: TVectorShapeUsermode;
1091 begin
1092   result := vsuEditPenFill;
1093 end;
1094 
BackGradTexModenull1095 function TEditShapeTool.BackGradTexMode: TVectorShapeUsermode;
1096 begin
1097   result := vsuEditBackFill;
1098 end;
1099 
TEditShapeTool.OutlineGradTexModenull1100 function TEditShapeTool.OutlineGradTexMode: TVectorShapeUsermode;
1101 begin
1102   result := vsuEditOutlineFill;
1103 end;
1104 
ForeFitModenull1105 function TEditShapeTool.ForeFitMode: TFitMode;
1106 begin
1107   if IsForeEditGradTexPoints then result := fmNever
1108   else result := fmIfChange;
1109 end;
1110 
BackFitModenull1111 function TEditShapeTool.BackFitMode: TFitMode;
1112 begin
1113   if IsBackEditGradTexPoints then result := fmNever
1114   else result := fmIfChange;
1115 end;
1116 
OutlineFitModenull1117 function TEditShapeTool.OutlineFitMode: TFitMode;
1118 begin
1119   if IsOutlineEditGradTexPoints then result := fmNever
1120   else result := fmIfChange;
1121 end;
1122 
GetIsForeEditGradTexPointsnull1123 function TEditShapeTool.GetIsForeEditGradTexPoints: boolean;
1124 begin
1125   result := (GetEditMode = esmShape) and (GetVectorOriginal.SelectedShape.Usermode = ForeGradTexMode);
1126 end;
1127 
TEditShapeTool.GetIsBackEditGradTexPointsnull1128 function TEditShapeTool.GetIsBackEditGradTexPoints: boolean;
1129 begin
1130   result := (GetEditMode = esmShape) and (GetVectorOriginal.SelectedShape.Usermode = BackGradTexMode);
1131 end;
1132 
TEditShapeTool.GetIsOutlineEditGradTexPointsnull1133 function TEditShapeTool.GetIsOutlineEditGradTexPoints: boolean;
1134 begin
1135   result := (GetEditMode = esmShape) and (GetVectorOriginal.SelectedShape.Usermode = OutlineGradTexMode);
1136 end;
1137 
GetAllowedBackFillTypesnull1138 function TEditShapeTool.GetAllowedBackFillTypes: TVectorialFillTypes;
1139 begin
1140   if GetEditMode = esmGradient then
1141     result := [vftGradient] else
1142     Result:=inherited GetAllowedBackFillTypes;
1143 end;
1144 
TEditShapeTool.GetStatusTextnull1145 function TEditShapeTool.GetStatusText: string;
1146 var
1147   m: TAffineMatrix;
1148 begin
1149   m := AffineMatrixTranslation(-0.5, -0.5) *
1150        Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex] *
1151        AffineMatrixTranslation(0.5, 0.5);
1152 
1153   if (GetEditMode = esmShape) and Assigned(GetVectorOriginal.SelectedShape) then
1154     result := GetShapeStatusText(GetVectorOriginal.SelectedShape, m) else
1155   if (GetEditMode = esmSelection) and Assigned(FSelectionRect) then
1156     result := GetShapeStatusText(FSelectionRect, AffineMatrixIdentity) else
1157   if (GetEditMode = esmOtherOriginal) and Assigned(FOriginalRect) then
1158     result := GetShapeStatusText(FOriginalRect, AffineMatrixIdentity) else
1159   if (GetEditMode = esmGradient) then
1160     result := GetGradientStatusText(GetGradientOriginal, m) else
1161     Result:=inherited GetStatusText;
1162 end;
1163 
1164 constructor TEditShapeTool.Create(AManager: TToolManager);
1165 var
1166   orig: TVectorOriginal;
1167 begin
1168   inherited Create(AManager);
1169   FRectEditor := nil;
1170   FSelectionRect := nil;
1171   FOriginalRect := nil;
1172   FIsEditingGradient:= false;
1173   FLeftButton:= false;
1174   FRightButton:= false;
1175   if GetCurrentLayerKind = lkVectorial then
1176     orig := GetVectorOriginal
1177     else orig := nil;
1178   if not Manager.Image.SelectionMaskEmpty then
1179   begin
1180     if Assigned(orig) and Assigned(orig.SelectedShape) then
1181       orig.DeselectShapes;
1182     DoEditSelection;
1183   end else
1184   if Assigned(orig) and Assigned(orig.SelectedShape) then
1185     UpdateToolManagerFromShape(orig.SelectedShape);
1186 end;
1187 
DoToolKeyDownnull1188 function TEditShapeTool.DoToolKeyDown(var key: Word): TRect;
1189 var
1190   handled: boolean;
1191   keyUtf8: TUTF8Char;
1192 begin
1193   Result:= EmptyRect;
1194   if (Key = VK_SPACE) and (GetEditMode = esmShape) and (GetVectorOriginal.SelectedShape is TTextShape) then
1195   begin
1196     keyUtf8:= ' ';
1197     result := ToolKeyPress(keyUtf8);
1198     Key := 0;
1199   end else
1200   begin
1201     if GetEditMode in [esmShape,esmNoShape] then
1202     begin
1203       BindOriginalEvent(true);
1204       try
1205         Manager.Image.CurrentState.LayeredBitmap.KeyDown(ShiftState, LCLKeyToSpecialKey(key, ShiftState), handled);
1206         if handled then key := 0 else
1207         begin
1208           if (key = VK_DELETE) and Assigned(GetVectorOriginal.SelectedShape) then
1209           begin
1210             GetVectorOriginal.RemoveShape(GetVectorOriginal.SelectedShape);
1211             key := 0;
1212           end else
1213           if (key = VK_ESCAPE) and Assigned(GetVectorOriginal.SelectedShape) then
1214           begin
1215             if GetVectorOriginal.SelectedShape.Usermode = vsuEditText then
1216               GetVectorOriginal.SelectedShape.Usermode := vsuEdit
1217             else
1218               GetVectorOriginal.DeselectShapes;
1219             key := 0;
1220           end;
1221         end;
1222       finally
1223         BindOriginalEvent(false);
1224       end;
1225     end else
1226     begin
1227       if (Key = VK_DELETE) and (GetEditMode in [esmGradient,esmOtherOriginal]) then
1228       begin
1229         StopEdit(true, true);
1230         Manager.Image.ClearLayer;
1231         Key := 0;
1232       end else
1233       if key = VK_RETURN then
1234       begin
1235         if IsEditing then
1236         begin
1237           StopEdit(true, true);
1238           key := 0;
1239         end;
1240       end;
1241     end;
1242   end;
1243 end;
1244 
TEditShapeTool.ToolKeyPressnull1245 function TEditShapeTool.ToolKeyPress(var key: TUTF8Char): TRect;
1246 var
1247   handled: boolean;
1248   keyCode: word;
1249 begin
1250   Result:= EmptyRect;
1251   if GetEditMode in [esmShape,esmNoShape] then
1252   begin
1253     if Assigned(GetVectorOriginal.SelectedShape) and
1254       (GetVectorOriginal.SelectedShape is TCustomPolypointShape) and
1255       ((Key='i') or (Key='I')) then
1256     begin
1257       keyCode := VK_INSERT;
1258       ToolKeyDown(keyCode);
1259       if keyCode = 0 then key := #0;
1260       keyCode := VK_INSERT;
1261       ToolKeyUp(keyCode);
1262       result := EmptyRect;
1263     end else
1264     begin
1265       BindOriginalEvent(true);
1266       try
1267         Manager.Image.CurrentState.LayeredBitmap.KeyPress(key, handled);
1268         if handled then key := #0;
1269       finally
1270         BindOriginalEvent(false);
1271       end;
1272     end;
1273   end;
1274 end;
1275 
DoToolKeyUpnull1276 function TEditShapeTool.DoToolKeyUp(var key: Word): TRect;
1277 var
1278   handled: boolean;
1279 begin
1280   Result:= EmptyRect;
1281   if GetEditMode in [esmShape,esmNoShape] then
1282   begin
1283     BindOriginalEvent(true);
1284     try
1285       Manager.Image.CurrentState.LayeredBitmap.KeyUp(ShiftState, LCLKeyToSpecialKey(key, ShiftState), handled);
1286       if handled then key := 0;
1287     finally
1288       BindOriginalEvent(false);
1289     end;
1290   end;
1291 end;
1292 
ToolUpnull1293 function TEditShapeTool.ToolUp: TRect;
1294 var
1295   cur: TOriginalEditorCursor;
1296   handled: boolean;
1297   m: TAffineMatrix;
1298   ptView, ptSel: TPointF;
1299   zoom: Single;
1300 begin
1301   Result:= EmptyRect;
1302   if FLeftButton or FRightButton then
1303   begin
1304     handled := false;
1305     if not handled and FRectEditorCapture and Assigned(FRectEditor) then
1306     begin
1307       ptView := FRectEditor.Matrix*FLastPos;
1308       UpdateSnap(FRectEditor);
1309       FRectEditor.MouseUp(FRightButton, ShiftState, ptView.X,ptView.Y, cur, handled);
1310       Cursor := OriginalCursorToCursor(cur);
1311       if handled then
1312       begin
1313         result := OnlyRenderChange;
1314         UpdateMatrixFromRect;
1315       end else
1316       begin
1317         StopEdit(False, False);
1318         result := OnlyRenderChange;
1319       end;
1320     end;
1321     if not handled and FLayerOriginalCapture and (GetEditMode in [esmGradient, esmShape, esmNoShape]) then
1322     begin
1323       BindOriginalEvent(true);
1324       try
1325         Manager.Image.CurrentState.LayeredBitmap.MouseUp(FRightButton, ShiftState, FLastPos.X,FLastPos.Y, cur, handled);
1326         if handled then
1327         begin
1328           Cursor := OriginalCursorToCursor(cur);
1329           result := OnlyRenderChange;
1330         end;
1331       finally
1332         BindOriginalEvent(false);
1333       end;
1334     end;
1335     if not handled and not Manager.Image.SelectionMaskEmpty then
1336     begin
1337       ptSel := AffineMatrixInverse(Manager.Image.SelectionTransform)*FLastPos;
1338       if (Manager.Image.SelectionMaskReadonly.GetPixel(ptSel.x,ptSel.y).green > 0) then
1339       begin
1340         if GetEditMode <> esmSelection then
1341         begin
1342           StopEdit(false, false);
1343           DoEditSelection;
1344           result := OnlyRenderChange;
1345         end;
1346         handled := true;
1347       end else
1348         if GetEditMode = esmSelection then
1349         begin
1350           StopEdit(false, false);
1351           result := OnlyRenderChange;
1352         end;
1353     end;
1354     if not handled then
1355     begin
1356       case GetEditMode of
1357       esmShape, esmNoShape:
1358         if not FDownHandled then
1359         begin
1360           m := AffineMatrixInverse(Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex]);
1361           zoom := (VectLen(m[1,1],m[2,1])+VectLen(m[1,2],m[2,2]))/2/Manager.Image.ZoomFactor;
1362           BindOriginalEvent(true);
1363           try
1364             if GetVectorOriginal.MouseClick(m*FLastPos, DoScaleX(PointSize*Manager.CanvasScale, OriginalDPI)*zoom, ssSnap in ShiftState) then
1365             begin
1366               handled := true;
1367               result := OnlyRenderChange;
1368             end;
1369           finally
1370             BindOriginalEvent(false);
1371           end;
1372         end;
1373       esmGradient:
1374         begin
1375           FIsEditingGradient:= false;
1376           result := OnlyRenderChange;
1377         end;
1378       end;
1379     end;
1380     if not handled and (GetCurrentLayerKind in [lkBitmap, lkTransformedBitmap, lkSVG, lkOther]) and
1381        (Manager.Image.CurrentLayerReadOnly.GetPixel(FLastPos.X-LayerOffset.X, FLastPos.Y-LayerOffset.Y).alpha <> 0) then
1382     begin
1383       if GetEditMode <> esmOtherOriginal then
1384       begin
1385         StopEdit(false, false);
1386         MakeImageOriginal;
1387         if GetCurrentLayerKind in [lkTransformedBitmap, lkSVG, lkOther] then
1388         begin
1389           with Manager.Image.LayerOriginal[Manager.Image.CurrentLayerIndex].
1390             GetRenderBounds(InfiniteRect, AffineMatrixIdentity) do
1391             FOriginalRectUntransformed := rectF(Left-0.5, Top-0.5, Right-0.5, Bottom-0.5);
1392           FOriginalRect := CreateRect(FOriginalRectUntransformed,
1393             Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex]);
1394           FOriginalLayerId:= Manager.Image.LayerId[Manager.Image.CurrentLayerIndex];
1395           result := OnlyRenderChange;
1396         end;
1397       end;
1398       handled := true;
1399     end;
1400     if not handled and (GetCurrentLayerKind = lkGradient) then
1401     begin
1402       if not FIsEditingGradient then
1403       begin
1404         FIsEditingGradient:= true;
1405         Manager.BackFill.SetGradient(GetGradientOriginal, false);
1406         Manager.UpdateContextualToolbars;
1407         handled := true;
1408         result := OnlyRenderChange;
1409       end;
1410     end;
1411     FLeftButton:= false;
1412     FRightButton:= false;
1413     if Manager.Image.DraftOriginal then
1414       UpdateDraftMode;
1415   end;
1416 end;
1417 
TEditShapeTool.ToolCommandnull1418 function TEditShapeTool.ToolCommand(ACommand: TToolCommand): boolean;
1419 var
1420   key: Word;
1421   b: TRect;
1422   bmp: TBGRABitmap;
1423   s: TRectShape;
1424 begin
1425   if not ToolProvideCommand(ACommand) then exit(false);
1426   if ACommand = tcDelete then
1427   begin
1428     key := VK_DELETE;
1429     ToolKeyDown(key);
1430     if key = 0 then
1431     begin
1432       key := VK_DELETE;
1433       ToolKeyUp(key);
1434       result := true;
1435     end else
1436       result := false;
1437   end else
1438   if ACommand = tcPaste then
1439   begin
1440     result := false;
1441     MakeVectorOriginal;
1442     if GetCurrentLayerKind = lkVectorial then
1443     begin
1444       BindOriginalEvent(true);
1445       try
1446         PasteShapesFromClipboard(GetVectorOriginal, GetOriginalTransform, Manager.Image.VisibleArea);
1447       finally
1448         BindOriginalEvent(false);
1449       end;
1450       result := true;
1451     end;
1452   end else
1453   begin
1454     result := true;
1455     case GetEditMode of
1456     esmShape:
1457       try
1458         BindOriginalEvent(true);
1459         case ACommand of
1460           tcMoveUp: GetVectorOriginal.SelectedShape.MoveUp(true);
1461           tcMoveToFront: GetVectorOriginal.SelectedShape.BringToFront;
1462           tcMoveDown: GetVectorOriginal.SelectedShape.MoveDown(true);
1463           tcMoveToBack: GetVectorOriginal.SelectedShape.SendToBack;
1464           tcCopy: Result:= CopyShapesToClipboard([GetVectorOriginal.SelectedShape], GetOriginalTransform);
1465           tcCut: begin
1466                    result := CopyShapesToClipboard([GetVectorOriginal.SelectedShape], GetOriginalTransform) and
1467                              GetVectorOriginal.RemoveShape(GetVectorOriginal.SelectedShape);
1468                  end;
1469           tcAlignLeft..tcAlignBottom: AlignShape(GetVectorOriginal.SelectedShape, ACommand,
1470                        Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex],
1471                        rect(0,0,Manager.Image.Width,Manager.Image.Height));
1472           tcForeEditGradTexPoints: if GetVectorOriginal.SelectedShape.Usermode = ForeGradTexMode then
1473                                     GetVectorOriginal.SelectedShape.Usermode := vsuEdit else
1474                                     GetVectorOriginal.SelectedShape.Usermode := ForeGradTexMode;
1475           tcBackEditGradTexPoints: if GetVectorOriginal.SelectedShape.Usermode = BackGradTexMode then
1476                                     GetVectorOriginal.SelectedShape.Usermode := vsuEdit else
1477                                     GetVectorOriginal.SelectedShape.Usermode := BackGradTexMode;
1478           tcOutlineEditGradTexPoints: if GetVectorOriginal.SelectedShape.Usermode = OutlineGradTexMode then
1479                                     GetVectorOriginal.SelectedShape.Usermode := vsuEdit else
1480                                     GetVectorOriginal.SelectedShape.Usermode := OutlineGradTexMode;
1481           tcForeAdjustToShape: GetVectorOriginal.SelectedShape.PenFill.FitGeometry(SuggestGradientBox);
1482           tcBackAdjustToShape: GetVectorOriginal.SelectedShape.BackFill.FitGeometry(SuggestGradientBox);
1483           tcOutlineAdjustToShape: GetVectorOriginal.SelectedShape.OutlineFill.FitGeometry(SuggestGradientBox);
1484           tcShapeToSpline: result := ConvertToSpline;
1485           else result := false;
1486         end;
1487       finally
1488         BindOriginalEvent(false);
1489       end;
1490     esmGradient:
1491       begin
1492         case ACommand of
1493           tcBackAdjustToShape: GetGradientOriginal.FitGeometry(SuggestGradientBox);
1494           tcCut,tcCopy: begin
1495             s := TRectShape.Create(nil);
1496             try
1497               s.PenStyle := ClearPenStyle;
1498               s.QuickDefine(PointF(-0.5,-0.5),PointF(Manager.Image.Width-0.5,Manager.Image.Height-0.5));
1499               s.BackFill.SetGradient(GetGradientOriginal, false);
1500               s.BackFill.Transform(Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex]);
1501               CopyShapesToClipboard([s],AffineMatrixIdentity);
1502             finally
1503               s.free;
1504             end;
1505             if ACommand = tcCut then ToolCommand(tcDelete);
1506           end;
1507           else result := false;
1508         end;
1509       end;
1510     esmOtherOriginal:
1511       begin
1512         case ACommand of
1513           tcCut,tcCopy: begin
1514               b := Manager.Image.CurrentLayerReadOnly.GetImageBounds;
1515               if not b.IsEmpty then
1516               begin
1517                 if GetCurrentLayerKind = lkTransformedBitmap then
1518                 begin
1519                   bmp := GetImageOriginal.GetImageCopy;
1520                   s:= TRectShape.Create(nil);
1521                   s.QuickDefine(PointF(-0.5,-0.5),PointF(bmp.Width-0.5,bmp.Height-0.5));
1522                   s.PenStyle := ClearPenStyle;
1523                   s.BackFill.SetTexture(bmp,AffineMatrixIdentity,255,trNone);
1524                   s.Transform(Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex]);
1525                   bmp.FreeReference;
1526                 end else
1527                 begin
1528                   bmp := Manager.Image.CurrentLayerReadOnly.GetPart(b) as TBGRABitmap;
1529                   s:= TRectShape.Create(nil);
1530                   s.QuickDefine(PointF(b.Left-0.5,b.Top-0.5),PointF(b.Right-0.5,b.Bottom-0.5));
1531                   s.PenStyle := ClearPenStyle;
1532                   s.BackFill.SetTexture(bmp,AffineMatrixTranslation(b.Left,b.Top),255,trNone);
1533                   with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
1534                     s.Transform(AffineMatrixTranslation(x,y));
1535                   bmp.FreeReference;
1536                 end;
1537                 try
1538                   CopyShapesToClipboard([s],AffineMatrixIdentity);
1539                 finally
1540                   s.Free;
1541                 end;
1542                 if ACommand = tcCut then ToolCommand(tcDelete);
1543               end;
1544             end;
1545           tcAlignLeft..tcAlignBottom:
1546               begin
1547                 AlignShape(FOriginalRect, ACommand,
1548                            AffineMatrixIdentity,rect(0,0,Manager.Image.Width,Manager.Image.Height));
1549                 UpdateMatrixFromRect;
1550               end
1551           else result := false;
1552         end;
1553       end;
1554     esmSelection:
1555       begin
1556         if ACommand in [tcAlignLeft..tcAlignBottom] then
1557         begin
1558           AlignShape(FSelectionRect, ACommand,
1559                      AffineMatrixIdentity,rect(0,0,Manager.Image.Width,Manager.Image.Height));
1560           UpdateMatrixFromRect;
1561         end;
1562       end;
1563     end;
1564   end;
1565 end;
1566 
TEditShapeTool.ToolProvideCommandnull1567 function TEditShapeTool.ToolProvideCommand(ACommand: TToolCommand): boolean;
1568 begin
1569   case ACommand of
1570   tcCut,tcCopy,tcDelete: result:= GetEditMode in [esmShape,esmOtherOriginal,esmGradient];
1571   tcForeAdjustToShape,tcOutlineAdjustToShape: result := GetEditMode = esmShape;
1572   tcBackAdjustToShape: result := GetEditMode in [esmShape,esmGradient];
1573   tcForeEditGradTexPoints: result := (GetEditMode = esmShape) and
1574                      (ForeGradTexMode in GetVectorOriginal.SelectedShape.MultiUsermodes);
1575   tcBackEditGradTexPoints: result := (GetEditMode = esmShape) and
1576                      (BackGradTexMode in GetVectorOriginal.SelectedShape.MultiUsermodes);
1577   tcOutlineEditGradTexPoints: result := (GetEditMode = esmShape) and
1578                      (OutlineGradTexMode in GetVectorOriginal.SelectedShape.MultiUsermodes);
1579   tcShapeToSpline: result:= (GetEditMode = esmShape)
1580                             and TCurveShape.CanCreateFrom(GetVectorOriginal.SelectedShape);
1581   tcAlignLeft..tcAlignBottom: result:= GetEditMode in [esmShape, esmOtherOriginal, esmSelection];
1582   tcPaste: result := ClipboardHasShapes and (GetCurrentLayerKind in [lkEmpty,lkBitmap,lkTransformedBitmap,lkVectorial]);
1583   tcMoveUp,tcMoveToFront: result := (GetEditMode = esmShape)
1584                                      and not GetVectorOriginal.SelectedShape.IsFront;
1585   tcMoveDown,tcMoveToBack: result := (GetEditMode = esmShape)
1586                                       and not GetVectorOriginal.SelectedShape.IsBack;
1587   else
1588     result := false;
1589   end;
1590 end;
1591 
SuggestGradientBoxnull1592 function TEditShapeTool.SuggestGradientBox: TAffineBox;
1593 begin
1594   if GetEditMode = esmShape then
1595     result := GetVectorOriginal.SelectedShape.SuggestGradientBox(AffineMatrixIdentity)
1596   else
1597     result:= inherited SuggestGradientBox;
1598 end;
1599 
1600 { TVectorialTool }
1601 
1602 procedure TVectorialTool.ShapeChange(ASender: TObject; ABounds: TRectF; ADiff: TVectorShapeDiff);
1603 var
1604   toolDest: TBGRABitmap;
1605   r: TRect;
1606   matrix: TAffineMatrix;
1607 begin
1608   toolDest := GetToolDrawingLayer;
1609   matrix := VectorTransform(false);
1610   r := (matrix*TAffineBox.AffineBox(ABounds)).RectBounds;
1611   UpdateShape(toolDest);
1612   Action.NotifyChange(toolDest, r);
1613   with FShape.GetRenderBounds(rect(0,0,toolDest.Width,toolDest.Height),matrix,[]) do
1614     FPreviousUpdateBounds := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
1615   if r.IsEmpty then ShapeEditingChange(ASender);
1616   ADiff.Free;
1617 end;
1618 
1619 procedure TVectorialTool.ShapeEditingChange(ASender: TObject);
1620 var
1621   toolDest: TBGRABitmap;
1622   newEditorBounds, r: TRect;
1623 begin
1624   toolDest := GetToolDrawingLayer;
1625   with (Editor.Matrix*PointF(toolDest.Width,toolDest.Height)) do
1626     newEditorBounds := Editor.GetRenderBounds(rect(0,0,ceil(x),ceil(y)));
1627   r := RectUnion(FPreviousEditorBounds,newEditorBounds);
1628   if not r.IsEmpty then
1629     Manager.Image.RenderMayChange(r,false);
1630   FPreviousEditorBounds := newEditorBounds;
1631 end;
1632 
1633 procedure TVectorialTool.ShapeRemoveQuery(ASender: TObject;
1634   var AHandled: boolean);
1635 var
1636   r: TRect;
1637   toolDest: TBGRABitmap;
1638 begin
1639   if ASender <> FShape then exit;
1640   AHandled := true;
1641   toolDest := GetToolDrawingLayer;
1642   r := CancelShape;
1643   Action.NotifyChange(toolDest, r);
1644 end;
1645 
TVectorialTool.GetStatusTextnull1646 function TVectorialTool.GetStatusText: string;
1647 begin
1648   if Assigned(FShape) then
1649     result := GetShapeStatusText(FShape, VectorTransform(True))
1650     else Result:=inherited GetStatusText;
1651 end;
1652 
TVectorialTool.SlowShapenull1653 function TVectorialTool.SlowShape: boolean;
1654 begin
1655   if Assigned(FShape) then
1656     result := FShape.GetIsSlow(VectorTransform(false))
1657   else
1658     result := false;
1659 end;
1660 
1661 procedure TVectorialTool.QuickDefineEnd;
1662 begin
1663   //nothing
1664 end;
1665 
1666 procedure TVectorialTool.OnTryStop(sender: TCustomLayerAction);
1667 begin
1668   ValidateShape;
1669 end;
1670 
1671 procedure TVectorialTool.UpdateUseOriginal;
1672 begin
1673   if not IsSelectingTool and Manager.Image.SelectionMaskEmpty and
1674      (GetCurrentLayerKind = lkVectorial) then
1675     FUseOriginal:= true
1676   else
1677     FUseOriginal:= false;
1678 end;
1679 
ReplaceLayerAndAddShapenull1680 function TVectorialTool.ReplaceLayerAndAddShape(out ARect: TRect): TCustomImageDifference;
1681 var
1682   transf: TAffineMatrix;
1683   diff: TComposedImageDifference;
1684   replaceDiff: TReplaceLayerByVectorOriginalDifference;
1685   layerId: integer;
1686   addDiff: TAddShapeToVectorOriginalDifference;
1687 begin
1688   layerId := Manager.Image.LayerId[Manager.Image.CurrentLayerIndex];
1689   transf := VectorTransform(false);
1690   diff := TComposedImageDifference.Create;
1691   replaceDiff := TReplaceLayerByVectorOriginalDifference.Create(Manager.Image.CurrentState,Manager.Image.CurrentLayerIndex,
1692                    GetCurrentLayerKind = lkVectorial);
1693   diff.Add(replaceDiff);
1694   transf := AffineMatrixInverse(Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex])*transf;
1695   FShape.Transform(transf);
1696   addDiff := TAddShapeToVectorOriginalDifference.Create(Manager.Image.CurrentState,layerId,FShape);
1697   diff.Add(addDiff);
1698   result := diff;
1699   ARect := addDiff.ChangingBounds;
1700   FShape := nil;
1701 end;
1702 
1703 procedure TVectorialTool.ShapeValidated;
1704 begin
1705   //nothing
1706 end;
1707 
TVectorialTool.ForeGradTexModenull1708 function TVectorialTool.ForeGradTexMode: TVectorShapeUsermode;
1709 begin
1710   if Assigned(FShape) and FSwapColor then
1711   begin
1712     if vsfBackFill in FShape.Fields then
1713       result := vsuEditBackFill
1714     else if vsfOutlineFill in FShape.Fields then
1715       result := vsuEditOutlineFill
1716     else
1717       result := vsuEditPenFill;
1718   end else
1719     result := vsuEditPenFill;
1720 end;
1721 
BackGradTexModenull1722 function TVectorialTool.BackGradTexMode: TVectorShapeUsermode;
1723 begin
1724   if Assigned(FShape) and FSwapColor and (vsfPenFill in FShape.Fields) then
1725     result := vsuEditPenFill
1726   else
1727     result := vsuEditBackFill;
1728 end;
1729 
TVectorialTool.OutlineGradTexModenull1730 function TVectorialTool.OutlineGradTexMode: TVectorShapeUsermode;
1731 begin
1732   if Assigned(FShape) and FSwapColor and ([vsfPenFill,vsfBackFill]*FShape.Fields = [vsfPenFill]) then
1733     result := vsuEditPenFill
1734   else
1735     result := vsuEditOutlineFill;
1736 end;
1737 
ForeFitModenull1738 function TVectorialTool.ForeFitMode: TFitMode;
1739 begin
1740   if IsForeEditGradTexPoints then result := fmNever
1741   else result := fmIfChange;
1742 end;
1743 
TVectorialTool.BackFitModenull1744 function TVectorialTool.BackFitMode: TFitMode;
1745 begin
1746   if IsBackEditGradTexPoints then result := fmNever
1747   else result := fmIfChange;
1748 end;
1749 
OutlineFitModenull1750 function TVectorialTool.OutlineFitMode: TFitMode;
1751 begin
1752   if IsOutlineEditGradTexPoints then result := fmNever
1753   else result := fmIfChange;
1754 end;
1755 
ManagerForeFillnull1756 function TVectorialTool.ManagerForeFill: TVectorialFill;
1757 begin
1758   if Assigned(FShape) and FSwapColor then
1759   begin
1760     if vsfBackFill in FShape.Fields then
1761       result := Manager.BackFill
1762     else if vsfOutlineFill in FShape.Fields then
1763       result := Manager.OutlineFill
1764     else
1765       result := Manager.ForeFill;
1766   end else
1767     result := Manager.ForeFill;
1768 end;
1769 
TVectorialTool.ManagerBackFillnull1770 function TVectorialTool.ManagerBackFill: TVectorialFill;
1771 begin
1772   if Assigned(FShape) and FSwapColor and (vsfPenFill in FShape.Fields) then
1773     result := Manager.ForeFill
1774   else
1775     result := Manager.BackFill;
1776 end;
1777 
ManagerOutlineFillnull1778 function TVectorialTool.ManagerOutlineFill: TVectorialFill;
1779 begin
1780   if Assigned(FShape) and FSwapColor and ([vsfPenFill,vsfBackFill]*FShape.Fields = [vsfPenFill]) then
1781     result := Manager.ForeFill
1782   else
1783     result := Manager.OutlineFill;
1784 end;
1785 
GetIsForeEditGradTexPointsnull1786 function TVectorialTool.GetIsForeEditGradTexPoints: boolean;
1787 begin
1788   result := Assigned(FShape) and (FShape.Usermode = ForeGradTexMode);
1789 end;
1790 
TVectorialTool.GetIsBackEditGradTexPointsnull1791 function TVectorialTool.GetIsBackEditGradTexPoints: boolean;
1792 begin
1793   result := Assigned(FShape) and (FShape.Usermode = BackGradTexMode);
1794 end;
1795 
GetIsOutlineEditGradTexPointsnull1796 function TVectorialTool.GetIsOutlineEditGradTexPoints: boolean;
1797 begin
1798   result := Assigned(FShape) and (FShape.Usermode = OutlineGradTexMode);
1799 end;
1800 
TVectorialTool.GetGridMatrixnull1801 function TVectorialTool.GetGridMatrix: TAffineMatrix;
1802 begin
1803   if Manager.Image.ZoomFactor > DoScaleX(35, OriginalDPI)/10 then
1804     result := AffineMatrixScale(0.5,0.5)
1805   else
1806   begin
1807     if Assigned(FShape) and
1808          (not (vsfPenFill in FShape.MultiFields) or
1809            (FShape.PenFill.IsFullyTransparent)) then
1810       result := AffineMatrixTranslation(0.5, 0.5)
1811     else
1812       result := AffineMatrixIdentity;
1813   end;
1814 end;
1815 
ValidateShapenull1816 function TVectorialTool.ValidateShape: TRect;
1817 var
1818   layerId: LongInt;
1819   rF: TRectF;
1820   changeBounds: TRect;
1821   addDiff: TAddShapeToVectorOriginalDifference;
1822 begin
1823   if Assigned(FShape) then
1824   begin
1825     FShape.OnChange:= nil;
1826     FShape.OnEditingChange:= nil;
1827     FShape.OnRemoveQuery:= nil;
1828     if not AlwaysRasterizeShape and Manager.Image.SelectionMaskEmpty then
1829     begin
1830       CancelAction;
1831       if FShape.Usermode = vsuCreate then FShape.Usermode:= vsuEdit;
1832       rF := FShape.GetRenderBounds(rect(0,0,Manager.Image.Width,Manager.Image.Height), VectorTransform(false));
1833       if rF.IntersectsWith(rectF(0,0,Manager.Image.Width,Manager.Image.Height)) then
1834       begin
1835         if UseOriginal then
1836         begin
1837           layerId := Manager.Image.LayerId[Manager.Image.CurrentLayerIndex];
1838           addDiff := TAddShapeToVectorOriginalDifference.Create(Manager.Image.CurrentState,layerId,FShape);
1839           changeBounds := addDiff.ChangingBounds;
1840           Manager.Image.AddUndo(addDiff);
1841           FShape := nil;
1842         end
1843         else
1844           Manager.Image.AddUndo(ReplaceLayerAndAddShape(changeBounds));
1845         Manager.Image.ImageMayChange(changeBounds);
1846       end;
1847       ClearShape;
1848     end else
1849     begin
1850       ValidateActionPartially;
1851       ClearShape;
1852     end;
1853     Cursor := crDefault;
1854     result := OnlyRenderChange;
1855     UpdateUseOriginal;
1856     ShapeValidated;
1857   end else
1858     result := EmptyRect;
1859 end;
1860 
TVectorialTool.CancelShapenull1861 function TVectorialTool.CancelShape: TRect;
1862 begin
1863   CancelActionPartially;
1864   ClearShape;
1865   Cursor := crDefault;
1866   result := OnlyRenderChange;
1867 end;
1868 
GetEditornull1869 function TVectorialTool.GetEditor: TBGRAOriginalEditor;
1870 begin
1871   FEditor.GridActive := ssSnap in ShiftState;
1872   result := FEditor;
1873 end;
1874 
TVectorialTool.GetIsHandDrawingnull1875 function TVectorialTool.GetIsHandDrawing: boolean;
1876 begin
1877   result := Assigned(FShape) and (FQuickDefine or (FShape.Usermode = vsuCreate));
1878 end;
1879 
TVectorialTool.GetIsIdlenull1880 function TVectorialTool.GetIsIdle: boolean;
1881 begin
1882   result := FShape = nil;
1883 end;
1884 
AlwaysRasterizeShapenull1885 function TVectorialTool.AlwaysRasterizeShape: boolean;
1886 begin
1887   result := false;
1888 end;
1889 
CreateShapenull1890 function TVectorialTool.CreateShape: TVectorShape;
1891 begin
1892   result := ShapeClass.Create(nil);
1893 end;
1894 
1895 procedure TVectorialTool.ClearShape;
1896 begin
1897   FreeAndNil(FShape);
1898   FreeAndNil(FTemporaryStorage);
1899   Editor.Clear;
1900 end;
1901 
UseOriginalnull1902 function TVectorialTool.UseOriginal: boolean;
1903 begin
1904   result := FUseOriginal;
1905 end;
1906 
HasBrushnull1907 function TVectorialTool.HasBrush: boolean;
1908 begin
1909   result := (toFillShape in GetManagerShapeOptions) or not (ctShape in GetContextualToolbars);
1910 end;
1911 
GetCustomShapeBoundsnull1912 function TVectorialTool.GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; ADraft: boolean): TRect;
1913 begin
1914   with FShape.GetRenderBounds(ADestBounds,AMatrix,[]) do
1915     result := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
1916 end;
1917 
1918 procedure TVectorialTool.DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean);
1919 begin
1920   FShape.Render(ADest,AMatrix,ADraft);
1921 end;
1922 
1923 procedure TVectorialTool.AssignShapeStyle(AMatrix: TAffineMatrix; AAlwaysFit: boolean);
1924 var
1925   f: TVectorShapeFields;
1926   zoom: Single;
1927   gradBox: TAffineBox;
1928   fitMode: TFitMode;
1929 begin
1930   zoom := (VectLen(AMatrix[1,1],AMatrix[2,1])+VectLen(AMatrix[1,2],AMatrix[2,2]))/2;
1931   f := FShape.MultiFields;
1932   gradBox := FShape.SuggestGradientBox(AffineMatrixIdentity);
1933   if vsfPenFill in f then
1934   begin
1935     if HasPen then
1936     begin
1937       if AAlwaysFit then fitMode := fmAlways else fitMode := ForeFitMode;
1938       AssignFill(FShape.PenFill, ManagerForeFill, gradBox, fitMode)
1939     end else
1940       FShape.PenFill.Clear;
1941   end;
1942   if vsfPenWidth in f then FShape.PenWidth := zoom*Manager.PenWidth;
1943   if vsfPenStyle in f Then FShape.PenStyle := PenStyleToBGRA(Manager.PenStyle);
1944   if vsfJoinStyle in f then FShape.JoinStyle:= Manager.JoinStyle;
1945   if vsfBackFill in f then
1946   begin
1947     if HasBrush then
1948     begin
1949       if AAlwaysFit then fitMode := fmAlways else fitMode := BackFitMode;
1950       AssignFill(FShape.BackFill, ManagerBackFill, gradBox, fitMode)
1951     end else
1952       FShape.BackFill.Clear;
1953   end;
1954   if vsfOutlineFill in f then
1955   begin
1956     if Manager.TextOutline then
1957     begin
1958       if AAlwaysFit then fitMode := fmAlways else fitMode := OutlineFitMode;
1959       AssignFill(FShape.OutlineFill, ManagerOutlineFill, gradBox, fitMode);
1960     end else
1961       FShape.OutlineFill.Clear;
1962   end;
1963   if (vsfOutlineWidth in f) and Manager.TextOutline then
1964     FShape.OutlineWidth := zoom*Manager.TextOutlineWidth;
1965 end;
1966 
TVectorialTool.GetManagerShapeOptionsnull1967 function TVectorialTool.GetManagerShapeOptions: TShapeOptions;
1968 begin
1969   result := Manager.ShapeOptions;
1970 end;
1971 
1972 procedure TVectorialTool.QuickDefineShape(AStart, AEnd: TPointF);
1973 begin
1974   FShape.QuickDefine(AStart, AEnd);
1975 end;
1976 
RoundCoordinatenull1977 function TVectorialTool.RoundCoordinate(constref ptF: TPointF): TPointF;
1978 begin
1979   if not (toDrawShape in GetManagerShapeOptions) or
1980     (Assigned(FShape) and not (vsfPenFill in FShape.MultiFields)) then
1981     result := PointF(floor(ptF.x)+0.5,floor(ptF.y)+0.5)
1982   else
1983     result := PointF(round(ptF.x),round(ptF.y));
1984 end;
1985 
TVectorialTool.GetIsSelectingToolnull1986 function TVectorialTool.GetIsSelectingTool: boolean;
1987 begin
1988   result := false;
1989 end;
1990 
TVectorialTool.UpdateShapenull1991 function TVectorialTool.UpdateShape(toolDest: TBGRABitmap): TRect;
1992 var
1993   newBounds: TRect;
1994   oldClip: TRect;
1995   matrix: TAffineMatrix;
1996 begin
1997   result := FPreviousUpdateBounds;
1998   RestoreBackupDrawingLayer;
1999   matrix := VectorTransform(false);
2000   FLastDraftUpdate := PreferDraftUpdate;
2001   newBounds := GetCustomShapeBounds(toolDest.ClipRect,matrix,FLastDraftUpdate);
2002   result := RectUnion(result, newBounds);
2003   oldClip := toolDest.IntersectClip(newBounds);
2004   DrawCustomShape(toolDest,matrix,FLastDraftUpdate);
2005   toolDest.ClipRect := oldClip;
2006   FPreviousUpdateBounds := newBounds;
2007 end;
2008 
PreferDraftUpdatenull2009 function TVectorialTool.PreferDraftUpdate: boolean;
2010 begin
2011   if Assigned(FShape) then
2012     result := (FEditor.IsMovingPoint or FShape.IsFollowingMouse or FQuickDefine) and SlowShape
2013   else
2014     result := false;
2015 end;
2016 
TVectorialTool.VectorTransformnull2017 function TVectorialTool.VectorTransform(APixelCentered: boolean): TAffineMatrix;
2018 begin
2019   if not UseOriginal then
2020     result := AffineMatrixIdentity
2021   else
2022     result := Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex];
2023   if APixelCentered then
2024     result := MatrixForPixelCentered(result);
2025 end;
2026 
2027 procedure TVectorialTool.UpdateCursor(ACursor: TOriginalEditorCursor);
2028 begin
2029   Cursor := OriginalCursorToCursor(ACursor);
2030 end;
2031 
TVectorialTool.FixLayerOffsetnull2032 function TVectorialTool.FixLayerOffset: boolean;
2033 begin
2034   Result:= false;
2035 end;
2036 
DoToolDownnull2037 function TVectorialTool.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
2038   ptF: TPointF; rightBtn: boolean): TRect;
2039 var
2040   viewPt, shapePt: TPointF;
2041   cur: TOriginalEditorCursor;
2042   handled: boolean;
2043 begin
2044   result := EmptyRect;
2045   FRightDown := rightBtn;
2046   FLeftDown := not rightBtn;
2047   with LayerOffset do
2048     FLastPos := AffineMatrixTranslation(X,Y)*ptF;
2049   if Assigned(FShape) then
2050   begin
2051     viewPt := Editor.Matrix*AffineMatrixInverse(VectorTransform(true))*FLastPos;
2052     Editor.MouseDown(rightBtn, ShiftState, viewPt.X,viewPt.Y, cur, handled);
2053     if not handled and Assigned(FShape) then
2054     begin
2055       shapePt := AffineMatrixInverse(VectorTransform(true))*FLastPos;
2056       If Editor.GridActive then shapePt := Editor.SnapToGrid(shapePt, false);
2057       FShape.MouseDown(rightBtn, ShiftState, shapePt.X,shapePt.Y, cur, handled);
2058     end;
2059     UpdateCursor(cur);
2060     if handled then exit
2061     else result := RectUnion(result, ValidateShape);
2062   end;
2063 
2064   if FShape=nil then
2065   begin
2066     if UseOriginal and
2067       ((Manager.Image.LayerOriginal[Manager.Image.CurrentLayerIndex] as TVectorOriginal).GetShapesCost >= MediumShapeCost) then
2068     begin
2069       MessagePopup(rsTooManyShapesInLayer, 3000);
2070     end
2071     else
2072     if (GetCurrentLayerKind = lkSVG) and not IsSelectingTool then
2073     begin
2074       MessagePopup(rsCannotDrawShapeOnSVGLayer, 3000);
2075     end
2076     else
2077     begin
2078       toolDest := GetToolDrawingLayer;
2079       FSwapColor:= rightBtn;
2080       if IsSelectingTool then
2081         FLayerWasEmpty := Manager.Image.SelectionMaskEmpty
2082       else if Manager.Image.SelectionMaskEmpty then
2083         FLayerWasEmpty := Manager.Image.CurrentLayerEmpty
2084       else
2085         FLayerWasEmpty := Manager.Image.SelectionLayerIsEmpty;
2086       FShape := CreateShape;
2087       if FTemporaryStorage = nil then FTemporaryStorage := TBGRAMemOriginalStorage.Create;
2088       FShape.TemporaryStorage := FTemporaryStorage;
2089       FQuickDefine := true;
2090       FQuickDefineStartPoint := RoundCoordinate(FLastPos);
2091       FQuickDefineEndPoint := FQuickDefineStartPoint;
2092       FShape.BeginUpdate;
2093         QuickDefineShape(FQuickDefineStartPoint,FQuickDefineEndPoint);
2094         FLastShapeTransform := AffineMatrixInverse(VectorTransform(false));
2095         FShape.Transform(FLastShapeTransform);
2096         shapePt := AffineMatrixInverse(VectorTransform(true))*FLastPos;
2097         handled := false;
2098         FShape.MouseMove(ShiftState, shapePt.X,shapePt.Y, cur, handled);
2099         AssignShapeStyle(FLastShapeTransform, true);
2100       FShape.EndUpdate;
2101       FShape.OnChange:= @ShapeChange;
2102       FShape.OnEditingChange:=@ShapeEditingChange;
2103       FShape.OnRemoveQuery:= @ShapeRemoveQuery;
2104       result := RectUnion(result, UpdateShape(toolDest));
2105       if FShape is TCustomRectShape then
2106         Manager.ToolPopup(tpmHoldKeyForSquare, VK_SHIFT);
2107     end;
2108   end;
2109 end;
2110 
DoToolMovenull2111 function TVectorialTool.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
2112   ptF: TPointF): TRect;
2113 var
2114   s: TPointF;
2115   avg: single;
2116   viewPt, shapePt: TPointF;
2117   handled: boolean;
2118   cur: TOriginalEditorCursor;
2119 begin
2120   Editor.GridMatrix := GetGridMatrix;
2121   with LayerOffset do
2122     FLastPos := AffineMatrixTranslation(X,Y)*ptF;
2123   if FQuickDefine then
2124   begin
2125     FQuickDefineEndPoint := RoundCoordinate(ptF);
2126     if ssShift in ShiftState then
2127     begin
2128       s := FQuickDefineEndPoint-FQuickDefineStartPoint;
2129       avg := sqrt(abs(s.x*s.y));
2130       if s.x > 0 then FQuickDefineEndPoint.x := FQuickDefineStartPoint.x + avg else FQuickDefineEndPoint.x := FQuickDefineStartPoint.x - avg;
2131       if s.y > 0 then FQuickDefineEndPoint.y := FQuickDefineStartPoint.y + avg else FQuickDefineEndPoint.y := FQuickDefineStartPoint.y - avg;
2132     end;
2133     FShape.BeginUpdate;
2134       QuickDefineShape(FQuickDefineStartPoint, FQuickDefineEndPoint);
2135       FLastShapeTransform := AffineMatrixInverse(VectorTransform(false));
2136       FShape.Transform(FLastShapeTransform);
2137       AssignShapeStyle(FLastShapeTransform, true);
2138     FShape.EndUpdate;
2139     result := OnlyRenderChange;
2140   end else
2141   begin
2142     viewPt := Editor.Matrix*AffineMatrixInverse(VectorTransform(true))*FLastPos;
2143     Editor.MouseMove(ShiftState, viewPt.X,viewPt.Y, cur, handled);
2144     if not handled and Assigned(FShape) then
2145     begin
2146       shapePt := AffineMatrixInverse(VectorTransform(true))*FLastPos;
2147       If Editor.GridActive then shapePt := Editor.SnapToGrid(shapePt, false);
2148       FShape.MouseMove(ShiftState, shapePt.X,shapePt.Y, cur, handled);
2149     end;
2150     UpdateCursor(cur);
2151     if handled then result := OnlyRenderChange
2152     else result := EmptyRect;
2153   end;
2154 end;
2155 
TVectorialTool.DoToolUpdatenull2156 function TVectorialTool.DoToolUpdate(toolDest: TBGRABitmap): TRect;
2157 begin
2158   if Assigned(FShape) then
2159   begin
2160     FShape.BeginUpdate;
2161     AssignShapeStyle(FLastShapeTransform, false);
2162     FShape.EndUpdate;
2163   end;
2164   result := EmptyRect;
2165 end;
2166 
2167 constructor TVectorialTool.Create(AManager: TToolManager);
2168 begin
2169   inherited Create(AManager);
2170   UpdateUseOriginal;
2171   FPreviousUpdateBounds := EmptyRect;
2172   FEditor := TVectorOriginalEditor.Create(nil);
2173   FEditor.GridMatrix := GetGridMatrix;
2174   FEditor.Focused := true;
2175   FPreviousEditorBounds := EmptyRect;
2176   FLastShapeTransform := AffineMatrixIdentity;
2177   FTemporaryStorage := TBGRAMemOriginalStorage.Create;
2178 end;
2179 
ToolUpnull2180 function TVectorialTool.ToolUp: TRect;
2181 var
2182   viewPt, shapePt: TPointF;
2183   cur: TOriginalEditorCursor;
2184   handled, wasRight: boolean;
2185 begin
2186   wasRight := FRightDown;
2187   FRightDown := false;
2188   FLeftDown := false;
2189   if FQuickDefine then
2190   begin
2191     FQuickDefine := false;
2192     result := EmptyRect;
2193     QuickDefineEnd;
2194   end else
2195   begin
2196     viewPt := Editor.Matrix*AffineMatrixInverse(VectorTransform(true))*FLastPos;
2197     Editor.MouseUp(wasRight, ShiftState, viewPt.X,viewPt.Y, cur, handled);
2198     if not handled and Assigned(FShape) then
2199     begin
2200       shapePt := AffineMatrixInverse(VectorTransform(true))*FLastPos;
2201       FShape.MouseUp(wasRight, ShiftState, shapePt.X,shapePt.Y, cur, handled);
2202     end;
2203     UpdateCursor(cur);
2204     result := EmptyRect;
2205   end;
2206   if (FLastDraftUpdate and not PreferDraftUpdate) and Assigned(FShape) then
2207     result := UpdateShape(GetToolDrawingLayer);
2208 end;
2209 
DoToolKeyDownnull2210 function TVectorialTool.DoToolKeyDown(var key: Word): TRect;
2211 var
2212   handled: boolean;
2213 begin
2214   result := EmptyRect;
2215   if (Key = VK_RETURN) and not FQuickDefine and
2216     Assigned(FShape) then
2217   begin
2218     result := ValidateShape;
2219     Key := 0;
2220   end else
2221   if (Key = VK_ESCAPE) and not FQuickDefine and
2222     Assigned(FShape) then
2223   begin
2224     result := CancelShape;
2225     Key := 0;
2226   end else
2227   begin
2228     Editor.KeyDown(ShiftState, LCLKeyToSpecialKey(Key, ShiftState), handled);
2229     if not handled and Assigned(FShape) then FShape.KeyDown(ShiftState, LCLKeyToSpecialKey(Key, ShiftState), handled);
2230     if handled then Key := 0;
2231   end;
2232 end;
2233 
ToolKeyPressnull2234 function TVectorialTool.ToolKeyPress(var key: TUTF8Char): TRect;
2235 var
2236   handled: boolean;
2237 begin
2238   result := EmptyRect;
2239   Editor.KeyPress(key, handled);
2240   if not handled and Assigned(FShape) then FShape.KeyPress(key, handled);
2241   if handled then Key := #0;
2242 end;
2243 
TVectorialTool.DoToolKeyUpnull2244 function TVectorialTool.DoToolKeyUp(var key: Word): TRect;
2245 var
2246   handled: boolean;
2247 begin
2248   result := EmptyRect;
2249   Editor.KeyUp(ShiftState, LCLKeyToSpecialKey(Key, ShiftState), handled);
2250   if not handled and Assigned(FShape) then FShape.KeyUp(ShiftState, LCLKeyToSpecialKey(Key, ShiftState), handled);
2251   if handled then Key := 0;
2252 end;
2253 
TVectorialTool.ToolCommandnull2254 function TVectorialTool.ToolCommand(ACommand: TToolCommand): boolean;
2255 var
2256   r: TRect;
2257   toolDest: TBGRABitmap;
2258 begin
2259   result := false;
2260   case ACommand of
2261   tcCopy:
2262       if ToolProvideCommand(tcCopy) then
2263         result := CopyShapesToClipboard([FShape], VectorTransform(false));
2264   tcCut:
2265       if ToolCommand(tcCopy) then
2266       begin
2267         toolDest := GetToolDrawingLayer;
2268         r := CancelShape;
2269         Action.NotifyChange(toolDest, r);
2270         result := true;
2271       end;
2272   tcForeAdjustToShape: if Assigned(FShape) then FShape.PenFill.FitGeometry(SuggestGradientBox);
2273   tcBackAdjustToShape: if Assigned(FShape) then FShape.BackFill.FitGeometry(SuggestGradientBox);
2274   tcOutlineAdjustToShape: if Assigned(FShape) then FShape.OutlineFill.FitGeometry(SuggestGradientBox);
2275   tcForeEditGradTexPoints: if Assigned(FShape) and not FQuickDefine then
2276                           begin
2277                             if FShape.Usermode = ForeGradTexMode then
2278                               FShape.Usermode := vsuEdit else
2279                               FShape.Usermode := ForeGradTexMode;
2280                           end;
2281   tcBackEditGradTexPoints: if Assigned(FShape) and not FQuickDefine then
2282                           begin
2283                             if FShape.Usermode = BackGradTexMode then
2284                               FShape.Usermode := vsuEdit else
2285                               FShape.Usermode := BackGradTexMode;
2286                           end;
2287   tcOutlineEditGradTexPoints: if Assigned(FShape) and not FQuickDefine then
2288                           begin
2289                             if FShape.Usermode = OutlineGradTexMode then
2290                               FShape.Usermode := vsuEdit else
2291                               FShape.Usermode := OutlineGradTexMode;
2292                           end;
2293   tcFinish: begin
2294               toolDest := GetToolDrawingLayer;
2295               r := ValidateShape;
2296               Action.NotifyChange(toolDest, r);
2297               result := true;
2298           end;
2299   tcAlignLeft..tcAlignBottom:
2300       if ToolProvideCommand(ACommand) then
2301       begin
2302         AlignShape(FShape, ACommand,
2303                  Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex],
2304                  rect(0,0,Manager.Image.Width,Manager.Image.Height));
2305         result := true;
2306       end;
2307   else
2308     result := false;
2309   end;
2310 end;
2311 
TVectorialTool.ToolProvideCommandnull2312 function TVectorialTool.ToolProvideCommand(ACommand: TToolCommand): boolean;
2313 begin
2314   case ACommand of
2315   tcCopy,tcCut: Result:= not IsSelectingTool and not FQuickDefine and Assigned(FShape);
2316   tcFinish: result := not IsIdle;
2317   tcForeAdjustToShape, tcBackAdjustToShape, tcOutlineAdjustToShape:
2318       result := not IsSelectingTool and Assigned(FShape) and not FQuickDefine;
2319   tcForeEditGradTexPoints: result := not IsSelectingTool and Assigned(FShape) and not FQuickDefine and
2320                             (ForeGradTexMode in FShape.Usermodes) and not (FShape.Usermode = vsuCreate);
2321   tcBackEditGradTexPoints: result := not IsSelectingTool and Assigned(FShape) and not FQuickDefine and
2322                             (BackGradTexMode in FShape.Usermodes) and not (FShape.Usermode = vsuCreate);
2323   tcOutlineEditGradTexPoints: result := not IsSelectingTool and Assigned(FShape) and not FQuickDefine and
2324                             (OutlineGradTexMode in FShape.Usermodes) and not (FShape.Usermode = vsuCreate);
2325   tcShapeToSpline: result:= not IsSelectingTool and not FQuickDefine and Assigned(FShape)
2326                             and TCurveShape.CanCreateFrom(FShape);
2327   tcAlignLeft..tcAlignBottom: Result:= not FQuickDefine and Assigned(FShape);
2328   tcMoveDown,tcMoveToBack: result := not IsSelectingTool and not FQuickDefine and Assigned(FShape)
2329           and not AlwaysRasterizeShape and Manager.Image.SelectionMaskEmpty and not FLayerWasEmpty;
2330   else result := false;
2331   end;
2332 end;
2333 
TVectorialTool.SuggestGradientBoxnull2334 function TVectorialTool.SuggestGradientBox: TAffineBox;
2335 begin
2336   if Assigned(FShape) then
2337     result := FShape.SuggestGradientBox(AffineMatrixIdentity)
2338   else
2339     result:= inherited SuggestGradientBox;
2340 end;
2341 
GetContextualToolbarsnull2342 function TVectorialTool.GetContextualToolbars: TContextualToolbars;
2343 begin
2344   result := ContextualToolbarsFromShape(ShapeClass, FShape);
2345 end;
2346 
TVectorialTool.Rendernull2347 function TVectorialTool.Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth,
2348   VirtualScreenHeight: integer;
2349   BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
2350 var
2351   orig, xAxis, yAxis: TPointF;
2352   editMatrix: TAffineMatrix;
2353 begin
2354   if Assigned(FShape) then
2355   begin
2356     with LayerOffset do
2357     begin
2358       orig := BitmapToVirtualScreen(PointF(0,0));
2359       xAxis := BitmapToVirtualScreen(PointF(1,0));
2360       yAxis := BitmapToVirtualScreen(PointF(0,1));
2361     end;
2362     Editor.Clear;
2363     editMatrix := AffineMatrix(xAxis-orig,yAxis-orig,orig)*VectorTransform(true);
2364     if IsAffineMatrixInversible(editMatrix) then
2365     begin
2366       Editor.Matrix := editMatrix;
2367       Editor.PointSize := DoScaleX(PointSize*Manager.CanvasScale, OriginalDPI);
2368       if Assigned(FShape) then FShape.ConfigureEditor(Editor);
2369       if Assigned(VirtualScreen) then
2370         Result:= Editor.Render(VirtualScreen, rect(0,0,VirtualScreen.Width,VirtualScreen.Height))
2371       else
2372         Result:= Editor.GetRenderBounds(rect(0,0,VirtualScreenWidth,VirtualScreenHeight));
2373     end else
2374       result := EmptyRect;
2375   end else
2376   begin
2377     result := EmptyRect;
2378     Editor.Clear;
2379   end;
2380   FPreviousEditorBounds := result;
2381 end;
2382 
2383 destructor TVectorialTool.Destroy;
2384 begin
2385   if Assigned(FShape) then ValidateShape;
2386   FEditor.Free;
2387   FTemporaryStorage.Free;
2388   inherited Destroy;
2389 end;
2390 
2391 initialization
2392 
2393   RegisterTool(ptEditShape, TEditShapeTool);
2394 
2395 end.
2396 
2397