TBXUtils.pas 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238
  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; HiContrast: Boolean);
  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; HiContrast: Boolean);
  882. {const
  883. CWeirdColor = $00203241;} {vb -}
  884. var
  885. ImageWidth, ImageHeight: Integer;
  886. I, J: Integer;
  887. Src, Dst: PColor;
  888. S, C: TColor;
  889. begin
  890. if not HiContrast then
  891. begin
  892. ImageList.Draw(Canvas, R.Left, R.Top, ImageIndex);
  893. Exit;
  894. end;
  895. ImageWidth := R.Right - R.Left;
  896. ImageHeight := R.Bottom - R.Top;
  897. with ImageList do
  898. begin
  899. if Width < ImageWidth then ImageWidth := Width;
  900. if Height < ImageHeight then ImageHeight := Height;
  901. end;
  902. StockBitmap1.Width := ImageWidth;
  903. StockBitmap1.Height := ImageHeight;
  904. StockBitmap2.Width := ImageWidth;
  905. StockBitmap2.Height := ImageHeight;
  906. BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  907. Canvas.Handle, R.Left, R.Top, SRCCOPY);
  908. {for J := 0 to ImageHeight - 1 do
  909. FillLongWord(StockBitmap2.ScanLine[J]^, ImageWidth, CWeirdColor);} {vb -}
  910. BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  911. Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
  912. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex);
  913. for J := 0 to ImageHeight - 1 do
  914. begin
  915. Src := StockBitmap2.ScanLine[J];
  916. Dst := StockBitmap1.ScanLine[J];
  917. for I := 0 to ImageWidth - 1 do
  918. begin
  919. {S := Src^ and $00FFFFFF;} {vb -}
  920. S := Src^; {vb +}
  921. {if S <> CWeirdColor then} {vb -}
  922. if S <> Dst^ then {vb +}
  923. begin
  924. {C := (S and $FF0000) shr 16 * 76 + (S and $00FF00) shr 8 * 150 +
  925. (S and $0000FF) * 29;} {vb -}
  926. C := (S and $00FF0000) shr 16 * 76 + (S and $0000FF00) shr 8 * 150 +
  927. (S and $000000FF) * 29; {vb +}
  928. if C > $FD00 then S := $000000
  929. else if C < $6400 then S := $FFFFFF;
  930. Dst^ := Lighten(S, 32);
  931. end;
  932. Inc(Src);
  933. Inc(Dst);
  934. end;
  935. end;
  936. BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
  937. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
  938. end;
  939. procedure BlendTBXIcon(Canvas: TCanvas; const R: TRect;
  940. ImageList: TCustomImageList; ImageIndex: Integer; Opacity: Byte);
  941. {const
  942. CWeirdColor = $00203241;} {vb -}
  943. var
  944. ImageWidth, ImageHeight: Integer;
  945. I, J: Integer;
  946. Src, Dst: ^Cardinal;
  947. S, C, CBRB, CBG: Cardinal;
  948. Wt1, Wt2: Cardinal;
  949. begin
  950. Wt2 := Opacity;
  951. Wt1 := 255 - Wt2;
  952. ImageWidth := R.Right - R.Left;
  953. ImageHeight := R.Bottom - R.Top;
  954. with ImageList do
  955. begin
  956. if Width < ImageWidth then ImageWidth := Width;
  957. if Height < ImageHeight then ImageHeight := Height;
  958. end;
  959. StockBitmap1.Width := ImageWidth;
  960. StockBitmap1.Height := ImageHeight;
  961. StockBitmap2.Width := ImageWidth;
  962. StockBitmap2.Height := ImageHeight;
  963. BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  964. Canvas.Handle, R.Left, R.Top, SRCCOPY);
  965. {BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  966. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);} {vb -}
  967. BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  968. Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
  969. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
  970. for J := 0 to ImageHeight - 1 do
  971. begin
  972. Src := StockBitmap2.ScanLine[J];
  973. Dst := StockBitmap1.ScanLine[J];
  974. for I := 0 to ImageWidth - 1 do
  975. begin
  976. S := Src^;
  977. if S <> Dst^ then
  978. begin
  979. CBRB := (Dst^ and $00FF00FF) * Wt1;
  980. CBG := (Dst^ and $0000FF00) * Wt1;
  981. {C := ((S and $FF00FF) * Wt2 + CBRB) and $FF00FF00 +
  982. ((S and $00FF00) * Wt2 + CBG) and $00FF0000;} {vb -}
  983. C := ((S and $00FF00FF) * Wt2 + CBRB) and $FF00FF00 +
  984. ((S and $0000FF00) * Wt2 + CBG) and $00FF0000; {vb +}
  985. Dst^ := C shr 8;
  986. end;
  987. Inc(Src);
  988. Inc(Dst);
  989. end;
  990. end;
  991. BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
  992. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
  993. end;
  994. procedure HighlightTBXIcon(Canvas: TCanvas; const R: TRect;
  995. ImageList: TCustomImageList; ImageIndex: Integer; HighlightColor: TColor; Amount: Byte);
  996. {const
  997. CWeirdColor = $00203241;} {vb -}
  998. var
  999. ImageWidth, ImageHeight: Integer;
  1000. I, J: Integer;
  1001. {Src, Dst: PColor;} {vb -}
  1002. Src, Dst: ^Cardinal; {vb +}
  1003. S, C: Cardinal;
  1004. CBRB, CBG: Cardinal;
  1005. W1, W2: Cardinal;
  1006. begin
  1007. ImageWidth := R.Right - R.Left;
  1008. ImageHeight := R.Bottom - R.Top;
  1009. with ImageList do
  1010. begin
  1011. if Width < ImageWidth then ImageWidth := Width;
  1012. if Height < ImageHeight then ImageHeight := Height;
  1013. end;
  1014. StockBitmap1.Width := ImageWidth;
  1015. StockBitmap1.Height := ImageHeight;
  1016. StockBitmap2.Width := ImageWidth;
  1017. StockBitmap2.Height := ImageHeight;
  1018. BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1019. Canvas.Handle, R.Left, R.Top, SRCCOPY);
  1020. {for J := 0 to ImageHeight - 1 do
  1021. FillLongWord(StockBitmap2.ScanLine[J]^, ImageWidth, CWeirdColor);} {vb -}
  1022. BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1023. Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
  1024. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex);
  1025. W2 := Amount;
  1026. W1 := 255 - W2;
  1027. HighlightColor := GetBGR(ColorToRGB(HighlightColor));
  1028. CBRB := (Cardinal(HighlightColor) and $00FF00FF) * W1;
  1029. CBG := (Cardinal(HighlightColor) and $0000FF00) * W1;
  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^ and $00FFFFFF;} {vb -}
  1037. S := Src^; {vb +}
  1038. {if S <> CWeirdColor then} {vb -}
  1039. if S <> Dst^ then {vb +}
  1040. begin
  1041. {C := ((S and $FF00FF) * W2 + CBRB) and $FF00FF00 +
  1042. ((S and $00FF00) * W2 + CBG) and $00FF0000;} {vb -}
  1043. C := ((S and $00FF00FF) * W2 + CBRB) and $FF00FF00 +
  1044. ((S and $0000FF00) * W2 + CBG) and $00FF0000; {vb +}
  1045. Dst^ := C shr 8;
  1046. end;
  1047. Inc(Src);
  1048. Inc(Dst);
  1049. end;
  1050. end;
  1051. BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
  1052. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
  1053. end;
  1054. procedure DrawTBXIconShadow(Canvas: TCanvas; const R: TRect;
  1055. ImageList: TCustomImageList; ImageIndex: Integer; Density: Integer);
  1056. const
  1057. D_DIV: array [0..2] of Cardinal = (3, 8, 20);
  1058. D_ADD: array [0..2] of Cardinal = (255 - 255 div 3, 255 - 255 div 8, 255 - 255 div 20);
  1059. var
  1060. ImageWidth, ImageHeight: Integer;
  1061. I, J: Integer;
  1062. Src, Dst: ^Cardinal;
  1063. S, C, CBRB, CBG: Cardinal;
  1064. begin
  1065. Assert(Density in [0..2]);
  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. StockBitmap1.Width := ImageWidth;
  1074. StockBitmap1.Height := ImageHeight;
  1075. StockBitmap2.Width := ImageWidth;
  1076. StockBitmap2.Height := ImageHeight;
  1077. BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1078. Canvas.Handle, R.Left, R.Top, SRCCOPY);
  1079. {BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1080. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);} {vb -}
  1081. BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1082. Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
  1083. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
  1084. for J := 0 to ImageHeight - 1 do
  1085. begin
  1086. Src := StockBitmap2.ScanLine[J];
  1087. Dst := StockBitmap1.ScanLine[J];
  1088. for I := 0 to ImageWidth - 1 do
  1089. begin
  1090. S := Src^;
  1091. if S <> Dst^ then
  1092. begin
  1093. CBRB := Dst^ and $00FF00FF;
  1094. CBG := Dst^ and $0000FF00;
  1095. {C := ((S and $FF0000) shr 16 * 29 + (S and $00FF00) shr 8 * 150 +
  1096. (S and $0000FF) * 76) shr 8;} {vb -}
  1097. C := ((S and $00FF0000) shr 16 * 29 + (S and $0000FF00) shr 8 * 150 +
  1098. (S and $000000FF) * 76) shr 8; {vb +}
  1099. C := C div D_DIV[Density] + D_ADD[Density];
  1100. Dst^ := ((CBRB * C and $FF00FF00) or (CBG * C and $00FF0000)) shr 8;
  1101. end;
  1102. Inc(Src);
  1103. Inc(Dst);
  1104. end;
  1105. end;
  1106. BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
  1107. StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
  1108. end;
  1109. procedure DrawTBXIconFlatShadow(Canvas: TCanvas; const R: TRect;
  1110. ImageList: TCustomImageList; ImageIndex: Integer; ShadowColor: TColor);
  1111. const
  1112. CShadowThreshold = 180 * 256;
  1113. var
  1114. ImageWidth, ImageHeight: Integer;
  1115. I, J: Integer;
  1116. P: ^Cardinal;
  1117. C: Cardinal;
  1118. SrcDC, DstDC: HDC;
  1119. begin
  1120. ImageWidth := R.Right - R.Left;
  1121. ImageHeight := R.Bottom - R.Top;
  1122. with ImageList do
  1123. begin
  1124. if Width < ImageWidth then ImageWidth := Width;
  1125. if Height < ImageHeight then ImageHeight := Height;
  1126. end;
  1127. StockBitmap2.Width := ImageWidth;
  1128. StockBitmap2.Height := ImageHeight;
  1129. StockBitmap2.Canvas.Brush.Color := clWhite;
  1130. StockBitmap2.Canvas.FillRect(Rect(0, 0, ImageWidth, ImageHeight));
  1131. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
  1132. for J := 0 to ImageHeight - 1 do
  1133. begin
  1134. P := StockBitmap2.ScanLine[J];
  1135. for I := 0 to ImageWidth - 1 do
  1136. begin
  1137. C := P^ and $00FFFFFF;
  1138. if C <> $0 then
  1139. begin
  1140. C := (C and $FF0000) shr 16 * 76 + (C and $00FF00) shr 8 * 150 + (C and $0000FF) * 29;
  1141. if C > CShadowThreshold then P^ := $00FFFFFF
  1142. else P^ := $00000000;
  1143. end;
  1144. Inc(P);
  1145. end;
  1146. end;
  1147. StockMonoBitmap.Width := ImageWidth;
  1148. StockMonoBitmap.Height := ImageHeight;
  1149. StockMonoBitmap.Canvas.Brush.Color := clBlack;
  1150. BitBlt(StockMonoBitmap.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1151. StockBitmap2.Canvas.Handle, 0, 0, SRCCOPY);
  1152. SrcDC := StockMonoBitmap.Canvas.Handle;
  1153. Canvas.Brush.Color := ColorToRGB(ShadowColor);
  1154. DstDC := Canvas.Handle;
  1155. Windows.SetTextColor(DstDC, clWhite);
  1156. Windows.SetBkColor(DstDC, clBlack);
  1157. BitBlt(DstDC, R.Left, R.Top, ImageWidth, ImageHeight, SrcDC, 0, 0, ROP_DSPDxax);
  1158. end;
  1159. procedure DrawTBXIconFullShadow(Canvas: TCanvas; const R: TRect;
  1160. ImageList: TCustomImageList; ImageIndex: Integer; ShadowColor: TColor);
  1161. const
  1162. CWeirdColor = $00203241;
  1163. var
  1164. ImageWidth, ImageHeight: Integer;
  1165. I, J: Integer;
  1166. P: ^Cardinal;
  1167. C: Cardinal;
  1168. SrcDC, DstDC: HDC;
  1169. begin
  1170. ImageWidth := R.Right - R.Left;
  1171. ImageHeight := R.Bottom - R.Top;
  1172. with ImageList do
  1173. begin
  1174. if Width < ImageWidth then ImageWidth := Width;
  1175. if Height < ImageHeight then ImageHeight := Height;
  1176. end;
  1177. StockBitmap2.Width := ImageWidth;
  1178. StockBitmap2.Height := ImageHeight;
  1179. for J := 0 to ImageHeight - 1 do
  1180. FillLongWord(StockBitmap2.ScanLine[J]^, ImageWidth, CWeirdColor);
  1181. ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
  1182. for J := 0 to ImageHeight - 1 do
  1183. begin
  1184. P := StockBitmap2.ScanLine[J];
  1185. for I := 0 to ImageWidth - 1 do
  1186. begin
  1187. C := P^ and $00FFFFFF;
  1188. if C <> CWeirdColor then P^ := $00000000
  1189. else P^ := $00FFFFFF;
  1190. Inc(P);
  1191. end;
  1192. end;
  1193. StockMonoBitmap.Width := ImageWidth;
  1194. StockMonoBitmap.Height := ImageHeight;
  1195. StockMonoBitmap.Canvas.Brush.Color := clBlack;
  1196. BitBlt(StockMonoBitmap.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
  1197. StockBitmap2.Canvas.Handle, 0, 0, SRCCOPY);
  1198. SrcDC := StockMonoBitmap.Canvas.Handle;
  1199. Canvas.Brush.Color := ColorToRGB(ShadowColor);
  1200. DstDC := Canvas.Handle;
  1201. Windows.SetTextColor(DstDC, clWhite);
  1202. Windows.SetBkColor(DstDC, clBlack);
  1203. BitBlt(DstDC, R.Left, R.Top, ImageWidth, ImageHeight, SrcDC, 0, 0, ROP_DSPDxax);
  1204. end;
  1205. procedure DrawGlyph(DC: HDC; X, Y: Integer; ImageList: TCustomImageList; ImageIndex: Integer; Color: TColor);
  1206. var
  1207. B: TBitmap;
  1208. OldTextColor, OldBkColor: Longword;
  1209. OldBrush, Brush: HBrush;
  1210. begin
  1211. if Color = clNone then Exit;
  1212. B := TBitmap.Create;
  1213. B.Monochrome := True;
  1214. ImageList.GetBitmap(ImageIndex, B);
  1215. OldTextColor := SetTextColor(DC, clBlack);
  1216. OldBkColor := SetBkColor(DC, clWhite);
  1217. if Color < 0 then Brush := GetSysColorBrush(Color and $FF)
  1218. else Brush := CreateSolidBrush(Color);
  1219. OldBrush := SelectObject(DC, Brush);
  1220. BitBlt(DC, X, Y, ImageList.Width, ImageList.Height, B.Canvas.Handle, 0, 0, ROP_DSPDxax);
  1221. SelectObject(DC, OldBrush);
  1222. if Color >= 0 then DeleteObject(Brush);
  1223. SetTextColor(DC, OldTextColor);
  1224. SetBkColor(DC, OldBkColor);
  1225. B.Free;
  1226. end;
  1227. procedure DrawGlyph(DC: HDC; const R: TRect; ImageList: TCustomImageList; ImageIndex: Integer; Color: TColor); overload;
  1228. begin
  1229. DrawGlyph(DC, (R.Left + R.Right + 1 - ImageList.Width) div 2, (R.Top + R.Bottom + 1 - ImageList.Height) div 2, ImageList, ImageIndex, Color);
  1230. end;
  1231. procedure DrawGlyph(DC: HDC; X, Y: Integer; const Bits; Color: TColor); overload;
  1232. var
  1233. B: TBitmap;
  1234. OldTextColor, OldBkColor: Longword;
  1235. OldBrush, Brush: HBrush;
  1236. begin
  1237. B := TBitmap.Create;
  1238. B.Handle := CreateBitmap(8, 8, 1, 1, @Bits);
  1239. OldTextColor := SetTextColor(DC, clBlack);
  1240. OldBkColor := SetBkColor(DC, clWhite);
  1241. if Color < 0 then Brush := GetSysColorBrush(Color and $FF)
  1242. else Brush := CreateSolidBrush(Color);
  1243. OldBrush := SelectObject(DC, Brush);
  1244. BitBlt(DC, X, Y, 8, 8, B.Canvas.Handle, 0, 0, ROP_DSPDxax);
  1245. SelectObject(DC, OldBrush);
  1246. if Color >= 0 then DeleteObject(Brush);
  1247. SetTextColor(DC, OldTextColor);
  1248. SetBkColor(DC, OldBkColor);
  1249. B.Free;
  1250. end;
  1251. procedure DrawGlyph(DC: HDC; const R: TRect; Width, Height: Integer; const Bits; Color: TColor); overload;
  1252. var
  1253. B: TBitmap;
  1254. OldTextColor, OldBkColor: Longword;
  1255. OldBrush, Brush: HBrush;
  1256. begin
  1257. B := TBitmap.Create;
  1258. B.Handle := CreateBitmap(8, 8, 1, 1, @Bits);
  1259. OldTextColor := SetTextColor(DC, clBlack);
  1260. OldBkColor := SetBkColor(DC, clWhite);
  1261. if Color < 0 then Brush := GetSysColorBrush(Color and $FF)
  1262. else Brush := CreateSolidBrush(Color);
  1263. OldBrush := SelectObject(DC, Brush);
  1264. 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);
  1265. SelectObject(DC, OldBrush);
  1266. if Color >= 0 then DeleteObject(Brush);
  1267. SetTextColor(DC, OldTextColor);
  1268. SetBkColor(DC, OldBkColor);
  1269. B.Free;
  1270. end;
  1271. type
  1272. TCustomFormAccess = class(TCustomForm);
  1273. function GetClientSizeEx(Control: TWinControl): TPoint;
  1274. var
  1275. R: TRect;
  1276. begin
  1277. if (Control is TCustomForm) and (TCustomFormAccess(Control).FormStyle = fsMDIForm)
  1278. and not (csDesigning in Control.ComponentState) then
  1279. GetWindowRect(TCustomFormAccess(Control).ClientHandle, R)
  1280. else
  1281. R := Control.ClientRect;
  1282. Result.X := R.Right - R.Left;
  1283. Result.Y := R.Bottom - R.Top;
  1284. end;
  1285. procedure InitializeStock;
  1286. var
  1287. NonClientMetrics: TNonClientMetrics;
  1288. begin
  1289. StockBitmap1 := TBitmap.Create;
  1290. StockBitmap1.PixelFormat := pf32bit;
  1291. StockBitmap2 := TBitmap.Create;
  1292. StockBitmap2.PixelFormat := pf32bit;
  1293. StockMonoBitmap := TBitmap.Create;
  1294. StockMonoBitmap.Monochrome := True;
  1295. StockCompatibleBitmap := TBitmap.Create;
  1296. StockCompatibleBitmap.Width := 8;
  1297. StockCompatibleBitmap.Height := 8;
  1298. SmCaptionFont := TFont.Create;
  1299. NonClientMetrics.cbSize := SizeOf(NonClientMetrics);
  1300. if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
  1301. SmCaptionFont.Handle := CreateFontIndirect(NonClientMetrics.lfSmCaptionFont);
  1302. end;
  1303. procedure FinalizeStock;
  1304. begin
  1305. SmCaptionFont.Free;
  1306. SmCaptionFont := nil;
  1307. StockCompatibleBitmap.Free;
  1308. StockMonoBitmap.Free;
  1309. StockBitmap2.Free;
  1310. StockBitmap1.Free;
  1311. end;
  1312. procedure RecreateStock;
  1313. begin
  1314. FinalizeStock;
  1315. InitializeStock;
  1316. end;
  1317. { TShadow } ////////////////////////////////////////////////////////////////////
  1318. procedure TShadow.Clear(const R: TRect);
  1319. begin
  1320. FClearRect := R;
  1321. end;
  1322. constructor TShadow.Create(const Bounds: TRect; Opacity: Byte; LoColor: Boolean; Edges: TShadowEdges);
  1323. begin
  1324. inherited Create(nil);
  1325. Hide;
  1326. ParentWindow := Application.Handle;
  1327. BoundsRect := Bounds;
  1328. Color := clBtnShadow;
  1329. FOpacity := Opacity;
  1330. FEdges := Edges;
  1331. FSaveBits := False;
  1332. if LoColor then FStyle := ssFlat
  1333. else FStyle := ssLayered;
  1334. end;
  1335. procedure TShadow.CreateParams(var Params: TCreateParams);
  1336. begin
  1337. inherited;
  1338. with Params do
  1339. begin
  1340. Style := (Style and not (WS_CHILD or WS_GROUP or WS_TABSTOP)) or WS_POPUP;
  1341. ExStyle := ExStyle or WS_EX_TOOLWINDOW;
  1342. if FSaveBits then WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
  1343. end;
  1344. end;
  1345. procedure TShadow.GradB(const R: TRect);
  1346. var
  1347. J, W, H: Integer;
  1348. V: Cardinal;
  1349. P: ^Cardinal;
  1350. begin
  1351. W := R.Right - R.Left;
  1352. H := R.Bottom - R.Top;
  1353. for J := 0 to H - 1 do
  1354. begin
  1355. P := FBuffer.ScanLine[J + R.Top];
  1356. Inc(P, R.Left);
  1357. V := (255 - J shl 8 div H) shl 24;
  1358. FillLongword(P^, W, V);
  1359. end;
  1360. end;
  1361. procedure TShadow.GradBL(const R: TRect);
  1362. var
  1363. I, J, W, H, CX, CY, D, DMax, A, B: Integer;
  1364. P: ^Cardinal;
  1365. begin
  1366. W := R.Right - R.Left;
  1367. H := R.Bottom - R.Top;
  1368. DMax := W;
  1369. if H > W then DMax := H;
  1370. CX := DMax - 1;
  1371. CY := H - DMax;
  1372. for J := 0 to H - 1 do
  1373. begin
  1374. P := FBuffer.ScanLine[J + R.Top];
  1375. Inc(P, R.Left);
  1376. for I := 0 to W - 1 do
  1377. begin
  1378. A := Abs(I - CX);
  1379. B := Abs(J - CY);
  1380. D := A;
  1381. if B > A then D := B;
  1382. D := (A + B + D) * 128 div DMax;
  1383. if D < 255 then P^ := (255 - D) shl 24
  1384. else P^ := 0;
  1385. Inc(P);
  1386. end;
  1387. end;
  1388. end;
  1389. procedure TShadow.GradBR(const R: TRect);
  1390. var
  1391. I, J, W, H, CX, CY, D, DMax, A, B: Integer;
  1392. P: ^Cardinal;
  1393. begin
  1394. W := R.Right - R.Left;
  1395. H := R.Bottom - R.Top;
  1396. DMax := W;
  1397. if H > W then DMax := H;
  1398. CX := W - DMax;
  1399. CY := H - DMax;
  1400. for J := 0 to H - 1 do
  1401. begin
  1402. P := FBuffer.ScanLine[J + R.Top];
  1403. Inc(P, R.Left);
  1404. for I := 0 to W - 1 do
  1405. begin
  1406. A := Abs(I - CX);
  1407. B := Abs(J - CY);
  1408. D := A;
  1409. if B > A then D := B;
  1410. D := (A + B + D) * 128 div DMax;
  1411. if D < 255 then P^ := (255 - D) shl 24
  1412. else P^ := 0;
  1413. Inc(P);
  1414. end;
  1415. end;
  1416. end;
  1417. procedure TShadow.GradR(const R: TRect);
  1418. var
  1419. I, J, W: Integer;
  1420. P: ^Cardinal;
  1421. ScanLine: array of Cardinal;
  1422. begin
  1423. W := R.Right - R.Left;
  1424. SetLength(ScanLine, W);
  1425. for I := 0 to W - 1 do
  1426. ScanLine[I] :=(255 - I shl 8 div W) shl 24;
  1427. for J := R.Top to R.Bottom - 1 do
  1428. begin
  1429. P := FBuffer.ScanLine[J];
  1430. Inc(P, R.Left);
  1431. MoveLongword(ScanLine[0], P^, W);
  1432. end;
  1433. end;
  1434. procedure TShadow.GradTR(const R: TRect);
  1435. var
  1436. I, J, W, H, CX, CY, D, DMax, A, B: Integer;
  1437. P: ^Cardinal;
  1438. begin
  1439. W := R.Right - R.Left;
  1440. H := R.Bottom - R.Top;
  1441. DMax := W;
  1442. if H > W then DMax := H;
  1443. CX := W - DMax;
  1444. CY := DMax - 1;
  1445. for J := 0 to H - 1 do
  1446. begin
  1447. P := FBuffer.ScanLine[J + R.Top];
  1448. Inc(P, R.Left);
  1449. for I := 0 to W - 1 do
  1450. begin
  1451. A := Abs(I - CX);
  1452. B := Abs(J - CY);
  1453. D := A;
  1454. if B > A then D := B;
  1455. D := (A + B + D) * 128 div DMax;
  1456. if D < 255 then P^ := (255 - D) shl 24
  1457. else P^ := 0;
  1458. Inc(P);
  1459. end;
  1460. end;
  1461. end;
  1462. procedure TShadow.Render;
  1463. var
  1464. DstDC: HDC;
  1465. SrcPos, DstPos: TPoint;
  1466. TheSize: TSize;
  1467. BlendFunc: TBlendFunction;
  1468. begin
  1469. if FStyle <> ssLayered then Exit;
  1470. SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or $00080000{WS_EX_LAYERED});
  1471. DstDC := GetDC(0);
  1472. try
  1473. SrcPos := Point(0, 0);
  1474. with BoundsRect do
  1475. begin
  1476. DstPos := Point(Left, Top);
  1477. TheSize.cx := Right - Left;
  1478. TheSize.cy := Bottom - Top;
  1479. end;
  1480. BlendFunc.BlendOp := 0;
  1481. BlendFunc.BlendFlags := 0;
  1482. BlendFunc.SourceConstantAlpha := FOpacity;
  1483. BlendFunc.AlphaFormat := 1;
  1484. FBuffer := TBitmap.Create;
  1485. FBuffer.PixelFormat := pf32bit;
  1486. FBuffer.Width := TheSize.cx;
  1487. FBuffer.Height := TheSize.cy;
  1488. FillBuffer;
  1489. UpdateLayeredWindow(
  1490. Handle,
  1491. DstDC,
  1492. @DstPos,
  1493. @TheSize,
  1494. FBuffer.Canvas.Handle,
  1495. @SrcPos,
  1496. 0,
  1497. @BlendFunc,
  1498. $00000002{ULW_ALPHA});
  1499. FBuffer.Free;
  1500. finally
  1501. ReleaseDC(0, DstDC);
  1502. end;
  1503. end;
  1504. procedure TShadow.Show(ParentHandle: HWND);
  1505. begin
  1506. SetWindowPos(Handle, ParentHandle, 0, 0, 0, 0,
  1507. SWP_NOACTIVATE or SWP_NOSENDCHANGING or SWP_NOMOVE or
  1508. SWP_NOOWNERZORDER or SWP_NOSIZE or SWP_SHOWWINDOW);
  1509. end;
  1510. procedure TShadow.WMNCHitTest(var Message: TMessage);
  1511. begin
  1512. Message.Result := HTTRANSPARENT;
  1513. end;
  1514. { THorzShadow }
  1515. procedure THorzShadow.FillBuffer;
  1516. var
  1517. R: TRect;
  1518. L1, L2, L3: Integer;
  1519. begin
  1520. if seTopLeft in FEdges then L1 := Height else L1 := 0;
  1521. if seBottomRight in FEdges then L3 := Height else L3 := 0;
  1522. if L1 + L3 > Width then
  1523. begin
  1524. if (L1 > 0) and (L3 > 0) then
  1525. begin
  1526. L1 := Width div 2;
  1527. L3 := L1;
  1528. end
  1529. else if L1 > 0 then L1 := Width
  1530. else if L3 > 0 then L3 := Width;
  1531. end;
  1532. L2 := Width - L1 - L3;
  1533. R := Rect(0, 0, Width, Height);
  1534. R.Right := R.Left + L1;
  1535. if L1 > 0 then GradBL(R);
  1536. R.Left := R.Right;
  1537. R.Right := R.Left + L2;
  1538. if L2 > 0 then GradB(R);
  1539. if L3 > 0 then
  1540. begin
  1541. R.Left := R.Right;
  1542. R.Right := R.Left + L3;
  1543. GradBR(R);
  1544. end;
  1545. end;
  1546. { TVertShadow }
  1547. procedure TVertShadow.FillBuffer;
  1548. var
  1549. R: TRect;
  1550. L1, L2, L3: Integer;
  1551. begin
  1552. if seTopLeft in FEdges then L1 := Width else L1 := 0;
  1553. if seBottomRight in FEdges then L3 := Width else L3 := 0;
  1554. if L1 + L3 > Height then
  1555. begin
  1556. if (L1 > 0) and (L3 > 0) then
  1557. begin
  1558. L1 := Height div 2;
  1559. L3 := L1;
  1560. end
  1561. else if L1 > 0 then L1 := Height
  1562. else if L3 > 0 then L3 := Height;
  1563. end;
  1564. L2 := Height - L1 - L3;
  1565. R := Rect(0, 0, Width, Height);
  1566. R.Bottom := R.Top + L1;
  1567. if L1 > 0 then GradTR(R);
  1568. R.Top := R.Bottom;
  1569. R.Bottom := R.Top + L2;
  1570. if L2 > 0 then GradR(R);
  1571. if L3 > 0 then
  1572. begin
  1573. R.Top := R.Bottom;
  1574. R.Bottom := R.Top + L3;
  1575. GradBR(R);
  1576. end;
  1577. end;
  1578. { TShadows }
  1579. constructor TShadows.Create(R1, R2: TRect; TheSize: Integer; Opacity: Byte; LoColor: Boolean);
  1580. var
  1581. R: TRect;
  1582. R1Valid, R2Valid: Boolean;
  1583. begin
  1584. if LoColor then
  1585. begin
  1586. TheSize := TheSize div 2;
  1587. end;
  1588. R1Valid := not IsRectEmpty(R1);
  1589. R2Valid := not IsRectEmpty(R2);
  1590. if not (R1Valid or R2Valid) then Exit;
  1591. if R1Valid xor R2Valid then
  1592. begin
  1593. { A simple square shadow }
  1594. if R1Valid then R := R1 else R:= R2;
  1595. with R do
  1596. begin
  1597. V1 := TVertShadow.Create(Rect(Right, Top + TheSize, Right + TheSize, Bottom), Opacity, LoColor, [seTopLeft]);
  1598. H1 := THorzShadow.Create(Rect(Left + TheSize, Bottom, Right + TheSize, Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight])
  1599. end;
  1600. end
  1601. else
  1602. begin
  1603. if (R1.Bottom <= R2.Top + 2) or (R1.Top >= R2.Bottom - 2) then
  1604. begin
  1605. if R1.Top > R2.Top then
  1606. begin
  1607. R := R2;
  1608. R2 := R1;
  1609. R1 := R;
  1610. end;
  1611. if R1.Left + TheSize < R2.Left then
  1612. H1 := THorzShadow.Create(Rect(R1.Left + TheSize, R1.Bottom, R2.Left, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft]);
  1613. H2 := THorzShadow.Create(Rect(R2.Left + TheSize, R2.Bottom, R2.Right + TheSize, R2.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
  1614. V1 := TVertShadow.Create(Rect(R1.Right, R1.Top + TheSize, R1.Right + TheSize, R1.Bottom), Opacity, LoColor, [seTopLeft]);
  1615. if R1.Right > R2.Right then
  1616. H3 := THorzShadow.Create(Rect(R2.Right, R1.Bottom, R1.Right + TheSize, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
  1617. if R1.Right + TheSize < R2.Right then
  1618. V2 := TVertShadow.Create(Rect(R2.Right, R2.Top + TheSize, R2.Right + TheSize, R2.Bottom), Opacity, LoColor, [seTopLeft])
  1619. else
  1620. V2 := TVertShadow.Create(Rect(R2.Right, R2.Top + 1, R2.Right + TheSize, R2.Bottom), Opacity, LoColor, []);
  1621. end
  1622. else if (R1.Right <= R2.Left + 2) or (R1.Left >= R2.Right - 2) then
  1623. begin
  1624. if R1.Left > R2.Left then
  1625. begin
  1626. R := R2;
  1627. R2 := R1;
  1628. R1 := R;
  1629. end;
  1630. if R1.Top + TheSize < R2.Top then
  1631. V1 := TVertShadow.Create(Rect(R1.Right, R1.Top + TheSize, R1.Right + TheSize, R2.Top), Opacity, LoColor, [seTopLeft]);
  1632. V2 := TVertShadow.Create(Rect(R2.Right, R2.Top + TheSize, R2.Right + TheSize, R2.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
  1633. H1 := THorzShadow.Create(Rect(R1.Left + TheSize, R1.Bottom, R1.Right, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft]);
  1634. if R1.Bottom > R2.Bottom then
  1635. V3 := TVertShadow.Create(Rect(R1.Right, R2.Bottom, R1.Right + TheSize, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
  1636. if R1.Bottom + TheSize < R2.Bottom then
  1637. H2 := THorzShadow.Create(Rect(R2.Left + TheSize, R2.Bottom, R2.Right, R2.Bottom + TheSize), Opacity, LoColor, [seTopLeft])
  1638. else
  1639. H2 := THorzShadow.Create(Rect(R2.Left, R2.Bottom, R2.Right, R2.Bottom + TheSize), Opacity, LoColor, []);
  1640. end;
  1641. end;
  1642. if V1 <> nil then V1.Render;
  1643. if H1 <> nil then H1.Render;
  1644. if V2 <> nil then V2.Render;
  1645. if H2 <> nil then H2.Render;
  1646. if V3 <> nil then V3.Render;
  1647. if H3 <> nil then H3.Render;
  1648. SetSaveBits(True);
  1649. end;
  1650. destructor TShadows.Destroy;
  1651. begin
  1652. H3.Free;
  1653. V3.Free;
  1654. H2.Free;
  1655. V2.Free;
  1656. H1.Free;
  1657. V1.Free;
  1658. inherited;
  1659. end;
  1660. procedure TShadows.SetSaveBits(Value: Boolean);
  1661. begin
  1662. FSaveBits := Value;
  1663. if V1 <> nil then V1.FSaveBits := Value;
  1664. if H1 <> nil then H1.FSaveBits := Value;
  1665. if V2 <> nil then V2.FSaveBits := Value;
  1666. if H2 <> nil then H2.FSaveBits := Value;
  1667. if V3 <> nil then V3.FSaveBits := Value;
  1668. if H3 <> nil then H3.FSaveBits := Value;
  1669. end;
  1670. procedure TShadows.Show(ParentHandle: HWND);
  1671. begin
  1672. if V1 <> nil then V1.Show(ParentHandle);
  1673. if H1 <> nil then H1.Show(ParentHandle);
  1674. if V2 <> nil then V2.Show(ParentHandle);
  1675. if H2 <> nil then H2.Show(ParentHandle);
  1676. if V3 <> nil then V3.Show(ParentHandle);
  1677. if H3 <> nil then H3.Show(ParentHandle);
  1678. end;
  1679. { Gradients } //////////////////////////////////////////////////////////////////
  1680. const
  1681. GRADIENT_CACHE_SIZE = 16;
  1682. type
  1683. PRGBQuad = ^TRGBQuad;
  1684. TRGBQuad = Integer;
  1685. PRGBQuadArray = ^TRGBQuadArray;
  1686. TRGBQuadArray = array [0..0] of TRGBQuad;
  1687. var
  1688. GradientCache: array [0..GRADIENT_CACHE_SIZE] of array of TRGBQuad;
  1689. NextCacheIndex: Integer = 0;
  1690. function FindGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
  1691. begin
  1692. Assert(Size > 0);
  1693. Result := GRADIENT_CACHE_SIZE - 1;
  1694. while Result >= 0 do
  1695. begin
  1696. if (Length(GradientCache[Result]) = Size) and
  1697. (GradientCache[Result][0] = CL) and
  1698. (GradientCache[Result][Length(GradientCache[Result]) - 1] = CR) then Exit;
  1699. Dec(Result);
  1700. end;
  1701. end;
  1702. function MakeGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
  1703. var
  1704. R1, G1, B1: Integer;
  1705. R2, G2, B2: Integer;
  1706. R, G, B: Integer;
  1707. I: Integer;
  1708. Bias: Integer;
  1709. begin
  1710. Assert(Size > 0);
  1711. Result := NextCacheIndex;
  1712. Inc(NextCacheIndex);
  1713. if NextCacheIndex >= GRADIENT_CACHE_SIZE then NextCacheIndex := 0;
  1714. R1 := CL and $FF;
  1715. G1 := CL shr 8 and $FF;
  1716. B1 := CL shr 16 and $FF;
  1717. R2 := CR and $FF - R1;
  1718. G2 := CR shr 8 and $FF - G1;
  1719. B2 := CR shr 16 and $FF - B1;
  1720. SetLength(GradientCache[Result], Size);
  1721. Dec(Size);
  1722. Bias := Size div 2;
  1723. if Size > 0 then
  1724. for I := 0 to Size do
  1725. begin
  1726. R := R1 + (R2 * I + Bias) div Size;
  1727. G := G1 + (G2 * I + Bias) div Size;
  1728. B := B1 + (B2 * I + Bias) div Size;
  1729. GradientCache[Result][I] := R + G shl 8 + B shl 16;
  1730. end
  1731. else
  1732. begin
  1733. R := R1 + R2 div 2;
  1734. G := G1 + G2 div 2;
  1735. B := B1 + B2 div 2;
  1736. GradientCache[Result][0] := R + G shl 8 + B shl 16;
  1737. end;
  1738. end;
  1739. function GetGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
  1740. begin
  1741. Result := FindGradient(Size, CL, CR);
  1742. if Result < 0 then Result := MakeGradient(Size, CL, CR);
  1743. end;
  1744. { GradFill function }
  1745. procedure GradFill(DC: HDC; ARect: TRect; ClrTopLeft, ClrBottomRight: TColor; Kind: TGradientKind);
  1746. const
  1747. GRAD_MODE: array [TGradientKind] of DWORD = (GRADIENT_FILL_RECT_H, GRADIENT_FILL_RECT_V);
  1748. W: array [TGradientKind] of Integer = (2, 1);
  1749. H: array [TGradientKind] of Integer = (1, 2);
  1750. type
  1751. TriVertex = packed record
  1752. X, Y: Longint;
  1753. R, G, B, A: Word;
  1754. end;
  1755. var
  1756. V: array [0..1] of TriVertex;
  1757. GR: GRADIENT_RECT;
  1758. begin
  1759. if not RectVisible(DC, ARect) then Exit;
  1760. ClrTopLeft := ColorToRGB(ClrTopLeft);
  1761. ClrBottomRight := ColorToRGB(ClrBottomRight);
  1762. with V[0] do
  1763. begin
  1764. X := ARect.Left;
  1765. Y := ARect.Top;
  1766. R := ClrTopLeft shl 8 and $FF00;
  1767. G := ClrTopLeft and $FF00;
  1768. B := ClrTopLeft shr 8 and $FF00;
  1769. A := 0;
  1770. end;
  1771. with V[1] do
  1772. begin
  1773. X := ARect.Right;
  1774. Y := ARect.Bottom;
  1775. R := ClrBottomRight shl 8 and $FF00;
  1776. G := ClrBottomRight and $FF00;
  1777. B := ClrBottomRight shr 8 and $FF00;
  1778. A := 0;
  1779. end;
  1780. GR.UpperLeft := 0; GR.LowerRight := 1;
  1781. GradientFill(DC, @V, 2, @GR, 1, GRAD_MODE[Kind]);
  1782. end;
  1783. { Brushed Fill } ///////////////////////////////////////////////////////////////
  1784. { Templates }
  1785. const
  1786. NUM_TEMPLATES = 8;
  1787. MIN_TEMPLATE_SIZE = 100;
  1788. MAX_TEMPLATE_SIZE = 200;
  1789. var
  1790. ThreadTemplates: array [0..NUM_TEMPLATES - 1] of array of Integer;
  1791. RandThreadIndex: array [0..1023] of Integer;
  1792. RandThreadPositions: array [0..1023] of Integer;
  1793. procedure InitializeBrushedFill;
  1794. const
  1795. Pi = 3.14159265358987;
  1796. var
  1797. TemplateIndex, Size, I, V, V1, V2: Integer;
  1798. T, R12, R13, R14, R21, R22, R23, R24: Single;
  1799. begin
  1800. { Make thread templates }
  1801. for TemplateIndex := 0 to NUM_TEMPLATES - 1 do
  1802. begin
  1803. Size := (MIN_TEMPLATE_SIZE + Random(MAX_TEMPLATE_SIZE - MIN_TEMPLATE_SIZE + 1)) div 2;
  1804. SetLength(ThreadTemplates[TemplateIndex], Size * 2);
  1805. R12 := Random * 2 * Pi;
  1806. R13 := Random * 2 * Pi;
  1807. R14 := Random * 2 * Pi;
  1808. R21 := Random * 2 * Pi;
  1809. R22 := Random * 2 * Pi;
  1810. R23 := Random * 2 * Pi;
  1811. R24 := Random * 2 * Pi;
  1812. for I := 0 to Size - 1 do
  1813. begin
  1814. T := 2 * Pi * I / Size;
  1815. V1 := Round(150 * Sin(T) + 100 * Sin(2 * T + R12) + 50 * Sin(3 * T + R13) + 20 * Sin(4 * T + R14));
  1816. if V1 > 255 then V1 := 255;
  1817. if V1 < -255 then V1 := -255;
  1818. V2 := Round(150 * Sin(T + R21) + 100 * Sin(2 * T + R22) + 50 * Sin(3 * T + R23) + 20 * Sin(4 * T + R24));
  1819. if V2 > 255 then V2 := 255;
  1820. if V2 < -255 then V2 := -255;
  1821. if Abs(V2 - V1) > 300 then
  1822. begin
  1823. V := (V1 + V2) div 2;
  1824. V1 := V - 150;
  1825. V2 := V + 150;
  1826. end;
  1827. ThreadTemplates[TemplateIndex][I * 2] := Min(V1, V2);
  1828. ThreadTemplates[TemplateIndex][I * 2 + 1] := Max(V1, V2);
  1829. end;
  1830. end;
  1831. { Initialize Rand arrays }
  1832. for I := 0 to 1023 do
  1833. begin
  1834. RandThreadIndex[I] := Random(NUM_TEMPLATES);
  1835. V1 := Random(Length(ThreadTemplates[RandThreadIndex[I]])) and not $1;
  1836. if Odd(I) then Inc(V1);
  1837. RandThreadPositions[I] := V1;
  1838. end;
  1839. end;
  1840. { Cache }
  1841. const
  1842. THREAD_CACHE_SIZE = 16;
  1843. type
  1844. TThreadCacheItem = record
  1845. BaseColor: TColorRef;
  1846. Roughness: Integer;
  1847. Bitmaps: array [0..NUM_TEMPLATES - 1] of HBITMAP;
  1848. end;
  1849. var
  1850. ThreadCache: array [0..THREAD_CACHE_SIZE] of TThreadCacheItem;
  1851. NextCacheEntry: Integer = 0;
  1852. procedure ClearCacheItem(var CacheItem: TThreadCacheItem);
  1853. var
  1854. I: Integer;
  1855. begin
  1856. with CacheItem do
  1857. begin
  1858. BaseColor := $FFFFFFFF;
  1859. Roughness := -1;
  1860. for I := NUM_TEMPLATES - 1 downto 0 do
  1861. begin
  1862. if Bitmaps[I] <> 0 then
  1863. begin
  1864. DeleteObject(Bitmaps[I]);
  1865. Bitmaps[I] := 0;
  1866. end;
  1867. end;
  1868. end;
  1869. end;
  1870. procedure ResetBrushedFillCache;
  1871. var
  1872. I: Integer;
  1873. begin
  1874. { Should be called each time the screen parameters change }
  1875. for I := THREAD_CACHE_SIZE - 1 downto 0 do ClearCacheItem(ThreadCache[I]);
  1876. end;
  1877. procedure FinalizeBrushedFill;
  1878. begin
  1879. ResetBrushedFillCache;
  1880. end;
  1881. procedure MakeCacheItem(var CacheItem: TThreadCacheItem; Color: TColorRef; Roughness: Integer);
  1882. var
  1883. TemplateIndex, Size, I, V: Integer;
  1884. CR, CG, CB: Integer;
  1885. R, G, B: Integer;
  1886. ScreenDC: HDC;
  1887. BMI: TBitmapInfo;
  1888. Bits: PRGBQuadArray;
  1889. DIBSection: HBITMAP;
  1890. DIBDC, CacheDC: HDC;
  1891. begin
  1892. ScreenDC := GetDC(0);
  1893. FillChar(BMI, SizeOf(TBitmapInfo), 0);
  1894. with BMI.bmiHeader do
  1895. begin
  1896. biSize := SizeOf(TBitmapInfoHeader);
  1897. biPlanes := 1;
  1898. biCompression := BI_RGB;
  1899. biWidth := MAX_TEMPLATE_SIZE;
  1900. biHeight := -1;
  1901. biBitCount := 32;
  1902. end;
  1903. DIBSection := CreateDIBSection(0, BMI, DIB_RGB_COLORS, Pointer(Bits), 0, 0);
  1904. DIBDC := CreateCompatibleDC(0);
  1905. SelectObject(DIBDC, DIBSection);
  1906. CacheDC := CreateCompatibleDC(0);
  1907. CR := Color shl 8 and $FF00;
  1908. CG := Color and $FF00;
  1909. CB := Color shr 8 and $FF00;
  1910. try
  1911. for TemplateIndex := 0 to NUM_TEMPLATES - 1 do
  1912. begin
  1913. CacheItem.BaseColor := Color;
  1914. CacheItem.Roughness := Roughness;
  1915. Size := Length(ThreadTemplates[TemplateIndex]);
  1916. if CacheItem.Bitmaps[TemplateIndex] = 0 then
  1917. CacheItem.Bitmaps[TemplateIndex] := CreateCompatibleBitmap(ScreenDC, Size, 1);
  1918. SelectObject(CacheDC, CacheItem.Bitmaps[TemplateIndex]);
  1919. for I := 0 to Size - 1 do
  1920. begin
  1921. V := ThreadTemplates[TemplateIndex][I];
  1922. R := CR + V * Roughness;
  1923. G := CG + V * Roughness;
  1924. B := CB + V * Roughness;
  1925. if R < 0 then R := 0;
  1926. if G < 0 then G := 0;
  1927. if B < 0 then B := 0;
  1928. if R > $EF00 then R := $EF00;
  1929. if G > $EF00 then G := $EF00;
  1930. if B > $EF00 then B := $EF00;
  1931. Bits^[I] := (R and $FF00 + (G and $FF00) shl 8 + (B and $FF00) shl 16) shr 8;
  1932. end;
  1933. BitBlt(CacheDC, 0, 0, Size, 1, DIBDC, 0, 0, SRCCOPY);
  1934. end;
  1935. finally
  1936. DeleteDC(CacheDC);
  1937. DeleteDC(DIBDC);
  1938. DeleteObject(DIBSection);
  1939. ReleaseDC(0, ScreenDC);
  1940. end;
  1941. end;
  1942. function FindCacheItem(Color: TColorRef; Roughness: Integer): Integer;
  1943. begin
  1944. Result := THREAD_CACHE_SIZE - 1;
  1945. while Result >= 0 do
  1946. if (ThreadCache[Result].BaseColor = Color) and (ThreadCache[Result].Roughness = Roughness) then Exit
  1947. else Dec(Result);
  1948. end;
  1949. function GetCacheItem(Color: TColorRef; Roughness: Integer): Integer;
  1950. begin
  1951. Result := FindCacheItem(Color, Roughness);
  1952. if Result >= 0 then Exit
  1953. else
  1954. begin
  1955. Result := NextCacheEntry;
  1956. MakeCacheItem(ThreadCache[Result], Color, Roughness);
  1957. NextCacheEntry := (NextCacheEntry + 1) mod THREAD_CACHE_SIZE;
  1958. end;
  1959. end;
  1960. procedure BrushedFill(DC: HDC; Origin: PPoint; ARect: TRect; Color: TColor; Roughness: Integer);
  1961. const
  1962. ZeroOrigin: TPoint = (X: 0; Y: 0);
  1963. var
  1964. CR: TColorRef;
  1965. X, Y: Integer;
  1966. CacheIndex: Integer;
  1967. TemplateIndex: Integer;
  1968. CacheDC: HDC;
  1969. Size: Integer;
  1970. BoxR: TRect;
  1971. begin
  1972. if (Color = clNone) or not RectVisible(DC, ARect) then Exit;
  1973. CR := GetBGR(ColorToRGB(Color));
  1974. if Origin = nil then Origin := @ZeroOrigin;
  1975. CacheIndex := GetCacheItem(CR, Roughness);
  1976. GetClipBox(DC, BoxR);
  1977. IntersectRect(ARect, ARect, BoxR);
  1978. SaveDC(DC);
  1979. with ARect do IntersectClipRect(DC, Left, Top, Right, Bottom);
  1980. CacheDC := CreateCompatibleDC(0);
  1981. for Y := ARect.Top to ARect.Bottom - 1 do
  1982. begin
  1983. TemplateIndex := RandThreadIndex[(65536 + Y - Origin.Y) mod 1024];
  1984. Size := Length(ThreadTemplates[TemplateIndex]);
  1985. X := -RandThreadPositions[(65536 + Y - Origin.Y) mod 1024] + Origin.X;
  1986. SelectObject(CacheDC, ThreadCache[CacheIndex].Bitmaps[TemplateIndex]);
  1987. while X < ARect.Right do
  1988. begin
  1989. if X + Size >= ARect.Left then BitBlt(DC, X, Y, Size, 1, CacheDC, 0, 0, SRCCOPY);
  1990. Inc(X, Size);
  1991. end;
  1992. end;
  1993. DeleteDC(CacheDC);
  1994. RestoreDC(DC, -1);
  1995. end;
  1996. initialization
  1997. InitializeStock;
  1998. InitializeBrushedFill;
  1999. ResetBrushedFillCache;
  2000. finalization
  2001. FinalizeBrushedFill;
  2002. FinalizeStock;
  2003. end.