ONE.Objects.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. //------------------------------------------------------------------------------
  2. // 2016.07.19 Editor by Aone -
  3. // 2016.10.11 修正等比问题 -
  4. // -
  5. // 本控件修改自 Delphi Berlin 10.1 的 TSelection (FMX.Controls.pas) -
  6. // -
  7. // 修改重点: -
  8. // 1. 移动点显示在上方 -
  9. // 2. 增加(左中,上中,右中,下中)控制点,含原来的总共有 8 个控制点 -
  10. // -
  11. // 代码说明: -
  12. // 1. 代码内 {+++> 代表我增加的代码 -
  13. // 2. 代码内 {---> 代表我删除的代码 -
  14. // 3. 未来新版 Delphi 可以自己将 {+++> {---> 移植到新版代码内 -
  15. // 4. 本控件不含 Register; 若需要请自行加入 -
  16. //------------------------------------------------------------------------------
  17. // http://www.cnblogs.com/onechen/ -
  18. //------------------------------------------------------------------------------
  19. unit ONE.Objects;
  20. interface
  21. uses
  22. System.Classes, System.Types, System.UITypes, System.SysUtils,
  23. {+++>}System.Math,
  24. System.UIConsts, System.Math.Vectors, FMX.Types, FMX.Graphics, FMX.Controls;
  25. type
  26. { TOneSelection }
  27. TOneSelection = class(TControl)
  28. public const
  29. DefaultColor = $FF1072C5;
  30. public type
  31. TGrabHandle = (None, LeftTop, RightTop, LeftBottom, RightBottom{+++>}, CenterLeft, CenterTop, CenterRight, CenterBottom{<+++});
  32. private
  33. FParentBounds: Boolean;
  34. FOnChange: TNotifyEvent;
  35. FHideSelection: Boolean;
  36. FMinSize: Integer;
  37. FOnTrack: TNotifyEvent;
  38. FProportional: Boolean;
  39. FGripSize: Single;
  40. FRatio: Single;
  41. FActiveHandle: TGrabHandle;
  42. FHotHandle: TGrabHandle;
  43. FDownPos: TPointF;
  44. FShowHandles: Boolean;
  45. FColor: TAlphaColor;
  46. procedure SetHideSelection(const Value: Boolean);
  47. procedure SetMinSize(const Value: Integer);
  48. procedure SetGripSize(const Value: Single);
  49. procedure ResetInSpace(const ARotationPoint: TPointF; ASize: TPointF);
  50. function GetProportionalSize(const ASize: TPointF): TPointF;
  51. function GetHandleForPoint(const P: TPointF): TGrabHandle;
  52. procedure GetTransformLeftTop(AX, AY: Single; var NewSize: TPointF; var Pivot: TPointF);
  53. procedure GetTransformLeftBottom(AX, AY: Single; var NewSize: TPointF; var Pivot: TPointF);
  54. procedure GetTransformRightTop(AX, AY: Single; var NewSize: TPointF; var Pivot: TPointF);
  55. procedure GetTransformRightBottom(AX, AY: Single; var NewSize: TPointF; var Pivot: TPointF);
  56. procedure MoveHandle(AX, AY: Single);
  57. procedure SetShowHandles(const Value: Boolean);
  58. procedure SetColor(const Value: TAlphaColor);
  59. protected
  60. function DoGetUpdateRect: TRectF; override;
  61. {---> procedure Paint; override;
  62. {+++>}procedure AfterPaint; override;
  63. ///<summary>Draw grip handle</summary>
  64. procedure DrawHandle(const Canvas: TCanvas; const Handle: TGrabHandle; const Rect: TRectF); virtual;
  65. ///<summary>Draw frame rectangle</summary>
  66. procedure DrawFrame(const Canvas: TCanvas; const Rect: TRectF); virtual;
  67. public
  68. function PointInObjectLocal(X, Y: Single): Boolean; override;
  69. constructor Create(AOwner: TComponent); override;
  70. destructor Destroy; override;
  71. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
  72. procedure MouseMove(Shift: TShiftState; X, Y: Single); override;
  73. procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
  74. procedure DoMouseLeave; override;
  75. ///<summary>Grip handle where mouse is hovered</summary>
  76. property HotHandle: TGrabHandle read FHotHandle;
  77. published
  78. property Align;
  79. property Anchors;
  80. property ClipChildren default False;
  81. property ClipParent default False;
  82. property Cursor default crDefault;
  83. ///<summary>Selection frame and handle's border color</summary>
  84. property Color: TAlphaColor read FColor write SetColor default DefaultColor;
  85. property DragMode default TDragMode.dmManual;
  86. property EnableDragHighlight default True;
  87. property Enabled default True;
  88. property GripSize: Single read FGripSize write SetGripSize;
  89. property Locked default False;
  90. property Height;
  91. property HideSelection: Boolean read FHideSelection write SetHideSelection;
  92. property HitTest default True;
  93. property Padding;
  94. property MinSize: Integer read FMinSize write SetMinSize default 15;
  95. property Opacity;
  96. property Margins;
  97. property ParentBounds: Boolean read FParentBounds write FParentBounds default True;
  98. property Proportional: Boolean read FProportional write FProportional;
  99. property PopupMenu;
  100. property Position;
  101. property RotationAngle;
  102. property RotationCenter;
  103. property Scale;
  104. property Size;
  105. ///<summary>Indicates visibility of handles</summary>
  106. property ShowHandles: Boolean read FShowHandles write SetShowHandles;
  107. property Visible default True;
  108. property Width;
  109. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  110. {Drag and Drop events}
  111. property OnDragEnter;
  112. property OnDragLeave;
  113. property OnDragOver;
  114. property OnDragDrop;
  115. property OnDragEnd;
  116. {Mouse events}
  117. property OnClick;
  118. property OnDblClick;
  119. property OnMouseDown;
  120. property OnMouseMove;
  121. property OnMouseUp;
  122. property OnMouseWheel;
  123. property OnMouseEnter;
  124. property OnMouseLeave;
  125. property OnPainting;
  126. property OnPaint;
  127. property OnResize;
  128. property OnTrack: TNotifyEvent read FOnTrack write FOnTrack;
  129. end;
  130. implementation
  131. { TOneSelection }
  132. constructor TOneSelection.Create(AOwner: TComponent);
  133. begin
  134. inherited;
  135. AutoCapture := True;
  136. ParentBounds := True;
  137. FColor := DefaultColor;
  138. FShowHandles := True;
  139. FMinSize := 15;
  140. FGripSize := 3;
  141. SetAcceptsControls(False);
  142. end;
  143. destructor TOneSelection.Destroy;
  144. begin
  145. inherited;
  146. end;
  147. function TOneSelection.GetProportionalSize(const ASize: TPointF): TPointF;
  148. begin
  149. Result := ASize;
  150. {---> if FRatio * Result.Y > Result.X then
  151. {+++>}
  152. if ((FRatio * Result.Y > Result.X) and
  153. not (FActiveHandle in [TGrabHandle.CenterTop, TGrabHandle.CenterBottom])) or
  154. (FActiveHandle in [TGrabHandle.CenterLeft, TGrabHandle.CenterRight]) then
  155. {<+++}
  156. begin
  157. if Result.X < FMinSize then
  158. Result.X := FMinSize;
  159. Result.Y := Result.X / FRatio;
  160. if Result.Y < FMinSize then
  161. begin
  162. Result.Y := FMinSize;
  163. Result.X := FMinSize * FRatio;
  164. end;
  165. end
  166. else
  167. begin
  168. if Result.Y < FMinSize then
  169. Result.Y := FMinSize;
  170. Result.X := Result.Y * FRatio;
  171. if Result.X < FMinSize then
  172. begin
  173. Result.X := FMinSize;
  174. Result.Y := FMinSize / FRatio;
  175. end;
  176. end;
  177. end;
  178. function TOneSelection.GetHandleForPoint(const P: TPointF): TGrabHandle;
  179. var
  180. {+++>}w, h: Single;
  181. Local, R: TRectF;
  182. begin
  183. Local := LocalRect;
  184. R := TRectF.Create(Local.Left - GripSize, Local.Top - GripSize, Local.Left + GripSize, Local.Top + GripSize);
  185. if R.Contains(P) then
  186. Exit(TGrabHandle.LeftTop);
  187. R := TRectF.Create(Local.Right - GripSize, Local.Top - GripSize, Local.Right + GripSize, Local.Top + GripSize);
  188. if R.Contains(P) then
  189. Exit(TGrabHandle.RightTop);
  190. R := TRectF.Create(Local.Right - GripSize, Local.Bottom - GripSize, Local.Right + GripSize, Local.Bottom + GripSize);
  191. if R.Contains(P) then
  192. Exit(TGrabHandle.RightBottom);
  193. R := TRectF.Create(Local.Left - GripSize, Local.Bottom - GripSize, Local.Left + GripSize, Local.Bottom + GripSize);
  194. if R.Contains(P) then
  195. Exit(TGrabHandle.LeftBottom);
  196. {+++>}
  197. w := (Local.Right - Local.Left) / 2;
  198. h := (Local.Bottom - Local.Top) / 2;
  199. R := TRectF.Create(Local.Left - GripSize, (Local.Top + h) - GripSize, Local.Left + GripSize, (Local.Top + h) + GripSize);
  200. if R.Contains(P) then
  201. Exit(TGrabHandle.CenterLeft);
  202. R := TRectF.Create((Local.Left + w) - GripSize, Local.Top - GripSize, (Local.Left + w) + GripSize, Local.Top + GripSize);
  203. if R.Contains(P) then
  204. Exit(TGrabHandle.CenterTop);
  205. R := TRectF.Create(Local.Right - GripSize, (Local.Top + h) - GripSize, Local.Right + GripSize, (Local.Top + h) + GripSize);
  206. if R.Contains(P) then
  207. Exit(TGrabHandle.CenterRight);
  208. R := TRectF.Create((Local.Left + w) - GripSize, Local.Bottom - GripSize, (Local.Left + w) + GripSize, Local.Bottom + GripSize);
  209. if R.Contains(P) then
  210. Exit(TGrabHandle.CenterBottom);
  211. {<+++}
  212. Result := TGrabHandle.None;
  213. end;
  214. procedure TOneSelection.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  215. begin
  216. // this line may be necessary because TOneSelection is not a styled control;
  217. // must further investigate for a better fix
  218. if not Enabled then
  219. Exit;
  220. inherited;
  221. FDownPos := TPointF.Create(X, Y);
  222. if Button = TMouseButton.mbLeft then
  223. begin
  224. FRatio := Width / Height;
  225. FActiveHandle := GetHandleForPoint(FDownPos);
  226. end;
  227. end;
  228. procedure TOneSelection.MouseMove(Shift: TShiftState; X, Y: Single);
  229. var
  230. P, OldPos: TPointF;
  231. MoveVector: TVector;
  232. MovePos: TPointF;
  233. GrabHandle: TGrabHandle;
  234. begin
  235. // this line may be necessary because TOneSelection is not a styled control;
  236. // must further investigate for a better fix
  237. if not Enabled then
  238. Exit;
  239. inherited;
  240. MovePos := TPointF.Create(X, Y);
  241. if not Pressed then
  242. begin
  243. // handle painting for hotspot mouse hovering
  244. GrabHandle := GetHandleForPoint(MovePos);
  245. if GrabHandle <> FHotHandle then
  246. Repaint;
  247. FHotHandle := GrabHandle;
  248. end
  249. else if ssLeft in Shift then
  250. begin
  251. if FActiveHandle = TGrabHandle.None then
  252. begin
  253. MoveVector := LocalToAbsoluteVector(TVector.Create(X - FDownPos.X, Y - FDownPos.Y));
  254. if ParentControl <> nil then
  255. MoveVector := ParentControl.AbsoluteToLocalVector(MoveVector);
  256. Position.Point := Position.Point + TPointF(MoveVector);
  257. if ParentBounds then
  258. begin
  259. if Position.X < 0 then
  260. Position.X := 0;
  261. if Position.Y < 0 then
  262. Position.Y := 0;
  263. if ParentControl <> nil then
  264. begin
  265. if Position.X + Width > ParentControl.Width then
  266. Position.X := ParentControl.Width - Width;
  267. if Position.Y + Height > ParentControl.Height then
  268. Position.Y := ParentControl.Height - Height;
  269. end
  270. else
  271. if Canvas <> nil then
  272. begin
  273. if Position.X + Width > Canvas.Width then
  274. Position.X := Canvas.Width - Width;
  275. if Position.Y + Height > Canvas.Height then
  276. Position.Y := Canvas.Height - Height;
  277. end;
  278. end;
  279. if Assigned(FOnTrack) then
  280. FOnTrack(Self);
  281. Exit;
  282. end;
  283. OldPos := Position.Point;
  284. P := LocalToAbsolute(MovePos);
  285. if ParentControl <> nil then
  286. P := ParentControl.AbsoluteToLocal(P);
  287. if ParentBounds then
  288. begin
  289. if P.Y < 0 then
  290. P.Y := 0;
  291. if P.X < 0 then
  292. P.X := 0;
  293. if ParentControl <> nil then
  294. begin
  295. if P.X > ParentControl.Width then
  296. P.X := ParentControl.Width;
  297. if P.Y > ParentControl.Height then
  298. P.Y := ParentControl.Height;
  299. end
  300. else
  301. if Canvas <> nil then
  302. begin
  303. if P.X > Canvas.Width then
  304. P.X := Canvas.Width;
  305. if P.Y > Canvas.Height then
  306. P.Y := Canvas.Height;
  307. end;
  308. end;
  309. MoveHandle(X, Y);
  310. end;
  311. end;
  312. function TOneSelection.PointInObjectLocal(X, Y: Single): Boolean;
  313. begin
  314. Result := inherited or (GetHandleForPoint(TPointF.Create(X, Y)) <> TGrabHandle.None);
  315. end;
  316. procedure TOneSelection.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  317. begin
  318. // this line may be necessary because TOneSelection is not a styled control;
  319. // must further investigate for a better fix
  320. if not Enabled then
  321. Exit;
  322. inherited;
  323. if Assigned(FOnChange) then
  324. FOnChange(Self);
  325. FActiveHandle := TGrabHandle.None;
  326. end;
  327. procedure TOneSelection.DrawFrame(const Canvas: TCanvas; const Rect: TRectF);
  328. begin
  329. Canvas.DrawDashRect(Rect, 0, 0, AllCorners, AbsoluteOpacity, FColor);
  330. end;
  331. procedure TOneSelection.DrawHandle(const Canvas: TCanvas; const Handle: TGrabHandle; const Rect: TRectF);
  332. var
  333. Fill: TBrush;
  334. Stroke: TStrokeBrush;
  335. begin
  336. Fill := TBrush.Create(TBrushKind.Solid, claWhite);
  337. Stroke := TStrokeBrush.Create(TBrushKind.Solid, FColor);
  338. try
  339. if Enabled then
  340. if FHotHandle = Handle then
  341. Canvas.Fill.Color := claRed
  342. else
  343. Canvas.Fill.Color := claWhite
  344. else
  345. Canvas.Fill.Color := claGrey;
  346. Canvas.FillEllipse(Rect, AbsoluteOpacity, Fill);
  347. Canvas.DrawEllipse(Rect, AbsoluteOpacity, Stroke);
  348. finally
  349. Fill.Free;
  350. Stroke.Free;
  351. end;
  352. end;
  353. {---> procedure TOneSelection.Paint;
  354. {+++>}procedure TOneSelection.AfterPaint;
  355. var
  356. {+++>}w, h: Single;
  357. R: TRectF;
  358. begin
  359. if FHideSelection then
  360. Exit;
  361. R := LocalRect;
  362. R.Inflate(-0.5, -0.5);
  363. DrawFrame(Canvas, R);
  364. if ShowHandles then
  365. begin
  366. R := LocalRect;
  367. DrawHandle(Canvas, TGrabHandle.LeftTop, TRectF.Create(R.Left - GripSize, R.Top - GripSize, R.Left + GripSize,
  368. R.Top + GripSize));
  369. DrawHandle(Canvas, TGrabHandle.RightTop, TRectF.Create(R.Right - GripSize, R.Top - GripSize, R.Right + GripSize,
  370. R.Top + GripSize));
  371. DrawHandle(Canvas, TGrabHandle.LeftBottom, TRectF.Create(R.Left - GripSize, R.Bottom - GripSize, R.Left + GripSize,
  372. R.Bottom + GripSize));
  373. DrawHandle(Canvas, TGrabHandle.RightBottom, TRectF.Create(R.Right - GripSize, R.Bottom - GripSize,
  374. R.Right + GripSize, R.Bottom + GripSize));
  375. {+++>}
  376. w := (R.Right - R.Left) / 2;
  377. h := (R.Bottom - R.Top) / 2;
  378. DrawHandle(Canvas, TGrabHandle.CenterLeft, TRectF.Create( R.Left - GripSize, (R.Top + h) - GripSize, R.Left + GripSize, (R.Top + h) + GripSize));
  379. DrawHandle(Canvas, TGrabHandle.CenterTop, TRectF.Create((R.Left + w) - GripSize, R.Top - GripSize, (R.Left + w) + GripSize, R.Top + GripSize));
  380. DrawHandle(Canvas, TGrabHandle.CenterRight, TRectF.Create( R.Right - GripSize, (R.Top + h) - GripSize, R.Right + GripSize, (R.Top + h) + GripSize));
  381. DrawHandle(Canvas, TGrabHandle.CenterBottom, TRectF.Create((R.Left + w) - GripSize, R.Bottom - GripSize, (R.Left + w) + GripSize, R.Bottom + GripSize));
  382. {<+++}
  383. end;
  384. end;
  385. function TOneSelection.DoGetUpdateRect: TRectF;
  386. begin
  387. Result := inherited;
  388. Result.Inflate((FGripSize + 1) * Scale.X, (FGripSize + 1) * Scale.Y);
  389. end;
  390. procedure TOneSelection.ResetInSpace(const ARotationPoint: TPointF; ASize: TPointF);
  391. var
  392. LLocalPos: TPointF;
  393. LAbsPos: TPointF;
  394. begin
  395. LAbsPos := LocalToAbsolute(ARotationPoint);
  396. if ParentControl <> nil then
  397. begin
  398. LLocalPos := ParentControl.AbsoluteToLocal(LAbsPos);
  399. LLocalPos.X := LLocalPos.X - ASize.X * RotationCenter.X * Scale.X;
  400. LLocalPos.Y := LLocalPos.Y - ASize.Y * RotationCenter.Y * Scale.Y;
  401. if ParentBounds then
  402. begin
  403. if LLocalPos.X < 0 then
  404. begin
  405. ASize.X := ASize.X + LLocalPos.X;
  406. LLocalPos.X := 0;
  407. end;
  408. if LLocalPos.Y < 0 then
  409. begin
  410. ASize.Y := ASize.Y + LLocalPos.Y;
  411. LLocalPos.Y := 0;
  412. end;
  413. if LLocalPos.X + ASize.X > ParentControl.Width then
  414. ASize.X := ParentControl.Width - LLocalPos.X;
  415. if LLocalPos.Y + ASize.Y > ParentControl.Height then
  416. ASize.Y := ParentControl.Height - LLocalPos.Y;
  417. end;
  418. end
  419. else
  420. begin
  421. LLocalPos.X := LAbsPos.X - ASize.X * RotationCenter.X * Scale.X;
  422. LLocalPos.Y := LAbsPos.Y - ASize.Y * RotationCenter.Y * Scale.Y;
  423. end;
  424. {+++>}if not FProportional or (FProportional and SameValue(ASize.X / ASize.Y, FRatio, 0.0001{SingleResolution})) then // 修正如果等比时,超界不会变形 by Aone @ 2016.10.11
  425. SetBounds(LLocalPos.X, LLocalPos.Y, ASize.X, ASize.Y);
  426. end;
  427. procedure TOneSelection.GetTransformLeftTop(AX, AY: Single; var NewSize: TPointF; var Pivot: TPointF);
  428. var
  429. LCorrect: TPointF;
  430. begin
  431. {+++>}
  432. if FActiveHandle = TGrabHandle.CenterTop then AX := 0 else
  433. if FActiveHandle = TGrabHandle.CenterLeft then AY := 0;
  434. {+++>}
  435. NewSize := Size.Size - TSizeF.Create(AX, AY);
  436. if NewSize.Y < FMinSize then
  437. begin
  438. AY := Height - FMinSize;
  439. NewSize.Y := FMinSize;
  440. end;
  441. if NewSize.X < FMinSize then
  442. begin
  443. AX := Width - FMinSize;
  444. NewSize.X := FMinSize;
  445. end;
  446. if FProportional then
  447. begin
  448. LCorrect := NewSize;
  449. NewSize := GetProportionalSize(NewSize);
  450. {+++>}if not (FActiveHandle in [TGrabHandle.CenterTop, TGrabHandle.CenterLeft]) then begin
  451. LCorrect := LCorrect - NewSize;
  452. AX := AX + LCorrect.X;
  453. AY := AY + LCorrect.Y;
  454. {+++>}end;
  455. end;
  456. Pivot := TPointF.Create(Width * RotationCenter.X + AX * (1 - RotationCenter.X),
  457. Height * RotationCenter.Y + AY * (1 - RotationCenter.Y));
  458. end;
  459. procedure TOneSelection.GetTransformLeftBottom(AX, AY: Single; var NewSize: TPointF; var Pivot: TPointF);
  460. var
  461. LCorrect: TPointF;
  462. begin
  463. {+++>}if FActiveHandle = TGrabHandle.CenterBottom then AX := 0;
  464. NewSize := TPointF.Create(Width - AX, AY);
  465. if NewSize.Y < FMinSize then
  466. begin
  467. AY := FMinSize;
  468. NewSize.Y := FMinSize;
  469. end;
  470. if NewSize.X < FMinSize then
  471. begin
  472. AX := Width - FMinSize;
  473. NewSize.X := FMinSize;
  474. end;
  475. if FProportional then
  476. begin
  477. LCorrect := NewSize;
  478. NewSize := GetProportionalSize(NewSize);
  479. {+++>}if FActiveHandle <> TGrabHandle.CenterBottom then begin
  480. LCorrect := LCorrect - NewSize;
  481. AX := AX + LCorrect.X;
  482. {---> AY := AY + LCorrect.Y;
  483. {+++>}AY := AY - LCorrect.Y; // 修正等比缩放时,拉动左下角,右上角会跟着移动 by Aone @ 2016.10.10
  484. {+++>}end;
  485. end;
  486. Pivot := TPointF.Create(Width * RotationCenter.X + AX * (1 - RotationCenter.X),
  487. Height * RotationCenter.Y + (AY - Height) * RotationCenter.Y);
  488. end;
  489. procedure TOneSelection.GetTransformRightTop(AX, AY: Single; var NewSize: TPointF; var Pivot: TPointF);
  490. var
  491. LCorrect: TPointF;
  492. begin
  493. {+++>}if FActiveHandle = TGrabHandle.CenterRight then AY := 0;
  494. NewSize := TPointF.Create(AX, Height - AY);
  495. if NewSize.Y < FMinSize then
  496. begin
  497. AY := Height - FMinSize;
  498. NewSize.Y := FMinSize;
  499. end;
  500. if AX < FMinSize then
  501. begin
  502. AX := FMinSize;
  503. NewSize.X := FMinSize;
  504. end;
  505. if FProportional then
  506. begin
  507. LCorrect := NewSize;
  508. NewSize := GetProportionalSize(NewSize);
  509. {+++>}if FActiveHandle <> TGrabHandle.CenterRight then begin
  510. LCorrect := LCorrect - NewSize;
  511. AX := AX - LCorrect.X;
  512. AY := AY + LCorrect.Y;
  513. {+++>}end;
  514. end;
  515. Pivot := TPointF.Create(Width * RotationCenter.X + (AX - Width) * RotationCenter.X,
  516. Height * RotationCenter.Y + AY * (1 - RotationCenter.Y));
  517. end;
  518. procedure TOneSelection.GetTransformRightBottom(AX, AY: Single; var NewSize: TPointF; var Pivot: TPointF);
  519. var
  520. LCorrect: TPointF;
  521. begin
  522. NewSize := TPointF.Create(AX, AY);
  523. if NewSize.Y < FMinSize then
  524. begin
  525. AY := FMinSize;
  526. NewSize.Y := FMinSize;
  527. end;
  528. if NewSize.X < FMinSize then
  529. begin
  530. AX := FMinSize;
  531. NewSize.X := FMinSize;
  532. end;
  533. if FProportional then
  534. begin
  535. LCorrect := NewSize;
  536. NewSize := GetProportionalSize(NewSize);
  537. LCorrect := LCorrect - NewSize;
  538. AX := AX - LCorrect.X;
  539. AY := AY - LCorrect.Y;
  540. end;
  541. Pivot := TPointF.Create(Width * RotationCenter.X + (AX - Width) * RotationCenter.X,
  542. Height * RotationCenter.Y + (AY - Height) * RotationCenter.Y);
  543. end;
  544. procedure TOneSelection.MoveHandle(AX, AY: Single);
  545. var
  546. NewSize, Pivot: TPointF;
  547. begin
  548. case FActiveHandle of
  549. TOneSelection.TGrabHandle.LeftTop: GetTransformLeftTop(AX, AY, NewSize, Pivot);
  550. TOneSelection.TGrabHandle.LeftBottom: GetTransformLeftBottom(AX, AY, NewSize, Pivot);
  551. TOneSelection.TGrabHandle.RightTop: GetTransformRightTop(AX, AY, NewSize, Pivot);
  552. TOneSelection.TGrabHandle.RightBottom: GetTransformRightBottom(AX, AY, NewSize, Pivot);
  553. {+++>}
  554. TOneSelection.TGrabHandle.CenterLeft: GetTransformLeftTop(AX, AY, NewSize, Pivot);
  555. TOneSelection.TGrabHandle.CenterTop: GetTransformLeftTop(AX, AY, NewSize, Pivot);
  556. TOneSelection.TGrabHandle.CenterRight: GetTransformRightTop(AX, AY, NewSize, Pivot);
  557. TOneSelection.TGrabHandle.CenterBottom: GetTransformLeftBottom(AX, AY, NewSize, Pivot);
  558. {<+++}
  559. end;
  560. ResetInSpace(Pivot, NewSize);
  561. if Assigned(FOnTrack) then
  562. FOnTrack(Self);
  563. end;
  564. procedure TOneSelection.DoMouseLeave;
  565. begin
  566. inherited;
  567. FHotHandle := TGrabHandle.None;
  568. Repaint;
  569. end;
  570. procedure TOneSelection.SetHideSelection(const Value: Boolean);
  571. begin
  572. if FHideSelection <> Value then
  573. begin
  574. FHideSelection := Value;
  575. Repaint;
  576. end;
  577. end;
  578. procedure TOneSelection.SetMinSize(const Value: Integer);
  579. begin
  580. if FMinSize <> Value then
  581. begin
  582. FMinSize := Value;
  583. if FMinSize < 1 then
  584. FMinSize := 1;
  585. end;
  586. end;
  587. procedure TOneSelection.SetShowHandles(const Value: Boolean);
  588. begin
  589. if FShowHandles <> Value then
  590. begin
  591. FShowHandles := Value;
  592. Repaint;
  593. end;
  594. end;
  595. procedure TOneSelection.SetColor(const Value: TAlphaColor);
  596. begin
  597. if FColor <> Value then
  598. begin
  599. FColor := Value;
  600. Repaint;
  601. end;
  602. end;
  603. procedure TOneSelection.SetGripSize(const Value: Single);
  604. begin
  605. if FGripSize <> Value then
  606. begin
  607. if Value < FGripSize then
  608. Repaint;
  609. FGripSize := Value;
  610. if FGripSize > 20 then
  611. FGripSize := 20;
  612. if FGripSize < 1 then
  613. FGripSize := 1;
  614. HandleSizeChanged;
  615. Repaint;
  616. end;
  617. end;
  618. end.