| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238 |
- unit TBXUtils;
- // TBX Package
- // Copyright 2001-2004 Alex A. Denisov. All Rights Reserved
- // See TBX.chm for license and installation instructions
- //
- // Id: TBXUtils.pas 11 2004-04-01 07:22:56Z Alex@ZEISS
- interface
- {$I TB2Ver.inc}
- {$I TBX.inc}
- uses
- Windows, Messages, Classes, SysUtils, Graphics, Controls, Forms, ImgList;
- {$IFDEF TBX_UNICODE}
- function GetTextHeightW(DC: HDC): Integer;
- function GetTextWidthW(DC: HDC; const S: WideString; StripAccelChar: Boolean): Integer;
- procedure DrawRotatedTextW(DC: HDC; AText: WideString; const ARect: TRect; const AFormat: Cardinal);
- function EscapeAmpersandsW(const S: WideString): WideString;
- function FindAccelCharW(const S: WideString): WideChar;
- function StripAccelCharsW(const S: WideString): WideString;
- function StripTrailingPunctuationW(const S: WideString): WideString;
- {$ENDIF}
- procedure GetRGB(C: TColor; out R, G, B: Integer);
- function MixColors(C1, C2: TColor; W1: Integer): TColor;
- function SameColors(C1, C2: TColor): Boolean;
- function Lighten(C: TColor; Amount: Integer): TColor;
- function NearestLighten(C: TColor; Amount: Integer): TColor;
- function NearestMixedColor(C1, C2: TColor; W1: Integer): TColor;
- function ColorIntensity(C: TColor): Integer;
- function IsDarkColor(C: TColor; Threshold: Integer = 100): Boolean;
- function Blend(C1, C2: TColor; W1: Integer): TColor;
- procedure SetContrast(var Color: TColor; BkgndColor: TColor; Threshold: Integer);
- procedure RGBtoHSL(RGB: TColor; out H, S, L : Single);
- function HSLtoRGB(H, S, L: Single): TColor;
- function GetBGR(C: TColorRef): Cardinal;
- function TBXScaleByTextHeightRunTime(Canvas: TCanvas; Dimension: Integer): Integer;
- { A few drawing functions }
- { these functions recognize clNone value of TColor }
- procedure SetPixelEx(DC: HDC; X, Y: Integer; C: TColorRef; Alpha: Longword = $FF);
- function CreatePenEx(Color: TColor): HPen;
- function CreateBrushEx(Color: TColor): HBrush;
- function CreateDitheredBrush(C1, C2: TColor): HBrush;
- function FillRectEx(DC: HDC; const Rect: TRect; Color: TColor): Boolean; {$IFDEF COMPATIBLE_GFX}overload;{$ENDIF}
- function FrameRectEx(DC: HDC; var Rect: TRect; Color: TColor; Adjust: Boolean): Boolean; {$IFDEF COMPATIBLE_GFX}overload;{$ENDIF}
- procedure DrawLineEx(DC: HDC; X1, Y1, X2, Y2: Integer; Color: TColor); {$IFDEF COMPATIBLE_GFX}overload;{$ENDIF}
- function PolyLineEx(DC: HDC; const Points: array of TPoint; Color: TColor): Boolean;
- procedure PolygonEx(DC: HDC; const Points: array of TPoint; OutlineColor, FillColor: TColor);
- procedure RoundRectEx(DC: HDC; Left, Top, Right, Bottom: Integer; EllipseWidth, EllipseHeight, OutlineColor, FillColor: TColor); overload; {vb+}
- procedure RoundRectEx(DC: HDC; const R: TRect; EllipseWidth, EllipseHeight, OutlineColor, FillColor: TColor); overload; {vb+}
- procedure EllipseEx(DC: HDC; Left, Top, Right, Bottom: Integer; OutlineColor, FillColor: TColor);
- procedure DitherRect(DC: HDC; const R: TRect; C1, C2: TColor); {$IFDEF COMPATIBLE_GFX}overload;{$ENDIF}
- procedure Frame3D(DC: HDC; var Rect: TRect; TopColor, BottomColor: TColor; Adjust: Boolean); {$IFDEF COMPATIBLE_GFX}overload;{$ENDIF}
- procedure DrawDraggingOutline(DC: HDC; const NewRect, OldRect: TRect);
- { Gradients }
- type
- TGradientKind = (gkHorz, gkVert);
- procedure GradFill(DC: HDC; ARect: TRect; ClrTopLeft, ClrBottomRight: TColor; Kind: TGradientKind);
- procedure BrushedFill(DC: HDC; Origin: PPoint; ARect: TRect; Color: TColor; Roughness: Integer);
- procedure ResetBrushedFillCache;
- { drawing functions for compatibility with previous versions }
- {$IFDEF COMPATIBLE_GFX}
- function FillRectEx(Canvas: TCanvas; const Rect: TRect; Color: TColor): Boolean; overload;
- function FrameRectEx(Canvas: TCanvas; var Rect: TRect; Color: TColor; Adjust: Boolean = False): Boolean; overload;
- procedure DrawLineEx(Canvas: TCanvas; X1, Y1, X2, Y2: Integer; Color: TColor); overload;
- procedure DitherRect(Canvas: TCanvas; const R: TRect; C1, C2: TColor); overload;
- procedure Frame3D(Canvas: TCanvas; var Rect: TRect; TopColor, BottomColor: TColor); overload;
- function FillRectEx2(DC: HDC; const Rect: TRect; Color: TColor): Boolean; deprecated;
- function FrameRectEx2(DC: HDC; var Rect: TRect; Color: TColor; Adjust: Boolean = False): Boolean; deprecated;
- {$ENDIF}
- { alternatives to fillchar and move routines what work with 32-bit aligned memory blocks }
- procedure FillLongword(var X; Count: Integer; Value: Longword);
- procedure MoveLongword(const Source; var Dest; Count: Integer);
- { extended icon painting routines }
- procedure DrawTBXIcon(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; HiContrast: Boolean);
- procedure BlendTBXIcon(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; Opacity: Byte);
- procedure HighlightTBXIcon(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; HighlightColor: TColor; Amount: Byte);
- procedure DrawTBXIconShadow(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; Density: Integer);
- procedure DrawTBXIconFlatShadow(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; ShadowColor: TColor);
- procedure DrawTBXIconFullShadow(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; ShadowColor: TColor);
- procedure DrawGlyph(DC: HDC; X, Y: Integer; ImageList: TCustomImageList; ImageIndex: Integer; Color: TColor); overload;
- procedure DrawGlyph(DC: HDC; const R: TRect; ImageList: TCustomImageList; ImageIndex: Integer; Color: TColor); overload;
- procedure DrawGlyph(DC: HDC; X, Y: Integer; const Bits; Color: TColor); overload;
- procedure DrawGlyph(DC: HDC; const R: TRect; Width, Height: Integer; const Bits; Color: TColor); overload;
- function GetClientSizeEx(Control: TWinControl): TPoint;
- const
- SHD_DENSE = 0;
- SHD_LIGHT = 1;
- { An additional declaration for D4 compiler }
- type
- PColor = ^TColor;
- { Stock Objects }
- var
- StockBitmap1, StockBitmap2: TBitmap;
- StockMonoBitmap, StockCompatibleBitmap: TBitmap;
- SmCaptionFont: TFont;
- const
- ROP_DSPDxax = $00E20746;
- { Support for window shadows }
- type
- TShadowEdges = set of (seTopLeft, seBottomRight);
- TShadowStyle = (ssFlat, ssLayered);
- TShadow = class(TCustomControl)
- protected
- FOpacity: Byte;
- FBuffer: TBitmap;
- FClearRect: TRect;
- FEdges: TShadowEdges;
- FStyle: TShadowStyle;
- FSaveBits: Boolean;
- procedure GradR(const R: TRect);
- procedure GradB(const R: TRect);
- procedure GradBR(const R: TRect);
- procedure GradTR(const R: TRect);
- procedure GradBL(const R: TRect);
- procedure CreateParams(var Params: TCreateParams); override;
- procedure FillBuffer; virtual; abstract;
- procedure WMNCHitTest(var Message: TMessage); message WM_NCHITTEST;
- public
- constructor Create(const Bounds: TRect; Opacity: Byte; LoColor: Boolean; Edges: TShadowEdges); reintroduce;
- procedure Clear(const R: TRect);
- procedure Render;
- procedure Show(ParentHandle: HWND);
- end;
- THorzShadow = class(TShadow)
- protected
- procedure FillBuffer; override;
- end;
- TVertShadow = class(TShadow)
- protected
- procedure FillBuffer; override;
- end;
- TShadows = class
- private
- FSaveBits: Boolean;
- procedure SetSaveBits(Value: Boolean);
- protected
- V1: TShadow;
- H1: TShadow;
- V2: TShadow;
- H2: TShadow;
- V3: TShadow;
- H3: TShadow;
- public
- constructor Create(R1, R2: TRect; TheSize: Integer; Opacity: Byte; LoColor: Boolean);
- destructor Destroy; override;
- procedure Show(ParentHandle: HWND);
- property SaveBits: Boolean read FSaveBits write SetSaveBits;
- end;
- procedure RecreateStock;
- implementation
- {$R-}{$Q-}
- uses TB2Common, Math, Types;
- {$IFDEF TBX_UNICODE}
- function GetTextHeightW(DC: HDC): Integer;
- var
- TextMetric: TTextMetricW;
- begin
- GetTextMetricsW(DC, TextMetric);
- Result := TextMetric.tmHeight;
- end;
- function GetTextWidthW(DC: HDC; const S: WideString; StripAccelChar: Boolean): Integer;
- var
- Size: TSize;
- S2: WideString;
- begin
- if StripAccelChar then
- begin
- S2 := StripAccelCharsW(S);
- GetTextExtentPoint32W(DC, PWideChar(S2), Length(S2), Size);
- end
- else GetTextExtentPoint32W(DC, PWideChar(S), Length(S), Size);
- Result := Size.cx;
- end;
- procedure DrawRotatedTextW(DC: HDC; AText: WideString; const ARect: TRect; const AFormat: Cardinal);
- { Like DrawText, but draws the text at a 270 degree angle.
- The format flag this function respects are
- DT_NOPREFIX, DT_HIDEPREFIX, DT_CENTER, DT_END_ELLIPSIS, DT_NOCLIP }
- var
- RotatedFont, SaveFont: HFONT;
- TextMetrics: TTextMetricW;
- X, Y, P, I, SU, FU, W: Integer;
- SaveAlign: UINT;
- Clip: Boolean;
- function GetSize(DC: HDC; const S: WideString): Integer;
- var
- Size: TSize;
- begin
- GetTextExtentPoint32W(DC, PWideChar(S), Length(S), Size);
- Result := Size.cx;
- end;
- begin
- if Length(AText) = 0 then Exit;
- RotatedFont := CreateRotatedFont(DC);
- SaveFont := SelectObject(DC, RotatedFont);
- GetTextMetricsW(DC, TextMetrics);
- X := ARect.Left + ((ARect.Right - ARect.Left) - TextMetrics.tmHeight) div 2;
- Clip := AFormat and DT_NOCLIP = 0;
- { Find the index of the character that should be underlined. Delete '&'
- characters from the string. Like DrawText, only the last prefixed character
- will be underlined. }
- P := 0;
- I := 1;
- if AFormat and DT_NOPREFIX = 0 then
- while I <= Length(AText) do
- begin
- if AText[I] = '&' then
- begin
- Delete(AText, I, 1);
- if PWideChar(AText)[I - 1] <> '&' then P := I;
- end;
- Inc(I);
- end;
- if AFormat and DT_END_ELLIPSIS <> 0 then
- begin
- if (Length(AText) > 1) and (GetSize(DC, AText) > ARect.Bottom - ARect.Top) then
- begin
- W := ARect.Bottom - ARect.Top;
- if W > 2 then
- begin
- Delete(AText, Length(AText), 1);
- while (Length(AText) > 1) and (GetSize(DC, AText + '...') > W) do
- Delete(AText, Length(AText), 1);
- end
- else AText := AText[1];
- if P > Length(AText) then P := 0;
- AText := AText + '...';
- end;
- end;
- if AFormat and DT_CENTER <> 0 then
- Y := ARect.Top + ((ARect.Bottom - ARect.Top) - GetSize(DC, AText)) div 2
- else
- Y := ARect.Top;
- if Clip then
- begin
- SaveDC(DC);
- with ARect do IntersectClipRect(DC, Left, Top, Right, Bottom);
- end;
- SaveAlign := SetTextAlign(DC, TA_BOTTOM);
- TextOutW(DC, X, Y, PWideChar(AText), Length(AText));
- SetTextAlign(DC, SaveAlign);
- { Underline }
- if (P > 0) and (AFormat and DT_HIDEPREFIX = 0) then
- begin
- SU := GetTextWidthW(DC, Copy(AText, 1, P - 1), False);
- FU := SU + GetTextWidthW(DC, PWideChar(AText)[P - 1], False);
- Inc(X, TextMetrics.tmDescent - 2);
- DrawLineEx(DC, X, Y + SU, X, Y + FU, GetTextColor(DC));
- end;
- if Clip then RestoreDC(DC, -1);
- SelectObject(DC, SaveFont);
- DeleteObject(RotatedFont);
- end;
- function EscapeAmpersandsW(const S: WideString): WideString;
- var
- I: Integer;
- begin
- Result := S;
- I := 1;
- while I <= Length(Result) do
- begin
- if Result[I] = '&' then
- begin
- Inc(I);
- Insert('&', Result, I);
- end;
- Inc(I);
- end;
- end;
- function FindAccelCharW(const S: WideString): WideChar;
- var
- PStart, P: PWideChar;
- begin
- { locate the last char with '&' prefix }
- Result := #0;
- if Length(S) > 0 then
- begin
- PStart := PWideChar(S);
- P := PStart;
- Inc(P, Length(S) - 2);
- while P >= PStart do
- begin
- if P^ = '&' then
- begin
- if (P = PStart) or (PWideChar(Integer(P) - 2)^ <> '&') then
- begin
- Result := PWideChar(Integer(P) + 2)^;
- Exit;
- end
- else Dec(P);
- end;
- Dec(P);
- end;
- end;
- end;
- function StripAccelCharsW(const S: WideString): WideString;
- var
- I: Integer;
- begin
- Result := S;
- I := 1;
- while I <= Length(Result) do
- begin
- if Result[I] = '&' then
- System.Delete(Result, I, 1);
- Inc(I);
- end;
- end;
- function StripTrailingPunctuationW(const S: WideString): WideString;
- var
- L: Integer;
- begin
- Result := S;
- L := Length(Result);
- if (L > 1) and (Result[L] = ':') then SetLength(Result, L - 1)
- else if (L > 3) and (Result[L - 2] = '.') and (Result[L - 1] = '.') and
- (Result[L] = '.') then SetLength(Result, L - 3);
- end;
- {$ENDIF}
- type
- PPoints = ^TPoints;
- TPoints = array [0..0] of TPoint;
- const
- WeightR: single = 0.764706;
- WeightG: single = 1.52941;
- WeightB: single = 0.254902;
- procedure GetRGB(C: TColor; out R, G, B: Integer);
- begin
- if Integer(C) < 0 then C := GetSysColor(C and $000000FF);
- R := C and $FF;
- G := C shr 8 and $FF;
- B := C shr 16 and $FF;
- end;
- function MixColors(C1, C2: TColor; W1: Integer): TColor;
- var
- W2: Cardinal;
- begin
- Assert(W1 in [0..255]);
- W2 := W1 xor 255;
- if Integer(C1) < 0 then C1 := GetSysColor(C1 and $000000FF);
- if Integer(C2) < 0 then C2 := GetSysColor(C2 and $000000FF);
- Result := Integer(
- ((Cardinal(C1) and $FF00FF) * Cardinal(W1) +
- (Cardinal(C2) and $FF00FF) * W2) and $FF00FF00 +
- ((Cardinal(C1) and $00FF00) * Cardinal(W1) +
- (Cardinal(C2) and $00FF00) * W2) and $00FF0000) shr 8;
- end;
- function SameColors(C1, C2: TColor): Boolean;
- begin
- if C1 < 0 then C1 := GetSysColor(C1 and $000000FF);
- if C2 < 0 then C2 := GetSysColor(C2 and $000000FF);
- Result := C1 = C2;
- end;
- function Lighten(C: TColor; Amount: Integer): TColor;
- var
- R, G, B: Integer;
- begin
- if C < 0 then C := GetSysColor(C and $000000FF);
- R := C and $FF + Amount;
- G := C shr 8 and $FF + Amount;
- B := C shr 16 and $FF + Amount;
- if R < 0 then R := 0 else if R > 255 then R := 255;
- if G < 0 then G := 0 else if G > 255 then G := 255;
- if B < 0 then B := 0 else if B > 255 then B := 255;
- Result := R or (G shl 8) or (B shl 16);
- end;
- function NearestLighten(C: TColor; Amount: Integer): TColor;
- begin
- Result := GetNearestColor(StockCompatibleBitmap.Canvas.Handle, Lighten(C, Amount));
- end;
- function NearestMixedColor(C1, C2: TColor; W1: Integer): TColor;
- begin
- Result := MixColors(C1, C2, W1);
- Result := GetNearestColor(StockCompatibleBitmap.Canvas.Handle, Result);
- end;
- function ColorIntensity(C: TColor): Integer;
- begin
- if C < 0 then C := GetSysColor(C and $FF);
- Result := ((C shr 16 and $FF) * 30 + (C shr 8 and $FF) * 150 + (C and $FF) * 76) shr 8;
- end;
- function IsDarkColor(C: TColor; Threshold: Integer = 100): Boolean;
- begin
- if C < 0 then C := GetSysColor(C and $FF);
- Threshold := Threshold shl 8;
- Result := ((C and $FF) * 76 + (C shr 8 and $FF) * 150 + (C shr 16 and $FF) * 30 ) < Threshold;
- end;
- function Blend(C1, C2: TColor; W1: Integer): TColor;
- var
- W2, A1, A2, D, F, G: Integer;
- begin
- if C1 < 0 then C1 := GetSysColor(C1 and $FF);
- if C2 < 0 then C2 := GetSysColor(C2 and $FF);
- if W1 >= 100 then D := 1000
- else D := 100;
- W2 := D - W1;
- F := D div 2;
- A2 := C2 shr 16 * W2;
- A1 := C1 shr 16 * W1;
- G := (A1 + A2 + F) div D and $FF;
- Result := G shl 16;
- A2 := (C2 shr 8 and $FF) * W2;
- A1 := (C1 shr 8 and $FF) * W1;
- G := (A1 + A2 + F) div D and $FF;
- Result := Result or G shl 8;
- A2 := (C2 and $FF) * W2;
- A1 := (C1 and $FF) * W1;
- G := (A1 + A2 + F) div D and $FF;
- Result := Result or G;
- end;
- function ColorDistance(C1, C2: Integer): Single;
- var
- DR, DG, DB: Integer;
- begin
- DR := (C1 and $FF) - (C2 and $FF);
- Result := Sqr(DR * WeightR);
- DG := (C1 shr 8 and $FF) - (C2 shr 8 and $FF);
- Result := Result + Sqr(DG * WeightG);
- DB := (C1 shr 16) - (C2 shr 16);
- Result := Result + Sqr(DB * WeightB);
- Result := SqRt(Result);
- end;
- function GetAdjustedThreshold(BkgndIntensity, Threshold: Single): Single;
- begin
- if BkgndIntensity < 220 then Result := (2 - BkgndIntensity / 220) * Threshold
- else Result := Threshold;
- end;
- function IsContrastEnough(AColor, ABkgndColor: Integer;
- DoAdjustThreshold: Boolean; Threshold: Single): Boolean;
- begin
- if DoAdjustThreshold then
- Threshold := GetAdjustedThreshold(ColorDistance(ABkgndColor, $000000), Threshold);
- Result := ColorDistance(ABkgndColor, AColor) > Threshold;
- end;
- procedure AdjustContrast(var AColor: Integer; ABkgndColor: Integer; Threshold: Single);
- var
- x, y, z: Single;
- r, g, b: Single;
- RR, GG, BB: Integer;
- i1, i2, s, q, w: Single;
- DoInvert: Boolean;
- begin
- i1 := ColorDistance(AColor, $000000);
- i2 := ColorDistance(ABkgndColor, $000000);
- Threshold := GetAdjustedThreshold(i2, Threshold);
- if i1 > i2 then DoInvert := i2 < 442 - Threshold
- else DoInvert := i2 < Threshold;
- x := (ABkgndColor and $FF) * WeightR;
- y := (ABkgndColor shr 8 and $FF) * WeightG;
- z := (ABkgndColor shr 16) * WeightB;
- r := (AColor and $FF) * WeightR;
- g := (AColor shr 8 and $FF) * WeightG;
- b := (AColor shr 16) * WeightB;
- if DoInvert then
- begin
- r := 195 - r;
- g := 390 - g;
- b := 65 - b;
- x := 195 - x;
- y := 390 - y;
- z := 65 - z;
- end;
- s := Sqrt(Sqr(b) + Sqr(g) + Sqr(r));
- if s < 0.01 then s := 0.01;
- q := (r * x + g * y + b * z) / S;
- x := Q / S * r - x;
- y := Q / S * g - y;
- z := Q / S * b - z;
- w := Sqrt(Sqr(Threshold) - Sqr(x) - Sqr(y) - Sqr(z));
- r := (q - w) * r / s;
- g := (q - w) * g / s;
- b := (q - w) * b / s;
- if DoInvert then
- begin
- r := 195 - r;
- g := 390 - g;
- b := 65 - b;
- end;
- if r < 0 then r := 0 else if r > 195 then r := 195;
- if g < 0 then g := 0 else if g > 390 then g := 390;
- if b < 0 then b := 0 else if b > 65 then b := 65;
- RR := Trunc(r * (1 / WeightR) + 0.5);
- GG := Trunc(g * (1 / WeightG) + 0.5);
- BB := Trunc(b * (1 / WeightB) + 0.5);
- if RR > $FF then RR := $FF else if RR < 0 then RR := 0;
- if GG > $FF then GG := $FF else if GG < 0 then GG := 0;
- if BB > $FF then BB := $FF else if BB < 0 then BB := 0;
- AColor := (BB and $FF) shl 16 or (GG and $FF) shl 8 or (RR and $FF);
- end;
- procedure SetContrast(var Color: TColor; BkgndColor: TColor; Threshold: Integer);
- var
- t: Single;
- begin
- if Color < 0 then Color := GetSysColor(Color and $FF);
- if BkgndColor < 0 then BkgndColor := GetSysColor(BkgndColor and $FF);
- t := Threshold;
- if not IsContrastEnough(Color, BkgndColor, True, t) then
- AdjustContrast(Integer(Color), BkgndColor, t);
- end;
- procedure RGBtoHSL(RGB: TColor; out H, S, L : Single);
- var
- R, G, B, D, Cmax, Cmin: Single;
- begin
- if RGB < 0 then RGB := GetSysColor(RGB and $FF);
- R := GetRValue(RGB) / 255;
- G := GetGValue(RGB) / 255;
- B := GetBValue(RGB) / 255;
- Cmax := Max(R, Max(G, B));
- Cmin := Min(R, Min(G, B));
- L := (Cmax + Cmin) / 2;
- if Cmax = Cmin then
- begin
- H := 0;
- S := 0
- end
- else
- begin
- D := Cmax - Cmin;
- if L < 0.5 then S := D / (Cmax + Cmin)
- else S := D / (2 - Cmax - Cmin);
- if R = Cmax then H := (G - B) / D
- else
- if G = Cmax then H := 2 + (B - R) / D
- else H := 4 + (R - G) / D;
- H := H / 6;
- if H < 0 then H := H + 1
- end;
- end;
- function HSLtoRGB(H, S, L: Single): TColor;
- const
- OneOverThree = 1 / 3;
- var
- M1, M2: Single;
- R, G, B: Byte;
- function HueToColor(Hue: Single): Byte;
- var
- V: Double;
- begin
- Hue := Hue - Floor(Hue);
- if 6 * Hue < 1 then V := M1 + (M2 - M1) * Hue * 6
- else if 2 * Hue < 1 then V := M2
- else if 3 * Hue < 2 then V := M1 + (M2 - M1) * (2 / 3 - Hue) * 6
- else V := M1;
- Result := Round(255 * V);
- end;
- begin
- if S = 0 then
- begin
- R := Round(255 * L);
- G := R;
- B := R;
- end
- else
- begin
- if L <= 0.5 then M2 := L * (1 + S)
- else M2 := L + S - L * S;
- M1 := 2 * L - M2;
- R := HueToColor(H + OneOverThree);
- G := HueToColor(H);
- B := HueToColor(H - OneOverThree)
- end;
- Result := RGB(R, G, B);
- end;
- const
- // This differs from PasTools as we use larger menu fonts
- OurDesignTimeTextHeight = 15;
- var
- LastFontName: string = '';
- LastFontHeight: Integer = -1;
- LastTextHeight: Integer = -1;
- function TBXScaleByTextHeightRunTime(Canvas: TCanvas; Dimension: Integer): Integer;
- begin
- // This should be called from the GUI thread only.
- // See ScaleByTextHeightRunTime in PasTools.
- if (LastTextHeight < 0) or
- (LastFontName <> Canvas.Font.Name) or
- (LastFontHeight <> Canvas.Font.Height) then
- begin
- LastTextHeight := Canvas.TextHeight('0');
- LastFontName := Canvas.Font.Name;
- LastFontHeight := Canvas.Font.Height;
- end;
- if LastTextHeight <> OurDesignTimeTextHeight then
- begin
- Dimension := MulDiv(Dimension, LastTextHeight, OurDesignTimeTextHeight);
- end;
- Result := Dimension;
- end;
- { Drawing routines }
- function GetBGR(C: TColorRef): Cardinal;
- asm
- MOV ECX,EAX // this function swaps R and B bytes in ABGR
- SHR EAX,16
- XCHG AL,CL
- MOV AH,$00 // and writes $FF into A component
- SHL EAX,16
- MOV AX,CX
- end;
- procedure SetPixelEx(DC: HDC; X, Y: Integer; C: TColorRef; Alpha: Longword = $FF);
- var
- W2: Cardinal;
- B: TColorRef;
- begin
- if Alpha <= 0 then Exit
- else if Alpha >= 255 then SetPixelV(DC, X, Y, C)
- else
- begin
- B := GetPixel(DC, X, Y);
- if B <> CLR_INVALID then
- begin
- Inc(Alpha, Integer(Alpha > 127));
- W2 := 256 - Alpha;
- B :=
- ((C and $FF00FF) * Alpha + (B and $FF00FF) * W2 + $007F007F) and $FF00FF00 +
- ((C and $00FF00) * Alpha + (B and $00FF00) * W2 + $00007F00) and $00FF0000;
- SetPixelV(DC, X, Y, B shr 8);
- end;
- end;
- end;
- function CreatePenEx(Color: TColor): HPen;
- begin
- if Color = clNone then Result := CreatePen(PS_NULL, 1, 0)
- else if Color < 0 then Result := CreatePen(PS_SOLID, 1, GetSysColor(Color and $000000FF))
- else Result := CreatePen(PS_SOLID, 1, Color);
- end;
- function CreateBrushEx(Color: TColor): HBrush;
- var
- LB: TLogBrush;
- begin
- if Color = clNone then
- begin
- LB.lbStyle := BS_HOLLOW;
- Result := CreateBrushIndirect(LB);
- end
- {else if Color < 0 then Result := GetSysColorBrush(Color and $000000FF)} {vb-}
- else begin {vb+}
- if Color < 0 then Color := GetSysColor(Color and $000000FF);
- Result := CreateSolidBrush(Color);
- end;
- end;
- function FillRectEx(DC: HDC; const Rect: TRect; Color: TColor): Boolean;
- var
- Brush: HBRUSH;
- begin
- Result := Color <> clNone;
- if Result then
- begin
- if Color < 0 then Brush := GetSysColorBrush(Color and $000000FF)
- else Brush := CreateSolidBrush(Color);
- Windows.FillRect(DC, Rect, Brush);
- {DeleteObject(Brush);} {vb-}
- if Color >= 0 then DeleteObject(Brush); {vb+}
- end;
- end;
- function FrameRectEx(DC: HDC; var Rect: TRect; Color: TColor; Adjust: Boolean): Boolean;
- var
- Brush: HBRUSH;
- begin
- Result := Color <> clNone;
- if Result then
- begin
- if Color < 0 then Brush := GetSysColorBrush(Color and $000000FF)
- else Brush := CreateSolidBrush(Color);
- Windows.FrameRect(DC, Rect, Brush);
- {DeleteObject(Brush);} {vb-}
- if Color >= 0 then DeleteObject(Brush); {vb+}
- end;
- if Adjust then with Rect do
- begin
- Inc(Left); Dec(Right);
- Inc(Top); Dec(Bottom);
- end;
- end;
- procedure DrawLineEx(DC: HDC; X1, Y1, X2, Y2: Integer; Color: TColor);
- var
- OldPen, Pen: HPen;
- begin
- Pen := CreatePen(PS_SOLID, 1, ColorToRGB(Color));
- OldPen := SelectObject(DC, Pen);
- Windows.MoveToEx(DC, X1, Y1, nil);
- Windows.LineTo(DC, X2, Y2);
- SelectObject(DC, OldPen);
- DeleteObject(Pen);
- end;
- function PolyLineEx(DC: HDC; const Points: array of TPoint; Color: TColor): Boolean; overload;
- var
- Pen, OldPen: HPEN;
- begin
- Result := Color <> clNone;
- if Result then
- begin
- if Color < 0 then Color := GetSysColor(Color and $FF);
- Pen := CreatePen(PS_SOLID, 1, Color);
- OldPen := SelectObject(DC, Pen);
- Windows.Polyline(DC, PPoints(@Points[0])^, Length(Points));
- SelectObject(DC, OldPen);
- DeleteObject(Pen);
- end;
- end;
- procedure PolygonEx(DC: HDC; const Points: array of TPoint; OutlineColor, FillColor: TColor);
- var
- OldBrush, Brush: HBrush;
- OldPen, Pen: HPen;
- begin
- if (OutlineColor = clNone) and (FillColor = clNone) then Exit;
- Pen := CreatePenEx(OutlineColor);
- Brush := CreateBrushEx(FillColor);
- OldPen := SelectObject(DC, Pen);
- OldBrush := SelectObject(DC, Brush);
- Windows.Polygon(DC, PPoints(@Points[0])^, Length(Points));
- SelectObject(DC, OldBrush);
- SelectObject(DC, OldPen);
- DeleteObject(Brush);
- DeleteObject(Pen);
- end;
- procedure RoundRectEx(DC: HDC; Left, Top, Right, Bottom: Integer;
- EllipseWidth, EllipseHeight, OutlineColor, FillColor: TColor); {vb+}
- var
- OldBrush, Brush: HBrush;
- OldPen, Pen: HPen;
- begin
- if (OutlineColor = clNone) and (FillColor = clNone) then Exit;
- Pen := CreatePenEx(OutlineColor);
- Brush := CreateBrushEx(FillColor);
- OldPen := SelectObject(DC, Pen);
- OldBrush := SelectObject(DC, Brush);
- Windows.RoundRect(DC, Left, Top, Right, Bottom, EllipseWidth, EllipseHeight);
- SelectObject(DC, OldBrush);
- SelectObject(DC, OldPen);
- DeleteObject(Brush);
- DeleteObject(Pen);
- end;
- procedure RoundRectEx(DC: HDC; const R: TRect; EllipseWidth, EllipseHeight,
- OutlineColor, FillColor: TColor); {vb+}
- begin
- with R do
- RoundRectEx(DC, Left, Top, Right, Bottom, EllipseWidth,
- EllipseHeight, OutlineColor, FillColor);
- end;
- procedure EllipseEx(DC: HDC; Left, Top, Right, Bottom: Integer; OutlineColor, FillColor: TColor);
- var
- OldBrush, Brush: HBrush;
- OldPen, Pen: HPen;
- begin
- Pen := CreatePenEx(OutlineColor);
- Brush := CreateBrushEx(FillColor);
- OldPen := SelectObject(DC, Pen);
- OldBrush := SelectObject(DC, Brush);
- Windows.Ellipse(DC, Left, Top, Right, Bottom);
- SelectObject(DC, OldBrush);
- SelectObject(DC, OldPen);
- DeleteObject(Brush);
- DeleteObject(Pen);
- end;
- function CreateDitheredBrush(C1, C2: TColor): HBrush;
- var
- B: TBitmap;
- begin
- B := AllocPatternBitmap(C1, C2);
- B.HandleType := bmDDB;
- Result := CreatePatternBrush(B.Handle);
- end;
- procedure DitherRect(DC: HDC; const R: TRect; C1, C2: TColor);
- var
- Brush: HBRUSH;
- begin
- Brush := CreateDitheredBrush(C1, C2);
- FillRect(DC, R, Brush);
- DeleteObject(Brush);
- end;
- procedure Frame3D(DC: HDC; var Rect: TRect; TopColor, BottomColor: TColor; Adjust: Boolean);
- var
- TopRight, BottomLeft: TPoint;
- begin
- with Rect do
- begin
- Dec(Bottom); Dec(Right);
- TopRight.X := Right;
- TopRight.Y := Top;
- BottomLeft.X := Left;
- BottomLeft.Y := Bottom;
- PolyLineEx(DC, [BottomLeft, TopLeft, TopRight], TopColor);
- Dec(BottomLeft.X);
- PolyLineEx(DC, [TopRight, BottomRight, BottomLeft], BottomColor);
- if Adjust then
- begin
- Inc(Left);
- Inc(Top);
- end
- else
- begin
- Dec(Right);
- Dec(Bottom);
- end;
- end;
- end;
- {$IFDEF COMPATIBLE_GFX}
- procedure DitherRect(Canvas: TCanvas; const R: TRect; C1, C2: TColor);
- begin
- DitherRect(Canvas.Handle, R, C1, C2);
- end;
- procedure Frame3D(Canvas: TCanvas; var Rect: TRect; TopColor, BottomColor: TColor);
- var
- TopRight, BottomLeft: TPoint;
- begin
- with Canvas, Rect do
- begin
- Pen.Width := 1;
- Dec(Bottom); Dec(Right);
- TopRight.X := Right;
- TopRight.Y := Top;
- BottomLeft.X := Left;
- BottomLeft.Y := Bottom;
- Pen.Color := TopColor;
- PolyLine([BottomLeft, TopLeft, TopRight]);
- Pen.Color := BottomColor;
- Dec(BottomLeft.X);
- PolyLine([TopRight, BottomRight, BottomLeft]);
- Inc(Left); Inc(Top);
- end;
- end;
- function FillRectEx(Canvas: TCanvas; const Rect: TRect; Color: TColor): Boolean;
- begin
- Result := FillRectEx(Canvas.Handle, Rect, Color);
- end;
- function FillRectEx2(DC: HDC; const Rect: TRect; Color: TColor): Boolean; deprecated;
- begin
- Result := FillRectEx(DC, Rect, Color);
- end;
- function FrameRectEx(Canvas: TCanvas; var Rect: TRect; Color: TColor; Adjust: Boolean = False): Boolean;
- begin
- Result := FrameRectEx(Canvas.Handle, Rect, Color, Adjust);
- end;
- function FrameRectEx2(DC: HDC; var Rect: TRect; Color: TColor; Adjust: Boolean = False): Boolean; deprecated;
- begin
- Result := FrameRectEx(DC, Rect, Color, Adjust);
- end;
- procedure DrawLineEx(Canvas: TCanvas; X1, Y1, X2, Y2: Integer; Color: TColor);
- begin
- DrawLineEx(Canvas.Handle, X1, Y1, X2, Y2, Color);
- end;
- {$ENDIF}
- procedure DrawDraggingOutline(DC: HDC; const NewRect, OldRect: TRect);
- var
- Sz: TSize;
- begin
- Sz.CX := 3; Sz.CY := 2;
- DrawHalftoneInvertRect(DC, @NewRect, @OldRect, Sz, Sz);
- end;
- procedure FillLongword(var X; Count: Integer; Value: Longword);
- asm
- // EAX = X; EDX = Count; ECX = Value
- PUSH EDI
- MOV EDI,EAX // Point EDI to destination
- MOV EAX,ECX
- MOV ECX,EDX
- TEST ECX,ECX
- JS @exit
- REP STOSD // Fill count dwords
- @exit:
- POP EDI
- end;
- procedure MoveLongword(const Source; var Dest; Count: Integer);
- asm
- // EAX = Source; EDX = Dest; ECX = Count
- PUSH ESI
- PUSH EDI
- MOV ESI,EAX // Source
- MOV EDI,EDX // Destination
- MOV EAX,ECX // Counter
- CMP EDI,ESI
- JE @exit
- REP MOVSD
- @exit:
- POP EDI
- POP ESI
- end;
- procedure DrawTBXIcon(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; HiContrast: Boolean);
- {const
- CWeirdColor = $00203241;} {vb -}
- var
- ImageWidth, ImageHeight: Integer;
- I, J: Integer;
- Src, Dst: PColor;
- S, C: TColor;
- begin
- if not HiContrast then
- begin
- ImageList.Draw(Canvas, R.Left, R.Top, ImageIndex);
- Exit;
- end;
- ImageWidth := R.Right - R.Left;
- ImageHeight := R.Bottom - R.Top;
- with ImageList do
- begin
- if Width < ImageWidth then ImageWidth := Width;
- if Height < ImageHeight then ImageHeight := Height;
- end;
- StockBitmap1.Width := ImageWidth;
- StockBitmap1.Height := ImageHeight;
- StockBitmap2.Width := ImageWidth;
- StockBitmap2.Height := ImageHeight;
- BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- Canvas.Handle, R.Left, R.Top, SRCCOPY);
- {for J := 0 to ImageHeight - 1 do
- FillLongWord(StockBitmap2.ScanLine[J]^, ImageWidth, CWeirdColor);} {vb -}
- BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
- ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex);
- for J := 0 to ImageHeight - 1 do
- begin
- Src := StockBitmap2.ScanLine[J];
- Dst := StockBitmap1.ScanLine[J];
- for I := 0 to ImageWidth - 1 do
- begin
- {S := Src^ and $00FFFFFF;} {vb -}
- S := Src^; {vb +}
- {if S <> CWeirdColor then} {vb -}
- if S <> Dst^ then {vb +}
- begin
- {C := (S and $FF0000) shr 16 * 76 + (S and $00FF00) shr 8 * 150 +
- (S and $0000FF) * 29;} {vb -}
- C := (S and $00FF0000) shr 16 * 76 + (S and $0000FF00) shr 8 * 150 +
- (S and $000000FF) * 29; {vb +}
- if C > $FD00 then S := $000000
- else if C < $6400 then S := $FFFFFF;
- Dst^ := Lighten(S, 32);
- end;
- Inc(Src);
- Inc(Dst);
- end;
- end;
- BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
- StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
- end;
- procedure BlendTBXIcon(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; Opacity: Byte);
- {const
- CWeirdColor = $00203241;} {vb -}
- var
- ImageWidth, ImageHeight: Integer;
- I, J: Integer;
- Src, Dst: ^Cardinal;
- S, C, CBRB, CBG: Cardinal;
- Wt1, Wt2: Cardinal;
- begin
- Wt2 := Opacity;
- Wt1 := 255 - Wt2;
- ImageWidth := R.Right - R.Left;
- ImageHeight := R.Bottom - R.Top;
- with ImageList do
- begin
- if Width < ImageWidth then ImageWidth := Width;
- if Height < ImageHeight then ImageHeight := Height;
- end;
- StockBitmap1.Width := ImageWidth;
- StockBitmap1.Height := ImageHeight;
- StockBitmap2.Width := ImageWidth;
- StockBitmap2.Height := ImageHeight;
- BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- Canvas.Handle, R.Left, R.Top, SRCCOPY);
- {BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);} {vb -}
- BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
- ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
- for J := 0 to ImageHeight - 1 do
- begin
- Src := StockBitmap2.ScanLine[J];
- Dst := StockBitmap1.ScanLine[J];
- for I := 0 to ImageWidth - 1 do
- begin
- S := Src^;
- if S <> Dst^ then
- begin
- CBRB := (Dst^ and $00FF00FF) * Wt1;
- CBG := (Dst^ and $0000FF00) * Wt1;
- {C := ((S and $FF00FF) * Wt2 + CBRB) and $FF00FF00 +
- ((S and $00FF00) * Wt2 + CBG) and $00FF0000;} {vb -}
- C := ((S and $00FF00FF) * Wt2 + CBRB) and $FF00FF00 +
- ((S and $0000FF00) * Wt2 + CBG) and $00FF0000; {vb +}
- Dst^ := C shr 8;
- end;
- Inc(Src);
- Inc(Dst);
- end;
- end;
- BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
- StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
- end;
- procedure HighlightTBXIcon(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; HighlightColor: TColor; Amount: Byte);
- {const
- CWeirdColor = $00203241;} {vb -}
- var
- ImageWidth, ImageHeight: Integer;
- I, J: Integer;
- {Src, Dst: PColor;} {vb -}
- Src, Dst: ^Cardinal; {vb +}
- S, C: Cardinal;
- CBRB, CBG: Cardinal;
- W1, W2: Cardinal;
- begin
- ImageWidth := R.Right - R.Left;
- ImageHeight := R.Bottom - R.Top;
- with ImageList do
- begin
- if Width < ImageWidth then ImageWidth := Width;
- if Height < ImageHeight then ImageHeight := Height;
- end;
- StockBitmap1.Width := ImageWidth;
- StockBitmap1.Height := ImageHeight;
- StockBitmap2.Width := ImageWidth;
- StockBitmap2.Height := ImageHeight;
- BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- Canvas.Handle, R.Left, R.Top, SRCCOPY);
- {for J := 0 to ImageHeight - 1 do
- FillLongWord(StockBitmap2.ScanLine[J]^, ImageWidth, CWeirdColor);} {vb -}
- BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
- ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex);
- W2 := Amount;
- W1 := 255 - W2;
- HighlightColor := GetBGR(ColorToRGB(HighlightColor));
- CBRB := (Cardinal(HighlightColor) and $00FF00FF) * W1;
- CBG := (Cardinal(HighlightColor) and $0000FF00) * W1;
- for J := 0 to ImageHeight - 1 do
- begin
- Src := StockBitmap2.ScanLine[J];
- Dst := StockBitmap1.ScanLine[J];
- for I := 0 to ImageWidth - 1 do
- begin
- {S := Src^ and $00FFFFFF;} {vb -}
- S := Src^; {vb +}
- {if S <> CWeirdColor then} {vb -}
- if S <> Dst^ then {vb +}
- begin
- {C := ((S and $FF00FF) * W2 + CBRB) and $FF00FF00 +
- ((S and $00FF00) * W2 + CBG) and $00FF0000;} {vb -}
- C := ((S and $00FF00FF) * W2 + CBRB) and $FF00FF00 +
- ((S and $0000FF00) * W2 + CBG) and $00FF0000; {vb +}
- Dst^ := C shr 8;
- end;
- Inc(Src);
- Inc(Dst);
- end;
- end;
- BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
- StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
- end;
- procedure DrawTBXIconShadow(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; Density: Integer);
- const
- D_DIV: array [0..2] of Cardinal = (3, 8, 20);
- D_ADD: array [0..2] of Cardinal = (255 - 255 div 3, 255 - 255 div 8, 255 - 255 div 20);
- var
- ImageWidth, ImageHeight: Integer;
- I, J: Integer;
- Src, Dst: ^Cardinal;
- S, C, CBRB, CBG: Cardinal;
- begin
- Assert(Density in [0..2]);
- ImageWidth := R.Right - R.Left;
- ImageHeight := R.Bottom - R.Top;
- with ImageList do
- begin
- if Width < ImageWidth then ImageWidth := Width;
- if Height < ImageHeight then ImageHeight := Height;
- end;
- StockBitmap1.Width := ImageWidth;
- StockBitmap1.Height := ImageHeight;
- StockBitmap2.Width := ImageWidth;
- StockBitmap2.Height := ImageHeight;
- BitBlt(StockBitmap1.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- Canvas.Handle, R.Left, R.Top, SRCCOPY);
- {BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);} {vb -}
- BitBlt(StockBitmap2.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- Canvas.Handle, R.Left, R.Top, SRCCOPY); {vb +}
- ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
- for J := 0 to ImageHeight - 1 do
- begin
- Src := StockBitmap2.ScanLine[J];
- Dst := StockBitmap1.ScanLine[J];
- for I := 0 to ImageWidth - 1 do
- begin
- S := Src^;
- if S <> Dst^ then
- begin
- CBRB := Dst^ and $00FF00FF;
- CBG := Dst^ and $0000FF00;
- {C := ((S and $FF0000) shr 16 * 29 + (S and $00FF00) shr 8 * 150 +
- (S and $0000FF) * 76) shr 8;} {vb -}
- C := ((S and $00FF0000) shr 16 * 29 + (S and $0000FF00) shr 8 * 150 +
- (S and $000000FF) * 76) shr 8; {vb +}
- C := C div D_DIV[Density] + D_ADD[Density];
- Dst^ := ((CBRB * C and $FF00FF00) or (CBG * C and $00FF0000)) shr 8;
- end;
- Inc(Src);
- Inc(Dst);
- end;
- end;
- BitBlt(Canvas.Handle, R.Left, R.Top, ImageWidth, ImageHeight,
- StockBitmap1.Canvas.Handle, 0, 0, SRCCOPY);
- end;
- procedure DrawTBXIconFlatShadow(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; ShadowColor: TColor);
- const
- CShadowThreshold = 180 * 256;
- var
- ImageWidth, ImageHeight: Integer;
- I, J: Integer;
- P: ^Cardinal;
- C: Cardinal;
- SrcDC, DstDC: HDC;
- begin
- ImageWidth := R.Right - R.Left;
- ImageHeight := R.Bottom - R.Top;
- with ImageList do
- begin
- if Width < ImageWidth then ImageWidth := Width;
- if Height < ImageHeight then ImageHeight := Height;
- end;
- StockBitmap2.Width := ImageWidth;
- StockBitmap2.Height := ImageHeight;
- StockBitmap2.Canvas.Brush.Color := clWhite;
- StockBitmap2.Canvas.FillRect(Rect(0, 0, ImageWidth, ImageHeight));
- ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
- for J := 0 to ImageHeight - 1 do
- begin
- P := StockBitmap2.ScanLine[J];
- for I := 0 to ImageWidth - 1 do
- begin
- C := P^ and $00FFFFFF;
- if C <> $0 then
- begin
- C := (C and $FF0000) shr 16 * 76 + (C and $00FF00) shr 8 * 150 + (C and $0000FF) * 29;
- if C > CShadowThreshold then P^ := $00FFFFFF
- else P^ := $00000000;
- end;
- Inc(P);
- end;
- end;
- StockMonoBitmap.Width := ImageWidth;
- StockMonoBitmap.Height := ImageHeight;
- StockMonoBitmap.Canvas.Brush.Color := clBlack;
- BitBlt(StockMonoBitmap.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- StockBitmap2.Canvas.Handle, 0, 0, SRCCOPY);
- SrcDC := StockMonoBitmap.Canvas.Handle;
- Canvas.Brush.Color := ColorToRGB(ShadowColor);
- DstDC := Canvas.Handle;
- Windows.SetTextColor(DstDC, clWhite);
- Windows.SetBkColor(DstDC, clBlack);
- BitBlt(DstDC, R.Left, R.Top, ImageWidth, ImageHeight, SrcDC, 0, 0, ROP_DSPDxax);
- end;
- procedure DrawTBXIconFullShadow(Canvas: TCanvas; const R: TRect;
- ImageList: TCustomImageList; ImageIndex: Integer; ShadowColor: TColor);
- const
- CWeirdColor = $00203241;
- var
- ImageWidth, ImageHeight: Integer;
- I, J: Integer;
- P: ^Cardinal;
- C: Cardinal;
- SrcDC, DstDC: HDC;
- begin
- ImageWidth := R.Right - R.Left;
- ImageHeight := R.Bottom - R.Top;
- with ImageList do
- begin
- if Width < ImageWidth then ImageWidth := Width;
- if Height < ImageHeight then ImageHeight := Height;
- end;
- StockBitmap2.Width := ImageWidth;
- StockBitmap2.Height := ImageHeight;
- for J := 0 to ImageHeight - 1 do
- FillLongWord(StockBitmap2.ScanLine[J]^, ImageWidth, CWeirdColor);
- ImageList.Draw(StockBitmap2.Canvas, 0, 0, ImageIndex, True);
- for J := 0 to ImageHeight - 1 do
- begin
- P := StockBitmap2.ScanLine[J];
- for I := 0 to ImageWidth - 1 do
- begin
- C := P^ and $00FFFFFF;
- if C <> CWeirdColor then P^ := $00000000
- else P^ := $00FFFFFF;
- Inc(P);
- end;
- end;
- StockMonoBitmap.Width := ImageWidth;
- StockMonoBitmap.Height := ImageHeight;
- StockMonoBitmap.Canvas.Brush.Color := clBlack;
- BitBlt(StockMonoBitmap.Canvas.Handle, 0, 0, ImageWidth, ImageHeight,
- StockBitmap2.Canvas.Handle, 0, 0, SRCCOPY);
- SrcDC := StockMonoBitmap.Canvas.Handle;
- Canvas.Brush.Color := ColorToRGB(ShadowColor);
- DstDC := Canvas.Handle;
- Windows.SetTextColor(DstDC, clWhite);
- Windows.SetBkColor(DstDC, clBlack);
- BitBlt(DstDC, R.Left, R.Top, ImageWidth, ImageHeight, SrcDC, 0, 0, ROP_DSPDxax);
- end;
- procedure DrawGlyph(DC: HDC; X, Y: Integer; ImageList: TCustomImageList; ImageIndex: Integer; Color: TColor);
- var
- B: TBitmap;
- OldTextColor, OldBkColor: Longword;
- OldBrush, Brush: HBrush;
- begin
- if Color = clNone then Exit;
- B := TBitmap.Create;
- B.Monochrome := True;
- ImageList.GetBitmap(ImageIndex, B);
- OldTextColor := SetTextColor(DC, clBlack);
- OldBkColor := SetBkColor(DC, clWhite);
- if Color < 0 then Brush := GetSysColorBrush(Color and $FF)
- else Brush := CreateSolidBrush(Color);
- OldBrush := SelectObject(DC, Brush);
- BitBlt(DC, X, Y, ImageList.Width, ImageList.Height, B.Canvas.Handle, 0, 0, ROP_DSPDxax);
- SelectObject(DC, OldBrush);
- if Color >= 0 then DeleteObject(Brush);
- SetTextColor(DC, OldTextColor);
- SetBkColor(DC, OldBkColor);
- B.Free;
- end;
- procedure DrawGlyph(DC: HDC; const R: TRect; ImageList: TCustomImageList; ImageIndex: Integer; Color: TColor); overload;
- begin
- DrawGlyph(DC, (R.Left + R.Right + 1 - ImageList.Width) div 2, (R.Top + R.Bottom + 1 - ImageList.Height) div 2, ImageList, ImageIndex, Color);
- end;
- procedure DrawGlyph(DC: HDC; X, Y: Integer; const Bits; Color: TColor); overload;
- var
- B: TBitmap;
- OldTextColor, OldBkColor: Longword;
- OldBrush, Brush: HBrush;
- begin
- B := TBitmap.Create;
- B.Handle := CreateBitmap(8, 8, 1, 1, @Bits);
- OldTextColor := SetTextColor(DC, clBlack);
- OldBkColor := SetBkColor(DC, clWhite);
- if Color < 0 then Brush := GetSysColorBrush(Color and $FF)
- else Brush := CreateSolidBrush(Color);
- OldBrush := SelectObject(DC, Brush);
- BitBlt(DC, X, Y, 8, 8, B.Canvas.Handle, 0, 0, ROP_DSPDxax);
- SelectObject(DC, OldBrush);
- if Color >= 0 then DeleteObject(Brush);
- SetTextColor(DC, OldTextColor);
- SetBkColor(DC, OldBkColor);
- B.Free;
- end;
- procedure DrawGlyph(DC: HDC; const R: TRect; Width, Height: Integer; const Bits; Color: TColor); overload;
- var
- B: TBitmap;
- OldTextColor, OldBkColor: Longword;
- OldBrush, Brush: HBrush;
- begin
- B := TBitmap.Create;
- B.Handle := CreateBitmap(8, 8, 1, 1, @Bits);
- OldTextColor := SetTextColor(DC, clBlack);
- OldBkColor := SetBkColor(DC, clWhite);
- if Color < 0 then Brush := GetSysColorBrush(Color and $FF)
- else Brush := CreateSolidBrush(Color);
- OldBrush := SelectObject(DC, Brush);
- 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);
- SelectObject(DC, OldBrush);
- if Color >= 0 then DeleteObject(Brush);
- SetTextColor(DC, OldTextColor);
- SetBkColor(DC, OldBkColor);
- B.Free;
- end;
- type
- TCustomFormAccess = class(TCustomForm);
- function GetClientSizeEx(Control: TWinControl): TPoint;
- var
- R: TRect;
- begin
- if (Control is TCustomForm) and (TCustomFormAccess(Control).FormStyle = fsMDIForm)
- and not (csDesigning in Control.ComponentState) then
- GetWindowRect(TCustomFormAccess(Control).ClientHandle, R)
- else
- R := Control.ClientRect;
- Result.X := R.Right - R.Left;
- Result.Y := R.Bottom - R.Top;
- end;
- procedure InitializeStock;
- var
- NonClientMetrics: TNonClientMetrics;
- begin
- StockBitmap1 := TBitmap.Create;
- StockBitmap1.PixelFormat := pf32bit;
- StockBitmap2 := TBitmap.Create;
- StockBitmap2.PixelFormat := pf32bit;
- StockMonoBitmap := TBitmap.Create;
- StockMonoBitmap.Monochrome := True;
- StockCompatibleBitmap := TBitmap.Create;
- StockCompatibleBitmap.Width := 8;
- StockCompatibleBitmap.Height := 8;
- SmCaptionFont := TFont.Create;
- NonClientMetrics.cbSize := SizeOf(NonClientMetrics);
- if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
- SmCaptionFont.Handle := CreateFontIndirect(NonClientMetrics.lfSmCaptionFont);
- end;
- procedure FinalizeStock;
- begin
- SmCaptionFont.Free;
- SmCaptionFont := nil;
- StockCompatibleBitmap.Free;
- StockMonoBitmap.Free;
- StockBitmap2.Free;
- StockBitmap1.Free;
- end;
- procedure RecreateStock;
- begin
- FinalizeStock;
- InitializeStock;
- end;
- { TShadow } ////////////////////////////////////////////////////////////////////
- procedure TShadow.Clear(const R: TRect);
- begin
- FClearRect := R;
- end;
- constructor TShadow.Create(const Bounds: TRect; Opacity: Byte; LoColor: Boolean; Edges: TShadowEdges);
- begin
- inherited Create(nil);
- Hide;
- ParentWindow := Application.Handle;
- BoundsRect := Bounds;
- Color := clBtnShadow;
- FOpacity := Opacity;
- FEdges := Edges;
- FSaveBits := False;
- if LoColor then FStyle := ssFlat
- else FStyle := ssLayered;
- end;
- procedure TShadow.CreateParams(var Params: TCreateParams);
- begin
- inherited;
- with Params do
- begin
- Style := (Style and not (WS_CHILD or WS_GROUP or WS_TABSTOP)) or WS_POPUP;
- ExStyle := ExStyle or WS_EX_TOOLWINDOW;
- if FSaveBits then WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
- end;
- end;
- procedure TShadow.GradB(const R: TRect);
- var
- J, W, H: Integer;
- V: Cardinal;
- P: ^Cardinal;
- begin
- W := R.Right - R.Left;
- H := R.Bottom - R.Top;
- for J := 0 to H - 1 do
- begin
- P := FBuffer.ScanLine[J + R.Top];
- Inc(P, R.Left);
- V := (255 - J shl 8 div H) shl 24;
- FillLongword(P^, W, V);
- end;
- end;
- procedure TShadow.GradBL(const R: TRect);
- var
- I, J, W, H, CX, CY, D, DMax, A, B: Integer;
- P: ^Cardinal;
- begin
- W := R.Right - R.Left;
- H := R.Bottom - R.Top;
- DMax := W;
- if H > W then DMax := H;
- CX := DMax - 1;
- CY := H - DMax;
- for J := 0 to H - 1 do
- begin
- P := FBuffer.ScanLine[J + R.Top];
- Inc(P, R.Left);
- for I := 0 to W - 1 do
- begin
- A := Abs(I - CX);
- B := Abs(J - CY);
- D := A;
- if B > A then D := B;
- D := (A + B + D) * 128 div DMax;
- if D < 255 then P^ := (255 - D) shl 24
- else P^ := 0;
- Inc(P);
- end;
- end;
- end;
- procedure TShadow.GradBR(const R: TRect);
- var
- I, J, W, H, CX, CY, D, DMax, A, B: Integer;
- P: ^Cardinal;
- begin
- W := R.Right - R.Left;
- H := R.Bottom - R.Top;
- DMax := W;
- if H > W then DMax := H;
- CX := W - DMax;
- CY := H - DMax;
- for J := 0 to H - 1 do
- begin
- P := FBuffer.ScanLine[J + R.Top];
- Inc(P, R.Left);
- for I := 0 to W - 1 do
- begin
- A := Abs(I - CX);
- B := Abs(J - CY);
- D := A;
- if B > A then D := B;
- D := (A + B + D) * 128 div DMax;
- if D < 255 then P^ := (255 - D) shl 24
- else P^ := 0;
- Inc(P);
- end;
- end;
- end;
- procedure TShadow.GradR(const R: TRect);
- var
- I, J, W: Integer;
- P: ^Cardinal;
- ScanLine: array of Cardinal;
- begin
- W := R.Right - R.Left;
- SetLength(ScanLine, W);
- for I := 0 to W - 1 do
- ScanLine[I] :=(255 - I shl 8 div W) shl 24;
- for J := R.Top to R.Bottom - 1 do
- begin
- P := FBuffer.ScanLine[J];
- Inc(P, R.Left);
- MoveLongword(ScanLine[0], P^, W);
- end;
- end;
- procedure TShadow.GradTR(const R: TRect);
- var
- I, J, W, H, CX, CY, D, DMax, A, B: Integer;
- P: ^Cardinal;
- begin
- W := R.Right - R.Left;
- H := R.Bottom - R.Top;
- DMax := W;
- if H > W then DMax := H;
- CX := W - DMax;
- CY := DMax - 1;
- for J := 0 to H - 1 do
- begin
- P := FBuffer.ScanLine[J + R.Top];
- Inc(P, R.Left);
- for I := 0 to W - 1 do
- begin
- A := Abs(I - CX);
- B := Abs(J - CY);
- D := A;
- if B > A then D := B;
- D := (A + B + D) * 128 div DMax;
- if D < 255 then P^ := (255 - D) shl 24
- else P^ := 0;
- Inc(P);
- end;
- end;
- end;
- procedure TShadow.Render;
- var
- DstDC: HDC;
- SrcPos, DstPos: TPoint;
- TheSize: TSize;
- BlendFunc: TBlendFunction;
- begin
- if FStyle <> ssLayered then Exit;
- SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or $00080000{WS_EX_LAYERED});
- DstDC := GetDC(0);
- try
- SrcPos := Point(0, 0);
- with BoundsRect do
- begin
- DstPos := Point(Left, Top);
- TheSize.cx := Right - Left;
- TheSize.cy := Bottom - Top;
- end;
- BlendFunc.BlendOp := 0;
- BlendFunc.BlendFlags := 0;
- BlendFunc.SourceConstantAlpha := FOpacity;
- BlendFunc.AlphaFormat := 1;
- FBuffer := TBitmap.Create;
- FBuffer.PixelFormat := pf32bit;
- FBuffer.Width := TheSize.cx;
- FBuffer.Height := TheSize.cy;
- FillBuffer;
- UpdateLayeredWindow(
- Handle,
- DstDC,
- @DstPos,
- @TheSize,
- FBuffer.Canvas.Handle,
- @SrcPos,
- 0,
- @BlendFunc,
- $00000002{ULW_ALPHA});
- FBuffer.Free;
- finally
- ReleaseDC(0, DstDC);
- end;
- end;
- procedure TShadow.Show(ParentHandle: HWND);
- begin
- SetWindowPos(Handle, ParentHandle, 0, 0, 0, 0,
- SWP_NOACTIVATE or SWP_NOSENDCHANGING or SWP_NOMOVE or
- SWP_NOOWNERZORDER or SWP_NOSIZE or SWP_SHOWWINDOW);
- end;
- procedure TShadow.WMNCHitTest(var Message: TMessage);
- begin
- Message.Result := HTTRANSPARENT;
- end;
- { THorzShadow }
- procedure THorzShadow.FillBuffer;
- var
- R: TRect;
- L1, L2, L3: Integer;
- begin
- if seTopLeft in FEdges then L1 := Height else L1 := 0;
- if seBottomRight in FEdges then L3 := Height else L3 := 0;
- if L1 + L3 > Width then
- begin
- if (L1 > 0) and (L3 > 0) then
- begin
- L1 := Width div 2;
- L3 := L1;
- end
- else if L1 > 0 then L1 := Width
- else if L3 > 0 then L3 := Width;
- end;
- L2 := Width - L1 - L3;
- R := Rect(0, 0, Width, Height);
- R.Right := R.Left + L1;
- if L1 > 0 then GradBL(R);
- R.Left := R.Right;
- R.Right := R.Left + L2;
- if L2 > 0 then GradB(R);
- if L3 > 0 then
- begin
- R.Left := R.Right;
- R.Right := R.Left + L3;
- GradBR(R);
- end;
- end;
- { TVertShadow }
- procedure TVertShadow.FillBuffer;
- var
- R: TRect;
- L1, L2, L3: Integer;
- begin
- if seTopLeft in FEdges then L1 := Width else L1 := 0;
- if seBottomRight in FEdges then L3 := Width else L3 := 0;
- if L1 + L3 > Height then
- begin
- if (L1 > 0) and (L3 > 0) then
- begin
- L1 := Height div 2;
- L3 := L1;
- end
- else if L1 > 0 then L1 := Height
- else if L3 > 0 then L3 := Height;
- end;
- L2 := Height - L1 - L3;
- R := Rect(0, 0, Width, Height);
- R.Bottom := R.Top + L1;
- if L1 > 0 then GradTR(R);
- R.Top := R.Bottom;
- R.Bottom := R.Top + L2;
- if L2 > 0 then GradR(R);
- if L3 > 0 then
- begin
- R.Top := R.Bottom;
- R.Bottom := R.Top + L3;
- GradBR(R);
- end;
- end;
- { TShadows }
- constructor TShadows.Create(R1, R2: TRect; TheSize: Integer; Opacity: Byte; LoColor: Boolean);
- var
- R: TRect;
- R1Valid, R2Valid: Boolean;
- begin
- if LoColor then
- begin
- TheSize := TheSize div 2;
- end;
- R1Valid := not IsRectEmpty(R1);
- R2Valid := not IsRectEmpty(R2);
- if not (R1Valid or R2Valid) then Exit;
- if R1Valid xor R2Valid then
- begin
- { A simple square shadow }
- if R1Valid then R := R1 else R:= R2;
- with R do
- begin
- V1 := TVertShadow.Create(Rect(Right, Top + TheSize, Right + TheSize, Bottom), Opacity, LoColor, [seTopLeft]);
- H1 := THorzShadow.Create(Rect(Left + TheSize, Bottom, Right + TheSize, Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight])
- end;
- end
- else
- begin
- if (R1.Bottom <= R2.Top + 2) or (R1.Top >= R2.Bottom - 2) then
- begin
- if R1.Top > R2.Top then
- begin
- R := R2;
- R2 := R1;
- R1 := R;
- end;
- if R1.Left + TheSize < R2.Left then
- H1 := THorzShadow.Create(Rect(R1.Left + TheSize, R1.Bottom, R2.Left, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft]);
- H2 := THorzShadow.Create(Rect(R2.Left + TheSize, R2.Bottom, R2.Right + TheSize, R2.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
- V1 := TVertShadow.Create(Rect(R1.Right, R1.Top + TheSize, R1.Right + TheSize, R1.Bottom), Opacity, LoColor, [seTopLeft]);
- if R1.Right > R2.Right then
- H3 := THorzShadow.Create(Rect(R2.Right, R1.Bottom, R1.Right + TheSize, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
- if R1.Right + TheSize < R2.Right then
- V2 := TVertShadow.Create(Rect(R2.Right, R2.Top + TheSize, R2.Right + TheSize, R2.Bottom), Opacity, LoColor, [seTopLeft])
- else
- V2 := TVertShadow.Create(Rect(R2.Right, R2.Top + 1, R2.Right + TheSize, R2.Bottom), Opacity, LoColor, []);
- end
- else if (R1.Right <= R2.Left + 2) or (R1.Left >= R2.Right - 2) then
- begin
- if R1.Left > R2.Left then
- begin
- R := R2;
- R2 := R1;
- R1 := R;
- end;
- if R1.Top + TheSize < R2.Top then
- V1 := TVertShadow.Create(Rect(R1.Right, R1.Top + TheSize, R1.Right + TheSize, R2.Top), Opacity, LoColor, [seTopLeft]);
- V2 := TVertShadow.Create(Rect(R2.Right, R2.Top + TheSize, R2.Right + TheSize, R2.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
- H1 := THorzShadow.Create(Rect(R1.Left + TheSize, R1.Bottom, R1.Right, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft]);
- if R1.Bottom > R2.Bottom then
- V3 := TVertShadow.Create(Rect(R1.Right, R2.Bottom, R1.Right + TheSize, R1.Bottom + TheSize), Opacity, LoColor, [seTopLeft, seBottomRight]);
- if R1.Bottom + TheSize < R2.Bottom then
- H2 := THorzShadow.Create(Rect(R2.Left + TheSize, R2.Bottom, R2.Right, R2.Bottom + TheSize), Opacity, LoColor, [seTopLeft])
- else
- H2 := THorzShadow.Create(Rect(R2.Left, R2.Bottom, R2.Right, R2.Bottom + TheSize), Opacity, LoColor, []);
- end;
- end;
- if V1 <> nil then V1.Render;
- if H1 <> nil then H1.Render;
- if V2 <> nil then V2.Render;
- if H2 <> nil then H2.Render;
- if V3 <> nil then V3.Render;
- if H3 <> nil then H3.Render;
- SetSaveBits(True);
- end;
- destructor TShadows.Destroy;
- begin
- H3.Free;
- V3.Free;
- H2.Free;
- V2.Free;
- H1.Free;
- V1.Free;
- inherited;
- end;
- procedure TShadows.SetSaveBits(Value: Boolean);
- begin
- FSaveBits := Value;
- if V1 <> nil then V1.FSaveBits := Value;
- if H1 <> nil then H1.FSaveBits := Value;
- if V2 <> nil then V2.FSaveBits := Value;
- if H2 <> nil then H2.FSaveBits := Value;
- if V3 <> nil then V3.FSaveBits := Value;
- if H3 <> nil then H3.FSaveBits := Value;
- end;
- procedure TShadows.Show(ParentHandle: HWND);
- begin
- if V1 <> nil then V1.Show(ParentHandle);
- if H1 <> nil then H1.Show(ParentHandle);
- if V2 <> nil then V2.Show(ParentHandle);
- if H2 <> nil then H2.Show(ParentHandle);
- if V3 <> nil then V3.Show(ParentHandle);
- if H3 <> nil then H3.Show(ParentHandle);
- end;
- { Gradients } //////////////////////////////////////////////////////////////////
- const
- GRADIENT_CACHE_SIZE = 16;
- type
- PRGBQuad = ^TRGBQuad;
- TRGBQuad = Integer;
- PRGBQuadArray = ^TRGBQuadArray;
- TRGBQuadArray = array [0..0] of TRGBQuad;
- var
- GradientCache: array [0..GRADIENT_CACHE_SIZE] of array of TRGBQuad;
- NextCacheIndex: Integer = 0;
- function FindGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
- begin
- Assert(Size > 0);
- Result := GRADIENT_CACHE_SIZE - 1;
- while Result >= 0 do
- begin
- if (Length(GradientCache[Result]) = Size) and
- (GradientCache[Result][0] = CL) and
- (GradientCache[Result][Length(GradientCache[Result]) - 1] = CR) then Exit;
- Dec(Result);
- end;
- end;
- function MakeGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
- var
- R1, G1, B1: Integer;
- R2, G2, B2: Integer;
- R, G, B: Integer;
- I: Integer;
- Bias: Integer;
- begin
- Assert(Size > 0);
- Result := NextCacheIndex;
- Inc(NextCacheIndex);
- if NextCacheIndex >= GRADIENT_CACHE_SIZE then NextCacheIndex := 0;
- R1 := CL and $FF;
- G1 := CL shr 8 and $FF;
- B1 := CL shr 16 and $FF;
- R2 := CR and $FF - R1;
- G2 := CR shr 8 and $FF - G1;
- B2 := CR shr 16 and $FF - B1;
- SetLength(GradientCache[Result], Size);
- Dec(Size);
- Bias := Size div 2;
- if Size > 0 then
- for I := 0 to Size do
- begin
- R := R1 + (R2 * I + Bias) div Size;
- G := G1 + (G2 * I + Bias) div Size;
- B := B1 + (B2 * I + Bias) div Size;
- GradientCache[Result][I] := R + G shl 8 + B shl 16;
- end
- else
- begin
- R := R1 + R2 div 2;
- G := G1 + G2 div 2;
- B := B1 + B2 div 2;
- GradientCache[Result][0] := R + G shl 8 + B shl 16;
- end;
- end;
- function GetGradient(Size: Integer; CL, CR: TRGBQuad): Integer;
- begin
- Result := FindGradient(Size, CL, CR);
- if Result < 0 then Result := MakeGradient(Size, CL, CR);
- end;
- { GradFill function }
- procedure GradFill(DC: HDC; ARect: TRect; ClrTopLeft, ClrBottomRight: TColor; Kind: TGradientKind);
- const
- GRAD_MODE: array [TGradientKind] of DWORD = (GRADIENT_FILL_RECT_H, GRADIENT_FILL_RECT_V);
- W: array [TGradientKind] of Integer = (2, 1);
- H: array [TGradientKind] of Integer = (1, 2);
- type
- TriVertex = packed record
- X, Y: Longint;
- R, G, B, A: Word;
- end;
- var
- V: array [0..1] of TriVertex;
- GR: GRADIENT_RECT;
- begin
- if not RectVisible(DC, ARect) then Exit;
- ClrTopLeft := ColorToRGB(ClrTopLeft);
- ClrBottomRight := ColorToRGB(ClrBottomRight);
- with V[0] do
- begin
- X := ARect.Left;
- Y := ARect.Top;
- R := ClrTopLeft shl 8 and $FF00;
- G := ClrTopLeft and $FF00;
- B := ClrTopLeft shr 8 and $FF00;
- A := 0;
- end;
- with V[1] do
- begin
- X := ARect.Right;
- Y := ARect.Bottom;
- R := ClrBottomRight shl 8 and $FF00;
- G := ClrBottomRight and $FF00;
- B := ClrBottomRight shr 8 and $FF00;
- A := 0;
- end;
- GR.UpperLeft := 0; GR.LowerRight := 1;
- GradientFill(DC, @V, 2, @GR, 1, GRAD_MODE[Kind]);
- end;
- { Brushed Fill } ///////////////////////////////////////////////////////////////
- { Templates }
- const
- NUM_TEMPLATES = 8;
- MIN_TEMPLATE_SIZE = 100;
- MAX_TEMPLATE_SIZE = 200;
- var
- ThreadTemplates: array [0..NUM_TEMPLATES - 1] of array of Integer;
- RandThreadIndex: array [0..1023] of Integer;
- RandThreadPositions: array [0..1023] of Integer;
- procedure InitializeBrushedFill;
- const
- Pi = 3.14159265358987;
- var
- TemplateIndex, Size, I, V, V1, V2: Integer;
- T, R12, R13, R14, R21, R22, R23, R24: Single;
- begin
- { Make thread templates }
- for TemplateIndex := 0 to NUM_TEMPLATES - 1 do
- begin
- Size := (MIN_TEMPLATE_SIZE + Random(MAX_TEMPLATE_SIZE - MIN_TEMPLATE_SIZE + 1)) div 2;
- SetLength(ThreadTemplates[TemplateIndex], Size * 2);
- R12 := Random * 2 * Pi;
- R13 := Random * 2 * Pi;
- R14 := Random * 2 * Pi;
- R21 := Random * 2 * Pi;
- R22 := Random * 2 * Pi;
- R23 := Random * 2 * Pi;
- R24 := Random * 2 * Pi;
- for I := 0 to Size - 1 do
- begin
- T := 2 * Pi * I / Size;
- V1 := Round(150 * Sin(T) + 100 * Sin(2 * T + R12) + 50 * Sin(3 * T + R13) + 20 * Sin(4 * T + R14));
- if V1 > 255 then V1 := 255;
- if V1 < -255 then V1 := -255;
- V2 := Round(150 * Sin(T + R21) + 100 * Sin(2 * T + R22) + 50 * Sin(3 * T + R23) + 20 * Sin(4 * T + R24));
- if V2 > 255 then V2 := 255;
- if V2 < -255 then V2 := -255;
- if Abs(V2 - V1) > 300 then
- begin
- V := (V1 + V2) div 2;
- V1 := V - 150;
- V2 := V + 150;
- end;
- ThreadTemplates[TemplateIndex][I * 2] := Min(V1, V2);
- ThreadTemplates[TemplateIndex][I * 2 + 1] := Max(V1, V2);
- end;
- end;
- { Initialize Rand arrays }
- for I := 0 to 1023 do
- begin
- RandThreadIndex[I] := Random(NUM_TEMPLATES);
- V1 := Random(Length(ThreadTemplates[RandThreadIndex[I]])) and not $1;
- if Odd(I) then Inc(V1);
- RandThreadPositions[I] := V1;
- end;
- end;
- { Cache }
- const
- THREAD_CACHE_SIZE = 16;
- type
- TThreadCacheItem = record
- BaseColor: TColorRef;
- Roughness: Integer;
- Bitmaps: array [0..NUM_TEMPLATES - 1] of HBITMAP;
- end;
- var
- ThreadCache: array [0..THREAD_CACHE_SIZE] of TThreadCacheItem;
- NextCacheEntry: Integer = 0;
- procedure ClearCacheItem(var CacheItem: TThreadCacheItem);
- var
- I: Integer;
- begin
- with CacheItem do
- begin
- BaseColor := $FFFFFFFF;
- Roughness := -1;
- for I := NUM_TEMPLATES - 1 downto 0 do
- begin
- if Bitmaps[I] <> 0 then
- begin
- DeleteObject(Bitmaps[I]);
- Bitmaps[I] := 0;
- end;
- end;
- end;
- end;
- procedure ResetBrushedFillCache;
- var
- I: Integer;
- begin
- { Should be called each time the screen parameters change }
- for I := THREAD_CACHE_SIZE - 1 downto 0 do ClearCacheItem(ThreadCache[I]);
- end;
- procedure FinalizeBrushedFill;
- begin
- ResetBrushedFillCache;
- end;
- procedure MakeCacheItem(var CacheItem: TThreadCacheItem; Color: TColorRef; Roughness: Integer);
- var
- TemplateIndex, Size, I, V: Integer;
- CR, CG, CB: Integer;
- R, G, B: Integer;
- ScreenDC: HDC;
- BMI: TBitmapInfo;
- Bits: PRGBQuadArray;
- DIBSection: HBITMAP;
- DIBDC, CacheDC: HDC;
- begin
- ScreenDC := GetDC(0);
- FillChar(BMI, SizeOf(TBitmapInfo), 0);
- with BMI.bmiHeader do
- begin
- biSize := SizeOf(TBitmapInfoHeader);
- biPlanes := 1;
- biCompression := BI_RGB;
- biWidth := MAX_TEMPLATE_SIZE;
- biHeight := -1;
- biBitCount := 32;
- end;
- DIBSection := CreateDIBSection(0, BMI, DIB_RGB_COLORS, Pointer(Bits), 0, 0);
- DIBDC := CreateCompatibleDC(0);
- SelectObject(DIBDC, DIBSection);
- CacheDC := CreateCompatibleDC(0);
- CR := Color shl 8 and $FF00;
- CG := Color and $FF00;
- CB := Color shr 8 and $FF00;
- try
- for TemplateIndex := 0 to NUM_TEMPLATES - 1 do
- begin
- CacheItem.BaseColor := Color;
- CacheItem.Roughness := Roughness;
- Size := Length(ThreadTemplates[TemplateIndex]);
- if CacheItem.Bitmaps[TemplateIndex] = 0 then
- CacheItem.Bitmaps[TemplateIndex] := CreateCompatibleBitmap(ScreenDC, Size, 1);
- SelectObject(CacheDC, CacheItem.Bitmaps[TemplateIndex]);
- for I := 0 to Size - 1 do
- begin
- V := ThreadTemplates[TemplateIndex][I];
- R := CR + V * Roughness;
- G := CG + V * Roughness;
- B := CB + V * Roughness;
- if R < 0 then R := 0;
- if G < 0 then G := 0;
- if B < 0 then B := 0;
- if R > $EF00 then R := $EF00;
- if G > $EF00 then G := $EF00;
- if B > $EF00 then B := $EF00;
- Bits^[I] := (R and $FF00 + (G and $FF00) shl 8 + (B and $FF00) shl 16) shr 8;
- end;
- BitBlt(CacheDC, 0, 0, Size, 1, DIBDC, 0, 0, SRCCOPY);
- end;
- finally
- DeleteDC(CacheDC);
- DeleteDC(DIBDC);
- DeleteObject(DIBSection);
- ReleaseDC(0, ScreenDC);
- end;
- end;
- function FindCacheItem(Color: TColorRef; Roughness: Integer): Integer;
- begin
- Result := THREAD_CACHE_SIZE - 1;
- while Result >= 0 do
- if (ThreadCache[Result].BaseColor = Color) and (ThreadCache[Result].Roughness = Roughness) then Exit
- else Dec(Result);
- end;
- function GetCacheItem(Color: TColorRef; Roughness: Integer): Integer;
- begin
- Result := FindCacheItem(Color, Roughness);
- if Result >= 0 then Exit
- else
- begin
- Result := NextCacheEntry;
- MakeCacheItem(ThreadCache[Result], Color, Roughness);
- NextCacheEntry := (NextCacheEntry + 1) mod THREAD_CACHE_SIZE;
- end;
- end;
- procedure BrushedFill(DC: HDC; Origin: PPoint; ARect: TRect; Color: TColor; Roughness: Integer);
- const
- ZeroOrigin: TPoint = (X: 0; Y: 0);
- var
- CR: TColorRef;
- X, Y: Integer;
- CacheIndex: Integer;
- TemplateIndex: Integer;
- CacheDC: HDC;
- Size: Integer;
- BoxR: TRect;
- begin
- if (Color = clNone) or not RectVisible(DC, ARect) then Exit;
- CR := GetBGR(ColorToRGB(Color));
- if Origin = nil then Origin := @ZeroOrigin;
- CacheIndex := GetCacheItem(CR, Roughness);
- GetClipBox(DC, BoxR);
- IntersectRect(ARect, ARect, BoxR);
- SaveDC(DC);
- with ARect do IntersectClipRect(DC, Left, Top, Right, Bottom);
- CacheDC := CreateCompatibleDC(0);
- for Y := ARect.Top to ARect.Bottom - 1 do
- begin
- TemplateIndex := RandThreadIndex[(65536 + Y - Origin.Y) mod 1024];
- Size := Length(ThreadTemplates[TemplateIndex]);
- X := -RandThreadPositions[(65536 + Y - Origin.Y) mod 1024] + Origin.X;
- SelectObject(CacheDC, ThreadCache[CacheIndex].Bitmaps[TemplateIndex]);
- while X < ARect.Right do
- begin
- if X + Size >= ARect.Left then BitBlt(DC, X, Y, Size, 1, CacheDC, 0, 0, SRCCOPY);
- Inc(X, Size);
- end;
- end;
- DeleteDC(CacheDC);
- RestoreDC(DC, -1);
- end;
- initialization
- InitializeStock;
- InitializeBrushedFill;
- ResetBrushedFillCache;
- finalization
- FinalizeBrushedFill;
- FinalizeStock;
- end.
|