GR32_Layers.pas 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879
  1. unit GR32_Layers;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Alex A. Denisov
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2009
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. * Andre Beckedorf <[email protected]>
  32. * Michael Hansen <[email protected]>
  33. * Dieter Köhler <[email protected]>
  34. *
  35. * ***** END LICENSE BLOCK ***** *)
  36. interface
  37. {$INCLUDE GR32.inc}
  38. uses
  39. {$IFDEF FPC}
  40. Controls, Graphics, Forms,
  41. {$ELSE}
  42. Windows, Controls, Graphics, Forms,
  43. {$ENDIF}
  44. Classes, SysUtils, Math, GR32;
  45. const
  46. { Layer Options Bits }
  47. LOB_VISIBLE = $80000000; // 31-st bit
  48. LOB_GDI_OVERLAY = $40000000; // 30-th bit
  49. LOB_MOUSE_EVENTS = $20000000; // 29-th bit
  50. LOB_NO_UPDATE = $10000000; // 28-th bit
  51. LOB_NO_CAPTURE = $08000000; // 27-th bit
  52. LOB_INVALID = $04000000; // 26-th bit
  53. LOB_FORCE_UPDATE = $02000000; // 25-th bit
  54. LOB_RESERVED_24 = $01000000; // 24-th bit
  55. LOB_RESERVED_MASK = $FF000000;
  56. type
  57. TCustomLayer = class;
  58. TPositionedLayer = class;
  59. TRubberbandLayer = class;
  60. TLayerClass = class of TCustomLayer;
  61. TLayerCollection = class;
  62. TLayerUpdateEvent = procedure(Sender: TObject; Layer: TCustomLayer) of object;
  63. TAreaUpdateEvent = TAreaChangedEvent;
  64. TLayerListNotification = (lnLayerAdded, lnLayerInserted, lnLayerDeleted, lnCleared);
  65. TLayerListNotifyEvent = procedure(Sender: TLayerCollection; Action: TLayerListNotification;
  66. Layer: TCustomLayer; Index: Integer) of object;
  67. TGetScaleEvent = procedure(Sender: TObject; out ScaleX, ScaleY: TFloat) of object;
  68. TGetShiftEvent = procedure(Sender: TObject; out ShiftX, ShiftY: TFloat) of object;
  69. TLayerCollection = class(TPersistent)
  70. private
  71. FItems: TList;
  72. FMouseEvents: Boolean;
  73. FMouseListener: TCustomLayer;
  74. FUpdateCount: Integer;
  75. FOwner: TPersistent;
  76. FOnChanging: TNotifyEvent;
  77. FOnChange: TNotifyEvent;
  78. FOnGDIUpdate: TNotifyEvent;
  79. FOnListNotify: TLayerListNotifyEvent;
  80. FOnLayerUpdated: TLayerUpdateEvent;
  81. FOnAreaUpdated: TAreaUpdateEvent;
  82. FOnGetViewportScale: TGetScaleEvent;
  83. FOnGetViewportShift: TGetShiftEvent;
  84. function GetCount: Integer;
  85. procedure InsertItem(Item: TCustomLayer);
  86. procedure RemoveItem(Item: TCustomLayer);
  87. procedure SetMouseEvents(Value: Boolean);
  88. procedure SetMouseListener(Value: TCustomLayer);
  89. protected
  90. procedure BeginUpdate;
  91. procedure Changed;
  92. procedure Changing;
  93. procedure EndUpdate;
  94. function FindLayerAtPos(X, Y: Integer; OptionsMask: Cardinal): TCustomLayer;
  95. function GetItem(Index: Integer): TCustomLayer;
  96. function GetOwner: TPersistent; override;
  97. procedure GDIUpdate;
  98. procedure DoUpdateLayer(Layer: TCustomLayer);
  99. procedure DoUpdateArea(const Rect: TRect);
  100. procedure Notify(Action: TLayerListNotification; Layer: TCustomLayer; Index: Integer);
  101. procedure SetItem(Index: Integer; Value: TCustomLayer);
  102. function MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
  103. function MouseMove(Shift: TShiftState; X, Y: Integer): TCustomLayer;
  104. function MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
  105. property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
  106. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  107. property OnListNotify: TLayerListNotifyEvent read FOnListNotify write FOnListNotify;
  108. property OnGDIUpdate: TNotifyEvent read FOnGDIUpdate write FOnGDIUpdate;
  109. property OnLayerUpdated: TLayerUpdateEvent read FOnLayerUpdated write FOnLayerUpdated;
  110. property OnAreaUpdated: TAreaUpdateEvent read FOnAreaUpdated write FOnAreaUpdated;
  111. property OnGetViewportScale: TGetScaleEvent read FOnGetViewportScale write FOnGetViewportScale;
  112. property OnGetViewportShift: TGetShiftEvent read FOnGetViewportShift write FOnGetViewportShift;
  113. public
  114. constructor Create(AOwner: TPersistent); virtual;
  115. destructor Destroy; override;
  116. function Add(ItemClass: TLayerClass): TCustomLayer;
  117. procedure Assign(Source: TPersistent); override;
  118. procedure Clear;
  119. procedure Delete(Index: Integer);
  120. function Insert(Index: Integer; ItemClass: TLayerClass): TCustomLayer;
  121. function LocalToViewport(const APoint: TFloatPoint; AScaled: Boolean): TFloatPoint;
  122. function ViewportToLocal(const APoint: TFloatPoint; AScaled: Boolean): TFloatPoint;
  123. procedure GetViewportScale(out ScaleX, ScaleY: TFloat); virtual;
  124. procedure GetViewportShift(out ShiftX, ShiftY: TFloat); virtual;
  125. property Count: Integer read GetCount;
  126. property Owner: TPersistent read FOwner;
  127. property Items[Index: Integer]: TCustomLayer read GetItem write SetItem; default;
  128. property MouseListener: TCustomLayer read FMouseListener write SetMouseListener;
  129. property MouseEvents: Boolean read FMouseEvents write SetMouseEvents;
  130. end;
  131. TLayerCollectionClass = class of TLayerCollection;
  132. {$IFDEF COMPILER2009_UP}
  133. TLayerEnum = class
  134. private
  135. FIndex: Integer;
  136. FLayerCollection: TLayerCollection;
  137. public
  138. constructor Create(ALayerCollection: TLayerCollection);
  139. function GetCurrent: TCustomLayer;
  140. function MoveNext: Boolean;
  141. property Current: TCustomLayer read GetCurrent;
  142. end;
  143. TLayerCollectionHelper = class Helper for TLayerCollection
  144. public
  145. function GetEnumerator: TLayerEnum;
  146. end;
  147. {$ENDIF}
  148. TLayerState = (lsMouseLeft, lsMouseRight, lsMouseMiddle);
  149. TLayerStates = set of TLayerState;
  150. TPaintLayerEvent = procedure(Sender: TObject; Buffer: TBitmap32) of object;
  151. THitTestEvent = procedure(Sender: TObject; X, Y: Integer; var Passed: Boolean) of object;
  152. TCustomLayer = class(TNotifiablePersistent)
  153. private
  154. FCursor: TCursor;
  155. FFreeNotifies: TList;
  156. FLayerCollection: TLayerCollection;
  157. FLayerStates: TLayerStates;
  158. FLayerOptions: Cardinal;
  159. FTag: NativeInt;
  160. FClicked: Boolean;
  161. FOnHitTest: THitTestEvent;
  162. FOnMouseDown: TMouseEvent;
  163. FOnMouseMove: TMouseMoveEvent;
  164. FOnMouseUp: TMouseEvent;
  165. FOnPaint: TPaintLayerEvent;
  166. FOnDestroy: TNotifyEvent;
  167. FOnDblClick: TNotifyEvent;
  168. FOnClick: TNotifyEvent;
  169. function GetIndex: Integer;
  170. function GetMouseEvents: Boolean;
  171. function GetVisible: Boolean;
  172. procedure SetMouseEvents(Value: Boolean);
  173. procedure SetVisible(Value: Boolean);
  174. function GetInvalid: Boolean;
  175. procedure SetInvalid(Value: Boolean);
  176. function GetForceUpdate: Boolean;
  177. procedure SetForceUpdate(Value: Boolean);
  178. protected
  179. procedure AddNotification(ALayer: TCustomLayer);
  180. procedure Changing;
  181. procedure Click;
  182. procedure DblClick;
  183. function DoHitTest(X, Y: Integer): Boolean; virtual;
  184. procedure DoPaint(Buffer: TBitmap32);
  185. function GetOwner: TPersistent; override;
  186. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
  187. procedure MouseMove(Shift: TShiftState; X, Y: Integer); virtual;
  188. procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
  189. procedure Notification(ALayer: TCustomLayer); virtual;
  190. procedure Paint(Buffer: TBitmap32); virtual;
  191. procedure PaintGDI(Canvas: TCanvas); virtual;
  192. procedure RemoveNotification(ALayer: TCustomLayer);
  193. procedure SetIndex(Value: Integer); virtual;
  194. procedure SetCursor(Value: TCursor); virtual;
  195. procedure SetLayerCollection(Value: TLayerCollection); virtual;
  196. procedure SetLayerOptions(Value: Cardinal); virtual;
  197. property Invalid: Boolean read GetInvalid write SetInvalid;
  198. property ForceUpdate: Boolean read GetForceUpdate write SetForceUpdate;
  199. public
  200. constructor Create(ALayerCollection: TLayerCollection); virtual;
  201. destructor Destroy; override;
  202. procedure BeforeDestruction; override;
  203. procedure BringToFront;
  204. procedure Changed; overload; override;
  205. procedure Changed(const Rect: TRect); reintroduce; overload;
  206. procedure Update; overload;
  207. procedure Update(const Rect: TRect); overload;
  208. function HitTest(X, Y: Integer): Boolean;
  209. procedure SendToBack;
  210. procedure SetAsMouseListener;
  211. property Cursor: TCursor read FCursor write SetCursor;
  212. property Index: Integer read GetIndex write SetIndex;
  213. property LayerCollection: TLayerCollection read FLayerCollection write SetLayerCollection;
  214. property LayerOptions: Cardinal read FLayerOptions write SetLayerOptions;
  215. property LayerStates: TLayerStates read FLayerStates;
  216. property MouseEvents: Boolean read GetMouseEvents write SetMouseEvents;
  217. property Tag: NativeInt read FTag write FTag;
  218. property Visible: Boolean read GetVisible write SetVisible;
  219. property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
  220. property OnHitTest: THitTestEvent read FOnHitTest write FOnHitTest;
  221. property OnPaint: TPaintLayerEvent read FOnPaint write FOnPaint;
  222. property OnClick: TNotifyEvent read FOnClick write FOnClick;
  223. property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
  224. property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
  225. property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
  226. property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
  227. end;
  228. TPositionedLayer = class(TCustomLayer)
  229. private
  230. FLocation: TFloatRect;
  231. FScaled: Boolean;
  232. procedure SetLocation(const Value: TFloatRect);
  233. procedure SetScaled(Value: Boolean);
  234. protected
  235. function DoHitTest(X, Y: Integer): Boolean; override;
  236. procedure DoSetLocation(const NewLocation: TFloatRect); virtual;
  237. public
  238. constructor Create(ALayerCollection: TLayerCollection); override;
  239. function GetAdjustedRect(const R: TFloatRect): TFloatRect; virtual;
  240. function GetAdjustedLocation: TFloatRect;
  241. property Location: TFloatRect read FLocation write SetLocation;
  242. property Scaled: Boolean read FScaled write SetScaled;
  243. end;
  244. TCustomBitmapLayer = class abstract(TPositionedLayer)
  245. private
  246. FBitmap: TCustomBitmap32;
  247. FAlphaHit: Boolean;
  248. FCropped: Boolean;
  249. protected
  250. function DoHitTest(X, Y: Integer): Boolean; override;
  251. procedure Paint(Buffer: TBitmap32); override;
  252. protected
  253. procedure BitmapAreaChanged(Sender: TObject; const Area: TRect; const Info: Cardinal);
  254. function GetBitmap: TCustomBitmap32;
  255. procedure SetBitmap(Value: TCustomBitmap32); virtual;
  256. procedure SetCropped(Value: Boolean);
  257. function CreateBitmap: TCustomBitmap32; virtual;
  258. function GetBitmapClass: TCustomBitmap32Class; virtual; abstract;
  259. property Bitmap: TCustomBitmap32 read FBitmap write SetBitmap;
  260. public
  261. constructor Create(ALayerCollection: TLayerCollection); override;
  262. destructor Destroy; override;
  263. property AlphaHit: Boolean read FAlphaHit write FAlphaHit;
  264. property Cropped: Boolean read FCropped write SetCropped;
  265. end;
  266. TBitmapLayer = class(TCustomBitmapLayer)
  267. private
  268. protected
  269. function GetBitmapClass: TCustomBitmap32Class; override;
  270. function GetBitmap: TBitmap32;
  271. procedure SetBitmap(Value: TBitmap32); reintroduce;
  272. public
  273. property Bitmap: TBitmap32 read GetBitmap write SetBitmap;
  274. end;
  275. TRBDragState = (dsNone, dsMove, dsSizeL, dsSizeT, dsSizeR, dsSizeB,
  276. dsSizeTL, dsSizeTR, dsSizeBL, dsSizeBR);
  277. TRBHandles = set of (rhCenter, rhSides, rhCorners, rhFrame,
  278. rhNotLeftSide, rhNotRightSide, rhNotTopSide, rhNotBottomSide,
  279. rhNotTLCorner, rhNotTRCorner, rhNotBLCorner, rhNotBRCorner);
  280. TRBOptions = set of (roProportional, roConstrained, roQuantized);
  281. TRBResizingEvent = procedure(
  282. Sender: TObject;
  283. const OldLocation: TFloatRect;
  284. var NewLocation: TFloatRect;
  285. DragState: TRBDragState;
  286. Shift: TShiftState) of object;
  287. TRBConstrainEvent = TRBResizingEvent;
  288. TRubberbandPassMouse = class(TPersistent)
  289. private
  290. FOwner: TRubberbandLayer;
  291. FEnabled: Boolean;
  292. FToChild: Boolean;
  293. FLayerUnderCursor: Boolean;
  294. FCancelIfPassed: Boolean;
  295. protected
  296. function GetChildUnderCursor(X, Y: Integer): TPositionedLayer;
  297. public
  298. constructor Create(AOwner: TRubberbandLayer);
  299. property Enabled: Boolean read FEnabled write FEnabled default False;
  300. property ToChild: Boolean read FToChild write FToChild default False;
  301. property ToLayerUnderCursor: Boolean read FLayerUnderCursor write FLayerUnderCursor default False;
  302. property CancelIfPassed: Boolean read FCancelIfPassed write FCancelIfPassed default False;
  303. end;
  304. TRubberbandLayer = class(TPositionedLayer)
  305. private
  306. FChildLayer: TPositionedLayer;
  307. FFrameStipplePattern: TArrayOfColor32;
  308. FFrameStippleStep: TFloat;
  309. FFrameStippleCounter: TFloat;
  310. FHandleFrame: TColor32;
  311. FHandleFill: TColor32;
  312. FHandles: TRBHandles;
  313. FHandleSize: TFloat;
  314. FMinWidth: TFloat;
  315. FMaxHeight: TFloat;
  316. FMinHeight: TFloat;
  317. FMaxWidth: TFloat;
  318. FOnUserChange: TNotifyEvent;
  319. FOnResizing: TRBResizingEvent;
  320. FOnConstrain: TRBConstrainEvent;
  321. FOptions: TRBOptions;
  322. FQuantized: Integer;
  323. FPassMouse: TRubberbandPassMouse;
  324. procedure SetFrameStippleStep(const Value: TFloat);
  325. procedure SetFrameStippleCounter(const Value: TFloat);
  326. procedure SetChildLayer(Value: TPositionedLayer);
  327. procedure SetHandleFill(Value: TColor32);
  328. procedure SetHandleFrame(Value: TColor32);
  329. procedure SetHandles(Value: TRBHandles);
  330. procedure SetHandleSize(Value: TFloat);
  331. procedure SetOptions(const Value: TRBOptions);
  332. procedure SetQuantized(const Value: Integer);
  333. protected
  334. FIsDragging: Boolean;
  335. FDragState: TRBDragState;
  336. FOldLocation: TFloatRect;
  337. FMouseShift: TFloatPoint;
  338. function DoHitTest(X, Y: Integer): Boolean; override;
  339. procedure DoResizing(var OldLocation, NewLocation: TFloatRect; DragState: TRBDragState; Shift: TShiftState); virtual;
  340. procedure DoConstrain(var OldLocation, NewLocation: TFloatRect; DragState: TRBDragState; Shift: TShiftState); virtual;
  341. procedure DoSetLocation(const NewLocation: TFloatRect); override;
  342. function GetDragState(X, Y: Integer): TRBDragState; virtual;
  343. function GetHandleCursor(DragState: TRBDragState; Angle: integer): TCursor; virtual;
  344. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  345. procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  346. procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  347. procedure Notification(ALayer: TCustomLayer); override;
  348. procedure Paint(Buffer: TBitmap32); override;
  349. procedure SetLayerOptions(Value: Cardinal); override;
  350. procedure SetDragState(const Value: TRBDragState); overload;
  351. procedure SetDragState(const Value: TRBDragState; const X, Y: Integer); overload;
  352. procedure UpdateChildLayer; virtual;
  353. procedure DrawHandle(Buffer: TBitmap32; X, Y: TFloat); virtual;
  354. public
  355. constructor Create(ALayerCollection: TLayerCollection); override;
  356. destructor Destroy; override;
  357. procedure SetFrameStipple(const Value: Array of TColor32);
  358. procedure Quantize;
  359. property ChildLayer: TPositionedLayer read FChildLayer write SetChildLayer;
  360. property Options: TRBOptions read FOptions write SetOptions;
  361. property Handles: TRBHandles read FHandles write SetHandles;
  362. property HandleSize: TFloat read FHandleSize write SetHandleSize;
  363. property HandleFill: TColor32 read FHandleFill write SetHandleFill;
  364. property HandleFrame: TColor32 read FHandleFrame write SetHandleFrame;
  365. property FrameStippleStep: TFloat read FFrameStippleStep write SetFrameStippleStep;
  366. property FrameStippleCounter: TFloat read FFrameStippleCounter write SetFrameStippleCounter;
  367. property MaxHeight: TFloat read FMaxHeight write FMaxHeight;
  368. property MaxWidth: TFloat read FMaxWidth write FMaxWidth;
  369. property MinHeight: TFloat read FMinHeight write FMinHeight;
  370. property MinWidth: TFloat read FMinWidth write FMinWidth;
  371. property Quantized: Integer read FQuantized write SetQuantized default 8;
  372. property PassMouseToChild: TRubberbandPassMouse read FPassMouse;
  373. property OnUserChange: TNotifyEvent read FOnUserChange write FOnUserChange;
  374. property OnConstrain: TRBConstrainEvent read FOnConstrain write FOnConstrain;
  375. property OnResizing: TRBResizingEvent read FOnResizing write FOnResizing;
  376. end;
  377. type
  378. // Compas directions, counter clockwise, from 0 degress to 360.
  379. // Each one direction covers 45 degrees.
  380. // Used inside TRubberbandLayer.GetCursor instead of the poorly ordered TRBDragState enum.
  381. TResizeDirection = (ResizeDirectionE, ResizeDirectionNE, ResizeDirectionN, ResizeDirectionNW,
  382. ResizeDirectionW, ResizeDirectionSW, ResizeDirectionS, ResizeDirectionSE);
  383. var
  384. // The TRubberbandLayer resize handle cursors.
  385. // These are the values returned by TRubberbandLayer.GetCursor
  386. DirectionCursors: array[TResizeDirection] of TCursor = (crSizeWE, crSizeNESW, crSizeNS, crSizeNWSE, crSizeWE, crSizeNESW, crSizeNS, crSizeNWSE);
  387. implementation
  388. uses
  389. TypInfo, GR32_Image, GR32_LowLevel, GR32_Resamplers, GR32_RepaintOpt, Types;
  390. { mouse state mapping }
  391. const
  392. CStateMap: array [TMouseButton] of TLayerState =
  393. (lsMouseLeft, lsMouseRight, lsMouseMiddle {$IFDEF FPC}, lsMouseMiddle,
  394. lsMouseMiddle{$ENDIF});
  395. type
  396. TImage32Access = class(TCustomImage32);
  397. { TLayerCollection }
  398. function TLayerCollection.Add(ItemClass: TLayerClass): TCustomLayer;
  399. begin
  400. Result := ItemClass.Create(Self);
  401. Result.Index := FItems.Count - 1;
  402. Notify(lnLayerAdded, Result, Result.Index);
  403. end;
  404. procedure TLayerCollection.Assign(Source: TPersistent);
  405. var
  406. I: Integer;
  407. Item: TCustomLayer;
  408. begin
  409. if Source is TLayerCollection then
  410. begin
  411. BeginUpdate;
  412. try
  413. while FItems.Count > 0 do TCustomLayer(FItems.Last).Free;
  414. for I := 0 to TLayerCollection(Source).Count - 1 do
  415. begin
  416. Item := TLayerCollection(Source).Items[I];
  417. Add(TLayerClass(Item.ClassType)).Assign(Item);
  418. end;
  419. finally
  420. EndUpdate;
  421. end;
  422. Exit;
  423. end;
  424. inherited Assign(Source);
  425. end;
  426. procedure TLayerCollection.BeginUpdate;
  427. begin
  428. if FUpdateCount = 0 then
  429. Changing;
  430. Inc(FUpdateCount);
  431. end;
  432. procedure TLayerCollection.Changed;
  433. begin
  434. if Assigned(FOnChange) then
  435. FOnChange(Self);
  436. end;
  437. procedure TLayerCollection.Changing;
  438. begin
  439. if Assigned(FOnChanging) then
  440. FOnChanging(Self);
  441. end;
  442. procedure TLayerCollection.Clear;
  443. begin
  444. BeginUpdate;
  445. try
  446. while FItems.Count > 0 do TCustomLayer(FItems.Last).Free;
  447. Notify(lnCleared, nil, 0);
  448. finally
  449. EndUpdate;
  450. end;
  451. end;
  452. constructor TLayerCollection.Create(AOwner: TPersistent);
  453. begin
  454. inherited Create;
  455. FOwner := AOwner;
  456. FItems := TList.Create;
  457. FMouseEvents := True;
  458. end;
  459. procedure TLayerCollection.Delete(Index: Integer);
  460. begin
  461. TCustomLayer(FItems[Index]).Free;
  462. end;
  463. destructor TLayerCollection.Destroy;
  464. begin
  465. FUpdateCount := 1; // disable update notification
  466. if Assigned(FItems) then
  467. Clear;
  468. FItems.Free;
  469. inherited;
  470. end;
  471. procedure TLayerCollection.EndUpdate;
  472. begin
  473. Dec(FUpdateCount);
  474. if FUpdateCount = 0 then
  475. Changed;
  476. Assert(FUpdateCount >= 0, 'Unpaired EndUpdate');
  477. end;
  478. function TLayerCollection.FindLayerAtPos(X, Y: Integer; OptionsMask: Cardinal): TCustomLayer;
  479. var
  480. I: Integer;
  481. begin
  482. for I := Count - 1 downto 0 do
  483. begin
  484. Result := Items[I];
  485. if (Result.LayerOptions and OptionsMask) = 0 then
  486. Continue; // skip to the next one
  487. if Result.HitTest(X, Y) then Exit;
  488. end;
  489. Result := nil;
  490. end;
  491. procedure TLayerCollection.GDIUpdate;
  492. begin
  493. if (FUpdateCount = 0) and Assigned(FOnGDIUpdate) then
  494. FOnGDIUpdate(Self);
  495. end;
  496. function TLayerCollection.GetCount: Integer;
  497. begin
  498. Result := FItems.Count;
  499. end;
  500. function TLayerCollection.GetItem(Index: Integer): TCustomLayer;
  501. begin
  502. Result := FItems[Index];
  503. end;
  504. function TLayerCollection.GetOwner: TPersistent;
  505. begin
  506. Result := FOwner;
  507. end;
  508. function TLayerCollection.Insert(Index: Integer; ItemClass: TLayerClass): TCustomLayer;
  509. begin
  510. BeginUpdate;
  511. try
  512. Result := Add(ItemClass);
  513. Result.Index := Index;
  514. Notify(lnLayerInserted, Result, Index);
  515. finally
  516. EndUpdate;
  517. end;
  518. end;
  519. procedure TLayerCollection.InsertItem(Item: TCustomLayer);
  520. var
  521. Index: Integer;
  522. begin
  523. BeginUpdate;
  524. try
  525. Index := FItems.Add(Item);
  526. Item.FLayerCollection := Self;
  527. Notify(lnLayerAdded, Item, Index);
  528. finally
  529. EndUpdate;
  530. end;
  531. end;
  532. function TLayerCollection.LocalToViewport(const APoint: TFloatPoint; AScaled: Boolean): TFloatPoint;
  533. var
  534. ScaleX, ScaleY, ShiftX, ShiftY: TFloat;
  535. begin
  536. if AScaled then
  537. begin
  538. GetViewportShift(ShiftX, ShiftY);
  539. GetViewportScale(ScaleX, ScaleY);
  540. Result.X := APoint.X * ScaleX + ShiftX;
  541. Result.Y := APoint.Y * ScaleY + ShiftY;
  542. end
  543. else
  544. Result := APoint;
  545. end;
  546. function TLayerCollection.ViewportToLocal(const APoint: TFloatPoint; AScaled: Boolean): TFloatPoint;
  547. var
  548. ScaleX, ScaleY, ShiftX, ShiftY: TFloat;
  549. begin
  550. if AScaled then
  551. begin
  552. GetViewportShift(ShiftX, ShiftY);
  553. GetViewportScale(ScaleX, ScaleY);
  554. Result.X := (APoint.X - ShiftX) / ScaleX;
  555. Result.Y := (APoint.Y - ShiftY) / ScaleY;
  556. end
  557. else
  558. Result := APoint;
  559. end;
  560. function TLayerCollection.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
  561. begin
  562. if Assigned(MouseListener) then
  563. Result := MouseListener
  564. else
  565. Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
  566. if (Result <> MouseListener) and ((Result = nil) or ((Result.FLayerOptions and LOB_NO_CAPTURE) = 0)) then
  567. MouseListener := Result; // capture the mouse
  568. if Assigned(MouseListener) then
  569. begin
  570. Include(MouseListener.FLayerStates, CStateMap[Button]);
  571. MouseListener.MouseDown(Button, Shift, X, Y);
  572. end;
  573. end;
  574. function TLayerCollection.MouseMove(Shift: TShiftState; X, Y: Integer): TCustomLayer;
  575. begin
  576. Result := MouseListener;
  577. if Result = nil then
  578. Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
  579. if Assigned(Result) then
  580. Result.MouseMove(Shift, X, Y)
  581. else if FOwner is TControl then
  582. Screen.Cursor := TControl(FOwner).Cursor;
  583. end;
  584. function TLayerCollection.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
  585. begin
  586. Result := MouseListener;
  587. if Result = nil then
  588. Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
  589. if Assigned(Result) then
  590. begin
  591. Exclude(Result.FLayerStates, CStateMap[Button]);
  592. Result.MouseUp(Button, Shift, X, Y);
  593. end;
  594. if Assigned(MouseListener) and
  595. (MouseListener.FLayerStates *
  596. [lsMouseLeft, lsMouseRight, lsMouseMiddle] = []) then
  597. MouseListener := nil; // reset mouse capture
  598. end;
  599. procedure TLayerCollection.Notify(Action: TLayerListNotification; Layer: TCustomLayer; Index: Integer);
  600. begin
  601. if Assigned(FOnListNotify) then
  602. FOnListNotify(Self, Action, Layer, Index);
  603. end;
  604. procedure TLayerCollection.RemoveItem(Item: TCustomLayer);
  605. var
  606. Index: Integer;
  607. begin
  608. BeginUpdate;
  609. try
  610. Index := FItems.IndexOf(Item);
  611. if Index >= 0 then
  612. begin
  613. FItems.Delete(Index);
  614. Item.FLayerCollection := nil;
  615. Notify(lnLayerDeleted, Item, Index);
  616. end;
  617. finally
  618. EndUpdate;
  619. end;
  620. end;
  621. procedure TLayerCollection.SetItem(Index: Integer; Value: TCustomLayer);
  622. begin
  623. TCollectionItem(FItems[Index]).Assign(Value);
  624. end;
  625. procedure TLayerCollection.SetMouseEvents(Value: Boolean);
  626. begin
  627. FMouseEvents := Value;
  628. MouseListener := nil;
  629. end;
  630. procedure TLayerCollection.SetMouseListener(Value: TCustomLayer);
  631. begin
  632. if Value <> FMouseListener then
  633. begin
  634. if Assigned(FMouseListener) then
  635. FMouseListener.FLayerStates := FMouseListener.FLayerStates -
  636. [lsMouseLeft, lsMouseRight, lsMouseMiddle];
  637. FMouseListener := Value;
  638. end;
  639. end;
  640. procedure TLayerCollection.DoUpdateArea(const Rect: TRect);
  641. begin
  642. if Assigned(FOnAreaUpdated) then
  643. FOnAreaUpdated(Self, Rect, AREAINFO_RECT);
  644. Changed;
  645. end;
  646. procedure TLayerCollection.DoUpdateLayer(Layer: TCustomLayer);
  647. begin
  648. if Assigned(FOnLayerUpdated) then
  649. FOnLayerUpdated(Self, Layer);
  650. Changed;
  651. end;
  652. procedure TLayerCollection.GetViewportScale(out ScaleX, ScaleY: TFloat);
  653. begin
  654. if Assigned(FOnGetViewportScale) then
  655. FOnGetViewportScale(Self, ScaleX, ScaleY)
  656. else
  657. begin
  658. ScaleX := 1;
  659. ScaleY := 1;
  660. end;
  661. end;
  662. procedure TLayerCollection.GetViewportShift(out ShiftX, ShiftY: TFloat);
  663. begin
  664. if Assigned(FOnGetViewportShift) then
  665. FOnGetViewportShift(Self, ShiftX, ShiftY)
  666. else
  667. begin
  668. ShiftX := 0;
  669. ShiftY := 0;
  670. end;
  671. end;
  672. {$IFDEF COMPILER2009_UP}
  673. { TLayerEnum }
  674. constructor TLayerEnum.Create(ALayerCollection: TLayerCollection);
  675. begin
  676. inherited Create;
  677. FLayerCollection := ALayerCollection;
  678. FIndex := -1;
  679. end;
  680. function TLayerEnum.GetCurrent: TCustomLayer;
  681. begin
  682. Result := FLayerCollection.Items[FIndex];
  683. end;
  684. function TLayerEnum.MoveNext: Boolean;
  685. begin
  686. Result := FIndex < Pred(FLayerCollection.Count);
  687. if Result then
  688. Inc(FIndex);
  689. end;
  690. { TLayerCollectionHelper }
  691. function TLayerCollectionHelper.GetEnumerator: TLayerEnum;
  692. begin
  693. Result := TLayerEnum.Create(Self);
  694. end;
  695. {$ENDIF}
  696. { TCustomLayer }
  697. constructor TCustomLayer.Create(ALayerCollection: TLayerCollection);
  698. begin
  699. LayerCollection := ALayerCollection;
  700. FLayerOptions := LOB_VISIBLE;
  701. end;
  702. destructor TCustomLayer.Destroy;
  703. var
  704. I: Integer;
  705. begin
  706. if Assigned(FFreeNotifies) then
  707. begin
  708. for I := FFreeNotifies.Count - 1 downto 0 do
  709. begin
  710. TCustomLayer(FFreeNotifies[I]).Notification(Self);
  711. if FFreeNotifies = nil then Break;
  712. end;
  713. FFreeNotifies.Free;
  714. FFreeNotifies := nil;
  715. end;
  716. SetLayerCollection(nil);
  717. inherited;
  718. end;
  719. procedure TCustomLayer.AddNotification(ALayer: TCustomLayer);
  720. begin
  721. if not Assigned(FFreeNotifies) then
  722. FFreeNotifies := TList.Create;
  723. if FFreeNotifies.IndexOf(ALayer) < 0 then
  724. FFreeNotifies.Add(ALayer);
  725. end;
  726. procedure TCustomLayer.BeforeDestruction;
  727. begin
  728. if Assigned(FOnDestroy) then
  729. FOnDestroy(Self);
  730. inherited;
  731. end;
  732. procedure TCustomLayer.BringToFront;
  733. begin
  734. Index := LayerCollection.Count;
  735. end;
  736. procedure TCustomLayer.Changed;
  737. begin
  738. if UpdateCount > 0 then Exit;
  739. if Assigned(FLayerCollection) and ((FLayerOptions and LOB_NO_UPDATE) = 0) then
  740. begin
  741. Update;
  742. if Visible then
  743. FLayerCollection.Changed
  744. else if (FLayerOptions and LOB_GDI_OVERLAY) <> 0 then
  745. FLayerCollection.GDIUpdate;
  746. inherited;
  747. end;
  748. end;
  749. procedure TCustomLayer.Changed(const Rect: TRect);
  750. begin
  751. if UpdateCount > 0 then Exit;
  752. if Assigned(FLayerCollection) and ((FLayerOptions and LOB_NO_UPDATE) = 0) then
  753. begin
  754. Update(Rect);
  755. if Visible then
  756. FLayerCollection.Changed
  757. else if (FLayerOptions and LOB_GDI_OVERLAY) <> 0 then
  758. FLayerCollection.GDIUpdate;
  759. inherited Changed;
  760. end;
  761. end;
  762. procedure TCustomLayer.Changing;
  763. begin
  764. if UpdateCount > 0 then Exit;
  765. if Visible and Assigned(FLayerCollection) and
  766. ((FLayerOptions and LOB_NO_UPDATE) = 0) then
  767. FLayerCollection.Changing;
  768. end;
  769. procedure TCustomLayer.Click;
  770. begin
  771. FClicked := False;
  772. if Assigned(FOnClick) then
  773. FOnClick(Self);
  774. end;
  775. procedure TCustomLayer.DblClick;
  776. begin
  777. FClicked := False;
  778. if Assigned(FOnDblClick) then
  779. FOnDblClick(Self);
  780. end;
  781. function TCustomLayer.DoHitTest(X, Y: Integer): Boolean;
  782. begin
  783. Result := Visible;
  784. end;
  785. procedure TCustomLayer.DoPaint(Buffer: TBitmap32);
  786. begin
  787. Paint(Buffer);
  788. if Assigned(FOnPaint) then
  789. FOnPaint(Self, Buffer);
  790. end;
  791. function TCustomLayer.GetIndex: Integer;
  792. begin
  793. if Assigned(FLayerCollection) then
  794. Result := FLayerCollection.FItems.IndexOf(Self)
  795. else
  796. Result := -1;
  797. end;
  798. function TCustomLayer.GetMouseEvents: Boolean;
  799. begin
  800. Result := FLayerOptions and LOB_MOUSE_EVENTS <> 0;
  801. end;
  802. function TCustomLayer.GetOwner: TPersistent;
  803. begin
  804. Result := FLayerCollection;
  805. end;
  806. function TCustomLayer.GetVisible: Boolean;
  807. begin
  808. Result := FLayerOptions and LOB_VISIBLE <> 0;
  809. end;
  810. function TCustomLayer.HitTest(X, Y: Integer): Boolean;
  811. begin
  812. Result := DoHitTest(X, Y);
  813. if Assigned(FOnHitTest) then
  814. FOnHitTest(Self, X, Y, Result);
  815. end;
  816. procedure TCustomLayer.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  817. begin
  818. if (Button = mbLeft) then
  819. begin
  820. if (ssDouble in Shift) then
  821. DblClick
  822. else
  823. FClicked := True;
  824. end;
  825. if Assigned(FOnMouseDown) then
  826. FOnMouseDown(Self, Button, Shift, X, Y);
  827. end;
  828. procedure TCustomLayer.MouseMove(Shift: TShiftState; X, Y: Integer);
  829. begin
  830. Screen.Cursor := Cursor;
  831. if Assigned(FOnMouseMove) then
  832. FOnMouseMove(Self, Shift, X, Y);
  833. end;
  834. procedure TCustomLayer.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  835. begin
  836. Screen.Cursor := crDefault;
  837. if (Button = mbLeft) and FClicked then
  838. Click;
  839. if Assigned(FOnMouseUp) then
  840. FOnMouseUp(Self, Button, Shift, X, Y);
  841. end;
  842. procedure TCustomLayer.Notification(ALayer: TCustomLayer);
  843. begin
  844. // do nothing by default
  845. end;
  846. procedure TCustomLayer.Paint(Buffer: TBitmap32);
  847. begin
  848. // descendants override this method
  849. end;
  850. procedure TCustomLayer.PaintGDI(Canvas: TCanvas);
  851. begin
  852. // descendants override this method
  853. end;
  854. procedure TCustomLayer.RemoveNotification(ALayer: TCustomLayer);
  855. begin
  856. if Assigned(FFreeNotifies) then
  857. begin
  858. FFreeNotifies.Remove(ALayer);
  859. if FFreeNotifies.Count = 0 then
  860. begin
  861. FFreeNotifies.Free;
  862. FFreeNotifies := nil;
  863. end;
  864. end;
  865. end;
  866. procedure TCustomLayer.SendToBack;
  867. begin
  868. Index := 0;
  869. end;
  870. procedure TCustomLayer.SetAsMouseListener;
  871. begin
  872. FLayerCollection.MouseListener := Self;
  873. Screen.Cursor := Cursor;
  874. end;
  875. procedure TCustomLayer.SetCursor(Value: TCursor);
  876. begin
  877. if Value <> FCursor then
  878. begin
  879. FCursor := Value;
  880. if FLayerCollection.MouseListener = Self then
  881. Screen.Cursor := Value;
  882. end;
  883. end;
  884. procedure TCustomLayer.SetIndex(Value: Integer);
  885. var
  886. CurIndex: Integer;
  887. begin
  888. CurIndex := GetIndex;
  889. if (CurIndex >= 0) and (CurIndex <> Value) then
  890. with FLayerCollection do
  891. begin
  892. if Value < 0 then Value := 0;
  893. if Value >= Count then Value := Count - 1;
  894. if Value <> CurIndex then
  895. begin
  896. if Visible then BeginUpdate;
  897. try
  898. FLayerCollection.FItems.Move(CurIndex, Value);
  899. finally
  900. if Visible then EndUpdate;
  901. end;
  902. end;
  903. end;
  904. end;
  905. procedure TCustomLayer.SetLayerCollection(Value: TLayerCollection);
  906. begin
  907. if FLayerCollection <> Value then
  908. begin
  909. if Assigned(FLayerCollection) then
  910. begin
  911. if FLayerCollection.MouseListener = Self then
  912. FLayerCollection.MouseListener := nil;
  913. FLayerCollection.RemoveItem(Self);
  914. end;
  915. if Assigned(Value) then
  916. Value.InsertItem(Self);
  917. FLayerCollection := Value;
  918. end;
  919. end;
  920. procedure TCustomLayer.SetLayerOptions(Value: Cardinal);
  921. begin
  922. if (FLayerOptions <> Value) then
  923. begin
  924. Changing;
  925. FLayerOptions := Value;
  926. Changed;
  927. end;
  928. end;
  929. procedure TCustomLayer.SetMouseEvents(Value: Boolean);
  930. begin
  931. if Value then
  932. LayerOptions := LayerOptions or LOB_MOUSE_EVENTS
  933. else
  934. LayerOptions := LayerOptions and not LOB_MOUSE_EVENTS;
  935. end;
  936. procedure TCustomLayer.SetVisible(Value: Boolean);
  937. begin
  938. if Value then
  939. LayerOptions := LayerOptions or LOB_VISIBLE
  940. else
  941. begin
  942. ForceUpdate := True;
  943. LayerOptions := LayerOptions and not LOB_VISIBLE;
  944. ForceUpdate := False;
  945. end;
  946. end;
  947. procedure TCustomLayer.Update;
  948. begin
  949. if Assigned(FLayerCollection) and
  950. (Visible or (LayerOptions and LOB_FORCE_UPDATE <> 0)) then
  951. FLayerCollection.DoUpdateLayer(Self);
  952. end;
  953. procedure TCustomLayer.Update(const Rect: TRect);
  954. begin
  955. if Assigned(FLayerCollection) then
  956. FLayerCollection.DoUpdateArea(Rect);
  957. end;
  958. function TCustomLayer.GetInvalid: Boolean;
  959. begin
  960. Result := LayerOptions and LOB_INVALID <> 0;
  961. end;
  962. procedure TCustomLayer.SetInvalid(Value: Boolean);
  963. begin
  964. // don't use LayerOptions here since this is internal and we don't want to
  965. // trigger Changing and Changed as this will definitely cause a stack overflow.
  966. if Value then
  967. FLayerOptions := FLayerOptions or LOB_INVALID
  968. else
  969. FLayerOptions := FLayerOptions and not LOB_INVALID;
  970. end;
  971. function TCustomLayer.GetForceUpdate: Boolean;
  972. begin
  973. Result := LayerOptions and LOB_FORCE_UPDATE <> 0;
  974. end;
  975. procedure TCustomLayer.SetForceUpdate(Value: Boolean);
  976. begin
  977. // don't use LayerOptions here since this is internal and we don't want to
  978. // trigger Changing and Changed as this will definitely cause a stack overflow.
  979. if Value then
  980. FLayerOptions := FLayerOptions or LOB_FORCE_UPDATE
  981. else
  982. FLayerOptions := FLayerOptions and not LOB_FORCE_UPDATE;
  983. end;
  984. { TPositionedLayer }
  985. constructor TPositionedLayer.Create(ALayerCollection: TLayerCollection);
  986. begin
  987. inherited;
  988. with FLocation do
  989. begin
  990. Left := 0;
  991. Top := 0;
  992. Right := 64;
  993. Bottom := 64;
  994. end;
  995. FLayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS;
  996. end;
  997. function TPositionedLayer.DoHitTest(X, Y: Integer): Boolean;
  998. begin
  999. with GetAdjustedRect(FLocation) do
  1000. Result := (X >= Left) and (X < Right) and (Y >= Top) and (Y < Bottom) and
  1001. inherited DoHitTest(X, Y);
  1002. end;
  1003. procedure TPositionedLayer.DoSetLocation(const NewLocation: TFloatRect);
  1004. begin
  1005. FLocation := NewLocation;
  1006. end;
  1007. function TPositionedLayer.GetAdjustedLocation: TFloatRect;
  1008. begin
  1009. Result := GetAdjustedRect(FLocation);
  1010. end;
  1011. function TPositionedLayer.GetAdjustedRect(const R: TFloatRect): TFloatRect;
  1012. var
  1013. ScaleX, ScaleY, ShiftX, ShiftY: TFloat;
  1014. begin
  1015. if Scaled and Assigned(FLayerCollection) then
  1016. begin
  1017. FLayerCollection.GetViewportShift(ShiftX, ShiftY);
  1018. FLayerCollection.GetViewportScale(ScaleX, ScaleY);
  1019. with Result do
  1020. begin
  1021. Left := R.Left * ScaleX + ShiftX;
  1022. Top := R.Top * ScaleY + ShiftY;
  1023. Right := R.Right * ScaleX + ShiftX;
  1024. Bottom := R.Bottom * ScaleY + ShiftY;
  1025. end;
  1026. end
  1027. else
  1028. Result := R;
  1029. end;
  1030. procedure TPositionedLayer.SetLocation(const Value: TFloatRect);
  1031. begin
  1032. Changing;
  1033. DoSetLocation(Value);
  1034. Changed;
  1035. end;
  1036. procedure TPositionedLayer.SetScaled(Value: Boolean);
  1037. begin
  1038. if Value <> FScaled then
  1039. begin
  1040. Changing;
  1041. FScaled := Value;
  1042. Changed;
  1043. end;
  1044. end;
  1045. { TCustomBitmapLayer }
  1046. procedure TCustomBitmapLayer.BitmapAreaChanged(Sender: TObject; const Area: TRect; const Info: Cardinal);
  1047. var
  1048. T: TRect;
  1049. ScaleX, ScaleY: TFloat;
  1050. Width: Integer;
  1051. begin
  1052. if FBitmap.Empty then
  1053. Exit;
  1054. if Assigned(FLayerCollection) and ((FLayerOptions and LOB_NO_UPDATE) = 0) then
  1055. begin
  1056. with GetAdjustedLocation do
  1057. begin
  1058. { TODO : Optimize me! }
  1059. ScaleX := (Right - Left) / FBitmap.Width;
  1060. ScaleY := (Bottom - Top) / FBitmap.Height;
  1061. T.Left := Floor(Left + Area.Left * ScaleX);
  1062. T.Top := Floor(Top + Area.Top * ScaleY);
  1063. T.Right := Ceil(Left + Area.Right * ScaleX);
  1064. T.Bottom := Ceil(Top + Area.Bottom * ScaleY);
  1065. end;
  1066. Width := Trunc(FBitmap.Resampler.Width) + 1;
  1067. InflateArea(T, Width, Width);
  1068. Changed(T);
  1069. end;
  1070. end;
  1071. constructor TCustomBitmapLayer.Create(ALayerCollection: TLayerCollection);
  1072. begin
  1073. inherited;
  1074. FBitmap := CreateBitmap;
  1075. FBitmap.OnAreaChanged := BitmapAreaChanged;
  1076. end;
  1077. function TCustomBitmapLayer.CreateBitmap: TCustomBitmap32;
  1078. begin
  1079. Result := GetBitmapClass.Create;
  1080. end;
  1081. function TCustomBitmapLayer.DoHitTest(X, Y: Integer): Boolean;
  1082. var
  1083. BitmapX, BitmapY: Integer;
  1084. LayerWidth, LayerHeight: Integer;
  1085. begin
  1086. Result := inherited DoHitTest(X, Y);
  1087. if Result and AlphaHit then
  1088. begin
  1089. with GetAdjustedRect(FLocation) do
  1090. begin
  1091. LayerWidth := Round(Right - Left);
  1092. LayerHeight := Round(Bottom - Top);
  1093. if (LayerWidth < 0.5) or (LayerHeight < 0.5) then Result := False
  1094. else
  1095. begin
  1096. // check the pixel alpha at (X, Y) position
  1097. BitmapX := Round((X - Left) * FBitmap.Width / LayerWidth);
  1098. BitmapY := Round((Y - Top) * FBitmap.Height / LayerHeight);
  1099. if FBitmap.PixelS[BitmapX, BitmapY] and $FF000000 = 0 then Result := False;
  1100. end;
  1101. end;
  1102. end;
  1103. end;
  1104. function TCustomBitmapLayer.GetBitmap: TCustomBitmap32;
  1105. begin
  1106. Result := FBitmap;
  1107. end;
  1108. destructor TCustomBitmapLayer.Destroy;
  1109. begin
  1110. FBitmap.Free;
  1111. inherited;
  1112. end;
  1113. procedure TCustomBitmapLayer.Paint(Buffer: TBitmap32);
  1114. var
  1115. SrcRect, DstRect, ClipRect, TempRect: TRect;
  1116. ImageRect: TRect;
  1117. LayerWidth, LayerHeight: TFloat;
  1118. begin
  1119. if FBitmap.Empty then
  1120. Exit;
  1121. DstRect := MakeRect(GetAdjustedRect(FLocation));
  1122. ClipRect := Buffer.ClipRect;
  1123. GR32.IntersectRect(TempRect, ClipRect, DstRect);
  1124. if GR32.IsRectEmpty(TempRect) then
  1125. Exit;
  1126. SrcRect := MakeRect(0, 0, FBitmap.Width, FBitmap.Height);
  1127. if Cropped and (LayerCollection.FOwner is TCustomImage32) and
  1128. not (TImage32Access(LayerCollection.FOwner).PaintToMode) then
  1129. begin
  1130. with DstRect do
  1131. begin
  1132. LayerWidth := Right - Left;
  1133. LayerHeight := Bottom - Top;
  1134. end;
  1135. if (LayerWidth < 0.5) or (LayerHeight < 0.5) then
  1136. Exit;
  1137. ImageRect := TCustomImage32(LayerCollection.FOwner).GetBitmapRect;
  1138. GR32.IntersectRect(ClipRect, ClipRect, ImageRect);
  1139. end;
  1140. StretchTransfer(Buffer, DstRect, ClipRect, FBitmap, SrcRect, FBitmap.Resampler, FBitmap.DrawMode, FBitmap.OnPixelCombine);
  1141. end;
  1142. procedure TCustomBitmapLayer.SetBitmap(Value: TCustomBitmap32);
  1143. begin
  1144. FBitmap.Assign(Value);
  1145. end;
  1146. procedure TCustomBitmapLayer.SetCropped(Value: Boolean);
  1147. begin
  1148. if Value <> FCropped then
  1149. begin
  1150. FCropped := Value;
  1151. Changed;
  1152. end;
  1153. end;
  1154. { TBitmapLayer }
  1155. function TBitmapLayer.GetBitmap: TBitmap32;
  1156. begin
  1157. Result := TBitmap32(inherited Bitmap);
  1158. end;
  1159. procedure TBitmapLayer.SetBitmap(Value: TBitmap32);
  1160. begin
  1161. inherited SetBitmap(Value);
  1162. end;
  1163. function TBitmapLayer.GetBitmapClass: TCustomBitmap32Class;
  1164. begin
  1165. Result := TBitmap32;
  1166. end;
  1167. { TRubberbandPassMouse }
  1168. constructor TRubberbandPassMouse.Create(AOwner: TRubberbandLayer);
  1169. begin
  1170. FOwner := AOwner;
  1171. FEnabled := False;
  1172. FToChild := False;
  1173. FLayerUnderCursor := False;
  1174. FCancelIfPassed := False;
  1175. end;
  1176. function TRubberbandPassMouse.GetChildUnderCursor(X, Y: Integer): TPositionedLayer;
  1177. var
  1178. Layer: TCustomLayer;
  1179. Index: Integer;
  1180. begin
  1181. Result := nil;
  1182. for Index := FOwner.LayerCollection.Count - 1 downto 0 do
  1183. begin
  1184. Layer := FOwner.LayerCollection.Items[Index];
  1185. if ((Layer.LayerOptions and LOB_MOUSE_EVENTS) > 0) and
  1186. (Layer is TPositionedLayer) and Layer.HitTest(X, Y) then
  1187. begin
  1188. Result := TPositionedLayer(Layer);
  1189. Exit;
  1190. end;
  1191. end;
  1192. end;
  1193. { TRubberbandLayer }
  1194. constructor TRubberbandLayer.Create(ALayerCollection: TLayerCollection);
  1195. begin
  1196. inherited;
  1197. FHandleFrame := clBlack32;
  1198. FHandleFill := clWhite32;
  1199. FHandles := [rhCenter, rhSides, rhCorners, rhFrame];
  1200. FHandleSize := 3;
  1201. FMinWidth := 10;
  1202. FMinHeight := 10;
  1203. FQuantized := 8;
  1204. FLayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS;
  1205. SetFrameStipple([clWhite32, clWhite32, clBlack32, clBlack32]);
  1206. FPassMouse := TRubberbandPassMouse.Create(Self);
  1207. FFrameStippleStep := 1;
  1208. FFrameStippleCounter := 0;
  1209. end;
  1210. destructor TRubberbandLayer.Destroy;
  1211. begin
  1212. FPassMouse.Free;
  1213. inherited;
  1214. end;
  1215. function TRubberbandLayer.DoHitTest(X, Y: Integer): Boolean;
  1216. begin
  1217. if (Visible) then
  1218. Result := (GetDragState(X, Y) <> dsNone)
  1219. else
  1220. Result := False;
  1221. end;
  1222. procedure TRubberbandLayer.DoResizing(var OldLocation,
  1223. NewLocation: TFloatRect; DragState: TRBDragState; Shift: TShiftState);
  1224. begin
  1225. if Assigned(FOnResizing) then
  1226. FOnResizing(Self, OldLocation, NewLocation, DragState, Shift);
  1227. end;
  1228. procedure TRubberbandLayer.DoConstrain(var OldLocation,
  1229. NewLocation: TFloatRect; DragState: TRBDragState; Shift: TShiftState);
  1230. begin
  1231. if Assigned(FOnConstrain) then
  1232. FOnConstrain(Self, OldLocation, NewLocation, DragState, Shift);
  1233. end;
  1234. procedure TRubberbandLayer.DoSetLocation(const NewLocation: TFloatRect);
  1235. begin
  1236. inherited;
  1237. UpdateChildLayer;
  1238. end;
  1239. function SnapAngleTo45(Angle: integer): integer;
  1240. begin
  1241. Result := (((Angle + 45 div 2) div 45) * 45 + 360) mod 360;
  1242. end;
  1243. function AngleToDirection(Angle: integer): TResizeDirection;
  1244. begin
  1245. Result := TResizeDirection(SnapAngleTo45(Angle) div 45);
  1246. end;
  1247. function TRubberbandLayer.GetHandleCursor(DragState: TRBDragState; Angle: integer): TCursor;
  1248. var
  1249. Direction: TResizeDirection;
  1250. begin
  1251. if (DragState in [dsNone, dsMove]) then
  1252. Exit(Cursor);
  1253. Direction := AngleToDirection(Angle);
  1254. Result := DirectionCursors[Direction];
  1255. end;
  1256. function TRubberbandLayer.GetDragState(X, Y: Integer): TRBDragState;
  1257. var
  1258. R: TRect;
  1259. dh_center, dh_sides, dh_corners: Boolean;
  1260. dl, dt, dr, db, dx, dy: Boolean;
  1261. Sz: Integer;
  1262. const
  1263. DragZone = 1;
  1264. begin
  1265. Result := dsNone;
  1266. Sz := Ceil(FHandleSize + DragZone);
  1267. dh_center := rhCenter in FHandles;
  1268. dh_sides := rhSides in FHandles;
  1269. dh_corners := rhCorners in FHandles;
  1270. R := MakeRect(GetAdjustedRect(FLocation));
  1271. with R do
  1272. begin
  1273. Dec(Right);
  1274. Dec(Bottom);
  1275. dl := Abs(Left - X) <= Sz;
  1276. dr := Abs(Right - X) <= Sz;
  1277. dx := Abs((Left + Right) div 2 - X) <= Sz;
  1278. dt := Abs(Top - Y) <= Sz;
  1279. db := Abs(Bottom - Y) <= Sz;
  1280. dy := Abs((Top + Bottom) div 2 - Y) <= Sz;
  1281. end;
  1282. if dr and db and dh_corners and not(rhNotBRCorner in FHandles) then Result := dsSizeBR
  1283. else if dl and db and dh_corners and not(rhNotBLCorner in FHandles) then Result := dsSizeBL
  1284. else if dr and dt and dh_corners and not(rhNotTRCorner in FHandles) then Result := dsSizeTR
  1285. else if dl and dt and dh_corners and not(rhNotTLCorner in FHandles) then Result := dsSizeTL
  1286. else if dr and dy and dh_sides and not(rhNotRightSide in FHandles) then Result := dsSizeR
  1287. else if db and dx and dh_sides and not(rhNotBottomSide in FHandles) then Result := dsSizeB
  1288. else if dl and dy and dh_sides and not(rhNotLeftSide in FHandles) then Result := dsSizeL
  1289. else if dt and dx and dh_sides and not(rhNotTopSide in FHandles) then Result := dsSizeT
  1290. else if dh_center and GR32.PtInRect(R, GR32.Point(X, Y)) then Result := dsMove;
  1291. end;
  1292. procedure TRubberbandLayer.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1293. var
  1294. PositionedLayer: TPositionedLayer;
  1295. begin
  1296. if FPassMouse.Enabled then
  1297. begin
  1298. if FPassMouse.ToLayerUnderCursor then
  1299. PositionedLayer := FPassMouse.GetChildUnderCursor(X, Y)
  1300. else
  1301. PositionedLayer := ChildLayer;
  1302. if FPassMouse.ToChild and Assigned(ChildLayer) then
  1303. begin
  1304. ChildLayer.MouseDown(Button, Shift, X, Y);
  1305. if FPassMouse.CancelIfPassed then
  1306. Exit;
  1307. end;
  1308. if (PositionedLayer <> ChildLayer) and Assigned(PositionedLayer) then
  1309. begin
  1310. PositionedLayer.MouseDown(Button, Shift, X, Y);
  1311. if FPassMouse.CancelIfPassed then
  1312. Exit;
  1313. end;
  1314. end;
  1315. if FIsDragging then Exit;
  1316. SetDragState(GetDragState(X, Y), X, Y);
  1317. inherited;
  1318. end;
  1319. procedure TRubberbandLayer.MouseMove(Shift: TShiftState; X, Y: Integer);
  1320. procedure IncLT(var LT, RB: TFloat; Delta, MinSize, MaxSize: TFloat);
  1321. begin
  1322. LT := LT + Delta;
  1323. if RB - LT < MinSize then
  1324. LT := RB - MinSize;
  1325. if MaxSize >= MinSize then
  1326. if RB - LT > MaxSize then
  1327. LT := RB - MaxSize;
  1328. end;
  1329. procedure IncRB(var LT, RB: TFloat; Delta, MinSize, MaxSize: TFloat);
  1330. begin
  1331. RB := RB + Delta;
  1332. if RB - LT < MinSize then
  1333. RB := LT + MinSize;
  1334. if MaxSize >= MinSize then
  1335. if RB - LT > MaxSize then
  1336. RB := LT + MaxSize;
  1337. end;
  1338. var
  1339. Mx, My: TFloat;
  1340. L, T, R, B, W, H: TFloat;
  1341. LQuantize: Boolean;
  1342. ALoc, NewLocation: TFloatRect;
  1343. Angle: integer;
  1344. const
  1345. DragStateToAngle: array[TRBDragState] of integer = (-1, -1, 180, 90, 0, 270, 135, 45, 225, 315);
  1346. begin
  1347. if not FIsDragging then
  1348. begin
  1349. FDragState := GetDragState(X, Y);
  1350. Angle := DragStateToAngle[FDragState];
  1351. Screen.Cursor := GetHandleCursor(FDragState, Angle);
  1352. end
  1353. else
  1354. begin
  1355. Mx := X - FMouseShift.X;
  1356. My := Y - FMouseShift.Y;
  1357. if Scaled then
  1358. with Location do
  1359. begin
  1360. ALoc := GetAdjustedRect(FLocation);
  1361. if GR32.IsRectEmpty(ALoc) then Exit;
  1362. Mx := (Mx - ALoc.Left) / (ALoc.Right - ALoc.Left) * (Right - Left) + Left;
  1363. My := (My - ALoc.Top) / (ALoc.Bottom - ALoc.Top) * (Bottom - Top) + Top;
  1364. end;
  1365. with FOldLocation do
  1366. begin
  1367. L := Left;
  1368. T := Top;
  1369. R := Right;
  1370. B := Bottom;
  1371. W := R - L;
  1372. H := B - T;
  1373. end;
  1374. LQuantize := (roQuantized in Options) and not (ssAlt in Shift);
  1375. if FDragState = dsMove then
  1376. begin
  1377. L := Mx;
  1378. T := My;
  1379. if LQuantize then
  1380. begin
  1381. L := Round(L / FQuantized) * FQuantized;
  1382. T := Round(T / FQuantized) * FQuantized;
  1383. end;
  1384. R := L + W;
  1385. B := T + H;
  1386. end
  1387. else
  1388. begin
  1389. if FDragState in [dsSizeL, dsSizeTL, dsSizeBL] then
  1390. begin
  1391. IncLT(L, R, Mx - L, MinWidth, MaxWidth);
  1392. if LQuantize then
  1393. L := Round(L / FQuantized) * FQuantized;
  1394. end;
  1395. if FDragState in [dsSizeR, dsSizeTR, dsSizeBR] then
  1396. begin
  1397. IncRB(L, R, Mx - R, MinWidth, MaxWidth);
  1398. if LQuantize then
  1399. R := Round(R / FQuantized) * FQuantized;
  1400. end;
  1401. if FDragState in [dsSizeT, dsSizeTL, dsSizeTR] then
  1402. begin
  1403. IncLT(T, B, My - T, MinHeight, MaxHeight);
  1404. if LQuantize then
  1405. T := Round(T / FQuantized) * FQuantized;
  1406. end;
  1407. if FDragState in [dsSizeB, dsSizeBL, dsSizeBR] then
  1408. begin
  1409. IncRB(T, B, My - B, MinHeight, MaxHeight);
  1410. if LQuantize then
  1411. B := Round(B / FQuantized) * FQuantized;
  1412. end;
  1413. end;
  1414. NewLocation := FloatRect(L, T, R, B);
  1415. if roConstrained in FOptions then
  1416. DoConstrain(FOldLocation, NewLocation, FDragState, Shift);
  1417. if roProportional in FOptions then
  1418. begin
  1419. case FDragState of
  1420. dsSizeB, dsSizeBR:
  1421. NewLocation.Right := FOldLocation.Left + (FOldLocation.Right - FOldLocation.Left) * (NewLocation.Bottom - NewLocation.Top) / (FOldLocation.Bottom - FOldLocation.Top);
  1422. dsSizeT, dsSizeTL:
  1423. NewLocation.Left := FOldLocation.Right - (FOldLocation.Right - FOldLocation.Left) * (NewLocation.Bottom - NewLocation.Top) / (FOldLocation.Bottom - FOldLocation.Top);
  1424. dsSizeR, dsSizeBL:
  1425. NewLocation.Bottom := FOldLocation.Top + (FOldLocation.Bottom - FOldLocation.Top) * (NewLocation.Right - NewLocation.Left) / (FOldLocation.Right - FOldLocation.Left);
  1426. dsSizeL, dsSizeTR:
  1427. NewLocation.Top := FOldLocation.Bottom - (FOldLocation.Bottom - FOldLocation.Top) * (NewLocation.Right - NewLocation.Left) / (FOldLocation.Right - FOldLocation.Left);
  1428. end;
  1429. end;
  1430. DoResizing(FOldLocation, NewLocation, FDragState, Shift);
  1431. if (NewLocation.Left <> Location.Left) or
  1432. (NewLocation.Right <> Location.Right) or
  1433. (NewLocation.Top <> Location.Top) or
  1434. (NewLocation.Bottom <> Location.Bottom) then
  1435. begin
  1436. Location := NewLocation;
  1437. if Assigned(FOnUserChange) then
  1438. FOnUserChange(Self);
  1439. end;
  1440. end;
  1441. end;
  1442. procedure TRubberbandLayer.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1443. var
  1444. PositionedLayer: TPositionedLayer;
  1445. begin
  1446. if FPassMouse.Enabled then
  1447. begin
  1448. if FPassMouse.ToLayerUnderCursor then
  1449. PositionedLayer := FPassMouse.GetChildUnderCursor(X, Y)
  1450. else
  1451. PositionedLayer := ChildLayer;
  1452. if FPassMouse.ToChild and Assigned(ChildLayer) then
  1453. begin
  1454. ChildLayer.MouseUp(Button, Shift, X, Y);
  1455. if FPassMouse.CancelIfPassed then
  1456. Exit;
  1457. end;
  1458. if (PositionedLayer <> ChildLayer) and Assigned(PositionedLayer) then
  1459. begin
  1460. PositionedLayer.MouseUp(Button, Shift, X, Y);
  1461. if FPassMouse.CancelIfPassed then
  1462. Exit;
  1463. end;
  1464. end;
  1465. FIsDragging := False;
  1466. inherited;
  1467. end;
  1468. procedure TRubberbandLayer.Notification(ALayer: TCustomLayer);
  1469. begin
  1470. if ALayer = FChildLayer then
  1471. FChildLayer := nil;
  1472. end;
  1473. procedure TRubberbandLayer.DrawHandle(Buffer: TBitmap32; X, Y: TFloat);
  1474. var
  1475. HandleRect: TRect;
  1476. begin
  1477. // Coordinate specifies exact center of handle. I.e. center of
  1478. // pixel if handle is odd number of pixels wide.
  1479. HandleRect.Left := Floor(X - FHandleSize);
  1480. HandleRect.Right := HandleRect.Left + Ceil(FHandleSize*2);
  1481. HandleRect.Top := Floor(Y - FHandleSize);
  1482. HandleRect.Bottom := HandleRect.Top + Ceil(FHandleSize*2);
  1483. Buffer.FrameRectTS(HandleRect, FHandleFrame);
  1484. GR32.InflateRect(HandleRect, -1, -1);
  1485. Buffer.FillRectTS(HandleRect, FHandleFill);
  1486. end;
  1487. procedure TRubberbandLayer.Paint(Buffer: TBitmap32);
  1488. var
  1489. CenterX, CenterY: TFloat;
  1490. R: TRect;
  1491. begin
  1492. R := MakeRect(GetAdjustedRect(FLocation));
  1493. with R do
  1494. begin
  1495. if rhFrame in FHandles then
  1496. begin
  1497. Buffer.SetStipple(FFrameStipplePattern);
  1498. Buffer.StippleCounter := 0;
  1499. Buffer.StippleStep := FFrameStippleStep;
  1500. Buffer.StippleCounter := FFrameStippleCounter;
  1501. Buffer.FrameRectTSP(Left, Top, Right, Bottom);
  1502. end;
  1503. if rhCorners in FHandles then
  1504. begin
  1505. if not(rhNotTLCorner in FHandles) then DrawHandle(Buffer, Left+0.5, Top+0.5);
  1506. if not(rhNotTRCorner in FHandles) then DrawHandle(Buffer, Right-0.5, Top+0.5);
  1507. if not(rhNotBLCorner in FHandles) then DrawHandle(Buffer, Left+0.5, Bottom-0.5);
  1508. if not(rhNotBRCorner in FHandles) then DrawHandle(Buffer, Right-0.5, Bottom-0.5);
  1509. end;
  1510. if rhSides in FHandles then
  1511. begin
  1512. CenterX := (Left + Right) / 2;
  1513. CenterY := (Top + Bottom) / 2;
  1514. if not(rhNotTopSide in FHandles) then DrawHandle(Buffer, CenterX, Top+0.5);
  1515. if not(rhNotLeftSide in FHandles) then DrawHandle(Buffer, Left+0.5, CenterY);
  1516. if not(rhNotRightSide in FHandles) then DrawHandle(Buffer, Right-0.5, CenterY);
  1517. if not(rhNotBottomSide in FHandles) then DrawHandle(Buffer, CenterX, Bottom-0.5);
  1518. end;
  1519. end;
  1520. end;
  1521. procedure TRubberbandLayer.Quantize;
  1522. begin
  1523. Location := FloatRect(
  1524. Round(Location.Left / Quantized) * Quantized,
  1525. Round(Location.Top / Quantized) * Quantized,
  1526. Round(Location.Right / Quantized) * Quantized,
  1527. Round(Location.Bottom / Quantized) * Quantized);
  1528. end;
  1529. procedure TRubberbandLayer.SetChildLayer(Value: TPositionedLayer);
  1530. begin
  1531. if Assigned(FChildLayer) then
  1532. RemoveNotification(FChildLayer);
  1533. FChildLayer := Value;
  1534. if Assigned(Value) then
  1535. begin
  1536. Location := Value.Location;
  1537. Scaled := Value.Scaled;
  1538. AddNotification(FChildLayer);
  1539. end;
  1540. end;
  1541. procedure TRubberbandLayer.SetDragState(const Value: TRBDragState);
  1542. begin
  1543. SetDragState(Value, 0, 0);
  1544. end;
  1545. procedure TRubberbandLayer.SetDragState(const Value: TRBDragState; const X, Y: Integer);
  1546. var
  1547. ALoc: TFloatRect;
  1548. begin
  1549. FDragState := Value;
  1550. FIsDragging := FDragState <> dsNone;
  1551. if FIsDragging then
  1552. begin
  1553. FOldLocation := Location;
  1554. ALoc := GetAdjustedRect(FLocation);
  1555. case FDragState of
  1556. dsMove: FMouseShift := FloatPoint(X - ALoc.Left, Y - ALoc.Top);
  1557. else
  1558. FMouseShift := FloatPoint(0, 0);
  1559. end;
  1560. end;
  1561. end;
  1562. procedure TRubberbandLayer.SetHandleFill(Value: TColor32);
  1563. begin
  1564. if Value <> FHandleFill then
  1565. begin
  1566. FHandleFill := Value;
  1567. FLayerCollection.GDIUpdate;
  1568. end;
  1569. end;
  1570. procedure TRubberbandLayer.SetHandleFrame(Value: TColor32);
  1571. begin
  1572. if Value <> FHandleFrame then
  1573. begin
  1574. FHandleFrame := Value;
  1575. FLayerCollection.GDIUpdate;
  1576. end;
  1577. end;
  1578. procedure TRubberbandLayer.SetHandles(Value: TRBHandles);
  1579. begin
  1580. if Value <> FHandles then
  1581. begin
  1582. FHandles := Value;
  1583. FLayerCollection.GDIUpdate;
  1584. end;
  1585. end;
  1586. procedure TRubberbandLayer.SetHandleSize(Value: TFloat);
  1587. begin
  1588. if Value < 1 then
  1589. Value := 1;
  1590. if Value <> FHandleSize then
  1591. begin
  1592. FHandleSize := Value;
  1593. FLayerCollection.GDIUpdate;
  1594. end;
  1595. end;
  1596. procedure TRubberbandLayer.SetFrameStipple(const Value: Array of TColor32);
  1597. var
  1598. L: Integer;
  1599. begin
  1600. L := High(Value) + 1;
  1601. SetLength(FFrameStipplePattern, L);
  1602. MoveLongword(Value[0], FFrameStipplePattern[0], L);
  1603. end;
  1604. procedure TRubberbandLayer.SetFrameStippleStep(const Value: TFloat);
  1605. begin
  1606. if Value <> FFrameStippleStep then
  1607. begin
  1608. FFrameStippleStep := Value;
  1609. FLayerCollection.GDIUpdate;
  1610. end;
  1611. end;
  1612. procedure TRubberbandLayer.UpdateChildLayer;
  1613. begin
  1614. if Assigned(FChildLayer) then FChildLayer.Location := Location;
  1615. end;
  1616. procedure TRubberbandLayer.SetFrameStippleCounter(const Value: TFloat);
  1617. begin
  1618. if Value <> FFrameStippleCounter then
  1619. begin
  1620. FFrameStippleCounter := Value;
  1621. FLayerCollection.GDIUpdate;
  1622. end;
  1623. end;
  1624. procedure TRubberbandLayer.SetLayerOptions(Value: Cardinal);
  1625. begin
  1626. Changing;
  1627. FLayerOptions := Value and not LOB_NO_UPDATE; // workaround for changed behaviour
  1628. Changed;
  1629. end;
  1630. procedure TRubberbandLayer.SetOptions(const Value: TRBOptions);
  1631. begin
  1632. FOptions := Value;
  1633. end;
  1634. procedure TRubberbandLayer.SetQuantized(const Value: Integer);
  1635. begin
  1636. if Value < 1 then
  1637. raise Exception.Create('Value must be larger than zero!');
  1638. FQuantized := Value;
  1639. end;
  1640. end.