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