GR32_Image.pas 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740
  1. unit GR32_Image;
  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. * Mattias Andersson <[email protected]>
  32. * Andre Beckedorf <[email protected]>
  33. * Andrew P. Rybin <[email protected]>
  34. * Dieter Köhler <[email protected]>
  35. * Michael Hansen <[email protected]>
  36. *
  37. * ***** END LICENSE BLOCK ***** *)
  38. interface
  39. {$I GR32.inc}
  40. uses
  41. {$IFDEF FPC}
  42. LCLIntf, LCLType, LMessages, Types,
  43. {$ELSE}
  44. Windows, Messages, {$IFDEF COMPILERXE2_UP}Types,{$ENDIF}
  45. {$ENDIF}
  46. Graphics, Controls, Forms,
  47. Classes, SysUtils, GR32, GR32_Layers, GR32_RangeBars, GR32_Containers,
  48. GR32_RepaintOpt;
  49. const
  50. { Paint Stage Constants }
  51. PST_CUSTOM = 1; // Calls OnPaint with # of current stage in parameter
  52. PST_CLEAR_BUFFER = 2; // Clears the buffer
  53. PST_CLEAR_BACKGND = 3; // Clears a visible buffer area
  54. PST_DRAW_BITMAP = 4; // Draws a bitmap
  55. PST_DRAW_LAYERS = 5; // Draw layers (Parameter = Layer Mask)
  56. PST_CONTROL_FRAME = 6; // Draws a dotted frame around the control
  57. PST_BITMAP_FRAME = 7; // Draws a dotted frame around the scaled bitmap
  58. type
  59. TPaintStageEvent = procedure(Sender: TObject; Buffer: TBitmap32; StageNum: Cardinal) of object;
  60. { TPaintStage }
  61. PPaintStage = ^TPaintStage;
  62. TPaintStage = record
  63. DsgnTime: Boolean;
  64. RunTime: Boolean;
  65. Stage: Cardinal; // a PST_* constant
  66. Parameter: Cardinal; // an optional parameter
  67. end;
  68. { TPaintStages }
  69. TPaintStages = class
  70. private
  71. FItems: array of TPaintStage;
  72. function GetItem(Index: Integer): PPaintStage;
  73. public
  74. destructor Destroy; override;
  75. function Add: PPaintStage;
  76. procedure Clear;
  77. function Count: Integer;
  78. procedure Delete(Index: Integer);
  79. function Insert(Index: Integer): PPaintStage;
  80. property Items[Index: Integer]: PPaintStage read GetItem; default;
  81. end;
  82. { Alignment of the bitmap in TCustomImage32 }
  83. TBitmapAlign = (baTopLeft, baCenter, baTile, baCustom);
  84. TScaleMode = (smNormal, smStretch, smScale, smResize, smOptimal, smOptimalScaled);
  85. TPaintBoxOptions = set of (pboWantArrowKeys, pboAutoFocus);
  86. TRepaintMode = (rmFull, rmDirect, rmOptimizer);
  87. { TCustomPaintBox32 }
  88. TCustomPaintBox32 = class(TCustomControl)
  89. private
  90. FBuffer: TBitmap32;
  91. FBufferOversize: Integer;
  92. FBufferValid: Boolean;
  93. FRepaintMode: TRepaintMode;
  94. FInvalidRects: TRectList;
  95. FForceFullRepaint: Boolean;
  96. FRepaintOptimizer: TCustomRepaintOptimizer;
  97. FOptions: TPaintBoxOptions;
  98. FOnGDIOverlay: TNotifyEvent;
  99. FMouseInControl: Boolean;
  100. FOnMouseEnter: TNotifyEvent;
  101. FOnMouseLeave: TNotifyEvent;
  102. procedure SetBufferOversize(Value: Integer);
  103. {$IFDEF FPC}
  104. procedure WMEraseBkgnd(var Message: TLMEraseBkgnd); message LM_ERASEBKGND;
  105. procedure WMGetDlgCode(var Msg: TLMessage); message LM_GETDLGCODE;
  106. procedure WMPaint(var Message: TLMPaint); message LM_PAINT;
  107. procedure CMMouseEnter(var Message: TLMessage); message LM_MOUSEENTER;
  108. procedure CMMouseLeave(var Message: TLMessage); message LM_MOUSELEAVE;
  109. {$ELSE}
  110. procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
  111. procedure WMGetDlgCode(var Msg: TWmGetDlgCode); message WM_GETDLGCODE;
  112. procedure WMPaint(var Message: TMessage); message WM_PAINT;
  113. procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
  114. procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  115. {$ENDIF}
  116. procedure DirectAreaUpdateHandler(Sender: TObject; const Area: TRect; const Info: Cardinal);
  117. protected
  118. procedure SetRepaintMode(const Value: TRepaintMode); virtual;
  119. function CustomRepaint: Boolean; virtual;
  120. function InvalidRectsAvailable: Boolean; virtual;
  121. procedure DoPrepareInvalidRects; virtual;
  122. procedure DoPaintBuffer; virtual;
  123. procedure DoPaintGDIOverlay; virtual;
  124. procedure DoBufferResized(const OldWidth, OldHeight: Integer); virtual;
  125. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  126. procedure MouseEnter; {$IFDEF FPC} override; {$ELSE} virtual; {$ENDIF}
  127. procedure MouseLeave; {$IFDEF FPC} override; {$ELSE} virtual; {$ENDIF}
  128. procedure Paint; override;
  129. procedure ResetInvalidRects;
  130. procedure ResizeBuffer;
  131. property RepaintOptimizer: TCustomRepaintOptimizer read FRepaintOptimizer;
  132. property BufferValid: Boolean read FBufferValid write FBufferValid;
  133. property InvalidRects: TRectList read FInvalidRects;
  134. public
  135. constructor Create(AOwner: TComponent); override;
  136. destructor Destroy; override;
  137. function GetViewportRect: TRect; virtual;
  138. procedure Flush; overload;
  139. procedure Flush(const SrcRect: TRect); overload;
  140. procedure Invalidate; override;
  141. procedure ForceFullInvalidate; virtual;
  142. procedure Loaded; override;
  143. procedure Resize; override;
  144. procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  145. procedure AssignTo(Dest: TPersistent); override;
  146. property Buffer: TBitmap32 read FBuffer;
  147. property BufferOversize: Integer read FBufferOversize write SetBufferOversize;
  148. property Options: TPaintBoxOptions read FOptions write FOptions default [];
  149. property MouseInControl: Boolean read FMouseInControl;
  150. property RepaintMode: TRepaintMode read FRepaintMode write SetRepaintMode default rmFull;
  151. property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
  152. property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
  153. property OnGDIOverlay: TNotifyEvent read FOnGDIOverlay write FOnGDIOverlay;
  154. end;
  155. { TPaintBox32 }
  156. TPaintBox32 = class(TCustomPaintBox32)
  157. private
  158. FOnPaintBuffer: TNotifyEvent;
  159. protected
  160. procedure DoPaintBuffer; override;
  161. public
  162. property Canvas;
  163. published
  164. property Align;
  165. property Anchors;
  166. property AutoSize;
  167. property Constraints;
  168. property Cursor;
  169. property DragCursor;
  170. property DragMode;
  171. property Options;
  172. property ParentShowHint;
  173. property PopupMenu;
  174. property RepaintMode;
  175. property ShowHint;
  176. property TabOrder;
  177. property TabStop;
  178. property Visible;
  179. {$IFNDEF PLATFORM_INDEPENDENT}
  180. property OnCanResize;
  181. {$ENDIF}
  182. property OnClick;
  183. property OnDblClick;
  184. property OnDragDrop;
  185. property OnDragOver;
  186. property OnEndDrag;
  187. property OnGDIOverlay;
  188. property OnMouseDown;
  189. property OnMouseMove;
  190. property OnMouseUp;
  191. property OnMouseWheel;
  192. property OnMouseWheelDown;
  193. property OnMouseWheelUp;
  194. property OnMouseEnter;
  195. property OnMouseLeave;
  196. property OnPaintBuffer: TNotifyEvent read FOnPaintBuffer write FOnPaintBuffer;
  197. property OnResize;
  198. property OnStartDrag;
  199. end;
  200. { TCustomImage32 }
  201. TImgMouseEvent = procedure(Sender: TObject; Button: TMouseButton;
  202. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer) of object;
  203. TImgMouseMoveEvent = procedure(Sender: TObject; Shift: TShiftState;
  204. X, Y: Integer; Layer: TCustomLayer) of object;
  205. TPaintStageHandler = procedure(Dest: TBitmap32; StageNum: Integer) of object;
  206. TCustomImage32 = class(TCustomPaintBox32)
  207. private
  208. FBitmap: TBitmap32;
  209. FBitmapAlign: TBitmapAlign;
  210. FLayers: TLayerCollection;
  211. FOffsetHorz: TFloat;
  212. FOffsetVert: TFloat;
  213. FPaintStages: TPaintStages;
  214. FPaintStageHandlers: array of TPaintStageHandler;
  215. FPaintStageNum: array of Integer;
  216. FScaleX: TFloat;
  217. FScaleY: TFloat;
  218. FScaleMode: TScaleMode;
  219. FUpdateCount: Integer;
  220. FOnBitmapResize: TNotifyEvent;
  221. FOnChange: TNotifyEvent;
  222. FOnInitStages: TNotifyEvent;
  223. FOnMouseDown: TImgMouseEvent;
  224. FOnMouseMove: TImgMouseMoveEvent;
  225. FOnMouseUp: TImgMouseEvent;
  226. FOnPaintStage: TPaintStageEvent;
  227. FOnScaleChange: TNotifyEvent;
  228. procedure BitmapResizeHandler(Sender: TObject);
  229. procedure BitmapChangeHandler(Sender: TObject);
  230. procedure BitmapAreaChangeHandler(Sender: TObject; const Area: TRect; const Info: Cardinal);
  231. procedure BitmapDirectAreaChangeHandler(Sender: TObject; const Area: TRect; const Info: Cardinal);
  232. procedure LayerCollectionChangeHandler(Sender: TObject);
  233. procedure LayerCollectionGDIUpdateHandler(Sender: TObject);
  234. procedure LayerCollectionGetViewportScaleHandler(Sender: TObject; out ScaleX, ScaleY: TFloat);
  235. procedure LayerCollectionGetViewportShiftHandler(Sender: TObject; out ShiftX, ShiftY: TFloat);
  236. function GetOnPixelCombine: TPixelCombineEvent;
  237. procedure SetBitmap(Value: TBitmap32);
  238. procedure SetBitmapAlign(Value: TBitmapAlign);
  239. procedure SetLayers(Value: TLayerCollection);
  240. procedure SetOffsetHorz(Value: TFloat);
  241. procedure SetOffsetVert(Value: TFloat);
  242. procedure SetScale(Value: TFloat);
  243. procedure SetScaleX(Value: TFloat);
  244. procedure SetScaleY(Value: TFloat);
  245. procedure SetOnPixelCombine(Value: TPixelCombineEvent);
  246. protected
  247. CachedBitmapRect: TRect;
  248. CachedShiftX, CachedShiftY,
  249. CachedScaleX, CachedScaleY,
  250. CachedRecScaleX, CachedRecScaleY: TFloat;
  251. CacheValid: Boolean;
  252. OldSzX, OldSzY: Integer;
  253. PaintToMode: Boolean;
  254. procedure BitmapResized; virtual;
  255. procedure BitmapChanged(const Area: TRect); reintroduce; virtual;
  256. function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; override;
  257. procedure DoInitStages; virtual;
  258. procedure DoPaintBuffer; override;
  259. procedure DoPaintGDIOverlay; override;
  260. procedure DoScaleChange; virtual;
  261. procedure InitDefaultStages; virtual;
  262. procedure InvalidateCache;
  263. function InvalidRectsAvailable: Boolean; override;
  264. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); overload; override;
  265. procedure MouseMove(Shift: TShiftState; X, Y: Integer); overload; override;
  266. procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); overload; override;
  267. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer); reintroduce; overload; virtual;
  268. procedure MouseMove(Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer); reintroduce; overload; virtual;
  269. procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer); reintroduce; overload; virtual;
  270. procedure MouseLeave; override;
  271. procedure SetRepaintMode(const Value: TRepaintMode); override;
  272. procedure SetScaleMode(Value: TScaleMode); virtual;
  273. procedure SetXForm(ShiftX, ShiftY, ScaleX, ScaleY: TFloat);
  274. procedure UpdateCache; virtual;
  275. function GetLayerCollectionClass: TLayerCollectionClass; virtual;
  276. function CreateLayerCollection: TLayerCollection; virtual;
  277. property UpdateCount: Integer read FUpdateCount;
  278. public
  279. constructor Create(AOwner: TComponent); override;
  280. destructor Destroy; override;
  281. procedure BeginUpdate; virtual;
  282. function BitmapToControl(const APoint: TPoint): TPoint; overload;
  283. function BitmapToControl(const APoint: TFloatPoint): TFloatPoint; overload;
  284. procedure Changed; virtual;
  285. procedure Update(const Rect: TRect); reintroduce; overload; virtual;
  286. function ControlToBitmap(const APoint: TPoint): TPoint; overload;
  287. function ControlToBitmap(const ARect: TRect): TRect; overload;
  288. function ControlToBitmap(const APoint: TFloatPoint): TFloatPoint; overload;
  289. procedure EndUpdate; virtual;
  290. procedure ExecBitmapFrame(Dest: TBitmap32; StageNum: Integer); virtual; // PST_BITMAP_FRAME
  291. procedure ExecClearBuffer(Dest: TBitmap32; StageNum: Integer); virtual; // PST_CLEAR_BUFFER
  292. procedure ExecClearBackgnd(Dest: TBitmap32; StageNum: Integer); virtual; // PST_CLEAR_BACKGND
  293. procedure ExecControlFrame(Dest: TBitmap32; StageNum: Integer); virtual; // PST_CONTROL_FRAME
  294. procedure ExecCustom(Dest: TBitmap32; StageNum: Integer); virtual; // PST_CUSTOM
  295. procedure ExecDrawBitmap(Dest: TBitmap32; StageNum: Integer); virtual; // PST_DRAW_BITMAP
  296. procedure ExecDrawLayers(Dest: TBitmap32; StageNum: Integer); virtual; // PST_DRAW_LAYERS
  297. function GetBitmapRect: TRect; virtual;
  298. function GetBitmapSize: TSize; virtual;
  299. procedure Invalidate; override;
  300. procedure Loaded; override;
  301. procedure PaintTo(Dest: TBitmap32; DestRect: TRect); virtual;
  302. procedure Resize; override;
  303. procedure SetupBitmap(DoClear: Boolean = False; ClearColor: TColor32 = $FF000000); virtual;
  304. property Bitmap: TBitmap32 read FBitmap write SetBitmap;
  305. property BitmapAlign: TBitmapAlign read FBitmapAlign write SetBitmapAlign;
  306. property Canvas;
  307. property Layers: TLayerCollection read FLayers write SetLayers;
  308. property OffsetHorz: TFloat read FOffsetHorz write SetOffsetHorz;
  309. property OffsetVert: TFloat read FOffsetVert write SetOffsetVert;
  310. property PaintStages: TPaintStages read FPaintStages;
  311. property Scale: TFloat read FScaleX write SetScale;
  312. property ScaleX: TFloat read FScaleX write SetScaleX;
  313. property ScaleY: TFloat read FScaleY write SetScaleY;
  314. property ScaleMode: TScaleMode read FScaleMode write SetScaleMode;
  315. property OnBitmapResize: TNotifyEvent read FOnBitmapResize write FOnBitmapResize;
  316. property OnBitmapPixelCombine: TPixelCombineEvent read GetOnPixelCombine write SetOnPixelCombine;
  317. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  318. property OnInitStages: TNotifyEvent read FOnInitStages write FOnInitStages;
  319. property OnMouseDown: TImgMouseEvent read FOnMouseDown write FOnMouseDown;
  320. property OnMouseMove: TImgMouseMoveEvent read FOnMouseMove write FOnMouseMove;
  321. property OnMouseUp: TImgMouseEvent read FOnMouseUp write FOnMouseUp;
  322. property OnPaintStage: TPaintStageEvent read FOnPaintStage write FOnPaintStage;
  323. property OnScaleChange: TNotifyEvent read FOnScaleChange write FOnScaleChange;
  324. end;
  325. TImage32 = class(TCustomImage32)
  326. published
  327. property Align;
  328. property Anchors;
  329. property AutoSize;
  330. property Bitmap;
  331. property BitmapAlign;
  332. property Color;
  333. property Constraints;
  334. property Cursor;
  335. property DragCursor;
  336. property DragMode;
  337. property ParentColor;
  338. property ParentShowHint;
  339. property PopupMenu;
  340. property RepaintMode;
  341. property Scale;
  342. property ScaleMode;
  343. property ShowHint;
  344. property TabOrder;
  345. property TabStop;
  346. property Visible;
  347. property OnBitmapResize;
  348. {$IFNDEF PLATFORM_INDEPENDENT}
  349. property OnCanResize;
  350. {$ENDIF}
  351. property OnClick;
  352. property OnChange;
  353. property OnContextPopup;
  354. property OnDblClick;
  355. property OnGDIOverlay;
  356. property OnDragDrop;
  357. property OnDragOver;
  358. property OnEndDrag;
  359. property OnInitStages;
  360. property OnKeyDown;
  361. property OnKeyPress;
  362. property OnKeyUp;
  363. property OnMouseDown;
  364. property OnMouseMove;
  365. property OnMouseUp;
  366. property OnMouseWheel;
  367. property OnMouseWheelDown;
  368. property OnMouseWheelUp;
  369. property OnMouseEnter;
  370. property OnMouseLeave;
  371. property OnPaintStage;
  372. property OnResize;
  373. property OnStartDrag;
  374. end;
  375. TCustomImgView32 = class;
  376. TScrollBarVisibility = (svAlways, svHidden, svAuto);
  377. { TIVScrollProperties }
  378. TIVScrollProperties = class(TArrowBarAccess)
  379. private
  380. function GetIncrement: Integer;
  381. function GetSize: Integer;
  382. function GetVisibility: TScrollbarVisibility;
  383. procedure SetIncrement(Value: Integer);
  384. procedure SetSize(Value: Integer);
  385. procedure SetVisibility(const Value: TScrollbarVisibility);
  386. protected
  387. ImgView: TCustomImgView32;
  388. published
  389. property Increment: Integer read GetIncrement write SetIncrement default 8;
  390. property Size: Integer read GetSize write SetSize default 0;
  391. property Visibility: TScrollBarVisibility read GetVisibility write SetVisibility default svAlways;
  392. end;
  393. TSizeGripStyle = (sgAuto, sgNone, sgAlways);
  394. { TCustomImgView32 }
  395. TCustomImgView32 = class(TCustomImage32)
  396. private
  397. FCentered: Boolean;
  398. FScrollBarSize: Integer;
  399. FScrollBarVisibility: TScrollBarVisibility;
  400. FScrollBars: TIVScrollProperties;
  401. FSizeGrip: TSizeGripStyle;
  402. FOnScroll: TNotifyEvent;
  403. FOverSize: Integer;
  404. procedure SetCentered(Value: Boolean);
  405. procedure SetScrollBars(Value: TIVScrollProperties);
  406. procedure SetSizeGrip(Value: TSizeGripStyle);
  407. procedure SetOverSize(const Value: Integer);
  408. protected
  409. DisableScrollUpdate: Boolean;
  410. HScroll: TCustomRangeBar;
  411. VScroll: TCustomRangeBar;
  412. procedure AlignAll;
  413. procedure BitmapResized; override;
  414. procedure DoDrawSizeGrip(R: TRect);
  415. procedure DoScaleChange; override;
  416. procedure DoScroll; virtual;
  417. function GetScrollBarsVisible: Boolean;
  418. function GetScrollBarSize: Integer;
  419. function GetSizeGripRect: TRect;
  420. function IsSizeGripVisible: Boolean;
  421. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  422. procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  423. procedure Paint; override;
  424. procedure Recenter;
  425. procedure SetScaleMode(Value: TScaleMode); override;
  426. procedure ScrollHandler(Sender: TObject); virtual;
  427. procedure ScrollChangingHandler(Sender: TObject; ANewPosition: Single; var Handled: boolean);
  428. procedure UpdateImage; virtual;
  429. procedure UpdateScrollBars; virtual;
  430. public
  431. constructor Create(AOwner: TComponent); override;
  432. destructor Destroy; override;
  433. function GetViewportRect: TRect; override;
  434. procedure Loaded; override;
  435. procedure Resize; override;
  436. procedure ScrollToCenter(X, Y: Integer);
  437. procedure Scroll(Dx, Dy: Integer); overload;
  438. procedure Scroll(Dx, Dy: Single); overload; virtual;
  439. property Centered: Boolean read FCentered write SetCentered default True;
  440. property ScrollBars: TIVScrollProperties read FScrollBars write SetScrollBars;
  441. property SizeGrip: TSizeGripStyle read FSizeGrip write SetSizeGrip default sgAuto;
  442. property OverSize: Integer read FOverSize write SetOverSize;
  443. property OnScroll: TNotifyEvent read FOnScroll write FOnScroll;
  444. end;
  445. TImgView32 = class(TCustomImgView32)
  446. property Align;
  447. property Anchors;
  448. property AutoSize;
  449. property Bitmap;
  450. property BitmapAlign;
  451. property Centered;
  452. property Color;
  453. property Constraints;
  454. property Cursor;
  455. property DragCursor;
  456. property DragMode;
  457. property ParentColor;
  458. property ParentShowHint;
  459. property PopupMenu;
  460. property RepaintMode;
  461. property Scale;
  462. property ScaleMode;
  463. property ScrollBars;
  464. property ShowHint;
  465. property SizeGrip;
  466. property OverSize;
  467. property TabOrder;
  468. property TabStop;
  469. property Visible;
  470. property OnBitmapResize;
  471. {$IFNDEF PLATFORM_INDEPENDENT}
  472. property OnCanResize;
  473. {$ENDIF}
  474. property OnClick;
  475. property OnChange;
  476. property OnDblClick;
  477. property OnDragDrop;
  478. property OnDragOver;
  479. property OnEndDrag;
  480. property OnGDIOverlay;
  481. property OnInitStages;
  482. property OnKeyDown;
  483. property OnKeyPress;
  484. property OnKeyUp;
  485. property OnMouseDown;
  486. property OnMouseEnter;
  487. property OnMouseLeave;
  488. property OnMouseMove;
  489. property OnMouseUp;
  490. property OnMouseWheel;
  491. property OnMouseWheelDown;
  492. property OnMouseWheelUp;
  493. property OnPaintStage;
  494. property OnResize;
  495. property OnScroll;
  496. property OnStartDrag;
  497. end;
  498. { TBitmap32Item }
  499. { A bitmap container designed to be inserted into TBitmap32Collection }
  500. TBitmap32Item = class(TCollectionItem)
  501. private
  502. FBitmap: TBitmap32;
  503. procedure SetBitmap(ABitmap: TBitmap32);
  504. protected
  505. procedure AssignTo(Dest: TPersistent); override;
  506. public
  507. constructor Create(Collection: TCollection); override;
  508. destructor Destroy; override;
  509. published
  510. property Bitmap: TBitmap32 read FBitmap write SetBitmap;
  511. end;
  512. TBitmap32ItemClass = class of TBitmap32Item;
  513. { TBitmap32Collection }
  514. { A collection of TBitmap32Item objects }
  515. TBitmap32Collection = class(TCollection)
  516. private
  517. FOwner: TPersistent;
  518. function GetItem(Index: Integer): TBitmap32Item;
  519. procedure SetItem(Index: Integer; Value: TBitmap32Item);
  520. protected
  521. function GetOwner: TPersistent; override;
  522. public
  523. constructor Create(AOwner: TPersistent; ItemClass: TBitmap32ItemClass);
  524. function Add: TBitmap32Item;
  525. property Items[Index: Integer]: TBitmap32Item read GetItem write SetItem; default;
  526. end;
  527. { TBitmap32List }
  528. { A component that stores TBitmap32Collection }
  529. TBitmap32List = class(TComponent)
  530. private
  531. FBitmap32Collection: TBitmap32Collection;
  532. procedure SetBitmap(Index: Integer; Value: TBitmap32);
  533. function GetBitmap(Index: Integer): TBitmap32;
  534. procedure SetBitmap32Collection(Value: TBitmap32Collection);
  535. public
  536. constructor Create(AOwner: TComponent); override;
  537. destructor Destroy; override;
  538. property Bitmap[Index: Integer]: TBitmap32 read GetBitmap write SetBitmap; default;
  539. published
  540. property Bitmaps: TBitmap32Collection read FBitmap32Collection write SetBitmap32Collection;
  541. end;
  542. implementation
  543. uses
  544. Math, TypInfo,
  545. GR32_MicroTiles, GR32_Backends, GR32_XPThemes, GR32_LowLevel;
  546. type
  547. TLayerAccess = class(TCustomLayer);
  548. TLayerCollectionAccess = class(TLayerCollection);
  549. TRangeBarAccess = class(TRangeBar);
  550. const
  551. DefaultRepaintOptimizerClass: TCustomRepaintOptimizerClass = TMicroTilesRepaintOptimizer;
  552. resourcestring
  553. RCStrInvalidStageIndex = 'Invalid stage index';
  554. { TPaintStages }
  555. function TPaintStages.Add: PPaintStage;
  556. var
  557. L: Integer;
  558. begin
  559. L := Length(FItems);
  560. SetLength(FItems, L + 1);
  561. Result := @FItems[L];
  562. with Result^ do
  563. begin
  564. DsgnTime := False;
  565. RunTime := True;
  566. Stage := 0;
  567. Parameter := 0;
  568. end;
  569. end;
  570. procedure TPaintStages.Clear;
  571. begin
  572. FItems := nil;
  573. end;
  574. function TPaintStages.Count: Integer;
  575. begin
  576. Result := Length(FItems);
  577. end;
  578. procedure TPaintStages.Delete(Index: Integer);
  579. var
  580. LCount: Integer;
  581. begin
  582. if (Index < 0) or (Index > High(FItems)) then
  583. raise EListError.Create(RCStrInvalidStageIndex);
  584. LCount := Length(FItems) - Index - 1;
  585. if LCount > 0 then
  586. Move(FItems[Index + 1], FItems[Index], LCount * SizeOf(TPaintStage));
  587. SetLength(FItems, High(FItems));
  588. end;
  589. destructor TPaintStages.Destroy;
  590. begin
  591. Clear;
  592. inherited;
  593. end;
  594. function TPaintStages.GetItem(Index: Integer): PPaintStage;
  595. begin
  596. Result := @FItems[Index];
  597. end;
  598. function TPaintStages.Insert(Index: Integer): PPaintStage;
  599. var
  600. LCount: Integer;
  601. begin
  602. if Index < 0 then
  603. Index := 0
  604. else
  605. if Index > Length(FItems) then
  606. Index := Length(FItems);
  607. LCount := Length(FItems) - Index;
  608. SetLength(FItems, Length(FItems) + 1);
  609. if LCount > 0 then
  610. Move(FItems[Index], FItems[Index + 1], LCount * SizeOf(TPaintStage));
  611. Result := @FItems[Index];
  612. with Result^ do
  613. begin
  614. DsgnTime := False;
  615. RunTime := True;
  616. Stage := 0;
  617. Parameter := 0;
  618. end;
  619. end;
  620. { TCustomPaintBox32 }
  621. procedure TCustomPaintBox32.AssignTo(Dest: TPersistent);
  622. begin
  623. inherited AssignTo(Dest);
  624. if Dest is TCustomPaintBox32 then
  625. begin
  626. FBuffer.Assign(TCustomPaintBox32(Dest).FBuffer);
  627. TCustomPaintBox32(Dest).FBufferOversize := FBufferOversize;
  628. TCustomPaintBox32(Dest).FBufferValid := FBufferValid;
  629. TCustomPaintBox32(Dest).FRepaintMode := FRepaintMode;
  630. TCustomPaintBox32(Dest).FInvalidRects := FInvalidRects;
  631. TCustomPaintBox32(Dest).FForceFullRepaint := FForceFullRepaint;
  632. TCustomPaintBox32(Dest).FOptions := FOptions;
  633. TCustomPaintBox32(Dest).FOnGDIOverlay := FOnGDIOverlay;
  634. TCustomPaintBox32(Dest).FOnMouseEnter := FOnMouseEnter;
  635. TCustomPaintBox32(Dest).FOnMouseLeave := FOnMouseLeave;
  636. end;
  637. end;
  638. procedure TCustomPaintBox32.CMMouseEnter(var Message: {$IFDEF FPC}TLMessage{$ELSE}TMessage{$ENDIF});
  639. begin
  640. inherited;
  641. MouseEnter;
  642. end;
  643. procedure TCustomPaintBox32.CMMouseLeave(var Message: {$IFDEF FPC}TLMessage{$ELSE}TMessage{$ENDIF});
  644. begin
  645. MouseLeave;
  646. inherited;
  647. end;
  648. constructor TCustomPaintBox32.Create(AOwner: TComponent);
  649. begin
  650. inherited;
  651. FBuffer := TBitmap32.Create;
  652. FBufferOversize := 40;
  653. FForceFullRepaint := True;
  654. FInvalidRects := TRectList.Create;
  655. FRepaintOptimizer := DefaultRepaintOptimizerClass.Create(Buffer, InvalidRects);
  656. { Setting a initial size here will cause the control to crash under LCL }
  657. {$IFNDEF FPC}
  658. SetBounds(0, 0, 192, 192);
  659. {$ENDIF}
  660. end;
  661. destructor TCustomPaintBox32.Destroy;
  662. begin
  663. FRepaintOptimizer.Free;
  664. FInvalidRects.Free;
  665. FBuffer.Free;
  666. inherited;
  667. end;
  668. procedure TCustomPaintBox32.DoBufferResized(const OldWidth, OldHeight: Integer);
  669. begin
  670. if FRepaintOptimizer.Enabled then
  671. FRepaintOptimizer.BufferResizedHandler(FBuffer.Width, FBuffer.Height);
  672. end;
  673. function TCustomPaintBox32.CustomRepaint: Boolean;
  674. begin
  675. Result := FRepaintOptimizer.Enabled and not FForceFullRepaint and
  676. FRepaintOptimizer.UpdatesAvailable;
  677. end;
  678. procedure TCustomPaintBox32.DoPrepareInvalidRects;
  679. begin
  680. if FRepaintOptimizer.Enabled and not FForceFullRepaint then
  681. FRepaintOptimizer.PerformOptimization;
  682. end;
  683. function TCustomPaintBox32.InvalidRectsAvailable: Boolean;
  684. begin
  685. Result := True;
  686. end;
  687. procedure TCustomPaintBox32.DoPaintBuffer;
  688. begin
  689. // force full repaint, this is necessary when Buffer is invalid and was never painted
  690. // This will omit calculating the invalid rects, thus we paint everything.
  691. if FForceFullRepaint then
  692. begin
  693. FForceFullRepaint := False;
  694. FInvalidRects.Clear;
  695. end
  696. else
  697. DoPrepareInvalidRects;
  698. // descendants should override this method for painting operations,
  699. // not the Paint method!!!
  700. FBufferValid := True;
  701. end;
  702. procedure TCustomPaintBox32.DoPaintGDIOverlay;
  703. begin
  704. if Assigned(FOnGDIOverlay) then
  705. FOnGDIOverlay(Self);
  706. end;
  707. procedure TCustomPaintBox32.Flush;
  708. begin
  709. if (FBuffer.Handle <> 0) then
  710. begin
  711. Canvas.Lock;
  712. try
  713. FBuffer.Lock;
  714. try
  715. if (Canvas.Handle <> 0) then
  716. with GetViewportRect do
  717. BitBlt(Canvas.Handle, Left, Top, Right - Left, Bottom - Top,
  718. FBuffer.Handle, 0, 0, SRCCOPY);
  719. finally
  720. FBuffer.Unlock;
  721. end;
  722. finally
  723. Canvas.Unlock;
  724. end;
  725. end;
  726. end;
  727. procedure TCustomPaintBox32.Flush(const SrcRect: TRect);
  728. var
  729. R: TRect;
  730. begin
  731. if (FBuffer.Handle <> 0) then
  732. begin
  733. Canvas.Lock;
  734. try
  735. FBuffer.Lock;
  736. try
  737. R := GetViewPortRect;
  738. if (Canvas.Handle <> 0) then
  739. with SrcRect do
  740. BitBlt(Canvas.Handle, Left + R.Left, Top + R.Top, Right - Left,
  741. Bottom - Top, FBuffer.Handle, Left, Top, SRCCOPY);
  742. finally
  743. FBuffer.Unlock;
  744. end;
  745. finally
  746. Canvas.Unlock;
  747. end;
  748. end;
  749. end;
  750. function TCustomPaintBox32.GetViewportRect: TRect;
  751. begin
  752. // returns position of the buffered area within the control bounds
  753. // by default, the whole control is buffered
  754. Result.Left := 0;
  755. Result.Top := 0;
  756. Result.Right := Width;
  757. Result.Bottom := Height;
  758. end;
  759. procedure TCustomPaintBox32.Invalidate;
  760. begin
  761. FBufferValid := False;
  762. inherited;
  763. end;
  764. procedure TCustomPaintBox32.ForceFullInvalidate;
  765. begin
  766. if FRepaintOptimizer.Enabled then
  767. FRepaintOptimizer.Reset;
  768. FForceFullRepaint := True;
  769. Invalidate;
  770. end;
  771. procedure TCustomPaintBox32.Loaded;
  772. begin
  773. ResizeBuffer;
  774. FBufferValid := False;
  775. inherited;
  776. end;
  777. procedure TCustomPaintBox32.MouseDown(Button: TMouseButton; Shift: TShiftState;
  778. X, Y: Integer);
  779. begin
  780. if (pboAutoFocus in Options) and CanFocus then
  781. SetFocus;
  782. inherited;
  783. end;
  784. procedure TCustomPaintBox32.MouseEnter;
  785. begin
  786. FMouseInControl := True;
  787. if Assigned(FOnMouseEnter) then
  788. FOnMouseEnter(Self);
  789. end;
  790. procedure TCustomPaintBox32.MouseLeave;
  791. begin
  792. FMouseInControl := False;
  793. if Assigned(FOnMouseLeave) then
  794. FOnMouseLeave(Self);
  795. end;
  796. procedure TCustomPaintBox32.Paint;
  797. var
  798. PaintSupport: IPaintSupport;
  799. begin
  800. if not Assigned(Parent) then
  801. Exit;
  802. if FRepaintOptimizer.Enabled then
  803. FRepaintOptimizer.BeginPaint;
  804. PaintSupport := FBuffer.Backend as IPaintSupport;
  805. if not FBufferValid then
  806. begin
  807. PaintSupport.ImageNeeded;
  808. DoPaintBuffer;
  809. PaintSupport.CheckPixmap;
  810. end;
  811. FBuffer.Lock;
  812. try
  813. PaintSupport.DoPaint(FBuffer, FInvalidRects, Canvas, Self);
  814. finally
  815. FBuffer.Unlock;
  816. end;
  817. DoPaintGDIOverlay;
  818. if FRepaintOptimizer.Enabled then
  819. FRepaintOptimizer.EndPaint;
  820. ResetInvalidRects;
  821. FForceFullRepaint := False;
  822. end;
  823. procedure TCustomPaintBox32.ResetInvalidRects;
  824. begin
  825. FInvalidRects.Clear;
  826. end;
  827. procedure TCustomPaintBox32.Resize;
  828. begin
  829. if (not (csLoading in ComponentState)) then
  830. ResizeBuffer;
  831. BufferValid := False;
  832. inherited;
  833. end;
  834. procedure TCustomPaintBox32.ResizeBuffer;
  835. var
  836. NewWidth, NewHeight, W, H: Integer;
  837. OldWidth, OldHeight: Integer;
  838. begin
  839. // get the viewport parameters
  840. with GetViewportRect do
  841. begin
  842. NewWidth := Right - Left;
  843. NewHeight := Bottom - Top;
  844. end;
  845. if NewWidth < 0 then
  846. NewWidth := 0;
  847. if NewHeight < 0 then
  848. NewHeight := 0;
  849. W := FBuffer.Width;
  850. if NewWidth > W then
  851. W := NewWidth + FBufferOversize
  852. else
  853. if NewWidth < W - FBufferOversize then
  854. W := NewWidth;
  855. if W < 1 then
  856. W := 1;
  857. H := FBuffer.Height;
  858. if NewHeight > H then
  859. H := NewHeight + FBufferOversize
  860. else
  861. if NewHeight < H - FBufferOversize then
  862. H := NewHeight;
  863. if H < 1 then
  864. H := 1;
  865. if (W <> FBuffer.Width) or (H <> FBuffer.Height) then
  866. begin
  867. FBuffer.Lock;
  868. OldWidth := Buffer.Width;
  869. OldHeight := Buffer.Height;
  870. FBuffer.SetSize(W, H);
  871. FBuffer.Unlock;
  872. DoBufferResized(OldWidth, OldHeight);
  873. ForceFullInvalidate;
  874. end;
  875. end;
  876. procedure TCustomPaintBox32.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  877. begin
  878. inherited;
  879. if (not (csLoading in ComponentState)) then
  880. ResizeBuffer;
  881. FBufferValid := False;
  882. end;
  883. procedure TCustomPaintBox32.SetBufferOversize(Value: Integer);
  884. begin
  885. if (Value < 0) then
  886. Value := 0;
  887. if (Value <> FBufferOversize) then
  888. begin
  889. FBufferOversize := Value;
  890. ResizeBuffer;
  891. FBufferValid := False
  892. end;
  893. end;
  894. procedure TCustomPaintBox32.WMEraseBkgnd(var Message: {$IFDEF FPC}TLmEraseBkgnd{$ELSE}TWmEraseBkgnd{$ENDIF});
  895. begin
  896. Message.Result := 1;
  897. end;
  898. procedure TCustomPaintBox32.WMGetDlgCode(var Msg: {$IFDEF FPC}TLMessage{$ELSE}TWmGetDlgCode{$ENDIF});
  899. begin
  900. if (pboWantArrowKeys in Options) then
  901. Msg.Result:= Msg.Result or DLGC_WANTARROWS
  902. else
  903. Msg.Result:= Msg.Result and not DLGC_WANTARROWS;
  904. end;
  905. procedure TCustomPaintBox32.WMPaint(var Message: {$IFDEF FPC}TLMPaint{$ELSE}TMessage{$ENDIF});
  906. begin
  907. if CustomRepaint then
  908. begin
  909. if InvalidRectsAvailable then
  910. // BeginPaint deeper might set invalid clipping, so we call Paint here
  911. // to force repaint of our invalid rects...
  912. {$IFNDEF FPC}
  913. Paint
  914. {$ENDIF}
  915. else
  916. // no invalid rects available? Invalidate the whole client area
  917. InvalidateRect(Handle, nil, False);
  918. end;
  919. {$IFDEF FPC}
  920. { On FPC we need to specify the name of the ancestor here }
  921. inherited WMPaint(Message);
  922. {$ELSE}
  923. inherited;
  924. {$ENDIF}
  925. end;
  926. procedure TCustomPaintBox32.DirectAreaUpdateHandler(Sender: TObject;
  927. const Area: TRect; const Info: Cardinal);
  928. begin
  929. FInvalidRects.Add(Area);
  930. if not(csCustomPaint in ControlState) then
  931. Repaint;
  932. end;
  933. procedure TCustomPaintBox32.SetRepaintMode(const Value: TRepaintMode);
  934. begin
  935. if Assigned(FRepaintOptimizer) then
  936. begin
  937. // setup event handler on change of area
  938. if (Value = rmOptimizer) and not(Self is TCustomImage32) then
  939. FBuffer.OnAreaChanged := FRepaintOptimizer.AreaUpdateHandler
  940. else
  941. if (Value = rmDirect) then
  942. FBuffer.OnAreaChanged := DirectAreaUpdateHandler
  943. else
  944. FBuffer.OnAreaChanged := nil;
  945. FRepaintOptimizer.Enabled := Value = rmOptimizer;
  946. FRepaintMode := Value;
  947. Invalidate;
  948. end;
  949. end;
  950. { TPaintBox32 }
  951. procedure TPaintBox32.DoPaintBuffer;
  952. begin
  953. if Assigned(FOnPaintBuffer) then
  954. FOnPaintBuffer(Self);
  955. inherited;
  956. end;
  957. { TCustomImage32 }
  958. constructor TCustomImage32.Create(AOwner: TComponent);
  959. begin
  960. inherited;
  961. ControlStyle := [csAcceptsControls, csCaptureMouse, csClickEvents, csDoubleClicks, csReplicatable, csOpaque];
  962. FBitmap := TBitmap32.Create;
  963. FBitmap.OnResize := BitmapResizeHandler;
  964. FLayers := CreateLayerCollection;
  965. FRepaintOptimizer.RegisterLayerCollection(FLayers);
  966. RepaintMode := rmFull;
  967. FPaintStages := TPaintStages.Create;
  968. FScaleX := 1;
  969. FScaleY := 1;
  970. SetXForm(0, 0, 1, 1);
  971. InitDefaultStages;
  972. end;
  973. destructor TCustomImage32.Destroy;
  974. begin
  975. BeginUpdate;
  976. FPaintStages.Free;
  977. FRepaintOptimizer.UnregisterLayerCollection(FLayers);
  978. FLayers.Free;
  979. FBitmap.Free;
  980. inherited;
  981. end;
  982. function TCustomImage32.GetLayerCollectionClass: TLayerCollectionClass;
  983. begin
  984. Result := TLayerCollection;
  985. end;
  986. function TCustomImage32.CreateLayerCollection: TLayerCollection;
  987. begin
  988. Result := GetLayerCollectionClass.Create(Self);
  989. TLayerCollectionAccess(Result).OnChange := LayerCollectionChangeHandler;
  990. TLayerCollectionAccess(Result).OnGDIUpdate := LayerCollectionGDIUpdateHandler;
  991. TLayerCollectionAccess(Result).OnGetViewportScale := LayerCollectionGetViewportScaleHandler;
  992. TLayerCollectionAccess(Result).OnGetViewportShift := LayerCollectionGetViewportShiftHandler;
  993. end;
  994. procedure TCustomImage32.BeginUpdate;
  995. begin
  996. // disable OnChange & OnChanging generation
  997. Inc(FUpdateCount);
  998. end;
  999. procedure TCustomImage32.BitmapResized;
  1000. var
  1001. W, H: Integer;
  1002. begin
  1003. if AutoSize then
  1004. begin
  1005. W := Bitmap.Width;
  1006. H := Bitmap.Height;
  1007. if (ScaleMode = smScale) then
  1008. begin
  1009. W := Round(W * Scale);
  1010. H := Round(H * Scale);
  1011. end;
  1012. if AutoSize and (W > 0) and (H > 0) then
  1013. SetBounds(Left, Top, W, H);
  1014. end;
  1015. if (FUpdateCount = 0) and Assigned(FOnBitmapResize) then
  1016. FOnBitmapResize(Self);
  1017. InvalidateCache;
  1018. ForceFullInvalidate;
  1019. end;
  1020. procedure TCustomImage32.BitmapChanged(const Area: TRect);
  1021. begin
  1022. Changed;
  1023. end;
  1024. function TCustomImage32.BitmapToControl(const APoint: TPoint): TPoint;
  1025. begin
  1026. // convert coordinates from bitmap's ref. frame to control's ref. frame
  1027. UpdateCache;
  1028. with APoint do
  1029. begin
  1030. Result.X := Trunc(X * CachedScaleX + CachedShiftX);
  1031. Result.Y := Trunc(Y * CachedScaleY + CachedShiftY);
  1032. end;
  1033. end;
  1034. function TCustomImage32.BitmapToControl(const APoint: TFloatPoint): TFloatPoint;
  1035. begin
  1036. // subpixel precision version
  1037. UpdateCache;
  1038. with APoint do
  1039. begin
  1040. Result.X := X * CachedScaleX + CachedShiftX;
  1041. Result.Y := Y * CachedScaleY + CachedShiftY;
  1042. end;
  1043. end;
  1044. procedure TCustomImage32.BitmapResizeHandler(Sender: TObject);
  1045. begin
  1046. BitmapResized;
  1047. end;
  1048. procedure TCustomImage32.BitmapChangeHandler(Sender: TObject);
  1049. begin
  1050. FRepaintOptimizer.Reset;
  1051. BitmapChanged(Bitmap.Boundsrect);
  1052. end;
  1053. procedure TCustomImage32.BitmapAreaChangeHandler(Sender: TObject;
  1054. const Area: TRect; const Info: Cardinal);
  1055. var
  1056. NewInfo: Cardinal;
  1057. T, R: TRect;
  1058. Width, Tx, Ty, I, J: Integer;
  1059. OffsetX, OffsetY: Integer;
  1060. WidthX, WidthY: Integer;
  1061. begin
  1062. if Sender = FBitmap then
  1063. begin
  1064. T := Area;
  1065. UpdateCache; // Ensure CachedScaleXY is up to date
  1066. NewInfo := Info;
  1067. if (NewInfo and AREAINFO_LINE <> 0) then
  1068. begin
  1069. if (T.Left = T.Right) and (T.Top = T.Bottom) then
  1070. Exit; // Zero length line
  1071. // Unpack line width from Info param
  1072. Width := integer(NewInfo and (not AREAINFO_MASK));
  1073. // Add line and resampler width and scale value to viewport
  1074. Width := Ceil((Width + FBitmap.Resampler.Width) * CachedScaleX);
  1075. // Pack width into Info param again
  1076. NewInfo := AREAINFO_LINE or Width;
  1077. end else
  1078. if (T.Left = T.Right) or (T.Top = T.Bottom) then
  1079. Exit; // Empty rect
  1080. // Make sure rect is positive (i.e. dX >= 0)
  1081. if (T.Left > T.Right) then
  1082. begin
  1083. Swap(T.Left, T.Right);
  1084. Swap(T.Top, T.Bottom);
  1085. end;
  1086. // Translate the coordinates from bitmap to viewport
  1087. T.TopLeft := BitmapToControl(T.TopLeft);
  1088. T.BottomRight := BitmapToControl(T.BottomRight);
  1089. if (NewInfo and AREAINFO_LINE <> 0) then
  1090. begin
  1091. // Line coordinates specify the center of the pixel.
  1092. // For example the rect (0, 0, 0, 1) is a one pixel long line while (0, 0, 0, 0) is empty.
  1093. OffsetX := Round(CachedScaleX / 2);
  1094. OffsetY := Round(CachedScaleY / 2);
  1095. GR32.OffsetRect(T, OffsetX, OffsetY);
  1096. end else
  1097. begin
  1098. // Rect coordinates specify the pixel corners.
  1099. // It is assumed that (Top, Left) specify the top/left corner of the top/left pixel and
  1100. // that (Right, Bottom) specify the bottom/right corner of the bottom/right pixel.
  1101. // For example the rect (0, 0, 1, 1) covers just one pixel while (0, 0, 0, 1) is empty.
  1102. Dec(T.Right);
  1103. Dec(T.Bottom);
  1104. WidthX := Ceil(FBitmap.Resampler.Width * CachedScaleX);
  1105. WidthY := Ceil(FBitmap.Resampler.Width * CachedScaleY);
  1106. InflateArea(T, WidthX, WidthY);
  1107. end;
  1108. if FBitmapAlign <> baTile then
  1109. FRepaintOptimizer.AreaUpdateHandler(Self, T, NewInfo)
  1110. else
  1111. begin
  1112. with CachedBitmapRect do
  1113. begin
  1114. Tx := Buffer.Width div Right;
  1115. Ty := Buffer.Height div Bottom;
  1116. for J := 0 to Ty do
  1117. for I := 0 to Tx do
  1118. begin
  1119. R := T;
  1120. GR32.OffsetRect(R, Right * I, Bottom * J);
  1121. FRepaintOptimizer.AreaUpdateHandler(Self, R, NewInfo);
  1122. end;
  1123. end;
  1124. end;
  1125. end;
  1126. BitmapChanged(Area);
  1127. end;
  1128. procedure TCustomImage32.BitmapDirectAreaChangeHandler(Sender: TObject;
  1129. const Area: TRect; const Info: Cardinal);
  1130. var
  1131. T, R: TRect;
  1132. Width, Tx, Ty, I, J: Integer;
  1133. begin
  1134. if Sender = FBitmap then
  1135. begin
  1136. T := Area;
  1137. Width := Trunc(FBitmap.Resampler.Width) + 1;
  1138. InflateArea(T, Width, Width);
  1139. T.TopLeft := BitmapToControl(T.TopLeft);
  1140. T.BottomRight := BitmapToControl(T.BottomRight);
  1141. if FBitmapAlign <> baTile then
  1142. InvalidRects.Add(T)
  1143. else
  1144. begin
  1145. with CachedBitmapRect do
  1146. begin
  1147. Tx := Buffer.Width div Right;
  1148. Ty := Buffer.Height div Bottom;
  1149. for J := 0 to Ty do
  1150. for I := 0 to Tx do
  1151. begin
  1152. R := T;
  1153. GR32.OffsetRect(R, Right * I, Bottom * J);
  1154. InvalidRects.Add(R);
  1155. end;
  1156. end;
  1157. end;
  1158. end;
  1159. if FUpdateCount = 0 then
  1160. begin
  1161. if not(csCustomPaint in ControlState) then
  1162. Repaint;
  1163. if Assigned(FOnChange) then
  1164. FOnChange(Self);
  1165. end;
  1166. end;
  1167. function TCustomImage32.CanAutoSize(var NewWidth, NewHeight: Integer): Boolean;
  1168. var
  1169. W, H: Integer;
  1170. begin
  1171. Result := True;
  1172. InvalidateCache;
  1173. W := Bitmap.Width;
  1174. H := Bitmap.Height;
  1175. if (ScaleMode = smScale) then
  1176. begin
  1177. W := Round(W * Scale);
  1178. H := Round(H * Scale);
  1179. end;
  1180. if not (csDesigning in ComponentState) or (W > 0) and (H > 0) then
  1181. begin
  1182. if Align in [alNone, alLeft, alRight] then
  1183. NewWidth := W;
  1184. if Align in [alNone, alTop, alBottom] then
  1185. NewHeight := H;
  1186. end;
  1187. end;
  1188. procedure TCustomImage32.Changed;
  1189. begin
  1190. if FUpdateCount = 0 then
  1191. begin
  1192. Invalidate;
  1193. if Assigned(FOnChange) then
  1194. FOnChange(Self);
  1195. end;
  1196. end;
  1197. function TCustomImage32.ControlToBitmap(const ARect: TRect): TRect;
  1198. begin
  1199. // Top/Left rounded down, Bottom/Right rounded up
  1200. // It is assumed that ARect.Top<=ARect.Bottom and ARect.Left<=ARect.Right
  1201. UpdateCache;
  1202. with ARect do
  1203. begin
  1204. if (CachedRecScaleX = 0) then
  1205. begin
  1206. Result.Left := High(Result.Left);
  1207. Result.Right := High(Result.Right);
  1208. end else
  1209. begin
  1210. Result.Left := Floor((Left - CachedShiftX) * CachedRecScaleX);
  1211. Result.Right := Ceil((Right - CachedShiftX) * CachedRecScaleX);
  1212. end;
  1213. if (CachedRecScaleY = 0) then
  1214. begin
  1215. Result.Top := High(Result.Top);
  1216. Result.Bottom := High(Result.Bottom);
  1217. end else
  1218. begin
  1219. Result.Top := Floor((Top - CachedShiftY) * CachedRecScaleY);
  1220. Result.Bottom := Ceil((Bottom - CachedShiftY) * CachedRecScaleY);
  1221. end;
  1222. end;
  1223. end;
  1224. function TCustomImage32.ControlToBitmap(const APoint: TPoint): TPoint;
  1225. begin
  1226. // convert point coords from control's ref. frame to bitmap's ref. frame
  1227. // the coordinates are not clipped to bitmap image boundary
  1228. UpdateCache;
  1229. with APoint do
  1230. begin
  1231. if (CachedRecScaleX = 0) then
  1232. Result.X := High(Result.X)
  1233. else
  1234. Result.X := Floor((X - CachedShiftX) * CachedRecScaleX);
  1235. if (CachedRecScaleY = 0) then
  1236. Result.Y := High(Result.Y)
  1237. else
  1238. Result.Y := Floor((Y - CachedShiftY) * CachedRecScaleY);
  1239. end;
  1240. end;
  1241. function TCustomImage32.ControlToBitmap(const APoint: TFloatPoint): TFloatPoint;
  1242. begin
  1243. // subpixel precision version
  1244. UpdateCache;
  1245. with APoint do
  1246. begin
  1247. if (CachedRecScaleX = 0) then
  1248. Result.X := MaxInt
  1249. else
  1250. Result.X := (X - CachedShiftX) * CachedRecScaleX;
  1251. if (CachedRecScaleY = 0) then
  1252. Result.Y := MaxInt
  1253. else
  1254. Result.Y := (Y - CachedShiftY) * CachedRecScaleY;
  1255. end;
  1256. end;
  1257. procedure TCustomImage32.DoInitStages;
  1258. begin
  1259. if Assigned(FOnInitStages) then
  1260. FOnInitStages(Self);
  1261. end;
  1262. procedure TCustomImage32.DoPaintBuffer;
  1263. var
  1264. PaintStageHandlerCount: Integer;
  1265. I, J: Integer;
  1266. DT, RT: Boolean;
  1267. begin
  1268. if FRepaintOptimizer.Enabled then
  1269. FRepaintOptimizer.BeginPaintBuffer;
  1270. UpdateCache;
  1271. SetLength(FPaintStageHandlers, FPaintStages.Count);
  1272. SetLength(FPaintStageNum, FPaintStages.Count);
  1273. PaintStageHandlerCount := 0;
  1274. DT := csDesigning in ComponentState;
  1275. RT := not DT;
  1276. // compile list of paintstage handler methods
  1277. for I := 0 to FPaintStages.Count - 1 do
  1278. begin
  1279. with FPaintStages[I]^ do
  1280. if (DsgnTime and DT) or (RunTime and RT) then
  1281. begin
  1282. FPaintStageNum[PaintStageHandlerCount] := I;
  1283. case Stage of
  1284. PST_CUSTOM: FPaintStageHandlers[PaintStageHandlerCount] := ExecCustom;
  1285. PST_CLEAR_BUFFER: FPaintStageHandlers[PaintStageHandlerCount] := ExecClearBuffer;
  1286. PST_CLEAR_BACKGND: FPaintStageHandlers[PaintStageHandlerCount] := ExecClearBackgnd;
  1287. PST_DRAW_BITMAP: FPaintStageHandlers[PaintStageHandlerCount] := ExecDrawBitmap;
  1288. PST_DRAW_LAYERS: FPaintStageHandlers[PaintStageHandlerCount] := ExecDrawLayers;
  1289. PST_CONTROL_FRAME: FPaintStageHandlers[PaintStageHandlerCount] := ExecControlFrame;
  1290. PST_BITMAP_FRAME: FPaintStageHandlers[PaintStageHandlerCount] := ExecBitmapFrame;
  1291. else
  1292. Dec(PaintStageHandlerCount); // this should not happen .
  1293. end;
  1294. Inc(PaintStageHandlerCount);
  1295. end;
  1296. end;
  1297. Buffer.BeginUpdate;
  1298. if FInvalidRects.Count = 0 then
  1299. begin
  1300. Buffer.ClipRect := GetViewportRect;
  1301. for I := 0 to PaintStageHandlerCount - 1 do
  1302. FPaintStageHandlers[I](Buffer, FPaintStageNum[I]);
  1303. end
  1304. else
  1305. begin
  1306. for J := 0 to FInvalidRects.Count - 1 do
  1307. begin
  1308. Buffer.ClipRect := FInvalidRects[J]^;
  1309. for I := 0 to PaintStageHandlerCount - 1 do
  1310. FPaintStageHandlers[I](Buffer, FPaintStageNum[I]);
  1311. end;
  1312. Buffer.ClipRect := GetViewportRect;
  1313. end;
  1314. Buffer.EndUpdate;
  1315. if FRepaintOptimizer.Enabled then
  1316. FRepaintOptimizer.EndPaintBuffer;
  1317. // avoid calling inherited, we have a totally different behaviour here...
  1318. FBufferValid := True;
  1319. end;
  1320. procedure TCustomImage32.DoPaintGDIOverlay;
  1321. var
  1322. I: Integer;
  1323. begin
  1324. for I := 0 to Layers.Count - 1 do
  1325. if (Layers[I].LayerOptions and LOB_GDI_OVERLAY) <> 0 then
  1326. TLayerAccess(Layers[I]).PaintGDI(Canvas);
  1327. inherited;
  1328. end;
  1329. procedure TCustomImage32.DoScaleChange;
  1330. begin
  1331. if Assigned(FOnScaleChange) then
  1332. FOnScaleChange(Self);
  1333. end;
  1334. procedure TCustomImage32.EndUpdate;
  1335. begin
  1336. // re-enable OnChange & OnChanging generation
  1337. Dec(FUpdateCount);
  1338. Assert(FUpdateCount >= 0, 'Unpaired EndUpdate call');
  1339. end;
  1340. procedure TCustomImage32.ExecBitmapFrame(Dest: TBitmap32; StageNum: Integer);
  1341. begin
  1342. Dest.Canvas.DrawFocusRect(CachedBitmapRect);
  1343. end;
  1344. procedure TCustomImage32.ExecClearBackgnd(Dest: TBitmap32; StageNum: Integer);
  1345. var
  1346. C: TColor32;
  1347. I: Integer;
  1348. begin
  1349. C := Color32(Color);
  1350. if FInvalidRects.Count > 0 then
  1351. begin
  1352. for I := 0 to FInvalidRects.Count - 1 do
  1353. with FInvalidRects[I]^ do
  1354. Dest.FillRectS(Left, Top, Right, Bottom, C);
  1355. end
  1356. else
  1357. begin
  1358. if ((Bitmap.Empty) or (Bitmap.DrawMode <> dmOpaque)) and assigned(Dest) then
  1359. Dest.Clear(C)
  1360. else
  1361. with CachedBitmapRect do
  1362. begin
  1363. if (Left > 0) or (Right < Self.Width) or (Top > 0) or (Bottom < Self.Height) and
  1364. not (BitmapAlign = baTile) then
  1365. begin
  1366. // clean only the part of the buffer lying around image edges
  1367. Dest.FillRectS(0, 0, Self.Width, Top, C); // top
  1368. Dest.FillRectS(0, Bottom, Self.Width, Self.Height, C); // bottom
  1369. Dest.FillRectS(0, Top, Left, Bottom, C); // left
  1370. Dest.FillRectS(Right, Top, Self.Width, Bottom, C); // right
  1371. end;
  1372. end;
  1373. end;
  1374. end;
  1375. procedure TCustomImage32.ExecClearBuffer(Dest: TBitmap32; StageNum: Integer);
  1376. begin
  1377. Dest.Clear(Color32(Color));
  1378. end;
  1379. procedure TCustomImage32.ExecControlFrame(Dest: TBitmap32; StageNum: Integer);
  1380. begin
  1381. DrawFocusRect(Dest.Handle, Rect(0, 0, Width, Height));
  1382. end;
  1383. procedure TCustomImage32.ExecCustom(Dest: TBitmap32; StageNum: Integer);
  1384. begin
  1385. if Assigned(FOnPaintStage) then
  1386. FOnPaintStage(Self, Dest, StageNum);
  1387. end;
  1388. procedure TCustomImage32.ExecDrawBitmap(Dest: TBitmap32; StageNum: Integer);
  1389. var
  1390. I, J, Tx, Ty: Integer;
  1391. R: TRect;
  1392. begin
  1393. if Bitmap.Empty or GR32.IsRectEmpty(CachedBitmapRect) then
  1394. Exit;
  1395. Bitmap.Lock;
  1396. try
  1397. if (BitmapAlign <> baTile) then
  1398. Bitmap.DrawTo(Dest, CachedBitmapRect)
  1399. else
  1400. with CachedBitmapRect do
  1401. begin
  1402. Tx := Dest.Width div Right;
  1403. Ty := Dest.Height div Bottom;
  1404. for J := 0 to Ty do
  1405. for I := 0 to Tx do
  1406. begin
  1407. R := CachedBitmapRect;
  1408. GR32.OffsetRect(R, Right * I, Bottom * J);
  1409. Bitmap.DrawTo(Dest, R);
  1410. end;
  1411. end;
  1412. finally
  1413. Bitmap.Unlock;
  1414. end;
  1415. end;
  1416. procedure TCustomImage32.ExecDrawLayers(Dest: TBitmap32; StageNum: Integer);
  1417. var
  1418. I: Integer;
  1419. Mask: Cardinal;
  1420. begin
  1421. Mask := PaintStages[StageNum]^.Parameter;
  1422. for I := 0 to Layers.Count - 1 do
  1423. if (Layers.Items[I].LayerOptions and Mask) <> 0 then
  1424. TLayerAccess(Layers.Items[I]).DoPaint(Dest);
  1425. end;
  1426. function TCustomImage32.GetBitmapRect: TRect;
  1427. var
  1428. Size: TSize;
  1429. begin
  1430. if Bitmap.Empty then
  1431. with Result do
  1432. begin
  1433. Left := 0;
  1434. Right := 0;
  1435. Top := 0;
  1436. Bottom := 0;
  1437. end
  1438. else
  1439. begin
  1440. Size := GetBitmapSize;
  1441. Result := Rect(0, 0, Size.Cx, Size.Cy);
  1442. if BitmapAlign = baCenter then
  1443. GR32.OffsetRect(Result, (Width - Size.Cx) div 2, (Height - Size.Cy) div 2)
  1444. else
  1445. if BitmapAlign = baCustom then
  1446. GR32.OffsetRect(Result, Round(OffsetHorz), Round(OffsetVert));
  1447. end;
  1448. end;
  1449. function TCustomImage32.GetBitmapSize: TSize;
  1450. var
  1451. Mode: TScaleMode;
  1452. ViewportWidth, ViewportHeight: Integer;
  1453. RScaleX, RScaleY: TFloat;
  1454. begin
  1455. begin
  1456. if Bitmap.Empty or (Width = 0) or (Height = 0) then
  1457. begin
  1458. Result.Cx := 0;
  1459. Result.Cy := 0;
  1460. Exit;
  1461. end;
  1462. with GetViewportRect do
  1463. begin
  1464. ViewportWidth := Right - Left;
  1465. ViewportHeight := Bottom - Top;
  1466. end;
  1467. // check for optimal modes as these are compounds of the other modes.
  1468. case ScaleMode of
  1469. smOptimal:
  1470. if (Bitmap.Width > ViewportWidth) or (Bitmap.Height > ViewportHeight) then
  1471. Mode := smResize
  1472. else
  1473. Mode := smNormal;
  1474. smOptimalScaled:
  1475. if (Round(Bitmap.Width * ScaleX) > ViewportWidth) or
  1476. (Round(Bitmap.Height * ScaleY) > ViewportHeight) then
  1477. Mode := smResize
  1478. else
  1479. Mode := smScale;
  1480. else
  1481. Mode := ScaleMode;
  1482. end;
  1483. case Mode of
  1484. smNormal:
  1485. begin
  1486. Result.Cx := Bitmap.Width;
  1487. Result.Cy := Bitmap.Height;
  1488. end;
  1489. smStretch:
  1490. begin
  1491. Result.Cx := ViewportWidth;
  1492. Result.Cy := ViewportHeight;
  1493. end;
  1494. smResize:
  1495. begin
  1496. Result.Cx := Bitmap.Width;
  1497. Result.Cy := Bitmap.Height;
  1498. RScaleX := ViewportWidth / Result.Cx;
  1499. RScaleY := ViewportHeight / Result.Cy;
  1500. if (RScaleX >= RScaleY) then
  1501. begin
  1502. Result.Cx := Round(Result.Cx * RScaleY);
  1503. Result.Cy := ViewportHeight;
  1504. end
  1505. else
  1506. begin
  1507. Result.Cx := ViewportWidth;
  1508. Result.Cy := Round(Result.Cy * RScaleX);
  1509. end;
  1510. end;
  1511. else // smScale
  1512. begin
  1513. Result.Cx := Round(Bitmap.Width * ScaleX);
  1514. Result.Cy := Round(Bitmap.Height * ScaleY);
  1515. end;
  1516. end;
  1517. if (Result.Cx <= 0) then
  1518. Result.Cx := 0;
  1519. if (Result.Cy <= 0) then
  1520. Result.Cy := 0;
  1521. end;
  1522. end;
  1523. function TCustomImage32.GetOnPixelCombine: TPixelCombineEvent;
  1524. begin
  1525. Result := FBitmap.OnPixelCombine;
  1526. end;
  1527. procedure TCustomImage32.InitDefaultStages;
  1528. begin
  1529. // background
  1530. with PaintStages.Add^ do
  1531. begin
  1532. DsgnTime := True;
  1533. RunTime := True;
  1534. Stage := PST_CLEAR_BACKGND;
  1535. end;
  1536. // control frame
  1537. with PaintStages.Add^ do
  1538. begin
  1539. DsgnTime := True;
  1540. RunTime := False;
  1541. Stage := PST_CONTROL_FRAME;
  1542. end;
  1543. // bitmap
  1544. with PaintStages.Add^ do
  1545. begin
  1546. DsgnTime := True;
  1547. RunTime := True;
  1548. Stage := PST_DRAW_BITMAP;
  1549. end;
  1550. // bitmap frame
  1551. with PaintStages.Add^ do
  1552. begin
  1553. DsgnTime := True;
  1554. RunTime := False;
  1555. Stage := PST_BITMAP_FRAME;
  1556. end;
  1557. // layers
  1558. with PaintStages.Add^ do
  1559. begin
  1560. DsgnTime := True;
  1561. RunTime := True;
  1562. Stage := PST_DRAW_LAYERS;
  1563. Parameter := LOB_VISIBLE;
  1564. end;
  1565. end;
  1566. procedure TCustomImage32.Invalidate;
  1567. begin
  1568. BufferValid := False;
  1569. CacheValid := False;
  1570. inherited;
  1571. end;
  1572. procedure TCustomImage32.InvalidateCache;
  1573. begin
  1574. if FRepaintOptimizer.Enabled and CacheValid then
  1575. FRepaintOptimizer.Reset;
  1576. CacheValid := False;
  1577. end;
  1578. function TCustomImage32.InvalidRectsAvailable: Boolean;
  1579. begin
  1580. // avoid calling inherited, we have a totally different behaviour here...
  1581. DoPrepareInvalidRects;
  1582. Result := (FInvalidRects.Count > 0);
  1583. end;
  1584. procedure TCustomImage32.LayerCollectionChangeHandler(Sender: TObject);
  1585. begin
  1586. Changed;
  1587. end;
  1588. procedure TCustomImage32.LayerCollectionGDIUpdateHandler(Sender: TObject);
  1589. begin
  1590. Paint;
  1591. end;
  1592. procedure TCustomImage32.LayerCollectionGetViewportScaleHandler(Sender: TObject;
  1593. out ScaleX, ScaleY: TFloat);
  1594. begin
  1595. UpdateCache;
  1596. ScaleX := CachedScaleX;
  1597. ScaleY := CachedScaleY;
  1598. end;
  1599. procedure TCustomImage32.LayerCollectionGetViewportShiftHandler(Sender: TObject;
  1600. out ShiftX, ShiftY: TFloat);
  1601. begin
  1602. UpdateCache;
  1603. ShiftX := CachedShiftX;
  1604. ShiftY := CachedShiftY;
  1605. end;
  1606. procedure TCustomImage32.Loaded;
  1607. begin
  1608. inherited;
  1609. DoInitStages;
  1610. end;
  1611. procedure TCustomImage32.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1612. var
  1613. Layer: TCustomLayer;
  1614. begin
  1615. inherited;
  1616. if TabStop and CanFocus then
  1617. SetFocus;
  1618. if Layers.MouseEvents then
  1619. Layer := TLayerCollectionAccess(Layers).MouseDown(Button, Shift, X, Y)
  1620. else
  1621. Layer := nil;
  1622. // lock the capture only if mbLeft was pushed or any mouse listener was activated
  1623. if (Button = mbLeft) or (TLayerCollectionAccess(Layers).MouseListener <> nil) then
  1624. MouseCapture := True;
  1625. MouseDown(Button, Shift, X, Y, Layer);
  1626. end;
  1627. procedure TCustomImage32.MouseMove(Shift: TShiftState; X, Y: Integer);
  1628. var
  1629. Layer: TCustomLayer;
  1630. begin
  1631. inherited;
  1632. if Layers.MouseEvents then
  1633. Layer := TLayerCollectionAccess(Layers).MouseMove(Shift, X, Y)
  1634. else
  1635. Layer := nil;
  1636. MouseMove(Shift, X, Y, Layer);
  1637. end;
  1638. procedure TCustomImage32.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1639. var
  1640. Layer: TCustomLayer;
  1641. MouseListener: TCustomLayer;
  1642. begin
  1643. MouseListener := TLayerCollectionAccess(Layers).MouseListener;
  1644. if Layers.MouseEvents then
  1645. Layer := TLayerCollectionAccess(Layers).MouseUp(Button, Shift, X, Y)
  1646. else
  1647. Layer := nil;
  1648. // unlock the capture using same criteria as was used to acquire it
  1649. if (Button = mbLeft) or ((MouseListener <> nil) and (TLayerCollectionAccess(Layers).MouseListener = nil)) then
  1650. MouseCapture := False;
  1651. MouseUp(Button, Shift, X, Y, Layer);
  1652. end;
  1653. procedure TCustomImage32.MouseDown(Button: TMouseButton;
  1654. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  1655. begin
  1656. if Assigned(FOnMouseDown) then
  1657. FOnMouseDown(Self, Button, Shift, X, Y, Layer);
  1658. end;
  1659. procedure TCustomImage32.MouseMove(Shift: TShiftState; X, Y: Integer;
  1660. Layer: TCustomLayer);
  1661. begin
  1662. if Assigned(FOnMouseMove) then
  1663. FOnMouseMove(Self, Shift, X, Y, Layer);
  1664. end;
  1665. procedure TCustomImage32.MouseUp(Button: TMouseButton; Shift: TShiftState;
  1666. X, Y: Integer; Layer: TCustomLayer);
  1667. begin
  1668. if Assigned(FOnMouseUp) then
  1669. FOnMouseUp(Self, Button, Shift, X, Y, Layer);
  1670. end;
  1671. procedure TCustomImage32.MouseLeave;
  1672. begin
  1673. if (Layers.MouseEvents) and (Layers.MouseListener = nil) then
  1674. Screen.Cursor := crDefault;
  1675. inherited;
  1676. end;
  1677. procedure TCustomImage32.PaintTo(Dest: TBitmap32; DestRect: TRect);
  1678. var
  1679. OldRepaintMode: TRepaintMode;
  1680. I: Integer;
  1681. begin
  1682. if not assigned(Dest) then
  1683. exit;
  1684. OldRepaintMode := RepaintMode;
  1685. RepaintMode := rmFull;
  1686. CachedBitmapRect := DestRect;
  1687. if (CachedBitmapRect.Right <= CachedBitmapRect.Left) or (CachedBitmapRect.Bottom <= CachedBitmapRect.Top) or Bitmap.Empty then
  1688. SetXForm(0, 0, 1, 1)
  1689. else
  1690. SetXForm(CachedBitmapRect.Left, CachedBitmapRect.Top, CachedBitmapRect.Width / Bitmap.Width, CachedBitmapRect.Height / Bitmap.Height);
  1691. CacheValid := True;
  1692. PaintToMode := True;
  1693. try
  1694. for I := 0 to FPaintStages.Count - 1 do
  1695. if FPaintStages[I].RunTime then
  1696. case FPaintStages[I].Stage of
  1697. PST_CUSTOM: ExecCustom(Dest, I);
  1698. PST_CLEAR_BUFFER: ExecClearBuffer(Dest, I);
  1699. PST_CLEAR_BACKGND: ExecClearBackgnd(Dest, I);
  1700. PST_DRAW_BITMAP: ExecDrawBitmap(Dest, I);
  1701. PST_DRAW_LAYERS: ExecDrawLayers(Dest, I);
  1702. PST_CONTROL_FRAME: ExecControlFrame(Dest, I);
  1703. PST_BITMAP_FRAME: ExecBitmapFrame(Dest, I);
  1704. end;
  1705. finally
  1706. PaintToMode := False;
  1707. end;
  1708. CacheValid := False;
  1709. RepaintMode := OldRepaintMode;
  1710. end;
  1711. procedure TCustomImage32.Resize;
  1712. begin
  1713. InvalidateCache;
  1714. inherited;
  1715. end;
  1716. procedure TCustomImage32.SetBitmap(Value: TBitmap32);
  1717. begin
  1718. InvalidateCache;
  1719. FBitmap.Assign(Value);
  1720. end;
  1721. procedure TCustomImage32.SetBitmapAlign(Value: TBitmapAlign);
  1722. begin
  1723. InvalidateCache;
  1724. FBitmapAlign := Value;
  1725. Changed;
  1726. end;
  1727. procedure TCustomImage32.SetLayers(Value: TLayerCollection);
  1728. begin
  1729. FLayers.Assign(Value);
  1730. end;
  1731. procedure TCustomImage32.SetOffsetHorz(Value: TFloat);
  1732. begin
  1733. if Value <> FOffsetHorz then
  1734. begin
  1735. InvalidateCache;
  1736. FOffsetHorz := Value;
  1737. Changed;
  1738. end;
  1739. end;
  1740. procedure TCustomImage32.SetOffsetVert(Value: TFloat);
  1741. begin
  1742. if Value <> FOffsetVert then
  1743. begin
  1744. FOffsetVert := Value;
  1745. InvalidateCache;
  1746. Changed;
  1747. end;
  1748. end;
  1749. procedure TCustomImage32.SetOnPixelCombine(Value: TPixelCombineEvent);
  1750. begin
  1751. FBitmap.OnPixelCombine := Value;
  1752. Changed;
  1753. end;
  1754. procedure TCustomImage32.SetScale(Value: TFloat);
  1755. begin
  1756. if Value < 0.001 then
  1757. Value := 0.001;
  1758. if Value <> FScaleX then
  1759. begin
  1760. InvalidateCache;
  1761. FScaleX := Value;
  1762. FScaleY := Value;
  1763. CachedScaleX := FScaleX;
  1764. CachedScaleY := FScaleY;
  1765. CachedRecScaleX := 1 / Value;
  1766. CachedRecScaleY := 1 / Value;
  1767. DoScaleChange;
  1768. Changed;
  1769. end;
  1770. end;
  1771. procedure TCustomImage32.SetScaleX(Value: TFloat);
  1772. begin
  1773. if Value < 0.001 then
  1774. Value := 0.001;
  1775. if Value <> FScaleX then
  1776. begin
  1777. InvalidateCache;
  1778. FScaleX := Value;
  1779. CachedScaleX := Value;
  1780. CachedRecScaleX := 1 / Value;
  1781. DoScaleChange;
  1782. Changed;
  1783. end;
  1784. end;
  1785. procedure TCustomImage32.SetScaleY(Value: TFloat);
  1786. begin
  1787. if Value < 0.001 then
  1788. Value := 0.001;
  1789. if Value <> FScaleY then
  1790. begin
  1791. InvalidateCache;
  1792. FScaleY := Value;
  1793. CachedScaleY := Value;
  1794. CachedRecScaleY := 1 / Value;
  1795. DoScaleChange;
  1796. Changed;
  1797. end;
  1798. end;
  1799. procedure TCustomImage32.SetScaleMode(Value: TScaleMode);
  1800. begin
  1801. if Value <> FScaleMode then
  1802. begin
  1803. InvalidateCache;
  1804. FScaleMode := Value;
  1805. Changed;
  1806. end;
  1807. end;
  1808. procedure TCustomImage32.SetupBitmap(DoClear: Boolean = False; ClearColor: TColor32 = $FF000000);
  1809. begin
  1810. FBitmap.BeginUpdate;
  1811. with GetViewPortRect do
  1812. FBitmap.SetSize(Right - Left, Bottom - Top);
  1813. if DoClear then
  1814. FBitmap.Clear(ClearColor);
  1815. FBitmap.EndUpdate;
  1816. InvalidateCache;
  1817. Changed;
  1818. end;
  1819. procedure TCustomImage32.SetXForm(ShiftX, ShiftY, ScaleX, ScaleY: TFloat);
  1820. begin
  1821. CachedShiftX := ShiftX;
  1822. CachedShiftY := ShiftY;
  1823. CachedScaleX := ScaleX;
  1824. CachedScaleY := ScaleY;
  1825. if (ScaleX <> 0) then
  1826. CachedRecScaleX := 1 / ScaleX
  1827. else
  1828. CachedRecScaleX := 0;
  1829. if (ScaleY <> 0) then
  1830. CachedRecScaleY := 1 / ScaleY
  1831. else
  1832. CachedRecScaleY := 0;
  1833. end;
  1834. procedure TCustomImage32.SetRepaintMode(const Value: TRepaintMode);
  1835. begin
  1836. inherited;
  1837. case Value of
  1838. rmOptimizer:
  1839. begin
  1840. FBitmap.OnAreaChanged := BitmapAreaChangeHandler;
  1841. FBitmap.OnChange := nil;
  1842. end;
  1843. rmDirect:
  1844. begin
  1845. FBitmap.OnAreaChanged := BitmapDirectAreaChangeHandler;
  1846. FBitmap.OnChange := nil;
  1847. end;
  1848. else
  1849. FBitmap.OnAreaChanged := nil;
  1850. FBitmap.OnChange := BitmapChangeHandler;
  1851. end;
  1852. end;
  1853. procedure TCustomImage32.Update(const Rect: TRect);
  1854. begin
  1855. if FRepaintOptimizer.Enabled then
  1856. FRepaintOptimizer.AreaUpdateHandler(Self, Rect, AREAINFO_RECT);
  1857. end;
  1858. procedure TCustomImage32.UpdateCache;
  1859. begin
  1860. if CacheValid then
  1861. Exit;
  1862. CachedBitmapRect := GetBitmapRect;
  1863. if Bitmap.Empty then
  1864. SetXForm(0, 0, 1, 1)
  1865. else
  1866. SetXForm(
  1867. CachedBitmapRect.Left, CachedBitmapRect.Top,
  1868. (CachedBitmapRect.Right - CachedBitmapRect.Left) / Bitmap.Width,
  1869. (CachedBitmapRect.Bottom - CachedBitmapRect.Top) / Bitmap.Height
  1870. );
  1871. CacheValid := True;
  1872. end;
  1873. { TIVScrollProperties }
  1874. function TIVScrollProperties.GetIncrement: Integer;
  1875. begin
  1876. Result := Round(TCustomRangeBar(Master).Increment);
  1877. end;
  1878. function TIVScrollProperties.GetSize: Integer;
  1879. begin
  1880. Result := ImgView.FScrollBarSize;
  1881. end;
  1882. function TIVScrollProperties.GetVisibility: TScrollbarVisibility;
  1883. begin
  1884. Result := ImgView.FScrollBarVisibility;
  1885. end;
  1886. procedure TIVScrollProperties.SetIncrement(Value: Integer);
  1887. begin
  1888. TCustomRangeBar(Master).Increment := Value;
  1889. TCustomRangeBar(Slave).Increment := Value;
  1890. end;
  1891. procedure TIVScrollProperties.SetSize(Value: Integer);
  1892. begin
  1893. ImgView.FScrollBarSize := Value;
  1894. ImgView.AlignAll;
  1895. ImgView.UpdateImage;
  1896. end;
  1897. procedure TIVScrollProperties.SetVisibility(const Value: TScrollbarVisibility);
  1898. begin
  1899. if Value <> ImgView.FScrollBarVisibility then
  1900. begin
  1901. ImgView.FScrollBarVisibility := Value;
  1902. ImgView.Resize;
  1903. end;
  1904. end;
  1905. { TCustomImgView32 }
  1906. procedure TCustomImgView32.AlignAll;
  1907. var
  1908. ScrollbarVisible: Boolean;
  1909. ViewPort: TRect;
  1910. NeedResize: boolean;
  1911. begin
  1912. if (Width <= 0) or (Height <= 0) then
  1913. Exit;
  1914. NeedResize := False;
  1915. ViewPort := GetViewportRect;
  1916. ScrollbarVisible := GetScrollBarsVisible;
  1917. if (HScroll <> nil) then
  1918. begin
  1919. NeedResize := (HScroll.Visible <> ScrollbarVisible);
  1920. HScroll.BoundsRect := Rect(ViewPort.Left, ViewPort.Bottom, ViewPort.Right, Self.Height);
  1921. HScroll.Visible := ScrollbarVisible;
  1922. end;
  1923. if (VScroll <> nil) then
  1924. begin
  1925. NeedResize := NeedResize or (VScroll.Visible <> ScrollbarVisible);
  1926. VScroll.BoundsRect := Rect(ViewPort.Right, ViewPort.Top, Self.Width, ViewPort.Bottom);
  1927. VScroll.Visible := ScrollbarVisible;
  1928. end;
  1929. if (NeedResize) then
  1930. begin
  1931. // Scrollbars has been shown or hidden. Buffer must resize to align with new viewport.
  1932. // This will automatically lead to the viewport being redrawn.
  1933. ResizeBuffer;
  1934. FBufferValid := False
  1935. end;
  1936. end;
  1937. procedure TCustomImgView32.BitmapResized;
  1938. begin
  1939. inherited;
  1940. UpdateScrollBars;
  1941. if Centered then
  1942. ScrollToCenter(Bitmap.Width div 2, Bitmap.Height div 2)
  1943. else
  1944. begin
  1945. HScroll.Position := 0;
  1946. VScroll.Position := 0;
  1947. UpdateImage;
  1948. end;
  1949. end;
  1950. constructor TCustomImgView32.Create(AOwner: TComponent);
  1951. begin
  1952. inherited;
  1953. FScrollBarSize := GetSystemMetrics(SM_CYHSCROLL);
  1954. HScroll := TCustomRangeBar.Create(Self);
  1955. VScroll := TCustomRangeBar.Create(Self);
  1956. with HScroll do
  1957. begin
  1958. HScroll.Parent := Self;
  1959. BorderStyle := bsNone;
  1960. Centered := True;
  1961. OnUserChange := ScrollHandler;
  1962. OnUserChanging := ScrollChangingHandler;
  1963. end;
  1964. with VScroll do
  1965. begin
  1966. Parent := Self;
  1967. BorderStyle := bsNone;
  1968. Centered := True;
  1969. Kind := sbVertical;
  1970. OnUserChange := ScrollHandler;
  1971. OnUserChanging := ScrollChangingHandler;
  1972. end;
  1973. FCentered := True;
  1974. ScaleMode := smScale;
  1975. BitmapAlign := baCustom;
  1976. with GetViewportRect do
  1977. begin
  1978. OldSzX := Right - Left;
  1979. OldSzY := Bottom - Top;
  1980. end;
  1981. FScrollBars := TIVScrollProperties.Create;
  1982. FScrollBars.ImgView := Self;
  1983. FScrollBars.Master := HScroll;
  1984. FScrollBars.Slave := VScroll;
  1985. AlignAll;
  1986. end;
  1987. destructor TCustomImgView32.Destroy;
  1988. begin
  1989. FreeAndNil(FScrollBars);
  1990. inherited;
  1991. end;
  1992. procedure TCustomImgView32.DoDrawSizeGrip(R: TRect);
  1993. begin
  1994. {$IFDEF Windows}
  1995. if USE_THEMES then
  1996. begin
  1997. Canvas.Brush.Color := clBtnFace;
  1998. Canvas.FillRect(R);
  1999. DrawThemeBackground(SCROLLBAR_THEME, Canvas.Handle, SBP_SIZEBOX, SZB_RIGHTALIGN, R, nil);
  2000. end
  2001. else
  2002. DrawFrameControl(Canvas.Handle, R, DFC_SCROLL, DFCS_SCROLLSIZEGRIP)
  2003. {$ENDIF}
  2004. end;
  2005. procedure TCustomImgView32.DoScaleChange;
  2006. begin
  2007. inherited;
  2008. InvalidateCache;
  2009. UpdateScrollBars;
  2010. UpdateImage;
  2011. Invalidate;
  2012. end;
  2013. procedure TCustomImgView32.DoScroll;
  2014. begin
  2015. if Assigned(FOnScroll) then
  2016. FOnScroll(Self);
  2017. end;
  2018. function TCustomImgView32.GetScrollBarSize: Integer;
  2019. begin
  2020. if GetScrollBarsVisible then
  2021. begin
  2022. Result := FScrollBarSize;
  2023. if (Result = 0) then
  2024. Result := GetSystemMetrics(SM_CYHSCROLL);
  2025. end
  2026. else
  2027. Result := 0;
  2028. end;
  2029. function TCustomImgView32.GetScrollBarsVisible: Boolean;
  2030. begin
  2031. if AutoSize then
  2032. begin
  2033. Result := False;
  2034. Exit;
  2035. end;
  2036. Result := True;
  2037. if Assigned(FScrollBars) and Assigned(HScroll) and Assigned(VScroll) then
  2038. case FScrollBars.Visibility of
  2039. svAlways:
  2040. Result := True;
  2041. svHidden:
  2042. Result := False;
  2043. svAuto:
  2044. Result := (BitmapAlign = baCustom) and (ScaleMode in [smScale,smNormal]) and
  2045. ((HScroll.Range > (TRangeBarAccess(HScroll).EffectiveWindow + VScroll.Width)) or
  2046. (VScroll.Range > (TRangeBarAccess(VScroll).EffectiveWindow + HScroll.Height)));
  2047. end;
  2048. end;
  2049. function TCustomImgView32.GetSizeGripRect: TRect;
  2050. var
  2051. Sz: Integer;
  2052. begin
  2053. Sz := GetScrollBarSize;
  2054. if not Assigned(Parent) then
  2055. Result := BoundsRect
  2056. else
  2057. Result := ClientRect;
  2058. with Result do
  2059. begin
  2060. Left := Right - Sz;
  2061. Top := Bottom - Sz;
  2062. end;
  2063. end;
  2064. function TCustomImgView32.GetViewportRect: TRect;
  2065. var
  2066. Sz: Integer;
  2067. begin
  2068. Result := Rect(0, 0, Width, Height);
  2069. Sz := GetScrollBarSize;
  2070. Dec(Result.Right, Sz);
  2071. Dec(Result.Bottom, Sz);
  2072. end;
  2073. function TCustomImgView32.IsSizeGripVisible: Boolean;
  2074. var
  2075. P: TWinControl;
  2076. begin
  2077. case SizeGrip of
  2078. sgAuto:
  2079. begin
  2080. Result := False;
  2081. if (Align <> alClient) then
  2082. Exit;
  2083. P := Parent;
  2084. while True do
  2085. begin
  2086. if P is TCustomForm then
  2087. begin
  2088. Result := True;
  2089. Break;
  2090. end else
  2091. if (not Assigned(P)) or (P.Align <> alClient) then
  2092. Exit;
  2093. P := P.Parent;
  2094. end;
  2095. end;
  2096. sgNone:
  2097. Result := False
  2098. else { sgAlways }
  2099. Result := True;
  2100. end;
  2101. end;
  2102. procedure TCustomImgView32.Loaded;
  2103. begin
  2104. AlignAll;
  2105. Invalidate;
  2106. UpdateScrollBars;
  2107. if Centered then
  2108. ScrollToCenter(Bitmap.Width div 2, Bitmap.Height div 2);
  2109. inherited;
  2110. end;
  2111. procedure TCustomImgView32.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  2112. {$IFNDEF PLATFORM_INDEPENDENT}
  2113. var
  2114. Action: Cardinal;
  2115. Msg: TMessage;
  2116. P: TPoint;
  2117. {$ENDIF}
  2118. begin
  2119. {$IFNDEF PLATFORM_INDEPENDENT}
  2120. if IsSizeGripVisible and (Owner is TCustomForm) then
  2121. begin
  2122. P.X := X; P.Y := Y;
  2123. if GR32.PtInRect(GetSizeGripRect, P) then
  2124. begin
  2125. Action := HTBOTTOMRIGHT;
  2126. Application.ProcessMessages;
  2127. Msg.Msg := WM_NCLBUTTONDOWN;
  2128. Msg.WParam := Action;
  2129. SetCaptureControl(nil);
  2130. SendMessage(TCustomForm(Owner).Handle, Msg.Msg, Msg.wParam, Msg.lParam);
  2131. Exit;
  2132. end;
  2133. end;
  2134. {$ENDIF}
  2135. inherited;
  2136. end;
  2137. procedure TCustomImgView32.MouseMove(Shift: TShiftState; X, Y: Integer);
  2138. var
  2139. P: TPoint;
  2140. begin
  2141. inherited;
  2142. if IsSizeGripVisible then
  2143. begin
  2144. P.X := X;
  2145. P.Y := Y;
  2146. if GR32.PtInRect(GetSizeGripRect, P) then
  2147. Screen.Cursor := crSizeNWSE;
  2148. end;
  2149. end;
  2150. procedure TCustomImgView32.Paint;
  2151. begin
  2152. if not Assigned(Parent) then
  2153. Exit;
  2154. if IsSizeGripVisible then
  2155. DoDrawSizeGrip(GetSizeGripRect)
  2156. else
  2157. begin
  2158. Canvas.Brush.Color := clBtnFace;
  2159. Canvas.FillRect(GetSizeGripRect);
  2160. end;
  2161. inherited;
  2162. end;
  2163. procedure TCustomImgView32.Resize;
  2164. begin
  2165. AlignAll;
  2166. if Assigned(Parent) then
  2167. begin
  2168. if IsSizeGripVisible then
  2169. DoDrawSizeGrip(GetSizeGripRect)
  2170. else
  2171. begin
  2172. Canvas.Brush.Color := clBtnFace;
  2173. Canvas.FillRect(GetSizeGripRect);
  2174. end;
  2175. end;
  2176. InvalidateCache;
  2177. UpdateScrollBars;
  2178. UpdateImage;
  2179. Invalidate;
  2180. inherited;
  2181. end;
  2182. procedure TCustomImgView32.Scroll(Dx, Dy: Integer);
  2183. begin
  2184. if (Dx = 0) and (Dy = 0) then
  2185. Exit;
  2186. Scroll(Dx+0.0, Dy+0.0);
  2187. end;
  2188. procedure TCustomImgView32.Scroll(Dx, Dy: Single);
  2189. begin
  2190. if (IsZero(Dx)) and (IsZero(Dy)) then
  2191. Exit;
  2192. BeginUpdate;
  2193. try
  2194. DisableScrollUpdate := True;
  2195. HScroll.Position := HScroll.Position + Dx;
  2196. VScroll.Position := VScroll.Position + Dy;
  2197. DisableScrollUpdate := False;
  2198. finally
  2199. EndUpdate;
  2200. end;
  2201. UpdateImage;
  2202. end;
  2203. procedure TCustomImgView32.ScrollHandler(Sender: TObject);
  2204. begin
  2205. if DisableScrollUpdate then
  2206. Exit;
  2207. if (Sender = HScroll) then
  2208. HScroll.Repaint
  2209. else
  2210. if (Sender = VScroll) then
  2211. VScroll.Repaint;
  2212. UpdateImage;
  2213. DoScroll;
  2214. Repaint;
  2215. end;
  2216. procedure TCustomImgView32.ScrollChangingHandler(Sender: TObject; ANewPosition: Single; var Handled: boolean);
  2217. begin
  2218. if (Sender = HScroll) then
  2219. Scroll(ANewPosition - HScroll.Position, 0)
  2220. else
  2221. if (Sender = VScroll) then
  2222. Scroll(0, ANewPosition - VScroll.Position);
  2223. Handled := True;
  2224. DoScroll;
  2225. end;
  2226. procedure TCustomImgView32.ScrollToCenter(X, Y: Integer);
  2227. var
  2228. ScaledDOversize: Integer;
  2229. begin
  2230. DisableScrollUpdate := True;
  2231. AlignAll;
  2232. ScaledDOversize := Round(FOversize * Scale);
  2233. with GetViewportRect do
  2234. begin
  2235. HScroll.Position := X * Scale - (Right - Left) * 0.5 + ScaledDOversize;
  2236. VScroll.Position := Y * Scale - (Bottom - Top) * 0.5 + ScaledDOversize;
  2237. end;
  2238. DisableScrollUpdate := False;
  2239. UpdateImage;
  2240. end;
  2241. procedure TCustomImgView32.Recenter;
  2242. begin
  2243. InvalidateCache;
  2244. HScroll.Centered := FCentered;
  2245. VScroll.Centered := FCentered;
  2246. UpdateScrollBars;
  2247. UpdateImage;
  2248. if FCentered then
  2249. ScrollToCenter(Bitmap.Width div 2, Bitmap.Height div 2)
  2250. else
  2251. ScrollToCenter(0, 0);
  2252. end;
  2253. procedure TCustomImgView32.SetCentered(Value: Boolean);
  2254. begin
  2255. FCentered := Value;
  2256. Recenter;
  2257. end;
  2258. procedure TCustomImgView32.SetOverSize(const Value: Integer);
  2259. begin
  2260. if Value <> FOverSize then
  2261. begin
  2262. FOverSize := Value;
  2263. Invalidate;
  2264. end;
  2265. end;
  2266. procedure TCustomImgView32.SetScrollBars(Value: TIVScrollProperties);
  2267. begin
  2268. FScrollBars.Assign(Value);
  2269. end;
  2270. procedure TCustomImgView32.SetSizeGrip(Value: TSizeGripStyle);
  2271. begin
  2272. if Value <> FSizeGrip then
  2273. begin
  2274. FSizeGrip := Value;
  2275. Invalidate;
  2276. end;
  2277. end;
  2278. procedure TCustomImgView32.UpdateImage;
  2279. var
  2280. Sz: TSize;
  2281. W, H: Integer;
  2282. ScaledOversize: Integer;
  2283. begin
  2284. Sz := GetBitmapSize;
  2285. ScaledOversize := Round(FOversize * Scale);
  2286. with GetViewportRect do
  2287. begin
  2288. W := Right - Left;
  2289. H := Bottom - Top;
  2290. end;
  2291. BeginUpdate;
  2292. if not Centered then
  2293. begin
  2294. OffsetHorz := -HScroll.Position + ScaledOversize;
  2295. OffsetVert := -VScroll.Position + ScaledOversize;
  2296. end
  2297. else
  2298. begin
  2299. if W > Sz.Cx + 2 * ScaledOversize then // Viewport is bigger than scaled Bitmap
  2300. OffsetHorz := (W - Sz.Cx) * 0.5
  2301. else
  2302. OffsetHorz := -HScroll.Position + ScaledOversize;
  2303. if H > Sz.Cy + 2 * ScaledOversize then // Viewport is bigger than scaled Bitmap
  2304. OffsetVert := (H - Sz.Cy) * 0.5
  2305. else
  2306. OffsetVert := -VScroll.Position + ScaledOversize;
  2307. end;
  2308. InvalidateCache;
  2309. EndUpdate;
  2310. Changed;
  2311. end;
  2312. procedure TCustomImgView32.UpdateScrollBars;
  2313. var
  2314. Sz: TSize;
  2315. ScaledDOversize: Integer;
  2316. begin
  2317. if Assigned(HScroll) and Assigned(VScroll) then
  2318. begin
  2319. Sz := GetBitmapSize;
  2320. ScaledDOversize := Round(2 * FOversize * Scale);
  2321. HScroll.Range := Sz.Cx + ScaledDOversize;
  2322. VScroll.Range := Sz.Cy + ScaledDOversize;
  2323. // call AlignAll for Visibility svAuto, because the ranges of the scrollbars
  2324. // may have just changed, thus we need to update the visibility of the scrollbars:
  2325. if (FScrollBarVisibility = svAuto) then
  2326. AlignAll;
  2327. end;
  2328. end;
  2329. procedure TCustomImgView32.SetScaleMode(Value: TScaleMode);
  2330. begin
  2331. inherited;
  2332. Recenter;
  2333. end;
  2334. { TBitmap32Item }
  2335. procedure TBitmap32Item.AssignTo(Dest: TPersistent);
  2336. begin
  2337. if Dest is TBitmap32Item then
  2338. TBitmap32Item(Dest).Bitmap.Assign(Bitmap)
  2339. else
  2340. inherited;
  2341. end;
  2342. constructor TBitmap32Item.Create(Collection: TCollection);
  2343. begin
  2344. inherited;
  2345. FBitmap := TBitmap32.Create;
  2346. end;
  2347. destructor TBitmap32Item.Destroy;
  2348. begin
  2349. FBitmap.Free;
  2350. inherited;
  2351. end;
  2352. procedure TBitmap32Item.SetBitmap(ABitmap: TBitmap32);
  2353. begin
  2354. FBitmap.Assign(ABitmap)
  2355. end;
  2356. { TBitmap32Collection }
  2357. function TBitmap32Collection.Add: TBitmap32Item;
  2358. begin
  2359. Result := TBitmap32Item(inherited Add);
  2360. end;
  2361. constructor TBitmap32Collection.Create(AOwner: TPersistent; ItemClass: TBitmap32ItemClass);
  2362. begin
  2363. inherited Create(ItemClass);
  2364. FOwner := AOwner;
  2365. end;
  2366. function TBitmap32Collection.GetItem(Index: Integer): TBitmap32Item;
  2367. begin
  2368. Result := TBitmap32Item(inherited GetItem(Index));
  2369. end;
  2370. function TBitmap32Collection.GetOwner: TPersistent;
  2371. begin
  2372. Result := FOwner;
  2373. end;
  2374. procedure TBitmap32Collection.SetItem(Index: Integer; Value: TBitmap32Item);
  2375. begin
  2376. inherited SetItem(Index, Value);
  2377. end;
  2378. { TBitmap32List }
  2379. constructor TBitmap32List.Create(AOwner: TComponent);
  2380. begin
  2381. inherited;
  2382. FBitmap32Collection := TBitmap32Collection.Create(Self, TBitmap32Item);
  2383. end;
  2384. destructor TBitmap32List.Destroy;
  2385. begin
  2386. FBitmap32Collection.Free;
  2387. inherited;
  2388. end;
  2389. function TBitmap32List.GetBitmap(Index: Integer): TBitmap32;
  2390. begin
  2391. Result := FBitmap32Collection.Items[Index].Bitmap;
  2392. end;
  2393. procedure TBitmap32List.SetBitmap(Index: Integer; Value: TBitmap32);
  2394. begin
  2395. FBitmap32Collection.Items[Index].Bitmap := Value;
  2396. end;
  2397. procedure TBitmap32List.SetBitmap32Collection(Value: TBitmap32Collection);
  2398. begin
  2399. FBitmap32Collection := Value;
  2400. end;
  2401. end.