TBXUtils.pas 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181
  1. unit TBXUtils;
  2. // TBX Package
  3. // Copyright 2001-2004 Alex A. Denisov. All Rights Reserved
  4. // See TBX.chm for license and installation instructions
  5. //
  6. // Id: TBXUtils.pas 11 2004-04-01 07:22:56Z Alex@ZEISS
  7. interface
  8. {$I TB2Ver.inc}
  9. {$I TBX.inc}
  10. uses
  11. Windows, Messages, Classes, SysUtils, Graphics, Controls, Forms, ImgList;
  12. {$IFDEF TBX_UNICODE}
  13. function GetTextHeightW(DC: HDC): Integer;
  14. function GetTextWidthW(DC: HDC; const S: WideString; StripAccelChar: Boolean): Integer;
  15. procedure DrawRotatedTextW(DC: HDC; AText: WideString; const ARect: TRect; const AFormat: Cardinal);
  16. function EscapeAmpersandsW(const S: WideString): WideString;
  17. function FindAccelCharW(const S: WideString): WideChar;
  18. function StripAccelCharsW(const S: WideString): WideString;
  19. function StripTrailingPunctuationW(const S: WideString): WideString;
  20. {$ENDIF}
  21. procedure GetRGB(C: TColor; out R, G, B: Integer);
  22. function MixColors(C1, C2: TColor; W1: Integer): TColor;
  23. function SameColors(C1, C2: TColor): Boolean;
  24. function Lighten(C: TColor; Amount: Integer): TColor;
  25. function NearestLighten(C: TColor; Amount: Integer): TColor;
  26. function NearestMixedColor(C1, C2: TColor; W1: Integer): TColor;
  27. function ColorIntensity(C: TColor): Integer;
  28. function IsDarkColor(C: TColor; Threshold: Integer = 100): Boolean;
  29. function Blend(C1, C2: TColor; W1: Integer): TColor;
  30. procedure SetContrast(var Color: TColor; BkgndColor: TColor; Threshold: Integer);
  31. procedure RGBtoHSL(RGB: TColor; out H, S, L : Single);
  32. function HSLtoRGB(H, S, L: Single): TColor;
  33. function GetBGR(C: TColorRef): Cardinal;
  34. function TBXScaleByTextHeightRunTime(Canvas: TCanvas; Dimension: Integer): Integer;
  35. { A few drawing functions }
  36. { these functions recognize clNone value of TColor }
  37. procedure SetPixelEx(DC: HDC; X, Y: Integer; C: TColorRef; Alpha: Longword = $FF);
  38. function CreatePenEx(Color: TColor): HPen;
  39. function CreateBrushEx(Color: TColor): HBrush;
  40. function CreateDitheredBrush(C1, C2: TColor): HBrush;
  41. function FillRectEx(DC: HDC; const Rect: TRect; Color: TColor): Boolean; {$IFDEF COMPATIBLE_GFX}overload;{$ENDIF}
  42. function FrameRectEx(DC: HDC; var Rect: TRect; Color: TColor; Adjust: Boolean): Boolean; {$IFDEF COMPATIBLE_GFX}overload;{$ENDIF}
  43. procedure DrawLineEx(DC: HDC; X1, Y1, X2, Y2: Integer; Color: TColor); {$IFDEF COMPATIBLE_GFX}overload;{$ENDIF}
  44. function PolyLineEx(DC: HDC; const Points: array of TPoint; Color: TColor): Boolean;
  45. procedure PolygonEx(DC: HDC; const Points: array of TPoint; OutlineColor, FillColor: TColor);
  46. procedure RoundRectEx(DC: HDC; Left, Top, Right, Bottom: Integer; EllipseWidth, EllipseHeight, OutlineColor, FillColor: TColor); overload; {vb+}
  47. procedure RoundRectEx(DC: HDC; const R: TRect; EllipseWidth, EllipseHeight, OutlineColor, FillColor: TColor); overload; {vb+}
  48. procedure EllipseEx(DC: HDC; Left, Top, Right, Bottom: Integer; OutlineColor, FillColor: TColor);
  49. procedure DitherRect(DC: HDC; const R: TRect; C1, C2: TColor); {$IFDEF COMPATIBLE_GFX}overload;{$ENDIF}
  50. procedure Frame3D(DC: HDC; var Rect: TRect; TopColor, BottomColor: TColor; Adjust: Boolean); {$IFDEF COMPATIBLE_GFX}overload;{$ENDIF}
  51. procedure DrawDraggingOutline(DC: HDC; const NewRect, OldRect: TRect);
  52. { Gradients }
  53. type
  54. TGradientKind = (gkHorz, gkVert);
  55. procedure GradFill(DC: HDC; ARect: TRect; ClrTopLeft, ClrBottomRight: TColor; Kind: TGradientKind);
  56. procedure BrushedFill(DC: HDC; Origin: PPoint; ARect: TRect; Color: TColor; Roughness: Integer);
  57. procedure ResetBrushedFillCache;
  58. { drawing functions for compatibility with previous versions }
  59. {$IFDEF COMPATIBLE_GFX}
  60. function FillRectEx(Canvas: TCanvas; const Rect: TRect; Color: TColor): Boolean; overload;
  61. function FrameRectEx(Canvas: TCanvas; var Rect: TRect; Color: TColor; Adjust: Boolean = False): Boolean; overload;
  62. procedure DrawLineEx(Canvas: TCanvas; X1, Y1, X2, Y2: Integer; Color: TColor); overload;
  63. procedure DitherRect(Canvas: TCanvas; const R: TRect; C1, C2: TColor); overload;
  64. procedure Frame3D(Canvas: TCanvas; var Rect: TRect; TopColor, BottomColor: TColor); overload;
  65. function FillRectEx2(DC: HDC; const Rect: TRect; Color: TColor): Boolean; deprecated;
  66. function FrameRectEx2(DC: HDC; var Rect: TRect; Color: TColor; Adjust: Boolean = False): Boolean; deprecated;
  67. {$ENDIF}
  68. { alternatives to fillchar and move routines what work with 32-bit aligned memory blocks }
  69. procedure FillLongword(var X; Count: Integer; Value: Longword);
  70. procedure MoveLongword(const Source; var Dest; Count: Integer);
  71. { extended icon painting routines }
  72. procedure DrawTBXIcon(Canvas: TCanvas; const R: TRect;
  73. ImageList: TCustomImageList; ImageIndex: Integer);
  74. procedure BlendTBXIcon(Canvas: TCanvas; const R: TRect;
  75. ImageList: TCustomImageList; ImageIndex: Integer; Opacity: Byte);
  76. procedure HighlightTBXIcon(Canvas: TCanvas; const R: TRect;
  77. ImageList: TCustomImageList; ImageIndex: Integer; HighlightColor: TColor; Amount: Byte);
  78. procedure DrawTBXIconShadow(Canvas: TCanvas; const R: TRect;
  79. ImageList: TCustomImageList; ImageIndex: Integer; Density: Integer);
  80. procedure DrawTBXIconFlatShadow(Canvas: TCanvas; const R: TRect;
  81. ImageList: TCustomImageList; ImageIndex: Integer; ShadowColor: TColor);
  82. procedure DrawTBXIconFullShadow(Canvas: TCanvas; const R: TRect;
  83. ImageList: TCustomImageList; ImageIndex: Integer; ShadowColor: TColor);
  84. procedure DrawGlyph(DC: HDC; X, Y: Integer; ImageList: TCustomImageList; ImageIndex: Integer; Color: TColor); overload;
  85. procedure DrawGlyph(DC: HDC; const R: TRect; ImageList: TCustomImageList; ImageIndex: Integer; Color: TColor); overload;
  86. procedure DrawGlyph(DC: HDC; X, Y: Integer; const Bits; Color: TColor); overload;
  87. procedure DrawGlyph(DC: HDC; const R: TRect; Width, Height: Integer; const Bits; Color: TColor); overload;
  88. function GetClientSizeEx(Control: TWinControl): TPoint;
  89. const
  90. SHD_DENSE = 0;
  91. SHD_LIGHT = 1;
  92. { An additional declaration for D4 compiler }
  93. type
  94. PColor = ^TColor;
  95. { Stock Objects }
  96. var
  97. StockBitmap1, StockBitmap2: TBitmap;
  98. StockMonoBitmap, StockCompatibleBitmap: TBitmap;
  99. SmCaptionFont: TFont;
  100. const
  101. ROP_DSPDxax = $00E20746;
  102. { Support for window shadows }
  103. type
  104. TShadowEdges = set of (seTopLeft, seBottomRight);
  105. TShadowStyle = (ssFlat, ssLayered);
  106. TShadow = class(TCustomControl)
  107. protected
  108. FOpacity: Byte;
  109. FBuffer: TBitmap;
  110. FClearRect: TRect;
  111. FEdges: TShadowEdges;
  112. FStyle: TShadowStyle;
  113. FSaveBits: Boolean;
  114. procedure GradR(const R: TRect);
  115. procedure GradB(const R: TRect);
  116. procedure GradBR(const R: TRect);
  117. procedure GradTR(const R: TRect);
  118. procedure GradBL(const R: TRect);
  119. procedure CreateParams(var Params: TCreateParams); override;
  120. procedure FillBuffer; virtual; abstract;
  121. procedure WMNCHitTest(var Message: TMessage); message WM_NCHITTEST;
  122. public
  123. constructor Create(const Bounds: TRect; Opacity: Byte; LoColor: Boolean; Edges: TShadowEdges); reintroduce;
  124. procedure Clear(const R: TRect);
  125. procedure Render;
  126. procedure Show(ParentHandle: HWND);
  127. end;
  128. THorzShadow = class(TShadow)
  129. protected
  130. procedure FillBuffer; override;
  131. end;
  132. TVertShadow = class(TShadow)
  133. protected
  134. procedure FillBuffer; override;
  135. end;
  136. TShadows = class
  137. private
  138. FSaveBits: Boolean;
  139. procedure SetSaveBits(Value: Boolean);
  140. protected
  141. V1: TShadow;
  142. H1: TShadow;
  143. V2: TShadow;
  144. H2: TShadow;
  145. V3: TShadow;
  146. H3: TShadow;
  147. public
  148. constructor Create(R1, R2: TRect; TheSize: Integer; Opacity: Byte; LoColor: Boolean);
  149. destructor Destroy; override;
  150. procedure Show(ParentHandle: HWND);
  151. property SaveBits: Boolean read FSaveBits write SetSaveBits;
  152. end;
  153. procedure RecreateStock;
  154. implementation
  155. {$R-}{$Q-}
  156. uses TB2Common, Math, Types;
  157. {$IFDEF TBX_UNICODE}
  158. function GetTextHeightW(DC: HDC): Integer;
  159. var
  160. TextMetric: TTextMetricW;
  161. begin
  162. GetTextMetricsW(DC, TextMetric);
  163. Result := TextMetric.tmHeight;
  164. end;
  165. function GetTextWidthW(DC: HDC; const S: WideString; StripAccelChar: Boolean): Integer;
  166. var
  167. Size: TSize;
  168. S2: WideString;
  169. begin
  170. if StripAccelChar then
  171. begin
  172. S2 := StripAccelCharsW(S);
  173. GetTextExtentPoint32W(DC, PWideChar(S2), Length(S2), Size);
  174. end
  175. else GetTextExtentPoint32W(DC, PWideChar(S), Length(S), Size);
  176. Result := Size.cx;
  177. end;
  178. procedure DrawRotatedTextW(DC: HDC; AText: WideString; const ARect: TRect; const AFormat: Cardinal);
  179. { Like DrawText, but draws the text at a 270 degree angle.
  180. The format flag this function respects are
  181. DT_NOPREFIX, DT_HIDEPREFIX, DT_CENTER, DT_END_ELLIPSIS, DT_NOCLIP }
  182. var
  183. RotatedFont, SaveFont: HFONT;
  184. TextMetrics: TTextMetricW;
  185. X, Y, P, I, SU, FU, W: Integer;
  186. SaveAlign: UINT;
  187. Clip: Boolean;
  188. function GetSize(DC: HDC; const S: WideString): Integer;
  189. var
  190. Size: TSize;
  191. begin
  192. GetTextExtentPoint32W(DC, PWideChar(S), Length(S), Size);
  193. Result := Size.cx;
  194. end;
  195. begin
  196. if Length(AText) = 0 then Exit;
  197. RotatedFont := CreateRotatedFont(DC);
  198. SaveFont := SelectObject(DC, RotatedFont);
  199. GetTextMetricsW(DC, TextMetrics);
  200. X := ARect.Left + ((ARect.Right - ARect.Left) - TextMetrics.tmHeight) div 2;
  201. Clip := AFormat and DT_NOCLIP = 0;
  202. { Find the index of the character that should be underlined. Delete '&'
  203. characters from the string. Like DrawText, only the last prefixed character
  204. will be underlined. }
  205. P := 0;
  206. I := 1;
  207. if AFormat and DT_NOPREFIX = 0 then
  208. while I <= Length(AText) do
  209. begin
  210. if AText[I] = '&' then
  211. begin
  212. Delete(AText, I, 1);
  213. if PWideChar(AText)[I - 1] <> '&' then P := I;
  214. end;
  215. Inc(I);
  216. end;
  217. if AFormat and DT_END_ELLIPSIS <> 0 then
  218. begin
  219. if (Length(AText) > 1) and (GetSize(DC, AText) > ARect.Bottom - ARect.Top) then
  220. begin
  221. W := ARect.Bottom - ARect.Top;
  222. if W > 2 then
  223. begin
  224. Delete(AText, Length(AText), 1);
  225. while (Length(AText) > 1) and (GetSize(DC, AText + '...') > W) do
  226. Delete(AText, Length(AText), 1);
  227. end
  228. else AText := AText[1];
  229. if P > Length(AText) then P := 0;
  230. AText := AText + '...';
  231. end;
  232. end;
  233. if AFormat and DT_CENTER <> 0 then
  234. Y := ARect.Top + ((ARect.Bottom - ARect.Top) - GetSize(DC, AText)) div 2
  235. else
  236. Y := ARect.Top;
  237. if Clip then
  238. begin
  239. SaveDC(DC);
  240. with ARect do IntersectClipRect(DC, Left, Top, Right, Bottom);
  241. end;
  242. SaveAlign := SetTextAlign(DC, TA_BOTTOM);
  243. TextOutW(DC, X, Y, PWideChar(AText), Length(AText));
  244. SetTextAlign(DC, SaveAlign);
  245. { Underline }
  246. if (P > 0) and (AFormat and DT_HIDEPREFIX = 0) then
  247. begin
  248. SU := GetTextWidthW(DC, Copy(AText, 1, P - 1), False);
  249. FU := SU + GetTextWidthW(DC, PWideChar(AText)[P - 1], False);
  250. Inc(X, TextMetrics.tmDescent - 2);
  251. DrawLineEx(DC, X, Y + SU, X, Y + FU, GetTextColor(DC));
  252. end;
  253. if Clip then RestoreDC(DC, -1);
  254. SelectObject(DC, SaveFont);
  255. DeleteObject(RotatedFont);
  256. end;
  257. function EscapeAmpersandsW(const S: WideString): WideString;
  258. var
  259. I: Integer;
  260. begin
  261. Result := S;
  262. I := 1;
  263. while I <= Length(Result) do
  264. begin
  265. if Result[I] = '&' then
  266. begin
  267. Inc(I);
  268. Insert('&', Result, I);
  269. end;
  270. Inc(I);
  271. end;
  272. end;
  273. function FindAccelCharW(const S: WideString): WideChar;
  274. var
  275. PStart, P: PWideChar;
  276. begin
  277. { locate the last char with '&' prefix }
  278. Result := #0;
  279. if Length(S) > 0 then
  280. begin
  281. PStart := PWideChar(S);
  282. P := PStart;
  283. Inc(P, Length(S) - 2);
  284. while P >= PStart do
  285. begin
  286. if P^ = '&' then
  287. begin
  288. if (P = PStart) or (PWideChar(Integer(P) - 2)^ <> '&') then
  289. begin
  290. Result := PWideChar(Integer(P) + 2)^;
  291. Exit;
  292. end
  293. else Dec(P);
  294. end;
  295. Dec(P);
  296. end;
  297. end;
  298. end;
  299. function StripAccelCharsW(const S: WideString): WideString;
  300. var
  301. I: Integer;
  302. begin
  303. Result := S;
  304. I := 1;
  305. while I <= Length(Result) do
  306. begin
  307. if Result[I] = '&' then
  308. System.Delete(Result, I, 1);
  309. Inc(I);
  310. end;
  311. end;
  312. function StripTrailingPunctuationW(const S: WideString): WideString;
  313. var
  314. L: Integer;
  315. begin
  316. Result := S;
  317. L := Length(Result);
  318. if (L > 1) and (Result[L] = ':') then SetLength(Result, L - 1)
  319. else if (L > 3) and (Result[L - 2] = '.') and (Result[L - 1] = '.') and
  320. (Result[L] = '.') then SetLength(Result, L - 3);
  321. end;
  322. {$ENDIF}
  323. type
  324. PPoints = ^TPoints;
  325. TPoints = array [0..0] of TPoint;
  326. const
  327. WeightR: single = 0.764706;
  328. WeightG: single = 1.52941;
  329. WeightB: single = 0.254902;
  330. procedure GetRGB(C: TColor; out R, G, B: Integer);
  331. begin
  332. if Integer(C) < 0 then C := GetSysColor(C and $000000FF);
  333. R := C and $FF;
  334. G := C shr 8 and $FF;
  335. B := C shr 16 and $FF;
  336. end;
  337. function MixColors(C1, C2: TColor; W1: Integer): TColor;
  338. var
  339. W2: Cardinal;
  340. begin
  341. Assert(W1 in [0..255]);
  342. W2 := W1 xor 255;
  343. if Integer(C1) < 0 then C1 := GetSysColor(C1 and $000000FF);
  344. if Integer(C2) < 0 then C2 := GetSysColor(C2 and $000000FF);
  345. Result := Integer(
  346. ((Cardinal(C1) and $FF00FF) * Cardinal(W1) +
  347. (Cardinal(C2) and $FF00FF) * W2) and $FF00FF00 +
  348. ((Cardinal(C1) and $00FF00) * Cardinal(W1) +
  349. (Cardinal(C2) and $00FF00) * W2) and $00FF0000) shr 8;
  350. end;
  351. function SameColors(C1, C2: TColor): Boolean;
  352. begin
  353. if C1 < 0 then C1 := GetSysColor(C1 and $000000FF);
  354. if C2 < 0 then C2 := GetSysColor(C2 and $000000FF);
  355. Result := C1 = C2;
  356. end;
  357. function Lighten(C: TColor; Amount: Integer): TColor;
  358. var
  359. R, G, B: Integer;
  360. begin
  361. if C < 0 then C := GetSysColor(C and $000000FF);
  362. R := C and $FF + Amount;
  363. G := C shr 8 and $FF + Amount;
  364. B := C shr 16 and $FF + Amount;
  365. if R < 0 then R := 0 else if R > 255 then R := 255;
  366. if G < 0 then G := 0 else if G > 255 then G := 255;
  367. if B < 0 then B := 0 else if B > 255 then B := 255;
  368. Result := R or (G shl 8) or (B shl 16);
  369. end;
  370. function NearestLighten(C: TColor; Amount: Integer): TColor;
  371. begin
  372. Result := GetNearestColor(StockCompatibleBitmap.Canvas.Handle, Lighten(C, Amount));
  373. end;
  374. function NearestMixedColor(C1, C2: TColor; W1: Integer): TColor;
  375. begin
  376. Result := MixColors(C1, C2, W1);
  377. Result := GetNearestColor(StockCompatibleBitmap.Canvas.Handle, Result);
  378. end;
  379. function ColorIntensity(C: TColor): Integer;
  380. begin
  381. if C < 0 then C := GetSysColor(C and $FF);
  382. Result := ((C shr 16 and $FF) * 30 + (C shr 8 and $FF) * 150 + (C and $FF) * 76) shr 8;
  383. end;
  384. function IsDarkColor(C: TColor; Threshold: Integer = 100): Boolean;
  385. begin
  386. if C < 0 then C := GetSysColor(C and $FF);
  387. Threshold := Threshold shl 8;
  388. Result := ((C and $FF) * 76 + (C shr 8 and $FF) * 150 + (C shr 16 and $FF) * 30 ) < Threshold;
  389. end;
  390. function Blend(C1, C2: TColor; W1: Integer): TColor;
  391. var
  392. W2, A1, A2, D, F, G: Integer;
  393. begin
  394. if C1 < 0 then C1 := GetSysColor(C1 and $FF);
  395. if C2 < 0 then C2 := GetSysColor(C2 and $FF);
  396. if W1 >= 100 then D := 1000
  397. else D := 100;
  398. W2 := D - W1;
  399. F := D div 2;
  400. A2 := C2 shr 16 * W2;
  401. A1 := C1 shr 16 * W1;
  402. G := (A1 + A2 + F) div D and $FF;
  403. Result := G shl 16;
  404. A2 := (C2 shr 8 and $FF) * W2;
  405. A1 := (C1 shr 8 and $FF) * W1;
  406. G := (A1 + A2 + F) div D and $FF;
  407. Result := Result or G shl 8;
  408. A2 := (C2 and $FF) * W2;
  409. A1 := (C1 and $FF) * W1;
  410. G := (A1 + A2 + F) div D and $FF;
  411. Result := Result or G;
  412. end;
  413. function ColorDistance(C1, C2: Integer): Single;
  414. var
  415. DR, DG, DB: Integer;
  416. begin
  417. DR := (C1 and $FF) - (C2 and $FF);
  418. Result := Sqr(DR * WeightR);
  419. DG := (C1 shr 8 and $FF) - (C2 shr 8 and $FF);
  420. Result := Result + Sqr(DG * WeightG);
  421. DB := (C1 shr 16) - (C2 shr 16);
  422. Result := Result + Sqr(DB * WeightB);
  423. Result := SqRt(Result);
  424. end;
  425. function GetAdjustedThreshold(BkgndIntensity, Threshold: Single): Single;
  426. begin
  427. if BkgndIntensity < 220 then Result := (2 - BkgndIntensity / 220) * Threshold
  428. else Result := Threshold;
  429. end;
  430. function IsContrastEnough(AColor, ABkgndColor: Integer;
  431. DoAdjustThreshold: Boolean; Threshold: Single): Boolean;
  432. begin
  433. if DoAdjustThreshold then
  434. Threshold := GetAdjustedThreshold(ColorDistance(ABkgndColor, $000000), Threshold);
  435. Result := ColorDistance(ABkgndColor, AColor) > Threshold;
  436. end;
  437. procedure AdjustContrast(var AColor: Integer; ABkgndColor: Integer; Threshold: Single);
  438. var
  439. x, y, z: Single;
  440. r, g, b: Single;
  441. RR, GG, BB: Integer;
  442. i1, i2, s, q, w: Single;
  443. DoInvert: Boolean;
  444. begin
  445. i1 := ColorDistance(AColor, $000000);
  446. i2 := ColorDistance(ABkgndColor, $000000);
  447. Threshold := GetAdjustedThreshold(i2, Threshold);
  448. if i1 > i2 then DoInvert := i2 < 442 - Threshold
  449. else DoInvert := i2 < Threshold;
  450. x := (ABkgndColor and $FF) * WeightR;
  451. y := (ABkgndColor shr 8 and $FF) * WeightG;
  452. z := (ABkgndColor shr 16) * WeightB;
  453. r := (AColor and $FF) * WeightR;
  454. g := (AColor shr 8 and $FF) * WeightG;
  455. b := (AColor shr 16) * WeightB;
  456. if DoInvert then
  457. begin
  458. r := 195 - r;
  459. g := 390 - g;
  460. b := 65 - b;
  461. x := 195 - x;
  462. y := 390 - y;
  463. z := 65 - z;
  464. end;
  465. s := Sqrt(Sqr(b) + Sqr(g) + Sqr(r));
  466. if s < 0.01 then s := 0.01;
  467. q := (r * x + g * y + b * z) / S;
  468. x := Q / S * r - x;
  469. y := Q / S * g - y;
  470. z := Q / S * b - z;
  471. w := Sqrt(Sqr(Threshold) - Sqr(x) - Sqr(y) - Sqr(z));
  472. r := (q - w) * r / s;
  473. g := (q - w) * g / s;
  474. b := (q - w) * b / s;
  475. if DoInvert then
  476. begin
  477. r := 195 - r;
  478. g := 390 - g;
  479. b := 65 - b;
  480. end;
  481. if r < 0 then r := 0 else if r > 195 then r := 195;
  482. if g < 0 then g := 0 else if g > 390 then g := 390;
  483. if b < 0 then b := 0 else if b > 65 then b := 65;
  484. RR := Trunc(r * (1 / WeightR) + 0.5);
  485. GG := Trunc(g * (1 / WeightG) + 0.5);
  486. BB := Trunc(b * (1 / WeightB) + 0.5);
  487. if RR > $FF then RR := $FF else if RR < 0 then RR := 0;
  488. if GG > $FF then GG := $FF else if GG < 0 then GG := 0;
  489. if BB > $FF then BB := $FF else if BB < 0 then BB := 0;
  490. AColor := (BB and $FF) shl 16 or (GG and $FF) shl 8 or (RR and $FF);
  491. end;
  492. procedure SetContrast(var Color: TColor; BkgndColor: TColor; Threshold: Integer);
  493. var
  494. t: Single;
  495. begin
  496. if Color < 0 then Color := GetSysColor(Color and $FF);
  497. if BkgndColor < 0 then BkgndColor := GetSysColor(BkgndColor and $FF);
  498. t := Threshold;
  499. if not IsContrastEnough(Color, BkgndColor, True, t) then
  500. AdjustContrast(Integer(Color), BkgndColor, t);
  501. end;
  502. procedure RGBtoHSL(RGB: TColor; out H, S, L : Single);
  503. var
  504. R, G, B, D, Cmax, Cmin: Single;
  505. begin
  506. if RGB < 0 then RGB := GetSysColor(RGB and $FF);
  507. R := GetRValue(RGB) / 255;
  508. G := GetGValue(RGB) / 255;
  509. B := GetBValue(RGB) / 255;
  510. Cmax := Max(R, Max(G, B));
  511. Cmin := Min(R, Min(G, B));
  512. L := (Cmax + Cmin) / 2;
  513. if Cmax = Cmin then
  514. begin
  515. H := 0;
  516. S := 0
  517. end
  518. else
  519. begin
  520. D := Cmax - Cmin;
  521. if L < 0.5 then S := D / (Cmax + Cmin)
  522. else S := D / (2 - Cmax - Cmin);
  523. if R = Cmax then H := (G - B) / D
  524. else
  525. if G = Cmax then H := 2 + (B - R) / D
  526. else H := 4 + (R - G) / D;
  527. H := H / 6;
  528. if H < 0 then H := H + 1
  529. end;
  530. end;
  531. function HSLtoRGB(H, S, L: Single): TColor;
  532. const
  533. OneOverThree = 1 / 3;
  534. var
  535. M1, M2: Single;
  536. R, G, B: Byte;
  537. function HueToColor(Hue: Single): Byte;
  538. var
  539. V: Double;
  540. begin
  541. Hue := Hue - Floor(Hue);
  542. if 6 * Hue < 1 then V := M1 + (M2 - M1) * Hue * 6
  543. else if 2 * Hue < 1 then V := M2
  544. else if 3 * Hue < 2 then V := M1 + (M2 - M1) * (2 / 3 - Hue) * 6
  545. else V := M1;
  546. Result := Round(255 * V);
  547. end;
  548. begin
  549. if S = 0 then
  550. begin
  551. R := Round(255 * L);
  552. G := R;
  553. B := R;
  554. end
  555. else
  556. begin
  557. if L <= 0.5 then M2 := L * (1 + S)
  558. else M2 := L + S - L * S;
  559. M1 := 2 * L - M2;
  560. R := HueToColor(H + OneOverThree);
  561. G := HueToColor(H);
  562. B := HueToColor(H - OneOverThree)
  563. end;
  564. Result := RGB(R, G, B);
  565. end;
  566. const
  567. // This differs from PasTools as we use larger menu fonts
  568. OurDesignTimeTextHeight = 15;
  569. var
  570. LastFontName: string = '';
  571. LastFontHeight: Integer = -1;
  572. LastTextHeight: Integer = -1;
  573. function TBXScaleByTextHeightRunTime(Canvas: TCanvas; Dimension: Integer): Integer;
  574. begin
  575. // This should be called from the GUI thread only.
  576. // See ScaleByTextHeightRunTime in PasTools.
  577. if (LastTextHeight < 0) or
  578. (LastFontName <> Canvas.Font.Name) or
  579. (LastFontHeight <> Canvas.Font.Height) then
  580. begin
  581. LastTextHeight := Canvas.TextHeight('0');
  582. LastFontName := Canvas.Font.Name;
  583. LastFontHeight := Canvas.Font.Height;
  584. end;
  585. if LastTextHeight <> OurDesignTimeTextHeight then
  586. begin
  587. Dimension := MulDiv(Dimension, LastTextHeight, OurDesignTimeTextHeight);
  588. end;
  589. Result := Dimension;
  590. end;
  591. { Drawing routines }
  592. function GetBGR(C: TColorRef): Cardinal;
  593. asm
  594. MOV ECX,EAX // this function swaps R and B bytes in ABGR
  595. SHR EAX,16
  596. XCHG AL,CL
  597. MOV AH,$00 // and writes $FF into A component
  598. SHL EAX,16
  599. MOV AX,CX
  600. end;
  601. procedure SetPixelEx(DC: HDC; X, Y: Integer; C: TColorRef; Alpha: Longword = $FF);
  602. var
  603. W2: Cardinal;
  604. B: TColorRef;
  605. begin
  606. if Alpha <= 0 then Exit
  607. else if Alpha >= 255 then SetPixelV(DC, X, Y, C)
  608. else
  609. begin
  610. B := GetPixel(DC, X, Y);
  611. if B <> CLR_INVALID then
  612. begin
  613. Inc(Alpha, Integer(Alpha > 127));
  614. W2 := 256 - Alpha;
  615. B :=
  616. ((C and $FF00FF) * Alpha + (B and $FF00FF) * W2 + $007F007F) and $FF00FF00 +
  617. ((C and $00FF00) * Alpha + (B and $00FF00) * W2 + $00007F00) and $00FF0000;
  618. SetPixelV(DC, X, Y, B shr 8);
  619. end;
  620. end;
  621. end;
  622. function CreatePenEx(Color: TColor): HPen;
  623. begin
  624. if Color = clNone then Result := CreatePen(PS_NULL, 1, 0)
  625. else if Color < 0 then Result := CreatePen(PS_SOLID, 1, GetSysColor(Color and $000000FF))
  626. else Result := CreatePen(PS_SOLID, 1, Color);
  627. end;
  628. function CreateBrushEx(Color: TColor): HBrush;
  629. var
  630. LB: TLogBrush;
  631. begin
  632. if Color = clNone then
  633. begin
  634. LB.lbStyle := BS_HOLLOW;
  635. Result := CreateBrushIndirect(LB);
  636. end
  637. {else if Color < 0 then Result := GetSysColorBrush(Color and $000000FF)} {vb-}
  638. else begin {vb+}
  639. if Color < 0 then Color := GetSysColor(Color and $000000FF);
  640. Result := CreateSolidBrush(Color);
  641. end;
  642. end;
  643. function FillRectEx(DC: HDC; const Rect: TRect; Color: TColor): Boolean;
  644. var
  645. Brush: HBRUSH;
  646. begin
  647. Result := Color <> clNone;
  648. if Result then
  649. begin
  650. if Color < 0 then Brush := GetSysColorBrush(Color and $000000FF)
  651. else Brush := CreateSolidBrush(Color);
  652. Windows.FillRect(DC, Rect, Brush);
  653. {DeleteObject(Brush);} {vb-}
  654. if Color >= 0 then DeleteObject(Brush); {vb+}
  655. end;
  656. end;
  657. function FrameRectEx(DC: HDC; var Rect: TRect; Color: TColor; Adjust: Boolean): Boolean;
  658. var
  659. Brush: HBRUSH;
  660. begin
  661. Result := Color <> clNone;
  662. if Result then
  663. begin
  664. if Color < 0 then Brush := GetSysColorBrush(Color and $000000FF)
  665. else Brush := CreateSolidBrush(Color);
  666. Windows.FrameRect(DC, Rect, Brush);
  667. {DeleteObject(Brush);} {vb-}
  668. if Color >= 0 then DeleteObject(Brush); {vb+}
  669. end;
  670. if Adjust then with Rect do
  671. begin
  672. Inc(Left); Dec(Right);
  673. Inc(Top); Dec(Bottom);
  674. end;
  675. end;
  676. procedure DrawLineEx(DC: HDC; X1, Y1, X2, Y2: Integer; Color: TColor);
  677. var
  678. OldPen, Pen: HPen;
  679. begin
  680. Pen := CreatePen(PS_SOLID, 1, ColorToRGB(Color));
  681. OldPen := SelectObject(DC, Pen);
  682. Windows.MoveToEx(DC, X1, Y1, nil);
  683. Windows.LineTo(DC, X2, Y2);
  684. SelectObject(DC, OldPen);
  685. DeleteObject(Pen);
  686. end;
  687. function PolyLineEx(DC: HDC; const Points: array of TPoint; Color: TColor): Boolean; overload;
  688. var
  689. Pen, OldPen: HPEN;
  690. begin
  691. Result := Color <> clNone;
  692. if Result then
  693. begin
  694. if Color < 0 then Color := GetSysColor(Color and $FF);
  695. Pen := CreatePen(PS_SOLID, 1, Color);
  696. OldPen := SelectObject(DC, Pen);
  697. Windows.Polyline(DC, PPoints(@Points[0])^, Length(Points));
  698. SelectObject(DC, OldPen);
  699. DeleteObject(Pen);
  700. end;
  701. end;
  702. procedure PolygonEx(DC: HDC; const Points: array of TPoint; OutlineColor, FillColor: TColor);
  703. var
  704. OldBrush, Brush: HBrush;
  705. OldPen, Pen: HPen;
  706. begin
  707. if (OutlineColor = clNone) and (FillColor = clNone) then Exit;
  708. Pen := CreatePenEx(OutlineColor);
  709. Brush := CreateBrushEx(FillColor);
  710. OldPen := SelectObject(DC, Pen);
  711. OldBrush := SelectObject(DC, Brush);
  712. Windows.Polygon(DC, PPoints(@Points[0])^, Length(Points));
  713. SelectObject(DC, OldBrush);
  714. SelectObject(DC, OldPen);
  715. DeleteObject(Brush);
  716. DeleteObject(Pen);
  717. end;
  718. procedure RoundRectEx(DC: HDC; Left, Top, Right, Bottom: Integer;
  719. EllipseWidth, EllipseHeight, OutlineColor, FillColor: TColor); {vb+}
  720. var
  721. OldBrush, Brush: HBrush;
  722. OldPen, Pen: HPen;
  723. begin
  724. if (OutlineColor = clNone) and (FillColor = clNone) then Exit;
  725. Pen := CreatePenEx(OutlineColor);
  726. Brush := CreateBrushEx(FillColor);
  727. OldPen := SelectObject(DC, Pen);
  728. OldBrush := SelectObject(DC, Brush);
  729. Windows.RoundRect(DC, Left, Top, Right, Bottom, EllipseWidth, EllipseHeight);
  730. SelectObject(DC, OldBrush);
  731. SelectObject(DC, OldPen);
  732. DeleteObject(Brush);
  733. DeleteObject(Pen);
  734. end;
  735. procedure RoundRectEx(DC: HDC; const R: TRect; EllipseWidth, EllipseHeight,
  736. OutlineColor, FillColor: TColor); {vb+}
  737. begin
  738. with R do
  739. RoundRectEx(DC, Left, Top, Right, Bottom, EllipseWidth,
  740. EllipseHeight, OutlineColor, FillColor);
  741. end;
  742. procedure EllipseEx(DC: HDC; Left, Top, Right, Bottom: Integer; OutlineColor, FillColor: TColor);
  743. var
  744. OldBrush, Brush: HBrush;
  745. OldPen, Pen: HPen;
  746. begin
  747. Pen := CreatePenEx(OutlineColor);
  748. Brush := CreateBrushEx(FillColor);
  749. OldPen := SelectObject(DC, Pen);
  750. OldBrush := SelectObject(DC, Brush);
  751. Windows.Ellipse(DC, Left, Top, Right, Bottom);
  752. SelectObject(DC, OldBrush);
  753. SelectObject(DC, OldPen);
  754. DeleteObject(Brush);
  755. DeleteObject(Pen);
  756. end;
  757. function CreateDitheredBrush(C1, C2: TColor): HBrush;
  758. var
  759. B: TBitmap;
  760. begin
  761. B := AllocPatternBitmap(C1, C2);
  762. B.HandleType := bmDDB;
  763. Result := CreatePatternBrush(B.Handle);
  764. end;
  765. procedure DitherRect(DC: HDC; const R: TRect; C1, C2: TColor);
  766. var
  767. Brush: HBRUSH;
  768. begin
  769. Brush := CreateDitheredBrush(C1, C2);
  770. FillRect(DC, R, Brush);
  771. DeleteObject(Brush);
  772. end;
  773. procedure Frame3D(DC: HDC; var Rect: TRect; TopColor, BottomColor: TColor; Adjust: Boolean);
  774. var
  775. TopRight, BottomLeft: TPoint;
  776. begin
  777. with Rect do
  778. begin
  779. Dec(Bottom); Dec(Right);
  780. TopRight.X := Right;
  781. TopRight.Y := Top;
  782. BottomLeft.X := Left;
  783. BottomLeft.Y := Bottom;
  784. PolyLineEx(DC, [BottomLeft, TopLeft, TopRight], TopColor);
  785. Dec(BottomLeft.X);
  786. PolyLineEx(DC, [TopRight, BottomRight, BottomLeft], BottomColor);
  787. if Adjust then
  788. begin
  789. Inc(Left);
  790. Inc(Top);
  791. end
  792. else
  793. begin
  794. Dec(Right);
  795. Dec(Bottom);
  796. end;
  797. end;
  798. end;
  799. {$IFDEF COMPATIBLE_GFX}
  800. procedure DitherRect(Canvas: TCanvas; const R: TRect; C1, C2: TColor);
  801. begin
  802. DitherRect(Canvas.Handle, R, C1, C2);
  803. end;
  804. procedure Frame3D(Canvas: TCanvas; var Rect: TRect; TopColor, BottomColor: TColor);
  805. var
  806. TopRight, BottomLeft: TPoint;
  807. begin
  808. with Canvas, Rect do
  809. begin
  810. Pen.Width := 1;
  811. Dec(Bottom); Dec(Right);
  812. TopRight.X := Right;
  813. TopRight.Y := Top;
  814. BottomLeft.X := Left;
  815. BottomLeft.Y := Bottom;
  816. Pen.Color := TopColor;
  817. PolyLine([BottomLeft, TopLeft, TopRight]);
  818. Pen.Color := BottomColor;
  819. Dec(BottomLeft.X);
  820. PolyLine([TopRight, BottomRight, BottomLeft]);
  821. Inc(Left); Inc(Top);
  822. end;
  823. end;
  824. function FillRectEx(Canvas: TCanvas; const Rect: TRect; Color: TColor): Boolean;
  825. begin
  826. Result := FillRectEx(Canvas.Handle, Rect, Color);
  827. end;
  828. function FillRectEx2(DC: HDC; const Rect: TRect; Color: TColor): Boolean; deprecated;
  829. begin
  830. Result := FillRectEx(DC, Rect, Color);
  831. end;
  832. function FrameRectEx(Canvas: TCanvas; var Rect: TRect; Color: TColor; Adjust: Boolean = False): Boolean;
  833. begin
  834. Result := FrameRectEx(Canvas.Handle, Rect, Color, Adjust);
  835. end;
  836. function FrameRectEx2(DC: HDC; var Rect: TRect; Color: TColor; Adjust: Boolean = False): Boolean; deprecated;
  837. begin
  838. Result := FrameRectEx(DC, Rect, Color, Adjust);
  839. end;
  840. procedure DrawLineEx(Canvas: TCanvas; X1, Y1, X2, Y2: Integer; Color: TColor);
  841. begin
  842. DrawLineEx(Canvas.Handle, X1, Y1, X2, Y2, Color);
  843. end;
  844. {$ENDIF}
  845. procedure DrawDraggingOutline(DC: HDC; const NewRect, OldRect: TRect);
  846. var
  847. Sz: TSize;
  848. begin
  849. Sz.CX := 3; Sz.CY := 2;
  850. DrawHalftoneInvertRect(DC, @NewRect, @OldRect, Sz, Sz);
  851. end;
  852. procedure FillLongword(var X; Count: Integer; Value: Longword);
  853. asm
  854. // EAX = X; EDX = Count; ECX = Value
  855. PUSH EDI
  856. MOV EDI,EAX // Point EDI to destination
  857. MOV EAX,ECX
  858. MOV ECX,EDX
  859. TEST ECX,ECX
  860. JS @exit
  861. REP STOSD // Fill count dwords
  862. @exit:
  863. POP EDI
  864. end;
  865. procedure MoveLongword(const Source; var Dest; Count: Integer);
  866. asm
  867. // EAX = Source; EDX = Dest; ECX = Count
  868. PUSH ESI
  869. PUSH EDI
  870. MOV ESI,EAX // Source
  871. MOV EDI,EDX // Destination
  872. MOV EAX,ECX // Counter
  873. CMP EDI,ESI
  874. JE @exit
  875. REP MOVSD
  876. @exit:
  877. POP EDI
  878. POP ESI
  879. end;
  880. procedure DrawTBXIcon(Canvas: TCanvas; const R: TRect;
  881. ImageList: TCustomImageList; ImageIndex: Integer);
  882. begin
  883. ImageList.Draw(Canvas, R.Left, R.Top, ImageIndex);
  884. end;
  885. procedure BlendTBXIcon(Canvas: TCanvas; const R: TRect;
  886. ImageList: TCustomImageList; ImageIndex: Integer; Opacity: Byte);
  887. {const
  888. CWeirdColor = $00203241;} {vb -}
  889. var
  890. ImageWidth, ImageHeight: Integer;
  891. I, J: Integer;
  892. Src, Dst: ^Cardinal;
  893. S, C, CBRB, CBG: Cardinal;
  894. Wt1, Wt2: Cardinal;
  895. begin
  896. Wt2 := Opacity;
  897. Wt1 := 255 - Wt2;
  898. ImageWidth := R.Right - R.Left;
  899. ImageHeight := R.Bottom - R.Top;
  900. with ImageList do
  901. begin
  902. if Width < ImageWidth then ImageWidth := Width;
  903. if Height < ImageHeight then ImageHeight := Height;
  904. end;
  905. StockBitmap1.Width := ImageWidth;
  906. StockBitmap1.Height := ImageHeight;
  907. StockBitmap2.Width := ImageWidth;
  908. StockBitmap2.Height := ImageHeight;
  909. BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  910. Canvas.Handle, R.Left, R.Top, SRCCOPY);
  911. {BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  912. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);} {vb -}
  913. BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  914. Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
  915. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
  916. for J := 0 to ImageHeight - 1 do
  917. begin
  918. Src := StockBitmap2.ScanLine[J];
  919. Dst := StockBitmap1.ScanLine[J];
  920. for I := 0 to ImageWidth - 1 do
  921. begin
  922. S := Src^;
  923. if S <> Dst^ then
  924. begin
  925. CBRB := (Dst^ and $00FF00FF) * Wt1;
  926. CBG := (Dst^ and $0000FF00) * Wt1;
  927. {C := ((S and $FF00FF) * Wt2 + CBRB) and $FF00FF00 +
  928. ((S and $00FF00) * Wt2 + CBG) and $00FF0000;} {vb -}
  929. C := ((S and $00FF00FF) * Wt2 + CBRB) and $FF00FF00 +
  930. ((S and $0000FF00) * Wt2 + CBG) and $00FF0000; {vb +}
  931. Dst^ := C shr 8;
  932. end;
  933. Inc(Src);
  934. Inc(Dst);
  935. end;
  936. end;
  937. BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
  938. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
  939. end;
  940. procedure HighlightTBXIcon(Canvas: TCanvas; const R: TRect;
  941. ImageList: TCustomImageList; ImageIndex: Integer; HighlightColor: TColor; Amount: Byte);
  942. {const
  943. CWeirdColor = $00203241;} {vb -}
  944. var
  945. ImageWidth, ImageHeight: Integer;
  946. I, J: Integer;
  947. {Src, Dst: PColor;} {vb -}
  948. Src, Dst: ^Cardinal; {vb +}
  949. S, C: Cardinal;
  950. CBRB, CBG: Cardinal;
  951. W1, W2: Cardinal;
  952. begin
  953. ImageWidth := R.Right - R.Left;
  954. ImageHeight := R.Bottom - R.Top;
  955. with ImageList do
  956. begin
  957. if Width < ImageWidth then ImageWidth := Width;
  958. if Height < ImageHeight then ImageHeight := Height;
  959. end;
  960. StockBitmap1.Width := ImageWidth;
  961. StockBitmap1.Height := ImageHeight;
  962. StockBitmap2.Width := ImageWidth;
  963. StockBitmap2.Height := ImageHeight;
  964. BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  965. Canvas.Handle, R.Left, R.Top, SRCCOPY);
  966. {for J := 0 to ImageHeight - 1 do
  967. FillLongWord(StockBitmap2.ScanLine[J]^, ImageWidth, CWeirdColor);} {vb -}
  968. BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  969. Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
  970. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex);
  971. W2 := Amount;
  972. W1 := 255 - W2;
  973. HighlightColor := GetBGR(ColorToRGB(HighlightColor));
  974. CBRB := (Cardinal(HighlightColor) and $00FF00FF) * W1;
  975. CBG := (Cardinal(HighlightColor) and $0000FF00) * W1;
  976. for J := 0 to ImageHeight - 1 do
  977. begin
  978. Src := StockBitmap2.ScanLine[J];
  979. Dst := StockBitmap1.ScanLine[J];
  980. for I := 0 to ImageWidth - 1 do
  981. begin
  982. {S := Src^ and $00FFFFFF;} {vb -}
  983. S := Src^; {vb +}
  984. {if S <> CWeirdColor then} {vb -}
  985. if S <> Dst^ then {vb +}
  986. begin
  987. {C := ((S and $FF00FF) * W2 + CBRB) and $FF00FF00 +
  988. ((S and $00FF00) * W2 + CBG) and $00FF0000;} {vb -}
  989. C := ((S and $00FF00FF) * W2 + CBRB) and $FF00FF00 +
  990. ((S and $0000FF00) * W2 + CBG) and $00FF0000; {vb +}
  991. Dst^ := C shr 8;
  992. end;
  993. Inc(Src);
  994. Inc(Dst);
  995. end;
  996. end;
  997. BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
  998. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
  999. end;
  1000. procedure DrawTBXIconShadow(Canvas: TCanvas; const R: TRect;
  1001. ImageList: TCustomImageList; ImageIndex: Integer; Density: Integer);
  1002. const
  1003. D_DIV: array [0..2] of Cardinal = (3, 8, 20);
  1004. D_ADD: array [0..2] of Cardinal = (255 - 255 div 3, 255 - 255 div 8, 255 - 255 div 20);
  1005. var
  1006. ImageWidth, ImageHeight: Integer;
  1007. I, J: Integer;
  1008. Src, Dst: ^Cardinal;
  1009. S, C, CBRB, CBG: Cardinal;
  1010. begin
  1011. Assert(Density in [0..2]);
  1012. ImageWidth := R.Right - R.Left;
  1013. ImageHeight := R.Bottom - R.Top;
  1014. with ImageList do
  1015. begin
  1016. if Width < ImageWidth then ImageWidth := Width;
  1017. if Height < ImageHeight then ImageHeight := Height;
  1018. end;
  1019. StockBitmap1.Width := ImageWidth;
  1020. StockBitmap1.Height := ImageHeight;
  1021. StockBitmap2.Width := ImageWidth;
  1022. StockBitmap2.Height := ImageHeight;
  1023. BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1024. Canvas.Handle, R.Left, R.Top, SRCCOPY);
  1025. {BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1026. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);} {vb -}
  1027. BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1028. Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
  1029. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
  1030. for J := 0 to ImageHeight - 1 do
  1031. begin
  1032. Src := StockBitmap2.ScanLine[J];
  1033. Dst := StockBitmap1.ScanLine[J];
  1034. for I := 0 to ImageWidth - 1 do
  1035. begin
  1036. S := Src^;
  1037. if S <> Dst^ then
  1038. begin
  1039. CBRB := Dst^ and $00FF00FF;
  1040. CBG := Dst^ and $0000FF00;
  1041. {C := ((S and $FF0000) shr 16 * 29 + (S and $00FF00) shr 8 * 150 +
  1042. (S and $0000FF) * 76) shr 8;} {vb -}
  1043. C := ((S and $00FF0000) shr 16 * 29 + (S and $0000FF00) shr 8 * 150 +
  1044. (S and $000000FF) * 76) shr 8; {vb +}
  1045. C := C div D_DIV[Density] + D_ADD[Density];
  1046. Dst^ := ((CBRB * C and $FF00FF00) or (CBG * C and $00FF0000)) shr 8;
  1047. end;
  1048. Inc(Src);
  1049. Inc(Dst);
  1050. end;
  1051. end;
  1052. BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
  1053. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
  1054. end;
  1055. procedure DrawTBXIconFlatShadow(Canvas: TCanvas; const R: TRect;
  1056. ImageList: TCustomImageList; ImageIndex: Integer; ShadowColor: TColor);
  1057. const
  1058. CShadowThreshold = 180 * 256;
  1059. var
  1060. ImageWidth, ImageHeight: Integer;
  1061. I, J: Integer;
  1062. P: ^Cardinal;
  1063. C: Cardinal;
  1064. SrcDC, DstDC: HDC;
  1065. begin
  1066. ImageWidth := R.Right - R.Left;
  1067. ImageHeight := R.Bottom - R.Top;
  1068. with ImageList do
  1069. begin
  1070. if Width < ImageWidth then ImageWidth := Width;
  1071. if Height < ImageHeight then ImageHeight := Height;
  1072. end;
  1073. StockBitmap2.Width := ImageWidth;
  1074. StockBitmap2.Height := ImageHeight;
  1075. StockBitmap2.Canvas.Brush.Color := clWhite;
  1076. StockBitmap2.Canvas.FillRect(Rect(0, 0, ImageWidth, ImageHeight));
  1077. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
  1078. for J := 0 to ImageHeight - 1 do
  1079. begin
  1080. P := StockBitmap2.ScanLine[J];
  1081. for I := 0 to ImageWidth - 1 do
  1082. begin
  1083. C := P^ and $00FFFFFF;
  1084. if C <> $0 then
  1085. begin
  1086. C := (C and $FF0000) shr 16 * 76 + (C and $00FF00) shr 8 * 150 + (C and $0000FF) * 29;
  1087. if C > CShadowThreshold then P^ := $00FFFFFF
  1088. else P^ := $00000000;
  1089. end;
  1090. Inc(P);
  1091. end;
  1092. end;
  1093. StockMonoBitmap.Width := ImageWidth;
  1094. StockMonoBitmap.Height := ImageHeight;
  1095. StockMonoBitmap.Canvas.Brush.Color := clBlack;
  1096. BitBlt(StockMonoBitmap.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1097. StockBitmap2.Canvas.Handle, 0, 0, SRCCOPY);
  1098. SrcDC := StockMonoBitmap.Canvas.Handle;
  1099. Canvas.Brush.Color := ColorToRGB(ShadowColor);
  1100. DstDC := Canvas.Handle;
  1101. Windows.SetTextColor(DstDC, clWhite);
  1102. Windows.SetBkColor(DstDC, clBlack);
  1103. BitBlt(DstDC, R.Left, R.Top, ImageWidth, ImageHeight, SrcDC, 0, 0, ROP_DSPDxax);
  1104. end;
  1105. procedure DrawTBXIconFullShadow(Canvas: TCanvas; const R: TRect;
  1106. ImageList: TCustomImageList; ImageIndex: Integer; ShadowColor: TColor);
  1107. const
  1108. CWeirdColor = $00203241;
  1109. var
  1110. ImageWidth, ImageHeight: Integer;
  1111. I, J: Integer;
  1112. P: ^Cardinal;
  1113. C: Cardinal;
  1114. SrcDC, DstDC: HDC;
  1115. begin
  1116. ImageWidth := R.Right - R.Left;
  1117. ImageHeight := R.Bottom - R.Top;
  1118. with ImageList do
  1119. begin
  1120. if Width < ImageWidth then ImageWidth := Width;
  1121. if Height < ImageHeight then ImageHeight := Height;
  1122. end;
  1123. StockBitmap2.Width := ImageWidth;
  1124. StockBitmap2.Height := ImageHeight;
  1125. for J := 0 to ImageHeight - 1 do
  1126. FillLongWord(StockBitmap2.ScanLine[J]^, ImageWidth, CWeirdColor);
  1127. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
  1128. for J := 0 to ImageHeight - 1 do
  1129. begin
  1130. P := StockBitmap2.ScanLine[J];
  1131. for I := 0 to ImageWidth - 1 do
  1132. begin
  1133. C := P^ and $00FFFFFF;
  1134. if C <> CWeirdColor then P^ := $00000000
  1135. else P^ := $00FFFFFF;
  1136. Inc(P);
  1137. end;
  1138. end;
  1139. StockMonoBitmap.Width := ImageWidth;
  1140. StockMonoBitmap.Height := ImageHeight;
  1141. StockMonoBitmap.Canvas.Brush.Color := clBlack;
  1142. BitBlt(StockMonoBitmap.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1143. StockBitmap2.Canvas.Handle, 0, 0, SRCCOPY);
  1144. SrcDC := StockMonoBitmap.Canvas.Handle;
  1145. Canvas.Brush.Color := ColorToRGB(ShadowColor);
  1146. DstDC := Canvas.Handle;
  1147. Windows.SetTextColor(DstDC, clWhite);
  1148. Windows.SetBkColor(DstDC, clBlack);
  1149. BitBlt(DstDC, R.Left, R.Top, ImageWidth, ImageHeight, SrcDC, 0, 0, ROP_DSPDxax);
  1150. end;
  1151. procedure DrawGlyph(DC: HDC; X, Y: Integer; ImageList: TCustomImageList; ImageIndex: Integer; Color: TColor);
  1152. var
  1153. B: TBitmap;
  1154. OldTextColor, OldBkColor: Longword;
  1155. OldBrush, Brush: HBrush;
  1156. begin
  1157. if Color = clNone then Exit;
  1158. B := TBitmap.Create;
  1159. B.Monochrome := True;
  1160. ImageList.GetBitmap(ImageIndex, B);
  1161. OldTextColor := SetTextColor(DC, clBlack);
  1162. OldBkColor := SetBkColor(DC, clWhite);
  1163. if Color < 0 then Brush := GetSysColorBrush(Color and $FF)
  1164. else Brush := CreateSolidBrush(Color);
  1165. OldBrush := SelectObject(DC, Brush);
  1166. BitBlt(DC, X, Y, ImageList.Width, ImageList.Height, B.Canvas.Handle, 0, 0, ROP_DSPDxax);
  1167. SelectObject(DC, OldBrush);
  1168. if Color >= 0 then DeleteObject(Brush);
  1169. SetTextColor(DC, OldTextColor);
  1170. SetBkColor(DC, OldBkColor);
  1171. B.Free;
  1172. end;
  1173. procedure DrawGlyph(DC: HDC; const R: TRect; ImageList: TCustomImageList; ImageIndex: Integer; Color: TColor); overload;
  1174. begin
  1175. DrawGlyph(DC, (R.Left + R.Right + 1 - ImageList.Width) div 2, (R.Top + R.Bottom + 1 - ImageList.Height) div 2, ImageList, ImageIndex, Color);
  1176. end;
  1177. procedure DrawGlyph(DC: HDC; X, Y: Integer; const Bits; Color: TColor); overload;
  1178. var
  1179. B: TBitmap;
  1180. OldTextColor, OldBkColor: Longword;
  1181. OldBrush, Brush: HBrush;
  1182. begin
  1183. B := TBitmap.Create;
  1184. B.Handle := CreateBitmap(8, 8, 1, 1, @Bits);
  1185. OldTextColor := SetTextColor(DC, clBlack);
  1186. OldBkColor := SetBkColor(DC, clWhite);
  1187. if Color < 0 then Brush := GetSysColorBrush(Color and $FF)
  1188. else Brush := CreateSolidBrush(Color);
  1189. OldBrush := SelectObject(DC, Brush);
  1190. BitBlt(DC, X, Y, 8, 8, B.Canvas.Handle, 0, 0, ROP_DSPDxax);
  1191. SelectObject(DC, OldBrush);
  1192. if Color >= 0 then DeleteObject(Brush);
  1193. SetTextColor(DC, OldTextColor);
  1194. SetBkColor(DC, OldBkColor);
  1195. B.Free;
  1196. end;
  1197. procedure DrawGlyph(DC: HDC; const R: TRect; Width, Height: Integer; const Bits; Color: TColor); overload;
  1198. var
  1199. B: TBitmap;
  1200. OldTextColor, OldBkColor: Longword;
  1201. OldBrush, Brush: HBrush;
  1202. begin
  1203. B := TBitmap.Create;
  1204. B.Handle := CreateBitmap(8, 8, 1, 1, @Bits);
  1205. OldTextColor := SetTextColor(DC, clBlack);
  1206. OldBkColor := SetBkColor(DC, clWhite);
  1207. if Color < 0 then Brush := GetSysColorBrush(Color and $FF)
  1208. else Brush := CreateSolidBrush(Color);
  1209. OldBrush := SelectObject(DC, Brush);
  1210. BitBlt(DC, (R.Left + R.Right + 1 - Width) div 2, (R.Top + R.Bottom + 1 - Height) div 2, Width, Height, B.Canvas.Handle, 0, 0, ROP_DSPDxax);
  1211. SelectObject(DC, OldBrush);
  1212. if Color >= 0 then DeleteObject(Brush);
  1213. SetTextColor(DC, OldTextColor);
  1214. SetBkColor(DC, OldBkColor);
  1215. B.Free;
  1216. end;
  1217. type
  1218. TCustomFormAccess = class(TCustomForm);
  1219. function GetClientSizeEx(Control: TWinControl): TPoint;
  1220. var
  1221. R: TRect;
  1222. begin
  1223. if (Control is TCustomForm) and (TCustomFormAccess(Control).FormStyle = fsMDIForm)
  1224. and not (csDesigning in Control.ComponentState) then
  1225. GetWindowRect(TCustomFormAccess(Control).ClientHandle, R)
  1226. else
  1227. R := Control.ClientRect;
  1228. Result.X := R.Right - R.Left;
  1229. Result.Y := R.Bottom - R.Top;
  1230. end;
  1231. procedure InitializeStock;
  1232. var
  1233. NonClientMetrics: TNonClientMetrics;
  1234. begin
  1235. StockBitmap1 := TBitmap.Create;
  1236. StockBitmap1.PixelFormat := pf32bit;
  1237. StockBitmap2 := TBitmap.Create;
  1238. StockBitmap2.PixelFormat := pf32bit;
  1239. StockMonoBitmap := TBitmap.Create;
  1240. StockMonoBitmap.Monochrome := True;
  1241. StockCompatibleBitmap := TBitmap.Create;
  1242. StockCompatibleBitmap.Width := 8;
  1243. StockCompatibleBitmap.Height := 8;
  1244. SmCaptionFont := TFont.Create;
  1245. NonClientMetrics.cbSize := SizeOf(NonClientMetrics);
  1246. if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
  1247. SmCaptionFont.Handle := CreateFontIndirect(NonClientMetrics.lfSmCaptionFont);
  1248. end;
  1249. procedure FinalizeStock;
  1250. begin
  1251. SmCaptionFont.Free;
  1252. SmCaptionFont := nil;
  1253. StockCompatibleBitmap.Free;
  1254. StockMonoBitmap.Free;
  1255. StockBitmap2.Free;
  1256. StockBitmap1.Free;
  1257. end;
  1258. procedure RecreateStock;
  1259. begin
  1260. FinalizeStock;
  1261. InitializeStock;
  1262. end;
  1263. { TShadow } ////////////////////////////////////////////////////////////////////
  1264. procedure TShadow.Clear(const R: TRect);
  1265. begin
  1266. FClearRect := R;
  1267. end;
  1268. constructor TShadow.Create(const Bounds: TRect; Opacity: Byte; LoColor: Boolean; Edges: TShadowEdges);
  1269. begin
  1270. inherited Create(nil);
  1271. Hide;
  1272. ParentWindow := Application.Handle;
  1273. BoundsRect := Bounds;
  1274. Color := clBtnShadow;
  1275. FOpacity := Opacity;
  1276. FEdges := Edges;
  1277. FSaveBits := False;
  1278. if LoColor then FStyle := ssFlat
  1279. else FStyle := ssLayered;
  1280. end;
  1281. procedure TShadow.CreateParams(var Params: TCreateParams);
  1282. begin
  1283. inherited;
  1284. with Params do
  1285. begin
  1286. Style := (Style and not (WS_CHILD or WS_GROUP or WS_TABSTOP)) or WS_POPUP;
  1287. ExStyle := ExStyle or WS_EX_TOOLWINDOW;
  1288. if FSaveBits then WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
  1289. end;
  1290. end;
  1291. procedure TShadow.GradB(const R: TRect);
  1292. var
  1293. J, W, H: Integer;
  1294. V: Cardinal;
  1295. P: ^Cardinal;
  1296. begin
  1297. W := R.Right - R.Left;
  1298. H := R.Bottom - R.Top;
  1299. for J := 0 to H - 1 do
  1300. begin
  1301. P := FBuffer.ScanLine[J + R.Top];
  1302. Inc(P, R.Left);
  1303. V := (255 - J shl 8 div H) shl 24;
  1304. FillLongword(P^, W, V);
  1305. end;
  1306. end;
  1307. procedure TShadow.GradBL(const R: TRect);
  1308. var
  1309. I, J, W, H, CX, CY, D, DMax, A, B: Integer;
  1310. P: ^Cardinal;
  1311. begin
  1312. W := R.Right - R.Left;
  1313. H := R.Bottom - R.Top;
  1314. DMax := W;
  1315. if H > W then DMax := H;
  1316. CX := DMax - 1;
  1317. CY := H - DMax;
  1318. for J := 0 to H - 1 do
  1319. begin
  1320. P := FBuffer.ScanLine[J + R.Top];
  1321. Inc(P, R.Left);
  1322. for I := 0 to W - 1 do
  1323. begin
  1324. A := Abs(I - CX);
  1325. B := Abs(J - CY);
  1326. D := A;
  1327. if B > A then D := B;
  1328. D := (A + B + D) * 128 div DMax;
  1329. if D < 255 then P^ := (255 - D) shl 24
  1330. else P^ := 0;
  1331. Inc(P);
  1332. end;
  1333. end;
  1334. end;
  1335. procedure TShadow.GradBR(const R: TRect);
  1336. var
  1337. I, J, W, H, CX, CY, D, DMax, A, B: Integer;
  1338. P: ^Cardinal;
  1339. begin
  1340. W := R.Right - R.Left;
  1341. H := R.Bottom - R.Top;
  1342. DMax := W;
  1343. if H > W then DMax := H;
  1344. CX := W - DMax;
  1345. CY := H - DMax;
  1346. for J := 0 to H - 1 do
  1347. begin
  1348. P := FBuffer.ScanLine[J + R.Top];
  1349. Inc(P, R.Left);
  1350. for I := 0 to W - 1 do
  1351. begin
  1352. A := Abs(I - CX);
  1353. B := Abs(J - CY);
  1354. D := A;
  1355. if B > A then D := B;
  1356. D := (A + B + D) * 128 div DMax;
  1357. if D < 255 then P^ := (255 - D) shl 24
  1358. else P^ := 0;
  1359. Inc(P);
  1360. end;
  1361. end;
  1362. end;
  1363. procedure TShadow.GradR(const R: TRect);
  1364. var
  1365. I, J, W: Integer;
  1366. P: ^Cardinal;
  1367. ScanLine: array of Cardinal;
  1368. begin
  1369. W := R.Right - R.Left;
  1370. SetLength(ScanLine, W);
  1371. for I := 0 to W - 1 do
  1372. ScanLine[I] :=(255 - I shl 8 div W) shl 24;
  1373. for J := R.Top to R.Bottom - 1 do
  1374. begin
  1375. P := FBuffer.ScanLine[J];
  1376. Inc(P, R.Left);
  1377. MoveLongword(ScanLine[0], P^, W);
  1378. end;
  1379. end;
  1380. procedure TShadow.GradTR(const R: TRect);
  1381. var
  1382. I, J, W, H, CX, CY, D, DMax, A, B: Integer;
  1383. P: ^Cardinal;
  1384. begin
  1385. W := R.Right - R.Left;
  1386. H := R.Bottom - R.Top;
  1387. DMax := W;
  1388. if H > W then DMax := H;
  1389. CX := W - DMax;
  1390. CY := DMax - 1;
  1391. for J := 0 to H - 1 do
  1392. begin
  1393. P := FBuffer.ScanLine[J + R.Top];
  1394. Inc(P, R.Left);
  1395. for I := 0 to W - 1 do
  1396. begin
  1397. A := Abs(I - CX);
  1398. B := Abs(J - CY);
  1399. D := A;
  1400. if B > A then D := B;
  1401. D := (A + B + D) * 128 div DMax;
  1402. if D < 255 then P^ := (255 - D) shl 24
  1403. else P^ := 0;
  1404. Inc(P);
  1405. end;
  1406. end;
  1407. end;
  1408. procedure TShadow.Render;
  1409. var
  1410. DstDC: HDC;
  1411. SrcPos, DstPos: TPoint;
  1412. TheSize: TSize;
  1413. BlendFunc: TBlendFunction;
  1414. begin
  1415. if FStyle <> ssLayered then Exit;
  1416. SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or $00080000{WS_EX_LAYERED});
  1417. DstDC := GetDC(0);
  1418. try
  1419. SrcPos := Point(0, 0);
  1420. with BoundsRect do
  1421. begin
  1422. DstPos := Point(Left, Top);
  1423. TheSize.cx := Right - Left;
  1424. TheSize.cy := Bottom - Top;
  1425. end;
  1426. BlendFunc.BlendOp := 0;
  1427. BlendFunc.BlendFlags := 0;
  1428. BlendFunc.SourceConstantAlpha := FOpacity;
  1429. BlendFunc.AlphaFormat := 1;
  1430. FBuffer := TBitmap.Create;
  1431. FBuffer.PixelFormat := pf32bit;
  1432. FBuffer.Width := TheSize.cx;
  1433. FBuffer.Height := TheSize.cy;
  1434. FillBuffer;
  1435. UpdateLayeredWindow(
  1436. Handle,
  1437. DstDC,
  1438. @DstPos,
  1439. @TheSize,
  1440. FBuffer.Canvas.Handle,
  1441. @SrcPos,
  1442. 0,
  1443. @BlendFunc,
  1444. $00000002{ULW_ALPHA});
  1445. FBuffer.Free;
  1446. finally
  1447. ReleaseDC(0, DstDC);
  1448. end;
  1449. end;
  1450. procedure TShadow.Show(ParentHandle: HWND);
  1451. begin
  1452. SetWindowPos(Handle, ParentHandle, 0, 0, 0, 0,
  1453. SWP_NOACTIVATE or SWP_NOSENDCHANGING or SWP_NOMOVE or
  1454. SWP_NOOWNERZORDER or SWP_NOSIZE or SWP_SHOWWINDOW);
  1455. end;
  1456. procedure TShadow.WMNCHitTest(var Message: TMessage);
  1457. begin
  1458. Message.Result := HTTRANSPARENT;
  1459. end;
  1460. { THorzShadow }
  1461. procedure THorzShadow.FillBuffer;
  1462. var
  1463. R: TRect;
  1464. L1, L2, L3: Integer;
  1465. begin
  1466. if seTopLeft in FEdges then L1 := Height else L1 := 0;
  1467. if seBottomRight in FEdges then L3 := Height else L3 := 0;
  1468. if L1 + L3 > Width then
  1469. begin
  1470. if (L1 > 0) and (L3 > 0) then
  1471. begin
  1472. L1 := Width div 2;
  1473. L3 := L1;
  1474. end
  1475. else if L1 > 0 then L1 := Width
  1476. else if L3 > 0 then L3 := Width;
  1477. end;
  1478. L2 := Width - L1 - L3;
  1479. R := Rect(0, 0, Width, Height);
  1480. R.Right := R.Left + L1;
  1481. if L1 > 0 then GradBL(R);
  1482. R.Left := R.Right;
  1483. R.Right := R.Left + L2;
  1484. if L2 > 0 then GradB(R);
  1485. if L3 > 0 then
  1486. begin
  1487. R.Left := R.Right;
  1488. R.Right := R.Left + L3;
  1489. GradBR(R);
  1490. end;
  1491. end;
  1492. { TVertShadow }
  1493. procedure TVertShadow.FillBuffer;
  1494. var
  1495. R: TRect;
  1496. L1, L2, L3: Integer;
  1497. begin
  1498. if seTopLeft in FEdges then L1 := Width else L1 := 0;
  1499. if seBottomRight in FEdges then L3 := Width else L3 := 0;
  1500. if L1 + L3 > Height then
  1501. begin
  1502. if (L1 > 0) and (L3 > 0) then
  1503. begin
  1504. L1 := Height div 2;
  1505. L3 := L1;
  1506. end
  1507. else if L1 > 0 then L1 := Height
  1508. else if L3 > 0 then L3 := Height;
  1509. end;
  1510. L2 := Height - L1 - L3;
  1511. R := Rect(0, 0, Width, Height);
  1512. R.Bottom := R.Top + L1;
  1513. if L1 > 0 then GradTR(R);
  1514. R.Top := R.Bottom;
  1515. R.Bottom := R.Top + L2;
  1516. if L2 > 0 then GradR(R);
  1517. if L3 > 0 then
  1518. begin
  1519. R.Top := R.Bottom;
  1520. R.Bottom := R.Top + L3;
  1521. GradBR(R);
  1522. end;
  1523. end;
  1524. { TShadows }
  1525. constructor TShadows.Create(R1, R2: TRect; TheSize: Integer; Opacity: Byte; LoColor: Boolean);
  1526. var
  1527. R: TRect;
  1528. R1Valid, R2Valid: Boolean;
  1529. begin
  1530. if LoColor then
  1531. begin
  1532. TheSize := TheSize div 2;
  1533. end;
  1534. R1Valid := not IsRectEmpty(R1);
  1535. R2Valid := not IsRectEmpty(R2);
  1536. if not (R1Valid or R2Valid) then Exit;
  1537. if R1Valid xor R2Valid then
  1538. begin
  1539. { A simple square shadow }
  1540. if R1Valid then R := R1 else R:= R2;
  1541. with R do
  1542. begin
  1543. V1 := TVertShadow.Create(Rect(Right, Top + TheSize, Right + TheSize, Bottom), Opacity, LoColor, [seTopLeft]);
  1544. H1 := THorzShadow.Create(Rect(Left + TheSize, Bottom, Right + TheSize, Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight])
  1545. end;
  1546. end
  1547. else
  1548. begin
  1549. if (R1.Bottom <= R2.Top + 2) or (R1.Top >= R2.Bottom - 2) then
  1550. begin
  1551. if R1.Top > R2.Top then
  1552. begin
  1553. R := R2;
  1554. R2 := R1;
  1555. R1 := R;
  1556. end;
  1557. if R1.Left + TheSize < R2.Left then
  1558. H1 := THorzShadow.Create(Rect(R1.Left + TheSize, R1.Bottom, R2.Left, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft]);
  1559. H2 := THorzShadow.Create(Rect(R2.Left + TheSize, R2.Bottom, R2.Right + TheSize, R2.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
  1560. V1 := TVertShadow.Create(Rect(R1.Right, R1.Top + TheSize, R1.Right + TheSize, R1.Bottom), Opacity, LoColor, [seTopLeft]);
  1561. if R1.Right > R2.Right then
  1562. H3 := THorzShadow.Create(Rect(R2.Right, R1.Bottom, R1.Right + TheSize, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
  1563. if R1.Right + TheSize < R2.Right then
  1564. V2 := TVertShadow.Create(Rect(R2.Right, R2.Top + TheSize, R2.Right + TheSize, R2.Bottom), Opacity, LoColor, [seTopLeft])
  1565. else
  1566. V2 := TVertShadow.Create(Rect(R2.Right, R2.Top + 1, R2.Right + TheSize, R2.Bottom), Opacity, LoColor, []);
  1567. end
  1568. else if (R1.Right <= R2.Left + 2) or (R1.Left >= R2.Right - 2) then
  1569. begin
  1570. if R1.Left > R2.Left then
  1571. begin
  1572. R := R2;
  1573. R2 := R1;
  1574. R1 := R;
  1575. end;
  1576. if R1.Top + TheSize < R2.Top then
  1577. V1 := TVertShadow.Create(Rect(R1.Right, R1.Top + TheSize, R1.Right + TheSize, R2.Top), Opacity, LoColor, [seTopLeft]);
  1578. V2 := TVertShadow.Create(Rect(R2.Right, R2.Top + TheSize, R2.Right + TheSize, R2.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
  1579. H1 := THorzShadow.Create(Rect(R1.Left + TheSize, R1.Bottom, R1.Right, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft]);
  1580. if R1.Bottom > R2.Bottom then
  1581. V3 := TVertShadow.Create(Rect(R1.Right, R2.Bottom, R1.Right + TheSize, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
  1582. if R1.Bottom + TheSize < R2.Bottom then
  1583. H2 := THorzShadow.Create(Rect(R2.Left + TheSize, R2.Bottom, R2.Right, R2.Bottom + TheSize), Opacity, LoColor, [seTopLeft])
  1584. else
  1585. H2 := THorzShadow.Create(Rect(R2.Left, R2.Bottom, R2.Right, R2.Bottom + TheSize), Opacity, LoColor, []);
  1586. end;
  1587. end;
  1588. if V1 <> nil then V1.Render;
  1589. if H1 <> nil then H1.Render;
  1590. if V2 <> nil then V2.Render;
  1591. if H2 <> nil then H2.Render;
  1592. if V3 <> nil then V3.Render;
  1593. if H3 <> nil then H3.Render;
  1594. SetSaveBits(True);
  1595. end;
  1596. destructor TShadows.Destroy;
  1597. begin
  1598. H3.Free;
  1599. V3.Free;
  1600. H2.Free;
  1601. V2.Free;
  1602. H1.Free;
  1603. V1.Free;
  1604. inherited;
  1605. end;
  1606. procedure TShadows.SetSaveBits(Value: Boolean);
  1607. begin
  1608. FSaveBits := Value;
  1609. if V1 <> nil then V1.FSaveBits := Value;
  1610. if H1 <> nil then H1.FSaveBits := Value;
  1611. if V2 <> nil then V2.FSaveBits := Value;
  1612. if H2 <> nil then H2.FSaveBits := Value;
  1613. if V3 <> nil then V3.FSaveBits := Value;
  1614. if H3 <> nil then H3.FSaveBits := Value;
  1615. end;
  1616. procedure TShadows.Show(ParentHandle: HWND);
  1617. begin
  1618. if V1 <> nil then V1.Show(ParentHandle);
  1619. if H1 <> nil then H1.Show(ParentHandle);
  1620. if V2 <> nil then V2.Show(ParentHandle);
  1621. if H2 <> nil then H2.Show(ParentHandle);
  1622. if V3 <> nil then V3.Show(ParentHandle);
  1623. if H3 <> nil then H3.Show(ParentHandle);
  1624. end;
  1625. { Gradients } //////////////////////////////////////////////////////////////////
  1626. const
  1627. GRADIENT_CACHE_SIZE = 16;
  1628. type
  1629. PRGBQuad = ^TRGBQuad;
  1630. TRGBQuad = Integer;
  1631. PRGBQuadArray = ^TRGBQuadArray;
  1632. TRGBQuadArray = array [0..0] of TRGBQuad;
  1633. var
  1634. GradientCache: array [0..GRADIENT_CACHE_SIZE] of array of TRGBQuad;
  1635. NextCacheIndex: Integer = 0;
  1636. function FindGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
  1637. begin
  1638. Assert(Size > 0);
  1639. Result := GRADIENT_CACHE_SIZE - 1;
  1640. while Result >= 0 do
  1641. begin
  1642. if (Length(GradientCache[Result]) = Size) and
  1643. (GradientCache[Result][0] = CL) and
  1644. (GradientCache[Result][Length(GradientCache[Result]) - 1] = CR) then Exit;
  1645. Dec(Result);
  1646. end;
  1647. end;
  1648. function MakeGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
  1649. var
  1650. R1, G1, B1: Integer;
  1651. R2, G2, B2: Integer;
  1652. R, G, B: Integer;
  1653. I: Integer;
  1654. Bias: Integer;
  1655. begin
  1656. Assert(Size > 0);
  1657. Result := NextCacheIndex;
  1658. Inc(NextCacheIndex);
  1659. if NextCacheIndex >= GRADIENT_CACHE_SIZE then NextCacheIndex := 0;
  1660. R1 := CL and $FF;
  1661. G1 := CL shr 8 and $FF;
  1662. B1 := CL shr 16 and $FF;
  1663. R2 := CR and $FF - R1;
  1664. G2 := CR shr 8 and $FF - G1;
  1665. B2 := CR shr 16 and $FF - B1;
  1666. SetLength(GradientCache[Result], Size);
  1667. Dec(Size);
  1668. Bias := Size div 2;
  1669. if Size > 0 then
  1670. for I := 0 to Size do
  1671. begin
  1672. R := R1 + (R2 * I + Bias) div Size;
  1673. G := G1 + (G2 * I + Bias) div Size;
  1674. B := B1 + (B2 * I + Bias) div Size;
  1675. GradientCache[Result][I] := R + G shl 8 + B shl 16;
  1676. end
  1677. else
  1678. begin
  1679. R := R1 + R2 div 2;
  1680. G := G1 + G2 div 2;
  1681. B := B1 + B2 div 2;
  1682. GradientCache[Result][0] := R + G shl 8 + B shl 16;
  1683. end;
  1684. end;
  1685. function GetGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
  1686. begin
  1687. Result := FindGradient(Size, CL, CR);
  1688. if Result < 0 then Result := MakeGradient(Size, CL, CR);
  1689. end;
  1690. { GradFill function }
  1691. procedure GradFill(DC: HDC; ARect: TRect; ClrTopLeft, ClrBottomRight: TColor; Kind: TGradientKind);
  1692. const
  1693. GRAD_MODE: array [TGradientKind] of DWORD = (GRADIENT_FILL_RECT_H, GRADIENT_FILL_RECT_V);
  1694. W: array [TGradientKind] of Integer = (2, 1);
  1695. H: array [TGradientKind] of Integer = (1, 2);
  1696. type
  1697. TriVertex = packed record
  1698. X, Y: Longint;
  1699. R, G, B, A: Word;
  1700. end;
  1701. var
  1702. V: array [0..1] of TriVertex;
  1703. GR: GRADIENT_RECT;
  1704. begin
  1705. if not RectVisible(DC, ARect) then Exit;
  1706. ClrTopLeft := ColorToRGB(ClrTopLeft);
  1707. ClrBottomRight := ColorToRGB(ClrBottomRight);
  1708. with V[0] do
  1709. begin
  1710. X := ARect.Left;
  1711. Y := ARect.Top;
  1712. R := ClrTopLeft shl 8 and $FF00;
  1713. G := ClrTopLeft and $FF00;
  1714. B := ClrTopLeft shr 8 and $FF00;
  1715. A := 0;
  1716. end;
  1717. with V[1] do
  1718. begin
  1719. X := ARect.Right;
  1720. Y := ARect.Bottom;
  1721. R := ClrBottomRight shl 8 and $FF00;
  1722. G := ClrBottomRight and $FF00;
  1723. B := ClrBottomRight shr 8 and $FF00;
  1724. A := 0;
  1725. end;
  1726. GR.UpperLeft := 0; GR.LowerRight := 1;
  1727. GradientFill(DC, @V, 2, @GR, 1, GRAD_MODE[Kind]);
  1728. end;
  1729. { Brushed Fill } ///////////////////////////////////////////////////////////////
  1730. { Templates }
  1731. const
  1732. NUM_TEMPLATES = 8;
  1733. MIN_TEMPLATE_SIZE = 100;
  1734. MAX_TEMPLATE_SIZE = 200;
  1735. var
  1736. ThreadTemplates: array [0..NUM_TEMPLATES - 1] of array of Integer;
  1737. RandThreadIndex: array [0..1023] of Integer;
  1738. RandThreadPositions: array [0..1023] of Integer;
  1739. procedure InitializeBrushedFill;
  1740. const
  1741. Pi = 3.14159265358987;
  1742. var
  1743. TemplateIndex, Size, I, V, V1, V2: Integer;
  1744. T, R12, R13, R14, R21, R22, R23, R24: Single;
  1745. begin
  1746. { Make thread templates }
  1747. for TemplateIndex := 0 to NUM_TEMPLATES - 1 do
  1748. begin
  1749. Size := (MIN_TEMPLATE_SIZE + Random(MAX_TEMPLATE_SIZE - MIN_TEMPLATE_SIZE + 1)) div 2;
  1750. SetLength(ThreadTemplates[TemplateIndex], Size * 2);
  1751. R12 := Random * 2 * Pi;
  1752. R13 := Random * 2 * Pi;
  1753. R14 := Random * 2 * Pi;
  1754. R21 := Random * 2 * Pi;
  1755. R22 := Random * 2 * Pi;
  1756. R23 := Random * 2 * Pi;
  1757. R24 := Random * 2 * Pi;
  1758. for I := 0 to Size - 1 do
  1759. begin
  1760. T := 2 * Pi * I / Size;
  1761. V1 := Round(150 * Sin(T) + 100 * Sin(2 * T + R12) + 50 * Sin(3 * T + R13) + 20 * Sin(4 * T + R14));
  1762. if V1 > 255 then V1 := 255;
  1763. if V1 < -255 then V1 := -255;
  1764. V2 := Round(150 * Sin(T + R21) + 100 * Sin(2 * T + R22) + 50 * Sin(3 * T + R23) + 20 * Sin(4 * T + R24));
  1765. if V2 > 255 then V2 := 255;
  1766. if V2 < -255 then V2 := -255;
  1767. if Abs(V2 - V1) > 300 then
  1768. begin
  1769. V := (V1 + V2) div 2;
  1770. V1 := V - 150;
  1771. V2 := V + 150;
  1772. end;
  1773. ThreadTemplates[TemplateIndex][I * 2] := Min(V1, V2);
  1774. ThreadTemplates[TemplateIndex][I * 2 + 1] := Max(V1, V2);
  1775. end;
  1776. end;
  1777. { Initialize Rand arrays }
  1778. for I := 0 to 1023 do
  1779. begin
  1780. RandThreadIndex[I] := Random(NUM_TEMPLATES);
  1781. V1 := Random(Length(ThreadTemplates[RandThreadIndex[I]])) and not $1;
  1782. if Odd(I) then Inc(V1);
  1783. RandThreadPositions[I] := V1;
  1784. end;
  1785. end;
  1786. { Cache }
  1787. const
  1788. THREAD_CACHE_SIZE = 16;
  1789. type
  1790. TThreadCacheItem = record
  1791. BaseColor: TColorRef;
  1792. Roughness: Integer;
  1793. Bitmaps: array [0..NUM_TEMPLATES - 1] of HBITMAP;
  1794. end;
  1795. var
  1796. ThreadCache: array [0..THREAD_CACHE_SIZE] of TThreadCacheItem;
  1797. NextCacheEntry: Integer = 0;
  1798. procedure ClearCacheItem(var CacheItem: TThreadCacheItem);
  1799. var
  1800. I: Integer;
  1801. begin
  1802. with CacheItem do
  1803. begin
  1804. BaseColor := $FFFFFFFF;
  1805. Roughness := -1;
  1806. for I := NUM_TEMPLATES - 1 downto 0 do
  1807. begin
  1808. if Bitmaps[I] <> 0 then
  1809. begin
  1810. DeleteObject(Bitmaps[I]);
  1811. Bitmaps[I] := 0;
  1812. end;
  1813. end;
  1814. end;
  1815. end;
  1816. procedure ResetBrushedFillCache;
  1817. var
  1818. I: Integer;
  1819. begin
  1820. { Should be called each time the screen parameters change }
  1821. for I := THREAD_CACHE_SIZE - 1 downto 0 do ClearCacheItem(ThreadCache[I]);
  1822. end;
  1823. procedure FinalizeBrushedFill;
  1824. begin
  1825. ResetBrushedFillCache;
  1826. end;
  1827. procedure MakeCacheItem(var CacheItem: TThreadCacheItem; Color: TColorRef; Roughness: Integer);
  1828. var
  1829. TemplateIndex, Size, I, V: Integer;
  1830. CR, CG, CB: Integer;
  1831. R, G, B: Integer;
  1832. ScreenDC: HDC;
  1833. BMI: TBitmapInfo;
  1834. Bits: PRGBQuadArray;
  1835. DIBSection: HBITMAP;
  1836. DIBDC, CacheDC: HDC;
  1837. begin
  1838. ScreenDC := GetDC(0);
  1839. FillChar(BMI, SizeOf(TBitmapInfo), 0);
  1840. with BMI.bmiHeader do
  1841. begin
  1842. biSize := SizeOf(TBitmapInfoHeader);
  1843. biPlanes := 1;
  1844. biCompression := BI_RGB;
  1845. biWidth := MAX_TEMPLATE_SIZE;
  1846. biHeight := -1;
  1847. biBitCount := 32;
  1848. end;
  1849. DIBSection := CreateDIBSection(0, BMI, DIB_RGB_COLORS, Pointer(Bits), 0, 0);
  1850. DIBDC := CreateCompatibleDC(0);
  1851. SelectObject(DIBDC, DIBSection);
  1852. CacheDC := CreateCompatibleDC(0);
  1853. CR := Color shl 8 and $FF00;
  1854. CG := Color and $FF00;
  1855. CB := Color shr 8 and $FF00;
  1856. try
  1857. for TemplateIndex := 0 to NUM_TEMPLATES - 1 do
  1858. begin
  1859. CacheItem.BaseColor := Color;
  1860. CacheItem.Roughness := Roughness;
  1861. Size := Length(ThreadTemplates[TemplateIndex]);
  1862. if CacheItem.Bitmaps[TemplateIndex] = 0 then
  1863. CacheItem.Bitmaps[TemplateIndex] := CreateCompatibleBitmap(ScreenDC, Size, 1);
  1864. SelectObject(CacheDC, CacheItem.Bitmaps[TemplateIndex]);
  1865. for I := 0 to Size - 1 do
  1866. begin
  1867. V := ThreadTemplates[TemplateIndex][I];
  1868. R := CR + V * Roughness;
  1869. G := CG + V * Roughness;
  1870. B := CB + V * Roughness;
  1871. if R < 0 then R := 0;
  1872. if G < 0 then G := 0;
  1873. if B < 0 then B := 0;
  1874. if R > $EF00 then R := $EF00;
  1875. if G > $EF00 then G := $EF00;
  1876. if B > $EF00 then B := $EF00;
  1877. Bits^[I] := (R and $FF00 + (G and $FF00) shl 8 + (B and $FF00) shl 16) shr 8;
  1878. end;
  1879. BitBlt(CacheDC, 0, 0, Size, 1, DIBDC, 0, 0, SRCCOPY);
  1880. end;
  1881. finally
  1882. DeleteDC(CacheDC);
  1883. DeleteDC(DIBDC);
  1884. DeleteObject(DIBSection);
  1885. ReleaseDC(0, ScreenDC);
  1886. end;
  1887. end;
  1888. function FindCacheItem(Color: TColorRef; Roughness: Integer): Integer;
  1889. begin
  1890. Result := THREAD_CACHE_SIZE - 1;
  1891. while Result >= 0 do
  1892. if (ThreadCache[Result].BaseColor = Color) and (ThreadCache[Result].Roughness = Roughness) then Exit
  1893. else Dec(Result);
  1894. end;
  1895. function GetCacheItem(Color: TColorRef; Roughness: Integer): Integer;
  1896. begin
  1897. Result := FindCacheItem(Color, Roughness);
  1898. if Result >= 0 then Exit
  1899. else
  1900. begin
  1901. Result := NextCacheEntry;
  1902. MakeCacheItem(ThreadCache[Result], Color, Roughness);
  1903. NextCacheEntry := (NextCacheEntry + 1) mod THREAD_CACHE_SIZE;
  1904. end;
  1905. end;
  1906. procedure BrushedFill(DC: HDC; Origin: PPoint; ARect: TRect; Color: TColor; Roughness: Integer);
  1907. const
  1908. ZeroOrigin: TPoint = (X: 0; Y: 0);
  1909. var
  1910. CR: TColorRef;
  1911. X, Y: Integer;
  1912. CacheIndex: Integer;
  1913. TemplateIndex: Integer;
  1914. CacheDC: HDC;
  1915. Size: Integer;
  1916. BoxR: TRect;
  1917. begin
  1918. if (Color = clNone) or not RectVisible(DC, ARect) then Exit;
  1919. CR := GetBGR(ColorToRGB(Color));
  1920. if Origin = nil then Origin := @ZeroOrigin;
  1921. CacheIndex := GetCacheItem(CR, Roughness);
  1922. GetClipBox(DC, BoxR);
  1923. IntersectRect(ARect, ARect, BoxR);
  1924. SaveDC(DC);
  1925. with ARect do IntersectClipRect(DC, Left, Top, Right, Bottom);
  1926. CacheDC := CreateCompatibleDC(0);
  1927. for Y := ARect.Top to ARect.Bottom - 1 do
  1928. begin
  1929. TemplateIndex := RandThreadIndex[(65536 + Y - Origin.Y) mod 1024];
  1930. Size := Length(ThreadTemplates[TemplateIndex]);
  1931. X := -RandThreadPositions[(65536 + Y - Origin.Y) mod 1024] + Origin.X;
  1932. SelectObject(CacheDC, ThreadCache[CacheIndex].Bitmaps[TemplateIndex]);
  1933. while X < ARect.Right do
  1934. begin
  1935. if X + Size >= ARect.Left then BitBlt(DC, X, Y, Size, 1, CacheDC, 0, 0, SRCCOPY);
  1936. Inc(X, Size);
  1937. end;
  1938. end;
  1939. DeleteDC(CacheDC);
  1940. RestoreDC(DC, -1);
  1941. end;
  1942. initialization
  1943. InitializeStock;
  1944. InitializeBrushedFill;
  1945. ResetBrushedFillCache;
  1946. finalization
  1947. FinalizeBrushedFill;
  1948. FinalizeStock;
  1949. end.