Files
HeidiSQL/source/vcl-styles-utils/Vcl.Styles.Utils.StdCtrls.pas

2885 lines
85 KiB
ObjectPascal

// **************************************************************************************************
//
// Unit Vcl.Styles.Utils.StdCtrls
// unit for the VCL Styles Utils
// https://github.com/RRUZ/vcl-styles-utils/
//
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License");
// you may not use this file except in compliance with the License. You may obtain a copy of the
// License at http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
// ANY KIND, either express or implied. See the License for the specific language governing rights
// and limitations under the License.
//
//
// Portions created by Mahdi Safsafi [SMP3] e-mail SMP@LIVE.FR
// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V.
// All Rights Reserved.
//
// **************************************************************************************************
unit Vcl.Styles.Utils.StdCtrls;
interface
uses
System.Classes,
System.SysUtils,
System.Types,
Winapi.Windows,
Winapi.Messages,
Winapi.CommCtrl,
Vcl.Themes,
Vcl.Graphics,
Vcl.Styles.Utils.SysStyleHook,
Vcl.Forms,
Vcl.StdCtrls,
Vcl.Styles.Utils.Forms,
Vcl.GraphUtil,
Vcl.Controls;
const
BS_SPLITBUTTON = $0000000C;
{$EXTERNALSYM BS_DEFSPLITBUTTON}
BS_DEFSPLITBUTTON = $0000000D;
{$EXTERNALSYM BS_COMMANDLINK}
BS_COMMANDLINK = $0000000E;
{$EXTERNALSYM BS_DEFCOMMANDLINK}
BS_DEFCOMMANDLINK = $0000000F;
type
TSysCheckBoxState = (cbUnchecked, cbChecked, cbGrayed);
TSysButtonStyleHook = class(TMouseTrackSysControlStyleHook)
private
function GetCaptionRect(Canvas: TCanvas): TRect;
function GetBoxRect: TRect;
function IsCheckBox: Boolean;
function IsRadioButton: Boolean;
function IsGroupBox: Boolean;
function IsPushButton: Boolean;
function IsSplitButton: Boolean;
function IsCommandButton: Boolean;
function GetTextAlign: TTextFormat;
function GetShowText: Boolean;
function GetCheckBoxState: TSysCheckBoxState;
procedure WMPaint(var Message: TMessage); message WM_PAINT;
procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
procedure WMEraseBkgnd(var Message: TMessage); message WM_ERASEBKGND;
function IsOwnerDraw: Boolean;
protected
procedure DrawCheckBoxText(DC: HDC; Text: String;
LDetails: TThemedElementDetails; R: TRect); virtual;
procedure PaintButton(Canvas: TCanvas); virtual;
procedure PaintCheckBox(Canvas: TCanvas); virtual;
procedure PaintRadioButton(Canvas: TCanvas); virtual;
procedure PaintGroupBox(Canvas: TCanvas); virtual;
procedure MouseEnter; override;
procedure MouseLeave; override;
procedure Paint(Canvas: TCanvas); override;
procedure PaintNC(Canvas: TCanvas); override;
procedure PaintBackground(Canvas: TCanvas); override;
procedure WndProc(var Message: TMessage); override;
procedure UpdateColors; override;
public
constructor Create(AHandle: THandle); override;
Destructor Destroy; override;
property CheckBox: Boolean read IsCheckBox;
property CommandButton: Boolean read IsCommandButton;
property RadioButton: Boolean read IsRadioButton;
property GroupBox: Boolean read IsGroupBox;
property PushButton: Boolean read IsPushButton;
property SplitButton: Boolean read IsSplitButton;
property CheckBoxState: TSysCheckBoxState read GetCheckBoxState;
property TextAlign: TTextFormat read GetTextAlign;
property ShowText: Boolean read GetShowText;
property OwnerDraw: Boolean read IsOwnerDraw;
end;
TSysEditStyleHook = class(TMouseTrackSysControlStyleHook)
private
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
protected
procedure PaintNC(Canvas: TCanvas); override;
procedure WndProc(var Message: TMessage); override;
procedure UpdateColors; override;
procedure MouseEnter; override;
procedure MouseLeave; override;
function GetBorderSize: TRect; override;
public
constructor Create(AHandle: THandle); override;
Destructor Destroy; override;
end;
TSysMemoStyleHook = class(TSysScrollingStyleHook)
strict protected
procedure UpdateColors; override;
procedure WndProc(var Message: TMessage); override;
function GetBorderSize: TRect; override;
public
constructor Create(AHandle: THandle); override;
end;
TSysListBoxStyleHook = class(TSysScrollingStyleHook)
protected
function GetBorderSize: TRect; override;
procedure WndProc(var Message: TMessage); override;
procedure UpdateColors; override;
procedure PaintBackground(Canvas: TCanvas); override;
public
constructor Create(AHandle: THandle); override;
Destructor Destroy; override;
end;
TSysComboBoxStyleHook = class(TMouseTrackSysControlStyleHook)
strict private
FDownPos, FMovePos: TPoint;
FDownSliderPos: Integer;
FOldIdx, FInvsibleCount, FSliderSize: Integer;
FVSliderState, FVUpState, FVDownState: TThemedScrollBar;
FIgnoreStyleChanged: Boolean;
FMouseOnButton: Boolean;
FListHandle, FEditHandle: HWnd;
FListBoxInstance: Pointer;
FDefListBoxProc: Pointer;
FListBoxTimerCode: Integer;
FListBoxUpBtnDown, FListBoxDownBtnDown, FListBoxTrackUpDown,
FListBoxTrackDownDown: Boolean;
procedure DrawListBoxVertScroll(DC: HDC);
procedure DrawListBoxBorder;
function IsDroppedDown: Boolean;
function GetButtonRect: TRect;
function Style: TComboBoxStyle;
function ListBoxBoundsRect: TRect;
function ListBoxClientRect: TRect;
procedure ListBoxSetTimer(const ATimerCode: Integer);
procedure ListBoxStopTimer;
function ListBoxVertScrollRect: TRect;
function ListBoxVertDownButtonRect: TRect;
function ListBoxVertUpButtonRect: TRect;
function ListBoxVertScrollArea: TRect;
function ListBoxVertSliderRect: TRect;
function ListBoxVertTrackRect: TRect;
function ListBoxVertTrackRectUp: TRect;
function ListBoxVertTrackRectDown: TRect;
procedure PaintListBoxBorder(Canvas: TCanvas; const R: TRect);
procedure WMCommand(var Message: TWMCommand); message WM_COMMAND;
procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
procedure WMPaint(var Message: TMessage); message WM_PAINT;
procedure WMMouseMove(var Message: TWMMouse); message WM_MOUSEMOVE;
procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
procedure WMDrawItem(var Message: TWMDrawItem); message WM_DRAWITEM;
procedure WMParentNotify(var Message: TMessage); message WM_PARENTNOTIFY;
strict protected
procedure UpdateColors; override;
function IsChildHandle(AHandle: HWnd): Boolean; override;
procedure DrawItem(Canvas: TCanvas;const Index: UINT; const R: TRect;
const Selected: Boolean); virtual;
procedure HookListBox(AListHandle: HWnd);
property ListBoxInstance: Pointer read FListBoxInstance;
procedure ListBoxWndProc(var Msg: TMessage); virtual;
property ListHandle: HWnd read FListHandle;
procedure MouseEnter; override;
procedure MouseLeave; override;
procedure PaintBorder(Canvas: TCanvas); virtual;
procedure WndProc(var Message: TMessage); override;
function CallDefaultListBoxProc(var Msg: TMessage): LRESULT;
property ButtonRect: TRect read GetButtonRect;
property MouseOnButton: Boolean read FMouseOnButton write FMouseOnButton;
property DroppedDown: Boolean read IsDroppedDown;
public
constructor Create(AHandle: THandle); override;
Destructor Destroy; override;
end;
TSysStaticStyleHook = class(TSysStyleHook)
private
FUpdatedColor: TColor;
function GetIsText: Boolean;
function GetTextFormat: TTextFormat;
function GetIsFrameOrLine: Boolean;
protected
procedure Paint(Canvas: TCanvas); override;
procedure PaintNC(Canvas: TCanvas); override;
procedure UpdateColors; override;
procedure WndProc(var Message: TMessage); override;
public
constructor Create(AHandle: THandle); override;
Destructor Destroy; override;
property IsText: Boolean read GetIsText;
property IsFrameOrLine: Boolean read GetIsFrameOrLine;
property TextFormat: TTextFormat read GetTextFormat;
end;
TSysCheckBoxStyleHook = class(TMouseTrackSysControlStyleHook)
strict private
FPressed: Boolean;
procedure WMLButtonDown(var Message: TWMMouse); message WM_LBUTTONDOWN;
procedure WMLButtonUp(var Message: TWMMouse); message WM_LBUTTONUP;
procedure WMLButtonDblClk(var Message: TWMMouse); message WM_LBUTTONDBLCLK;
procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
procedure WMKeyUp(var Message: TWMKeyUp); message WM_KEYUP;
procedure BMSetCheck(var Message: TMessage); message BM_SETCHECK;
function RightAlignment: Boolean;
strict protected
function GetDrawState(State: TSysCheckBoxState): TThemedButton; virtual;
procedure Paint(Canvas: TCanvas); override;
procedure PaintBackground(Canvas: TCanvas); override;
procedure MouseEnter; override;
procedure MouseLeave; override;
procedure WndProc(var Message: TMessage); override;
property Pressed: Boolean read FPressed;
public
constructor Create(AHandle: THandle); override;
end;
TSysRadioButtonStyleHook = class(TSysCheckBoxStyleHook)
strict protected
function GetDrawState(State: TSysCheckBoxState): TThemedButton; override;
procedure WndProc(var Message: TMessage); override;
public
constructor Create(AHandle: THandle); override;
end;
implementation
uses
Vcl.ExtCtrls,
System.UITypes,
Vcl.Styles.Utils.Misc,
Vcl.Styles.Utils.SysControls, Vcl.Styles.Utils.Graphics;
{ TSysEditStyleHook }
constructor TSysEditStyleHook.Create(AHandle: THandle);
begin
inherited;
{$IF CompilerVersion > 23}
StyleElements := [seFont, seBorder];
{$ELSE}
OverridePaint := False;
OverridePaintNC := True;
OverrideFont := True;
{$IFEND}
end;
destructor TSysEditStyleHook.Destroy;
begin
inherited;
end;
function TSysEditStyleHook.GetBorderSize: TRect;
begin
if SysControl.HasBorder then
Result := Rect(2, 2, 2, 2);
end;
procedure TSysEditStyleHook.MouseEnter;
begin
InvalidateNC;
end;
procedure TSysEditStyleHook.MouseLeave;
begin
InvalidateNC;
end;
procedure TSysEditStyleHook.PaintNC(Canvas: TCanvas);
var
Details: TThemedElementDetails;
R: TRect;
begin
if StyleServicesEnabled and SysControl.HasBorder then
begin
if Focused then
Details := StyleServices.GetElementDetails(teEditBorderNoScrollFocused)
else if MouseInControl then
Details := StyleServices.GetElementDetails(teEditBorderNoScrollHot)
else if SysControl.Enabled then
Details := StyleServices.GetElementDetails(teEditBorderNoScrollNormal)
else
Details := StyleServices.GetElementDetails(teEditBorderNoScrollDisabled);
R := Rect(0, 0, SysControl.Width, SysControl.Height);
InflateRect(R, -2, -2);
ExcludeClipRect(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom);
DrawStyleElement(Canvas.Handle, Details,
Rect(0, 0, SysControl.Width, SysControl.Height));
end;
end;
procedure TSysEditStyleHook.UpdateColors;
const
ColorStates: array [Boolean] of TStyleColor = (scEditDisabled, scEdit);
FontColorStates: array [Boolean] of TStyleFont = (sfEditBoxTextDisabled,
sfEditBoxTextNormal);
begin
Color := StyleServices.GetStyleColor(ColorStates[SysControl.Enabled]);
{$IF CompilerVersion > 23}
if seFont in StyleElements then
FontColor := StyleServices.GetStyleFontColor
(FontColorStates[SysControl.Enabled])
else
FontColor := clWindowText;
{$ELSE}
FontColor := StyleServices.GetStyleFontColor
(FontColorStates[SysControl.Enabled]);
{$IFEND}
end;
procedure TSysEditStyleHook.WMNCCalcSize(var Message: TWMNCCalcSize);
var
Params: PNCCalcSizeParams;
begin
Handled := False;
if (not StyleServicesEnabled) or (not OverridePaintNC) then
Exit;
Params := Message.CalcSize_Params;
if SysControl.HasBorder then
with Params^.rgrc[0] do
begin
Inc(Left, 2);
Inc(Top, 2);
Dec(Right, 2);
Dec(Bottom, 2);
end;
Handled := True;
end;
procedure TSysEditStyleHook.WndProc(var Message: TMessage);
begin
case Message.Msg of
CM_CTLCOLORMSGBOX .. CM_CTLCOLORSTATIC:
begin
{ Change edit control color . }
SetTextColor(Message.wParam, ColorToRGB(FontColor));
SetBkColor(Message.wParam, ColorToRGB(Color));
Message.Result := LRESULT(Brush.Handle);
end;
else
inherited WndProc(Message);
end;
end;
{ TSysListBoxStyleHook }
constructor TSysListBoxStyleHook.Create(AHandle: THandle);
begin
inherited;
{$IF CompilerVersion > 23}
StyleElements := [seBorder];
{$ELSE}
OverridePaint := False;
OverridePaintNC := True;
OverrideFont := False;
{$IFEND}
//OverrideEraseBkgnd:=True;
end;
destructor TSysListBoxStyleHook.Destroy;
begin
inherited;
end;
function TSysListBoxStyleHook.GetBorderSize: TRect;
begin
Result := inherited GetBorderSize;
if (SysControl.HasBorder) then
begin
Result := Rect(2, 2, 2, 2);
end;
if SameText(SysControl.ControlClassName, 'ComboLBox') then
begin
if SysControl.Parent.Style and CBS_SIMPLE = CBS_SIMPLE then
Exit;
Result := Rect(0, 0, 0, 0);
end;
end;
procedure TSysListBoxStyleHook.PaintBackground(Canvas: TCanvas);
begin
inherited;
end;
procedure TSysListBoxStyleHook.UpdateColors;
const
ColorStates: array[Boolean] of TStyleColor = (scListBoxDisabled, scListBox);
FontColorStates: array[Boolean] of TStyleFont = (sfListItemTextDisabled, sfListItemTextNormal);
var
LStyle: TCustomStyleServices;
begin
LStyle := StyleServices;
Brush.Color := LStyle.GetStyleColor(ColorStates[SysControl.Enabled]);
FontColor := LStyle.GetStyleFontColor(FontColorStates[SysControl.Enabled]);
end;
procedure TSysListBoxStyleHook.WndProc(var Message: TMessage);
begin
inherited;
end;
{ TSysButtonStyleHook }
constructor TSysButtonStyleHook.Create(AHandle: THandle);
begin
inherited;
ParentColor := True;
{$IF CompilerVersion > 23}
StyleElements := [seFont, seClient, seBorder];
{$ELSE}
OverridePaint := True;
OverridePaintNC := True;
OverrideFont := True;
{$IFEND}
Color := StyleServices.GetStyleColor(scWindow);
end;
destructor TSysButtonStyleHook.Destroy;
begin
inherited;
end;
procedure TSysButtonStyleHook.DrawCheckBoxText(DC: HDC; Text: String;
LDetails: TThemedElementDetails; R: TRect);
var
TextFormat: TTextFormat;
begin
if ShowText then
begin
TextFormat := [tfVerticalCenter, tfHidePrefix];
if (SysControl.Style and BS_MULTILINE = BS_MULTILINE) then
include(TextFormat, tfWordBreak)
else
include(TextFormat, tfSingleLine);
if (SysControl.Style and BS_LEFT = BS_LEFT) then
include(TextFormat, tfLeft)
else if (SysControl.Style and BS_RIGHT = BS_RIGHT) then
include(TextFormat, tfRight)
else if (SysControl.Style and BS_CENTER = BS_CENTER) then
include(TextFormat, tfCenter);
DrawText(DC, LDetails, SysControl.Text, R, TextFormat);
end;
end;
function TSysButtonStyleHook.GetCheckBoxState: TSysCheckBoxState;
var
LState: DWORD;
begin
LState := SendMessage(Handle, BM_GETCHECK, 0, 0);
Result := TSysCheckBoxState(LState)
end;
function TSysButtonStyleHook.GetShowText: Boolean;
begin
Result := (SysControl.Style and BS_TEXT = BS_TEXT);
end;
function TSysButtonStyleHook.GetTextAlign: TTextFormat;
begin
Result := [];
with SysControl do
begin
// if Style and BS_LEFTTEXT then
end;
end;
function TSysButtonStyleHook.IsCheckBox: Boolean;
begin
with SysControl do
Result := (Style and BS_CHECKBOX = BS_CHECKBOX) or
(Style and BS_AUTOCHECKBOX = BS_AUTOCHECKBOX);
end;
function TSysButtonStyleHook.IsCommandButton: Boolean;
begin
Result := (SysControl.Style and BS_COMMANDLINK = BS_COMMANDLINK) or
(SysControl.Style and BS_DEFCOMMANDLINK = BS_DEFCOMMANDLINK);
end;
function TSysButtonStyleHook.IsGroupBox: Boolean;
begin
Result := (SysControl.Style and BS_GROUPBOX = BS_GROUPBOX);
end;
function TSysButtonStyleHook.IsOwnerDraw: Boolean;
begin
Result := (SysControl.Style and BS_OWNERDRAW = BS_OWNERDRAW);
end;
function TSysButtonStyleHook.IsPushButton: Boolean;
begin
with SysControl do
Result := (Style and BS_PUSHBUTTON = BS_PUSHBUTTON) or
(not CheckBox and not RadioButton and not GroupBox and not CommandButton);
end;
function TSysButtonStyleHook.IsRadioButton: Boolean;
begin
with SysControl do
Result := (Style and BS_RADIOBUTTON = BS_RADIOBUTTON) or
(Style and BS_AUTORADIOBUTTON = BS_AUTORADIOBUTTON);
if Result then
Result:= not IsSplitButton;
end;
function TSysButtonStyleHook.IsSplitButton: Boolean;
begin
Result := (SysControl.Style and BS_SPLITBUTTON = BS_SPLITBUTTON) or
(SysControl.Style and BS_DEFSPLITBUTTON = BS_DEFSPLITBUTTON);
end;
procedure TSysButtonStyleHook.MouseEnter;
begin
// Invalidate;
end;
procedure TSysButtonStyleHook.MouseLeave;
begin
Invalidate;
end;
procedure TSysButtonStyleHook.Paint(Canvas: TCanvas);
begin
//OutputDebugString(PChar('Paint '+IntToHex(SysControl.Handle, 8)));
if not GroupBox or CommandButton then
PaintBackground(Canvas)
else
Exit;
if CommandButton then
PaintButton(Canvas)
else
if CheckBox then
PaintCheckBox(Canvas)
else
if RadioButton then
PaintRadioButton(Canvas)
else
if PushButton then
PaintButton(Canvas);
end;
procedure TSysButtonStyleHook.PaintBackground(Canvas: TCanvas);
begin
if not GroupBox then
inherited;
end;
procedure TSysButtonStyleHook.PaintButton(Canvas: TCanvas);
var
LDetails: TThemedElementDetails;
LRect: TRect;
Detail: TThemedButton;
X, Y, i: Integer;
IW, IH, IY: Integer;
TextFormat: TTextFormat;
IL: BUTTON_IMAGELIST;
LText: string;
DrawRect: TRect;
ThemeTextColor: TColor;
Buffer: string;
BufferLength: Integer;
begin
Canvas.Font.Assign(SysControl.Font);
LText := SysControl.Text;
LRect := SysControl.ClientRect;
if SysControl.Enabled then
Detail := tbPushButtonNormal
else
Detail := tbPushButtonDisabled;
if MouseDown then
Detail := tbPushButtonPressed
else
if MouseInControl then
Detail := tbPushButtonHot
else
if Focused then
Detail := tbPushButtonDefaulted;
LDetails := StyleServices.GetElementDetails(Detail);
DrawRect := SysControl.ClientRect;
DrawStyleElement(Canvas.Handle, LDetails, LRect);
if Button_GetImageList(handle, IL) and (IL.himl <> 0) and
ImageList_GetIconSize(IL.himl, IW, IH) then
begin
if (GetWindowLong(Handle, GWL_STYLE) and BS_COMMANDLINK) = BS_COMMANDLINK then
IY := DrawRect.Top + 15
else
IY := DrawRect.Top + (DrawRect.Height - IH) div 2;
ImageList_Draw(IL.himl, 0, Canvas.Handle, DrawRect.Left + 3, IY, ILD_NORMAL);
Inc(DrawRect.Left, IW + 3);
end;
if CommandButton then
begin
if IL.himl = 0 then
Inc(DrawRect.Left, 35);
Inc(DrawRect.Top, 15);
Inc(DrawRect.Left, 5);
Canvas.Font := SysControl.Font;
TextFormat := TTextFormatFlags(DT_LEFT);
if StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor) then
Canvas.Font.Color := ThemeTextColor;
StyleServices.DrawText(Canvas.Handle, LDetails, LText, DrawRect, TextFormat, Canvas.Font.Color);
SetLength(Buffer, Button_GetNoteLength(Handle) + 1);
if Length(Buffer) <> 0 then
begin
BufferLength := Length(Buffer);
if Button_GetNote(Handle, PChar(Buffer), BufferLength) then
begin
TextFormat := TTextFormatFlags(DT_LEFT or DT_WORDBREAK);
Inc(DrawRect.Top, Canvas.TextHeight('Wq') + 2);
Canvas.Font.Size := 8;
StyleServices.DrawText(Canvas.Handle, LDetails, Buffer, DrawRect,
TextFormat, Canvas.Font.Color);
end;
end;
if IL.himl = 0 then
begin
if MouseDown then
LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphPressed)
else if MouseInControl then
LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphHot)
else if SysControl.Enabled then
LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphNormal)
else
LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphDisabled);
DrawRect.Right := 35;
DrawRect.Left := 3;
DrawRect.Top := 10;
DrawRect.Bottom := DrawRect.Top + 32;
StyleServices.DrawElement(Canvas.Handle, LDetails, DrawRect);
end;
end
else
if SplitButton then
with Canvas, SysControl do
begin
{ draw vertical line }
Pen.Color := StyleServices.GetSystemColor(clBtnShadow);
MoveTo(Width - 15, 3);
LineTo(Width - 15, Height - 3);
if Enabled then
Pen.Color := StyleServices.GetSystemColor(clBtnHighLight)
else
Pen.Color := Font.Color;
MoveTo(Width - 14, 3);
LineTo(Width - 14, Height - 3);
{ Draw arrow }
Pen.Color := Font.Color;
X := Width - 8;
Y := Height div 2 + 1;
for i := 3 downto 0 do
begin
MoveTo(X - i, Y - i);
LineTo(X + i + 1, Y - i);
end;
end;
if ShowText and not IsCommandButton then
begin
TextFormat := [tfCenter, tfVerticalCenter, tfSingleLine, tfHidePrefix];
if (SysControl.Style and BS_MULTILINE = BS_MULTILINE) then
begin
Exclude(TextFormat, tfSingleLine);
include(TextFormat, tfWordBreak);
end;
DrawText(Canvas.Handle, LDetails, SysControl.Text, LRect, TextFormat);
end;
end;
function TSysButtonStyleHook.GetBoxRect: TRect;
var
DC: HDC;
sSize: TSize;
begin
DC := GetDC(Handle);
with SysControl do
begin
GetTextExtentPoint32(DC, Text, Length(Text) - 1, sSize);
Result := Rect(0, sSize.Height div 2 + 1, Width - 0, Height - 0);
end;
ReleaseDC(Handle, DC);
DeleteDC(DC);
end;
function TSysButtonStyleHook.GetCaptionRect(Canvas: TCanvas): TRect;
const
FCaptionMargin = 12;
begin
with SysControl do
if BiDiMode <> bmRightToLeft then
Result := Rect(FCaptionMargin, 0, FCaptionMargin + Canvas.TextWidth(Text),
Canvas.TextHeight(Text))
else
Result := Rect(Width - Canvas.TextWidth(Text) - FCaptionMargin, 0,
Width - FCaptionMargin, Canvas.TextHeight(Text));
end;
procedure TSysButtonStyleHook.PaintRadioButton(Canvas: TCanvas);
var
LDetails: TThemedElementDetails;
DC: HDC;
LRect: TRect;
Detail: TThemedButton;
TxtRect, BoxRect: TRect;
LState: TSysCheckBoxState;
Size: TSize;
begin
Canvas.Font.Assign(SysControl.Font);
DC := Canvas.Handle;
LRect := SysControl.ClientRect;
LState := CheckBoxState;
Canvas.Brush.Color := Color;
Canvas.FillRect(LRect);
if SysControl.Enabled then
Detail := tbRadioButtonUncheckedNormal
else
Detail := tbRadioButtonUncheckedDisabled;
if MouseDown then
Detail := tbRadioButtonUncheckedPressed
else if MouseInControl then
Detail := tbRadioButtonUncheckedHot;
if LState = cbChecked then
Detail := TThemedButton(Integer(Detail) + 4);
Size.cx := GetSysMetrics(SM_CXMENUCHECK);
Size.cy := GetSysMetrics(SM_CYMENUCHECK);
LDetails := StyleServices.GetElementDetails(Detail);
BoxRect := Rect(0, 0, Size.cx, Size.cy);
RectVCenter(BoxRect, LRect);
if (SysControl.Style and BS_LEFTTEXT = BS_LEFTTEXT) then
begin
BoxRect.Left := LRect.Right - BoxRect.Width - 2;
BoxRect.Right := LRect.Right;
TxtRect := Rect(LRect.Left + 1, LRect.Top, BoxRect.Left, LRect.Bottom);
end
else
begin
OffsetRect(BoxRect, 1, 0);
TxtRect := Rect(BoxRect.Right + 2, LRect.Top, LRect.Right, LRect.Bottom);
end;
DrawStyleElement(DC, LDetails, BoxRect);
if Focused then
Canvas.DrawFocusRect(LRect);
DrawCheckBoxText(DC, SysControl.Text, LDetails, TxtRect);
end;
procedure TSysButtonStyleHook.PaintCheckBox(Canvas: TCanvas);
var
LDetails: TThemedElementDetails;
DC: HDC;
LRect: TRect;
Detail: TThemedButton;
TxtRect, BoxRect: TRect;
LState: TSysCheckBoxState;
Size: TSize;
begin
Canvas.Font.Assign(SysControl.Font);
DC := Canvas.Handle;
LRect := SysControl.ClientRect;
LState := CheckBoxState;
Canvas.Brush.Color := Color;
Canvas.FillRect(LRect);
if SysControl.Enabled then
Detail := tbCheckBoxUncheckedNormal
else
Detail := tbCheckBoxUncheckedDisabled;
if MouseDown then
Detail := tbCheckBoxUncheckedPressed
else if MouseInControl then
Detail := tbCheckBoxUncheckedHot;
if LState = cbChecked then
Detail := TThemedButton(Integer(Detail) + 4);
if LState = cbGrayed then
Detail := TThemedButton(Integer(Detail) + 8);
// LDetails := StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal);
// StyleServices.GetElementSize(DC, LDetails, esActual, Size);
Size.cx := GetSysMetrics(SM_CXMENUCHECK);
Size.cy := GetSysMetrics(SM_CYMENUCHECK);
LDetails := StyleServices.GetElementDetails(Detail);
BoxRect := Rect(0, 0, Size.cx, Size.cy);
BoxRect := RectVCenter(BoxRect, LRect);
if (SysControl.Style and BS_LEFTTEXT = BS_LEFTTEXT) then
begin
BoxRect.Left := LRect.Right - BoxRect.Width - 2;
BoxRect.Right := LRect.Right;
TxtRect := Rect(LRect.Left + 1, LRect.Top, BoxRect.Left, LRect.Bottom);
end
else
begin
OffsetRect(BoxRect, 1, 0);
TxtRect := Rect(BoxRect.Right + 2, LRect.Top, LRect.Right, LRect.Bottom);
end;
DrawStyleElement(DC, LDetails, BoxRect);
if Focused then
Canvas.DrawFocusRect(LRect);
DrawCheckBoxText(DC, SysControl.Text, LDetails, TxtRect);
end;
procedure TSysButtonStyleHook.PaintGroupBox(Canvas: TCanvas);
var
R, CaptionRect: TRect;
LDetails: TThemedElementDetails;
SaveIndex: Integer;
procedure DoDrawParentBackground(DC: HDC; ARect: TRect);
begin
if SysControl.ParentHandle > 0 then
DrawParentBackground(DC, @ARect)
else
begin
Canvas.Brush.Color := StyleServices.GetStyleColor(scWindow);
Canvas.FillRect(ARect);
end;
end;
begin
Canvas.Font.Assign(SysControl.Font);
CaptionRect := GetCaptionRect(Canvas);
R := GetBoxRect;
if SysControl.Enabled then
LDetails := StyleServices.GetElementDetails(tbGroupBoxNormal)
else
LDetails := StyleServices.GetElementDetails(tbGroupBoxDisabled);
{ Clean caption area }
DoDrawParentBackground(Canvas.Handle, CaptionRect);
ExcludeClipRect(Canvas.Handle, R.Left + 4, CaptionRect.Height + 2,
R.Right - 4, R.Height - 2);
{ Clean GroupBox corners area }
DoDrawParentBackground(Canvas.Handle, R);
SaveIndex := SaveDC(Canvas.Handle);
try
ExcludeClipRect(Canvas.Handle, CaptionRect.Left, CaptionRect.Top,
CaptionRect.Right, CaptionRect.Bottom);
DrawStyleElement(Canvas.Handle, LDetails, R);
finally
RestoreDC(Canvas.Handle, SaveIndex);
end;
Inc(CaptionRect.Top, 3);
{ Paint Text }
StyleServices.DrawText(Canvas.Handle, LDetails, SysControl.Text, CaptionRect,
[tfSingleLine, tfVerticalCenter, tfLeft, tfHidePrefix]);
end;
procedure TSysButtonStyleHook.PaintNC(Canvas: TCanvas);
begin
if GroupBox then
PaintGroupBox(Canvas);
end;
procedure TSysButtonStyleHook.UpdateColors;
begin
inherited;
end;
procedure TSysButtonStyleHook.WMEraseBkgnd(var Message: TMessage);
begin
if (not OwnerDraw) and (not GroupBox and ParentBkGndPainted) then
Message.Result := 1
else
begin
Handled := False;
Exit;
end;
Handled := True;
end;
procedure TSysButtonStyleHook.WMNCPaint(var Message: TMessage);
begin
if (not OwnerDraw and ParentBkGndPainted) then
Inherited
else
begin
Handled := False;
Exit;
end;
Handled := True;
end;
procedure TSysButtonStyleHook.WMPaint(var Message: TMessage);
begin
if (not OwnerDraw and ParentBkGndPainted) then
Inherited
else
begin
Handled := False;
Exit;
end;
Handled := True;
end;
procedure TSysButtonStyleHook.WndProc(var Message: TMessage);
begin
case Message.Msg of
WM_ENABLE:
begin
{ Check first if Window is visible
if you dont check ..the InVisible window will be visible .
}
if SysControl.Visible then
Invalidate;
end;
WM_STYLECHANGING, WM_STYLECHANGED:
begin
Invalidate;
end;
WM_SETTEXT:
begin
SetRedraw(False);
CallDefaultProc(Message);
SetRedraw(True);
Invalidate;
end;
WM_SETFOCUS, WM_KILLFOCUS:
begin
inherited;
Invalidate;
end;
else
inherited;
end;
end;
{ TSysMemoStyleHook }
constructor TSysMemoStyleHook.Create(AHandle: THandle);
begin
inherited;
{$IF CompilerVersion > 23}
StyleElements := [seBorder, seFont];
{$ELSE}
OverridePaintNC := True;
OverrideFont := True;
{$IFEND}
UpdateColors;
end;
function TSysMemoStyleHook.GetBorderSize: TRect;
begin
if SysControl.HasBorder then
Result := Rect(2, 2, 2, 2);
end;
procedure TSysMemoStyleHook.UpdateColors;
const
ColorStates: array [Boolean] of TStyleColor = (scEditDisabled, scEdit);
FontColorStates: array [Boolean] of TStyleFont = (sfEditBoxTextDisabled,
sfEditBoxTextNormal);
var
LStyle: TCustomStyleServices;
begin
LStyle := StyleServices;
Brush.Color := LStyle.GetStyleColor(ColorStates[SysControl.Enabled]);
FontColor := LStyle.GetStyleFontColor(FontColorStates[SysControl.Enabled]);
end;
procedure TSysMemoStyleHook.WndProc(var Message: TMessage);
begin
case Message.Msg of
WM_ERASEBKGND:
begin
CallDefaultProc(Message);
Exit;
end;
CN_CTLCOLORMSGBOX .. CN_CTLCOLORSTATIC:
begin
SetTextColor(Message.wParam, ColorToRGB(FontColor));
SetBkColor(Message.wParam, ColorToRGB(Brush.Color));
Message.Result := LRESULT(Brush.Handle);
end;
CM_ENABLEDCHANGED:
begin
UpdateColors;
CallDefaultProc(Message);
end
else
inherited WndProc(Message);
end;
end;
{ TSysComboBoxStyleHook }
constructor TSysComboBoxStyleHook.Create(AHandle: THandle);
begin
inherited;
if Style = csSimple then
OverrideEraseBkgnd := True;
FMouseOnButton := False;
FEditHandle := 0;
FListHandle := 0;
FListBoxInstance := nil;
FIgnoreStyleChanged := False;
FVSliderState := tsThumbBtnVertNormal;
FVUpState := tsArrowBtnUpNormal;
FVDownState := tsArrowBtnDownNormal;
FSliderSize := 0;
FListBoxTimerCode := 0;
FListBoxUpBtnDown := False;
FListBoxDownBtnDown := False;
FListBoxTrackUpDown := False;
FListBoxTrackDownDown := False;
OverrideFont := True;
UpdateColors;
end;
destructor TSysComboBoxStyleHook.Destroy;
begin
if (FListHandle <> 0) and (FListBoxInstance <> nil) then
begin
SetWindowLong(FListHandle, GWL_WNDPROC, IntPtr(FDefListBoxProc));
FreeObjectInstance(FListBoxInstance);
FListBoxInstance := nil;
end;
if FListBoxTimerCode <> 0 then
ListBoxStopTimer;
inherited;
end;
procedure TSysComboBoxStyleHook.CNCommand(var Message: TWMCommand);
begin
if (Message.NotifyCode = CBN_SELENDCANCEL) or
(Message.NotifyCode = CBN_SELENDOK) or (Message.NotifyCode = CBN_CLOSEUP) or
(Message.NotifyCode = CBN_DROPDOWN) or (Message.NotifyCode = CBN_SELCHANGE)
then
begin
if FListBoxTimerCode <> 0 then
ListBoxStopTimer;
FMouseOnButton := False;
Invalidate;
end;
end;
procedure TSysComboBoxStyleHook.CNDrawItem(var Message: TWMDrawItem);
begin
WMDrawItem(Message);
Handled := True;
end;
procedure TSysComboBoxStyleHook.DrawItem(Canvas: TCanvas;const Index: UINT;
const R: TRect;const Selected: Boolean);
var
DIS: TDrawItemStruct;
begin
FillChar(DIS, SizeOf(DIS), 0);
DIS.CtlType := ODT_COMBOBOX;
DIS.CtlID := GetDlgCtrlID(Handle);
DIS.itemAction := ODA_DRAWENTIRE;
DIS.HDC := Canvas.Handle;
DIS.hwndItem := Handle;
DIS.rcItem := R;
DIS.itemID := Index;
DIS.itemData := SendMessage(FListHandle, LB_GETITEMDATA, 0, 0);
if Selected then
DIS.itemState := DIS.itemState or ODS_FOCUS or ODS_SELECTED;
SendMessage(Handle, WM_DRAWITEM, Handle, LPARAM(@DIS));
end;
procedure TSysComboBoxStyleHook.DrawListBoxBorder;
var
R: TRect;
Canvas: TCanvas;
SaveIdx: Integer;
P: TPoint;
begin
Canvas := TCanvas.Create;
try
Canvas.Handle := GetWindowDC(FListHandle);
P := Point(0, 0);
ClientToScreen(FListHandle, P);
GetWindowRect(FListHandle, R);
P.X := P.X - R.Left;
P.Y := P.Y - R.Top;
if (R.Width < 5000) and (R.Height < 5000) then
begin
GetClientRect(FListHandle, R);
ExcludeClipRect(Canvas.Handle, P.X, P.Y, R.Right - R.Left + P.X,
R.Bottom - R.Top + P.Y);
GetWindowRect(FListHandle, R);
OffsetRect(R, -R.Left, -R.Top);
SaveIdx := SaveDC(Canvas.Handle);
try
PaintListBoxBorder(Canvas, R);
finally
RestoreDC(Canvas.Handle, SaveIdx);
end;
DrawListBoxVertScroll(Canvas.Handle);
end;
finally
ReleaseDC(FListHandle, Canvas.Handle);
Canvas.Handle := 0;
Canvas.Free;
end;
end;
procedure TSysComboBoxStyleHook.DrawListBoxVertScroll(DC: HDC);
var
B: TBitmap;
Details: TThemedElementDetails;
Canvas: TCanvas;
R: TRect;
begin
if GetWindowLong(FListHandle, GWL_STYLE) and WS_VSCROLL = 0 then
Exit;
Canvas := TCanvas.Create;
try
if DC <> 0 then
Canvas.Handle := DC
else
Canvas.Handle := GetWindowDC(FListHandle);
if ListBoxVertScrollRect.Width > 0 then
begin
B := TBitmap.Create;
try
B.Width := ListBoxVertScrollRect.Width;
B.Height := ListBoxVertScrollRect.Height;
MoveWindowOrg(B.Canvas.Handle, -ListBoxVertScrollRect.Left,
-ListBoxVertScrollRect.Top);
if StyleServices.Available then
begin
R := ListBoxVertScrollRect;
R.Top := ListBoxVertUpButtonRect.Bottom;
R.Bottom := ListBoxVertDownButtonRect.Top;
if R.Height > 0 then
begin
Details := StyleServices.GetElementDetails(tsUpperTrackVertNormal);
DrawStyleElement(B.Canvas.Handle, Details, R);
end;
Details := StyleServices.GetElementDetails(FVSliderState);
DrawStyleElement(B.Canvas.Handle, Details,
ListBoxVertSliderRect);
Details := StyleServices.GetElementDetails(FVUpState);
DrawStyleElement(B.Canvas.Handle, Details,
ListBoxVertUpButtonRect);
Details := StyleServices.GetElementDetails(FVDownState);
DrawStyleElement(B.Canvas.Handle, Details,
ListBoxVertDownButtonRect);
end;
MoveWindowOrg(B.Canvas.Handle, ListBoxVertScrollRect.Left,
ListBoxVertScrollRect.Top);
Canvas.Draw(ListBoxVertScrollRect.Left, ListBoxVertScrollRect.Top, B);
finally
B.Free;
end;
end;
finally
if DC <> 0 then
Canvas.Handle := 0
else
begin
ReleaseDC(FListHandle, Canvas.Handle);
Canvas.Handle := 0;
end;
Canvas.Free;
end;
end;
function TSysComboBoxStyleHook.IsDroppedDown: Boolean;
begin
if Handle <> 0 then
Result := LongBool(SendMessage(Handle, CB_GETDROPPEDSTATE, 0, 0))
else
Result := False;
end;
function TSysComboBoxStyleHook.GetButtonRect: TRect;
begin
Result := SysControl.ClientRect;
InflateRect(Result, -2, -2);
if SysControl.BiDiMode <> bmRightToLeft then
Result.Left := Result.Right - GetSysMetrics(SM_CXVSCROLL) + 1
else
Result.Right := Result.Left + GetSysMetrics(SM_CXVSCROLL) - 1;
end;
procedure TSysComboBoxStyleHook.HookListBox(AListHandle: HWnd);
begin
if (AListHandle <> 0) and (FListBoxInstance = nil) then
begin
FListHandle := AListHandle;
FListBoxInstance := MakeObjectInstance(ListBoxWndProc);
FDefListBoxProc := Pointer(GetWindowLong(FListHandle, GWL_WNDPROC));
SetWindowLong(FListHandle, GWL_WNDPROC, IntPtr(FListBoxInstance));
end;
end;
function TSysComboBoxStyleHook.IsChildHandle(AHandle: HWnd): Boolean;
begin
Result := (FEditHandle <> 0) and (FEditHandle = AHandle);
end;
function TSysComboBoxStyleHook.ListBoxBoundsRect: TRect;
begin
GetWindowRect(FListHandle, Result);
end;
function TSysComboBoxStyleHook.ListBoxClientRect: TRect;
begin
GetClientRect(FListHandle, Result);
end;
procedure TSysComboBoxStyleHook.ListBoxSetTimer(const ATimerCode: Integer);
begin
if FListBoxTimerCode <> 0 then
ListBoxStopTimer;
FListBoxTimerCode := ATimerCode;
if ATimerCode < 4 then
SetTimer(FListHandle, 1, 300, nil)
else
SetTimer(FListHandle, 1, 50, nil);
end;
procedure TSysComboBoxStyleHook.ListBoxStopTimer;
begin
FListBoxTimerCode := -1;
KillTimer(FListHandle, 1);
end;
function TSysComboBoxStyleHook.ListBoxVertDownButtonRect: TRect;
begin
Result := ListBoxVertScrollRect;
if Result.Width > 0 then
Result.Top := Result.Bottom - GetSysMetrics(SM_CYVTHUMB)
else
Result := TRect.Empty;
end;
function TSysComboBoxStyleHook.ListBoxVertScrollArea: TRect;
begin
if GetWindowLong(FListHandle, GWL_STYLE) and WS_VSCROLL = 0 then
begin
Result := TRect.Empty;
Exit;
end;
Result := ListBoxBoundsRect;
OffsetRect(Result, -Result.Left, -Result.Top);
if SysControl.BiDiMode <> bmRightToLeft then
Result.Left := Result.Right - GetSysMetrics(SM_CYVSCROLL) - 1
else
Result.Right := Result.Left + GetSysMetrics(SM_CYVSCROLL);
end;
function TSysComboBoxStyleHook.ListBoxVertScrollRect: TRect;
begin
Result := ListBoxBoundsRect;
OffsetRect(Result, -Result.Left, -Result.Top);
InflateRect(Result, -1, -1);
OffsetRect(Result, 1, 1);
if SysControl.BiDiMode <> TBidiModeDirection.bmRightToLeft then
Result.Left := Result.Right - GetSysMetrics(SM_CXVSCROLL)
else
Result.Right := Result.Left + GetSysMetrics(SM_CXVSCROLL);
if ListBoxBoundsRect.Height > 30 then OffsetRect(Result, -1, -1);
end;
function TSysComboBoxStyleHook.ListBoxVertSliderRect: TRect;
var
i, LVisibleHeight, LTotalHeight, LSize, LTotalSize, LFinalHeight, LItemHeight,
LBoundsHeight, LBorderHeight: Integer;
begin
Result := ListBoxVertScrollRect;
Result.Top := ListBoxVertUpButtonRect.Bottom;
Result.Bottom := ListBoxVertDownButtonRect.Top;
LSize := Result.Bottom - Result.Top;
LTotalSize := SendMessage(FListHandle, LB_GETCOUNT, 0, 0) * LSize;
if LTotalSize = 0 then
Exit;
Result.Top := Result.Top + Round((SendMessage(FListHandle, LB_GETTOPINDEX, 0,
0) / SendMessage(FListHandle, LB_GETCOUNT, 0, 0)) * LSize);
LTotalHeight := 1;
FInvsibleCount := 0;
LBoundsHeight := ListBoxBoundsRect.Height;
for i := 0 to SendMessage(FListHandle, LB_GETCOUNT, 0, 0) - 1 do
begin
LItemHeight := SendMessage(FListHandle, LB_GETITEMHEIGHT, i, 0);
LTotalHeight := LTotalHeight + LItemHeight;
if (LTotalHeight > LBoundsHeight) and (FInvsibleCount = 0) then
FInvsibleCount := SendMessage(FListHandle, LB_GETCOUNT, 0, 0) - i;
end;
LVisibleHeight := 0;
for i := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0)
to SendMessage(FListHandle, LB_GETCOUNT, 0, 0) - 1 do
begin
LVisibleHeight := LVisibleHeight + SendMessage(FListHandle,
LB_GETITEMHEIGHT, i, 0);
if Style <> csSimple then
LBorderHeight := 2
else
LBorderHeight := 4;
if LVisibleHeight >= ListBoxBoundsRect.Height - LBorderHeight then
Break;
end;
Result.Bottom := Result.Top + Round((LVisibleHeight / LTotalHeight) * LSize);
if (i = SendMessage(FListHandle, LB_GETCOUNT, 0, 0) - 1) and
(Result.Bottom <> ListBoxVertDownButtonRect.Top) then
begin
LFinalHeight := Result.Height;
Result.Bottom := ListBoxVertDownButtonRect.Top;
Result.Top := Result.Bottom - LFinalHeight;
end;
FSliderSize := Round((LVisibleHeight / LTotalHeight) * LSize);
end;
function TSysComboBoxStyleHook.ListBoxVertTrackRect: TRect;
begin
Result := ListBoxVertScrollRect;
if Result.Width > 0 then
begin
Result.Top := Result.Top + GetSysMetrics(SM_CYVTHUMB);
Result.Bottom := Result.Bottom - GetSysMetrics(SM_CYVTHUMB);
end
else
Result := TRect.Empty;
end;
function TSysComboBoxStyleHook.ListBoxVertTrackRectDown: TRect;
begin
Result := ListBoxVertTrackRect;
if (Result.Width > 0) and (ListBoxVertSliderRect.Height > 0) then
Result.Top := ListBoxVertSliderRect.Bottom;
end;
function TSysComboBoxStyleHook.ListBoxVertTrackRectUp: TRect;
begin
Result := ListBoxVertTrackRect;
if (Result.Width > 0) and (ListBoxVertSliderRect.Height > 0) then
Result.Bottom := ListBoxVertSliderRect.Top;
end;
function TSysComboBoxStyleHook.ListBoxVertUpButtonRect: TRect;
begin
Result := ListBoxVertScrollRect;
if Result.Width > 0 then
Result.Top := Result.Bottom - GetSysMetrics(SM_CYVTHUMB)
else
Result := TRect.Empty;
end;
procedure TSysComboBoxStyleHook.ListBoxWndProc(var Msg: TMessage);
var
MsgHandled: Boolean;
procedure WMNCCalcSize(var Msg: TWMNCCalcSize);
var
LCalcSizeParams: PNCCalcSizeParams;
LWindowPos: PWindowPos;
LLeft, LRight, LTop, LBottom: Integer;
LStyle, LNewStyle: Integer;
begin
LStyle := GetWindowLong(FListHandle, GWL_STYLE);
if ((LStyle and WS_VSCROLL = WS_VSCROLL) or
(LStyle and WS_HSCROLL = WS_HSCROLL)) then
begin
LNewStyle := LStyle and not WS_VSCROLL and not WS_HSCROLL;
FIgnoreStyleChanged := True;
SetWindowLong(FListHandle, GWL_STYLE, LNewStyle);
Msg.Result := CallDefaultListBoxProc(TMessage(Msg));
SetWindowLong(FListHandle, GWL_STYLE, LStyle);
FIgnoreStyleChanged := False;
end
else
Msg.Result := CallDefaultListBoxProc(TMessage(Msg));
if (Msg.CalcValidRects) then
begin
LCalcSizeParams := Msg.CalcSize_Params;
if SysControl.BiDiMode <> bmRightToLeft then
begin
LLeft := 1;
if LStyle and WS_VSCROLL = WS_VSCROLL then
LRight := ListBoxVertScrollRect.Width + 1
else
LRight := 1;
end
else
begin
LRight := 1;
if LStyle and WS_VSCROLL = WS_VSCROLL then
LLeft := ListBoxVertScrollRect.Width + 1
else
LLeft := 1;
end;
LTop := 1;
LBottom := 1;
LWindowPos := LCalcSizeParams.lppos;
with LCalcSizeParams^.rgrc[0] do
begin
Left := LWindowPos^.X;
Top := LWindowPos^.Y;
Right := LWindowPos^.X + LWindowPos^.cx;
Bottom := LWindowPos^.Y + LWindowPos^.cy;
Left := Left + LLeft;
Top := Top + LTop;
Right := Right - LRight;
Bottom := Bottom - LBottom;
end;
LCalcSizeParams^.rgrc[1] := LCalcSizeParams^.rgrc[0];
Msg.CalcSize_Params := LCalcSizeParams;
Msg.Result := WVR_VALIDRECTS;
end;
Msg.Result := 0;
MsgHandled := True;
end;
procedure WMMouseWheel(var Msg: TWMMouseWheel);
var
Index: Integer;
R: TRect;
begin
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
Index := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0);
if Msg.WheelDelta < 0 then
Inc(Index)
else
Dec(Index);
SendMessage(FListHandle, LB_SETTOPINDEX, Index, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
DrawListBoxVertScroll(0);
MsgHandled := True;
end;
procedure WMNCLButtonDblClk(var Msg: TWMMouse);
var
R: TRect;
P: TPoint;
begin
P := Point(Msg.XPos, Msg.YPos);
if ListBoxVertScrollArea.Contains(P) then
begin
if ListBoxVertUpButtonRect.Contains(Point(Msg.XPos, Msg.YPos)) then
begin
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX, SendMessage(FListHandle,
LB_GETTOPINDEX, 0, 0) - 1, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
DrawListBoxVertScroll(0);
Exit;
end;
if ListBoxVertDownButtonRect.Contains(Point(Msg.XPos, Msg.YPos)) then
begin
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX, SendMessage(FListHandle,
LB_GETTOPINDEX, 0, 0) + 1, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
DrawListBoxVertScroll(0);
Exit;
end;
end;
MsgHandled := True;
end;
procedure WMLButtonDown(var Msg: TWMMouse);
var
P: TPoint;
R: TRect;
ItemHeight, VisibleCount, TopIndex: Integer;
begin
MsgHandled := False;
P := Point(Msg.XPos, Msg.YPos);
if SysControl.BiDiMode = bmRightToLeft then
P.X := -P.X;
FDownPos := P;
if ListBoxVertScrollArea.Contains(P) then
begin
if Style = csSimple then
SetCapture(FListHandle);
FDownPos := P;
if ListBoxVertTrackRectUp.Contains(P) then
begin
ItemHeight := SendMessage(FListHandle, LB_GETITEMHEIGHT, 0, 0);
if ItemHeight > 0 then
VisibleCount := ListBoxClientRect.Height div ItemHeight
else
VisibleCount := 0;
TopIndex := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) -
VisibleCount + 1;
if TopIndex < 0 then
TopIndex := 0;
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX, TopIndex, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
DrawListBoxVertScroll(0);
ListBoxSetTimer(3);
end
else if ListBoxVertTrackRectDown.Contains(P) then
begin
ItemHeight := SendMessage(FListHandle, LB_GETITEMHEIGHT, 0, 0);
if ItemHeight > 0 then
VisibleCount := ListBoxClientRect.Height div ItemHeight
else
VisibleCount := 0;
TopIndex := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) +
VisibleCount - 1;
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX, TopIndex, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
DrawListBoxVertScroll(0);
ListBoxSetTimer(4);
end
else if ListBoxVertSliderRect.Contains(P) then
begin
FVSliderState := tsThumbBtnVertPressed;
FDownSliderPos := FDownPos.Y - ListBoxVertSliderRect.Top;
DrawListBoxVertScroll(0);
end
else if ListBoxVertDownButtonRect.Contains(P) then
begin
FListBoxDownBtnDown := True;
FVDownState := tsArrowBtnDownPressed;
DrawListBoxVertScroll(0);
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX, SendMessage(FListHandle,
LB_GETTOPINDEX, 0, 0) + 1, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
ListBoxSetTimer(2);
end
else if ListBoxVertUpButtonRect.Contains(P) then
begin
FListBoxUpBtnDown := True;
FVUpState := tsArrowBtnUpPressed;
DrawListBoxVertScroll(0);
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX, SendMessage(FListHandle,
LB_GETTOPINDEX, 0, 0) - 1, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
ListBoxSetTimer(1);
end;
MsgHandled := True;
end
else
begin
if (FVSliderState <> tsThumbBtnVertNormal) or
(FVUpState <> tsArrowBtnUpNormal) or
(FVDownState <> tsArrowBtnDownNormal) then
begin
FVSliderState := tsArrowBtnUpNormal;
FVUpState := tsArrowBtnUpNormal;
FVDownState := tsArrowBtnDownNormal;
DrawListBoxVertScroll(0);
end;
end;
FOldIdx := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0);
end;
procedure WMMouseMove(var Msg: TWMMouse);
var
P: TPoint;
NewIndex, Index: Integer;
Dist: Integer;
R: TRect;
begin
P := Point(Msg.XPos, Msg.YPos);
if SysControl.BiDiMode = bmRightToLeft then
P.X := -P.X;
FMovePos := P;
if (FVSliderState = tsThumbBtnVertPressed) then
begin
Index := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0);
Dist := (ListBoxVertScrollRect.Height - ListBoxVertUpButtonRect.Height -
ListBoxVertDownButtonRect.Height - ListBoxVertSliderRect.Height);
if Dist > 0 then
begin
NewIndex :=
Round((((FMovePos.Y - FDownSliderPos - ListBoxVertUpButtonRect.Bottom)
/ Dist) * FInvsibleCount));
if NewIndex <> Index then
begin
if NewIndex < 0 then
NewIndex := 0;
if NewIndex >= SendMessage(FListHandle, LB_GETCOUNT, 0, 0) then
NewIndex := SendMessage(FListHandle, LB_GETCOUNT, 0, 0) - 1;
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX, NewIndex, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
DrawListBoxVertScroll(0);
end;
end;
MsgHandled := True;
Exit;
end;
if FListBoxUpBtnDown and not ListBoxVertUpButtonRect.Contains(P) and
(FVUpState = tsArrowBtnUpPressed) then
begin
FVUpState := tsArrowBtnUpNormal;
DrawListBoxVertScroll(0);
ListBoxStopTimer;
Exit;
end;
if FListBoxUpBtnDown and ListBoxVertUpButtonRect.Contains(P) and
(FVUpState = tsArrowBtnUpNormal) then
begin
FVUpState := tsArrowBtnUpPressed;
DrawListBoxVertScroll(0);
ListBoxSetTimer(5);
Exit;
end;
if FListBoxDownBtnDown and not ListBoxVertDownButtonRect.Contains(P) and
(FVDownState = tsArrowBtnDownPressed) then
begin
FVDownState := tsArrowBtnDownNormal;
DrawListBoxVertScroll(0);
ListBoxStopTimer;
Exit;
end;
if FListBoxDownBtnDown and ListBoxVertDownButtonRect.Contains(P) and
(FVDownState = tsArrowBtnDownNormal) then
begin
FVDownState := tsArrowBtnDownPressed;
DrawListBoxVertScroll(0);
ListBoxSetTimer(6);
Exit;
end;
if ListBoxVertScrollArea.Contains(P) then
begin
if ListBoxVertSliderRect.Contains(P) and
(FVSliderState = tsThumbBtnVertNormal) then
begin
FVSliderState := tsThumbBtnVertHot;
DrawListBoxVertScroll(0);
end
else if not ListBoxVertSliderRect.Contains(P) and
(FVSliderState = tsThumbBtnVertHot) then
begin
FVSliderState := tsThumbBtnVertNormal;
DrawListBoxVertScroll(0);
end
else if ListBoxVertUpButtonRect.Contains(P) and
(FVUpState = tsArrowBtnUpNormal) then
begin
FVUpState := tsArrowBtnUpHot;
DrawListBoxVertScroll(0);
end
else if not ListBoxVertUpButtonRect.Contains(P) and
(FVUpState = tsArrowBtnUpHot) then
begin
FVUpState := tsArrowBtnUpNormal;
DrawListBoxVertScroll(0);
end
else if ListBoxVertDownButtonRect.Contains(P) and
(FVDownState = tsArrowBtnDownNormal) then
begin
FVDownState := tsArrowBtnDownHot;
DrawListBoxVertScroll(0);
end
else if not ListBoxVertDownButtonRect.Contains(P) and
(FVDownState = tsArrowBtnDownHot) then
begin
FVDownState := tsArrowBtnDownNormal;
DrawListBoxVertScroll(0);
end;
MsgHandled := True;
end
else
begin
if (FVSliderState <> tsThumbBtnVertNormal) or
(FVUpState <> tsArrowBtnUpNormal) or (FVUpState <> tsArrowBtnDownNormal)
then
begin
if FListBoxTimerCode <> 0 then
ListBoxStopTimer;
FVSliderState := tsThumbBtnVertNormal;
FVUpState := tsArrowBtnUpNormal;
FVDownState := tsArrowBtnDownNormal;
DrawListBoxVertScroll(0);
end;
end;
end;
procedure WMLButtonUp(var Msg: TWMMouse);
var
P: TPoint;
begin
FListBoxUpBtnDown := False;
FListBoxDownBtnDown := False;
FListBoxTrackUpDown := False;
FListBoxTrackDownDown := False;
P := Point(Msg.XPos, Msg.YPos);
if SysControl.BiDiMode = bmRightToLeft then
P.X := -P.X;
if (Style = csSimple) and ListBoxVertScrollArea.Contains(FDownPos) then
ReleaseCapture;
if ListBoxVertSliderRect.Contains(P) then
FVSliderState := tsThumbBtnVertHot
else
FVSliderState := tsThumbBtnVertNormal;
if ListBoxVertUpButtonRect.Contains(P) then
FVUpState := tsArrowBtnUpHot
else
FVUpState := tsArrowBtnUpNormal;
if ListBoxVertDownButtonRect.Contains(P) then
FVDownState := tsArrowBtnDownHot
else
FVDownState := tsArrowBtnDownNormal;
DrawListBoxVertScroll(0);
if FListBoxTimerCode <> 0 then
ListBoxStopTimer;
MsgHandled := ListBoxVertScrollArea.Contains(P);
end;
procedure WMNCLButtonDown(var Msg: TWMMouse);
var
P: TPoint;
begin
if Style <> csSimple then
SetCapture(FListHandle);
P := Point(Msg.XPos, Msg.YPos);
ScreenToClient(FListHandle, P);
with P do
begin
Msg.XPos := X;
Msg.YPos := Y;
end;
WMLButtonDown(Msg);
MsgHandled := True;
end;
procedure WMPrint(var Msg: TMessage);
var
SaveIndex: Integer;
Canvas: TCanvas;
R: TRect;
begin
Msg.Result := CallDefaultListBoxProc(Msg);
if (Msg.LPARAM and PRF_NONCLIENT = PRF_NONCLIENT) and (Msg.wParam > 0) then
begin
SaveIndex := 0;
Canvas := TCanvas.Create;
try
SaveIndex := SaveDC(Msg.wParam);
Canvas.Handle := Msg.wParam;
GetWindowRect(FListHandle, R);
OffsetRect(R, -R.Left, -R.Top);
ExcludeClipRect(Canvas.Handle, R.Left + 2, R.Top + 2, R.Right - 2,
R.Bottom - 2);
PaintListBoxBorder(Canvas, R);
finally
if SaveIndex <> 0 then
RestoreDC(Canvas.Handle, SaveIndex);
Canvas.Handle := 0;
Canvas.Free;
end;
DrawListBoxVertScroll(Msg.wParam);
end;
MsgHandled := True;
end;
procedure WMTimer(var Msg: TMessage);
var
R: TRect;
ItemHeight, VisibleCount, TopIndex: Integer;
begin
case FListBoxTimerCode of
1:
ListBoxSetTimer(5);
2:
ListBoxSetTimer(6);
3:
ListBoxSetTimer(7);
4:
ListBoxSetTimer(8);
5:
begin
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX,
SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) - 1, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
DrawListBoxVertScroll(0);
end;
6:
begin
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX,
SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) + 1, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
DrawListBoxVertScroll(0);
end;
7:
begin
if ListBoxVertSliderRect.Contains(FMovePos) or
(FMovePos.Y > ListBoxVertSliderRect.Bottom) then
begin
ListBoxStopTimer;
Exit;
end;
ItemHeight := SendMessage(FListHandle, LB_GETITEMHEIGHT, 0, 0);
if ItemHeight > 0 then
VisibleCount := ListBoxClientRect.Height div ItemHeight
else
VisibleCount := 0;
TopIndex := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) -
VisibleCount + 1;
if TopIndex < 0 then
TopIndex := 0;
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX, TopIndex, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
DrawListBoxVertScroll(0);
end;
8:
begin
if ListBoxVertSliderRect.Contains(FMovePos) or
(FMovePos.Y < ListBoxVertSliderRect.Top) then
begin
ListBoxStopTimer;
Exit;
end;
ItemHeight := SendMessage(FListHandle, LB_GETITEMHEIGHT, 0, 0);
if ItemHeight > 0 then
VisibleCount := ListBoxClientRect.Height div ItemHeight
else
VisibleCount := 0;
TopIndex := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) +
VisibleCount - 1;
SendMessage(FListHandle, WM_SETREDRAW, 0, 0);
SendMessage(FListHandle, LB_SETTOPINDEX, TopIndex, 0);
SendMessage(FListHandle, WM_SETREDRAW, 1, 0);
R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height);
RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE);
DrawListBoxVertScroll(0);
end;
end;
end;
begin
MsgHandled := False;
if ListBoxVertScrollArea.Height = 0 then
begin
case Msg.Msg of
WM_NCCALCSIZE:
WMNCCalcSize(TWMNCCalcSize(Msg));
WM_NCPAINT:
begin
DrawListBoxBorder;
MsgHandled := True;
end;
end;
end
else
case Msg.Msg of
WM_NCHITTEST:
if Style = csSimple then
begin
Msg.Result := HTCLIENT;
MsgHandled := True;
end;
WM_MOUSELEAVE, WM_NCMOUSELEAVE:
if Style = csSimple then
begin
FVSliderState := tsThumbBtnVertNormal;
FVUpState := tsArrowBtnUpNormal;
FVDownState := tsArrowBtnDownNormal;
DrawListBoxVertScroll(0);
end;
WM_TIMER:
WMTimer(Msg);
WM_UpdateUIState:
MsgHandled := True;
WM_NCCALCSIZE:
WMNCCalcSize(TWMNCCalcSize(Msg));
WM_MOUSEWHEEL:
WMMouseWheel(TWMMouseWheel(Msg));
WM_NCLButtonDblClk:
WMNCLButtonDblClk(TWMMouse(Msg));
WM_LBUTTONDOWN:
WMLButtonDown(TWMMouse(Msg));
WM_MOUSEMOVE:
WMMouseMove(TWMMouse(Msg));
WM_LBUTTONUP:
WMLButtonUp(TWMMouse(Msg));
WM_NCLButtonDown:
WMNCLButtonDown(TWMMouse(Msg));
WM_NCLButtonUp, WM_NCMouseMove:
MsgHandled := True;
WM_PRINT:
WMPrint(Msg);
WM_KEYDOWN, WM_KEYUP:
begin
Msg.Result := CallDefaultListBoxProc(Msg);
DrawListBoxVertScroll(0);
MsgHandled := True;
end;
WM_NCPAINT:
begin
DrawListBoxBorder;
DrawListBoxVertScroll(0);
MsgHandled := True;
end;
LB_SETTOPINDEX:
begin
Msg.Result := CallDefaultListBoxProc(Msg);
DrawListBoxVertScroll(0);
MsgHandled := True;
end;
WM_STYLECHANGED, WM_STYLECHANGING:
if FIgnoreStyleChanged then
begin
Msg.Result := 0;
MsgHandled := True;
end;
end;
if not MsgHandled then
Msg.Result := CallDefaultListBoxProc(Msg);
end;
function TSysComboBoxStyleHook.CallDefaultListBoxProc(var Msg: TMessage): LRESULT;
begin
Result := 0;
try
if (FDefListBoxProc <> nil) then
Result := CallWindowProc(FDefListBoxProc, FListHandle, Msg.Msg, Msg.wParam, Msg.lParam);
except
on e: exception do
OutputDebugString(PWideChar('CallDefaultListBoxProc error: ' + e.message + chr(0)));
end;
end;
procedure TSysComboBoxStyleHook.MouseEnter;
begin
inherited;
Invalidate;
end;
procedure TSysComboBoxStyleHook.MouseLeave;
begin
inherited;
if not DroppedDown and FMouseOnButton then
begin
FMouseOnButton := False;
Invalidate;
end
end;
procedure TSysComboBoxStyleHook.PaintBorder(Canvas: TCanvas);
var
R, ControlRect, EditRect, ListRect: TRect;
DrawState: TThemedComboBox;
BtnDrawState: TThemedComboBox;
Details: TThemedElementDetails;
Buffer: TBitmap;
begin
if not StyleServices.Available then
Exit;
if not SysControl.Enabled then
BtnDrawState := tcDropDownButtonDisabled
else if DroppedDown then
BtnDrawState := tcDropDownButtonPressed
else if (FMouseOnButton and MouseInControl) then
BtnDrawState := tcDropDownButtonHot
else
BtnDrawState := tcDropDownButtonNormal;
if not SysControl.Enabled then
DrawState := tcBorderDisabled
else if SysControl.Focused then
DrawState := tcBorderFocused
else if MouseInControl then
DrawState := tcBorderHot
else
DrawState := tcBorderNormal;
Buffer := TBitmap.Create;
Buffer.SetSize(SysControl.Width, SysControl.Height);
try
R := Rect(0, 0, Buffer.Width, Buffer.Height);
// draw border + client in buffer
Details := StyleServices.GetElementDetails(DrawState);
if (Style = csSimple) and (FListHandle <> 0) then
begin
GetWindowRect(FListHandle, ListRect);
GetWindowRect(Handle, ControlRect);
R.Bottom := ListRect.Top - ControlRect.Top;
DrawStyleElement(Buffer.Canvas.Handle, Details, R);
R := Rect(0, SysControl.Height - (ControlRect.Bottom - ListRect.Bottom),
SysControl.Width, SysControl.Height);
with Buffer.Canvas do
begin
Brush.Style := bsSolid;
Brush.Color := StyleServices.GetSystemColor(clBtnFace);
FillRect(R);
end;
R := Rect(0, 0, Buffer.Width, Buffer.Height);
R.Bottom := ListRect.Top - ControlRect.Top;
end
else
DrawStyleElement(Buffer.Canvas.Handle, Details, R);
// if not (seClient in SysControl.StyleElements) and (FEditHandle = 0) then
// begin
// R := SysControl.ClientRect;
// InflateRect(R, -3, -3);
// R.Right := ButtonRect.Left - 2;
// with Buffer.Canvas do
// begin
// Brush.Color := TWinControlClass(Control).Color;
// FillRect(R);
// end;
// end;
// draw button in buffer
if Style <> csSimple then
begin
Details := StyleServices.GetElementDetails(BtnDrawState);
DrawStyleElement(Buffer.Canvas.Handle, Details, ButtonRect);
end;
// calculation of exclude area for drawing buffer
if (SendMessage(Handle, CB_GETCURSEL, 0, 0) >= 0) and (FEditHandle = 0) then
begin
R := SysControl.ClientRect;
InflateRect(R, -3, -3);
R.Right := ButtonRect.Left - 2;
ExcludeClipRect(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom);
end
else if FEditHandle <> 0 then
begin
GetWindowRect(Handle, R);
GetWindowRect(FEditHandle, EditRect);
OffsetRect(EditRect, -R.Left, -R.Top);
with EditRect do
ExcludeClipRect(Canvas.Handle, Left, Top, Right, Bottom);
end;
// draw buffer
Canvas.Draw(0, 0, Buffer);
finally
Buffer.Free;
end;
end;
procedure TSysComboBoxStyleHook.PaintListBoxBorder(Canvas: TCanvas;
const R: TRect);
begin
with Canvas do
begin
Brush.Color := StyleServices.GetSystemColor(clWindowFrame);
FillRect(R);
end;
end;
function TSysComboBoxStyleHook.Style: TComboBoxStyle;
const
ComboBoxStyles: array [TComboBoxStyle] of DWORD = (CBS_DROPDOWN, CBS_SIMPLE,
CBS_DROPDOWNLIST, CBS_DROPDOWNLIST or CBS_OWNERDRAWFIXED,
CBS_DROPDOWNLIST or CBS_OWNERDRAWVARIABLE);
var
LStyle: Cardinal;
begin
if Handle <> 0 then
begin
LStyle := GetWindowLong(Handle, GWL_STYLE);
Result := csDropDown;
if LStyle and ComboBoxStyles[csDropDown] = ComboBoxStyles[csDropDown] then
Result := csDropDown;
if LStyle and ComboBoxStyles[csSimple] = ComboBoxStyles[csSimple] then
Result := csSimple;
if LStyle and ComboBoxStyles[csDropDownList] = ComboBoxStyles[csDropDownList]
then
Result := csDropDownList;
if LStyle and ComboBoxStyles[csOwnerDrawFixed] = ComboBoxStyles
[csOwnerDrawFixed] then
Result := csOwnerDrawFixed;
if LStyle and ComboBoxStyles[csOwnerDrawVariable] = ComboBoxStyles
[csOwnerDrawVariable] then
Result := csOwnerDrawVariable;
end
else
Result := csDropDown;
end;
{$HINTS OFF}
procedure TSysComboBoxStyleHook.UpdateColors;
const
ColorStates: array [Boolean] of TStyleColor = (scComboBoxDisabled,
scComboBox);
FontColorStates: array [Boolean] of TStyleFont = (sfComboBoxItemDisabled,
sfComboBoxItemNormal);
var
LStyle: TCustomStyleServices;
begin
LStyle := StyleServices;
Color := StyleServices.GetStyleColor(ColorStates[SysControl.Enabled]);
{$IF CompilerVersion > 23}
if OverrideFont then
FontColor := StyleServices.GetStyleFontColor(FontColorStates[True])
else
FontColor := clWindowText;
{$ELSE}
FontColor := StyleServices.GetStyleFontColor
(FontColorStates[SysControl.Enabled]);
Brush.Color := LStyle.GetStyleColor(ColorStates[SysControl.Enabled]);
{$IFEND}
end;
{$HINTS ON}
procedure TSysComboBoxStyleHook.WMCommand(var Message: TWMCommand);
begin
if (Message.NotifyCode = CBN_SELENDCANCEL) or
(Message.NotifyCode = CBN_SELENDOK) or (Message.NotifyCode = CBN_CLOSEUP) or
(Message.NotifyCode = CBN_DROPDOWN) or (Message.NotifyCode = CBN_SELCHANGE)
then
begin
if FListBoxTimerCode <> 0 then
ListBoxStopTimer;
FMouseOnButton := False;
Invalidate;
end;
end;
procedure TSysComboBoxStyleHook.WMDrawItem(var Message: TWMDrawItem);
begin
CallDefaultProc(TMessage(Message));
Handled := True;
end;
procedure TSysComboBoxStyleHook.WMMouseMove(var Message: TWMMouse);
var
P: TPoint;
R: TRect;
FOldMouseOnButton: Boolean;
begin
CallDefaultProc(TMessage(Message));
inherited;
P := Point(Message.XPos, Message.YPos);
FOldMouseOnButton := FMouseOnButton;
R := ButtonRect;
if R.Contains(P) then
FMouseOnButton := True
else
FMouseOnButton := False;
if FOldMouseOnButton <> FMouseOnButton then
InvalidateRect(Handle, @R, False);
Handled := True;
end;
procedure TSysComboBoxStyleHook.WMPaint(var Message: TMessage);
var
R: TRect;
Canvas: TCanvas;
PS: TPaintStruct;
SaveIndex: Integer;
DC: HDC;
//LItemIndex: UINT;
LDetails: TThemedElementDetails;
begin
DC := Message.wParam;
Canvas := TCanvas.Create;
try
if DC = 0 then
Canvas.Handle := BeginPaint(Handle, PS)
else
Canvas.Handle := DC;
SaveIndex := SaveDC(Canvas.Handle);
try
PaintBorder(Canvas);
finally
RestoreDC(Canvas.Handle, SaveIndex);
end;
if (Style <> csSimple) and (FEditHandle = 0) then
begin
R := SysControl.ClientRect;
InflateRect(R, -3, -3);
if SysControl.BiDiMode <> bmRightToLeft then
R.Right := ButtonRect.Left - 1
else
R.Left := ButtonRect.Right + 1;
SaveIndex := SaveDC(Canvas.Handle);
try
IntersectClipRect(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom);
//LItemIndex := UINT(SendMessage(SysControl.Handle, CB_GETCURSEL, 0, 0));
Canvas.Brush.Color := StyleServices.GetSystemColor(clWindow);
Canvas.FillRect(R);
if (SysControl.Style and CBS_OWNERDRAWFIXED = CBS_OWNERDRAWFIXED) or
(SysControl.Style and CBS_OWNERDRAWVARIABLE = CBS_OWNERDRAWVARIABLE)
then
begin
//DrawItem(Canvas, LItemIndex, R, Focused);
LDetails := StyleServices.GetElementDetails(TThemedComboBox.tcComboBoxDontCare);
{$IF (CompilerVersion >= 33)}
if Assigned(Application.Mainform) then
Canvas.Font.Size := Round(Font.Size * Application.MainForm.Monitor.PixelsPerInch / Screen.PixelsPerInch)
else
Canvas.Font.Size := Font.Size;
{$ENDIF}
DrawText(Canvas.Handle, LDetails, SysControl.Text, R,
[tfLeft, tfVerticalCenter, tfSingleLine]);
end
else
begin
LDetails := StyleServices.GetElementDetails(TThemedComboBox.tcComboBoxDontCare);
{$IF (CompilerVersion >= 33)}
if Assigned(Application.Mainform) then
Canvas.Font.Size := Round(Font.Size * Application.MainForm.Monitor.PixelsPerInch / Screen.PixelsPerInch)
else
Canvas.Font.Size := Font.Size;
{$ENDIF}
DrawText(Canvas.Handle, LDetails, SysControl.Text, R,
[tfLeft, tfVerticalCenter, tfSingleLine]);
end;
finally
RestoreDC(Canvas.Handle, SaveIndex);
end;
end;
finally
Canvas.Handle := 0;
Canvas.Free;
if DC = 0 then
EndPaint(Handle, PS);
end;
Handled := True;
end;
procedure TSysComboBoxStyleHook.WMParentNotify(var Message: TMessage);
begin
if (FListHandle = 0) and (LoWord(Message.wParam) = WM_CREATE) then
begin
if (Message.LPARAM <> 0) and (FListBoxInstance = nil) then
HookListBox(Message.LPARAM);
end
else if (FEditHandle = 0) and (LoWord(Message.wParam) = WM_CREATE) then
FEditHandle := Message.LPARAM;
end;
procedure TSysComboBoxStyleHook.WndProc(var Message: TMessage);
const
States: array [Boolean] of TStyleColor = (scEditDisabled, scComboBox);
begin
case Message.Msg of
CB_SETCURSEL, WM_KILLFOCUS:
begin
SetRedraw(False); // do not allow default drawing .
CallDefaultProc(Message);
SetRedraw(True); // allow vcl style drawing .
Invalidate;
Exit;
end;
WM_CTLCOLORMSGBOX .. WM_CTLCOLORSTATIC,
CN_CTLCOLORMSGBOX .. CN_CTLCOLORSTATIC:
begin
SetTextColor(Message.wParam, ColorToRGB(FontColor));
Brush.Color := StyleServices.GetStyleColor(States[SysControl.Enabled]);
SetBkColor(Message.wParam, ColorToRGB(Brush.Color));
Message.Result := LRESULT(Brush.Handle);
end;
CM_ENABLEDCHANGED:
begin
UpdateColors;
CallDefaultProc(Message); // Allow control to handle message
end;
CM_FOCUSCHANGED:
begin
Invalidate;
// Handled := False; // Allow control to handle message
CallDefaultProc(Message);
end;
else
inherited WndProc(Message);
end;
end;
{ TSysStaticStyleHook }
constructor TSysStaticStyleHook.Create(AHandle: THandle);
var
Style: DWORD;
begin
Style := GetWindowLongPtr(AHandle, GWL_STYLE);
if (Style and SS_ICON <> SS_ICON) and (Style and SS_BITMAP <> SS_BITMAP) then
inherited;
FUpdatedColor := 0;
{$IF CompilerVersion > 23}
StyleElements := [seFont, seBorder, seClient];
{$ELSE}
OverridePaint := True;
OverridePaintNC := True;
OverrideFont := True;
{$IFEND}
UpdateColors;
end;
destructor TSysStaticStyleHook.Destroy;
begin
inherited;
end;
function TSysStaticStyleHook.GetIsFrameOrLine: Boolean;
begin
with SysControl do
Result :=
(Style and SS_ETCHEDFRAME = SS_ETCHEDFRAME) or
(Style and SS_ETCHEDHORZ = SS_ETCHEDHORZ) or
(Style and SS_SUNKEN = SS_SUNKEN) or
(Style and SS_ETCHEDVERT = SS_ETCHEDVERT);
end;
function TSysStaticStyleHook.GetIsText: Boolean;
begin
with SysControl do
Result := (Style and SS_ICON <> SS_ICON) and
(Style and SS_BITMAP <> SS_BITMAP) and
(Style and SS_GRAYRECT <> SS_GRAYRECT) and
(Style and SS_GRAYFRAME <> SS_GRAYFRAME) and
(Style and SS_OWNERDRAW <> SS_OWNERDRAW) and
(Style and SS_REALSIZEIMAGE <> SS_REALSIZEIMAGE) and
(Style and SS_ICON <> SS_ICON) and (Style and SS_USERITEM <> SS_USERITEM)
and (Style and SS_REALSIZEIMAGE <> SS_REALSIZEIMAGE) and
(Style and SS_SIMPLE <> SS_SIMPLE);
end;
function TSysStaticStyleHook.GetTextFormat: TTextFormat;
const
SS_EDITCONTROL = $2000;
begin
Result := [tfHidePrefix];
with SysControl do
begin
if Style and SS_LEFT = SS_LEFT then
include(Result, tfLeft)
else if Style and SS_RIGHT = SS_RIGHT then
include(Result, tfRight)
else if Style and SS_CENTER = SS_CENTER then
include(Result, tfCenter);
if Style and SS_ENDELLIPSIS = SS_ENDELLIPSIS then
include(Result, tfEndEllipsis);
if Style and SS_PATHELLIPSIS = SS_PATHELLIPSIS then
include(Result, tfPathEllipsis);
if Style and SS_WORDELLIPSIS = SS_WORDELLIPSIS then
include(Result, tfWordEllipsis);
if Style and SS_NOPREFIX = SS_NOPREFIX then
include(Result, tfNoPrefix);
if Style and SS_EDITCONTROL = SS_EDITCONTROL then
include(Result, tfEditControl);
if not(Style and SS_ENDELLIPSIS = SS_ENDELLIPSIS) and
not(Style and SS_PATHELLIPSIS = SS_PATHELLIPSIS) and
not(Style and SS_WORDELLIPSIS = SS_WORDELLIPSIS) then
include(Result, tfWordBreak);
end;
end;
procedure TSysStaticStyleHook.Paint(Canvas: TCanvas);
const
States: array [Boolean] of TThemedTextLabel = (ttlTextLabelDisabled,
ttlTextLabelNormal);
var
LDetails: TThemedElementDetails;
LRect: TRect;
begin
LRect := SysControl.ClientRect;
if GetBkMode(Canvas.Handle) = TRANSPARENT then
begin
LDetails := StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal);
StyleServices.DrawParentBackground(Handle, Canvas.Handle, LDetails, False);
Canvas.Brush.Style := bsClear;
end
else
begin
Canvas.Brush.Color := StyleServices.GetStyleColor(scWindow);
Canvas.FillRect(LRect);
end;
LDetails := StyleServices.GetElementDetails(States[SysControl.Enabled]);
Canvas.Font := SysControl.Font;
DrawText(Canvas.Handle, LDetails, SysControl.Text, LRect, TextFormat);
end;
procedure TSysStaticStyleHook.PaintNC(Canvas: TCanvas);
var
LRect: TRect;
LBitMap: TBitmap;
begin
if IsFrameOrLine then
begin
LRect := Rect(0, 0, SysControl.Width, SysControl.Height);
LBitMap := TBitmap.Create;
try
LBitMap.Width := LRect.Width;
LBitMap.Height := LRect.Height;
Frame3D(LBitMap.Canvas, LRect, StyleServices.ColorToRGB(clBtnShadow),
StyleServices.ColorToRGB(clBtnHighLight), 1);
ExcludeClipRect(Canvas.Handle, 1, 1, SysControl.Width - 1,
SysControl.Height - 1);
Canvas.Draw(0, 0, LBitMap);
finally
LBitMap.Free;
end;
end;
end;
procedure TSysStaticStyleHook.UpdateColors;
const
ColorStates: array [Boolean] of TStyleColor = (scEditDisabled, scEdit);
FontColorStates: array [Boolean] of TStyleFont = (sfEditBoxTextDisabled,
sfEditBoxTextNormal);
begin
Color := StyleServices.GetStyleColor(scWindow);
FontColor := StyleServices.GetSystemColor(clWindowText);
//Addlog(Format('UpdateColors Handle %d Color %d FontColor %d ',[SysControl.Handle, Color, FontColor]));
end;
procedure TSysStaticStyleHook.WndProc(var Message: TMessage);
begin
//Addlog(Format('TSysStaticStyleHook $0x%x %s', [SysControl.Handle, WM_To_String(Message.Msg)]));
case Message.Msg of
WM_SETTEXT:
begin
CallDefaultProc(Message);
if SysControl.Visible then
Invalidate;
end;
WM_ENABLE:
if SysControl.Visible then
Invalidate;
WM_PAINT:
begin
if OverridePaint and StyleServicesEnabled then
begin
if (IsText and (Length(SysControl.Text) > 0)) then
inherited
else
CallDefaultProc(Message);
end
else
CallDefaultProc(Message);
end;
else
inherited;
end;
end;
{ TSysCheckBoxStyleHook }
function RectVCenter(var R: TRect; Bounds: TRect): TRect;
begin
OffsetRect(R, -R.Left, -R.Top);
OffsetRect(R, 0, (Bounds.Height - R.Height) div 2);
OffsetRect(R, Bounds.Left, Bounds.Top);
Result := R;
end;
procedure TSysCheckBoxStyleHook.BMSetCheck(var Message: TMessage);
begin
SetRedraw(False);
CallDefaultProc(TMessage(Message));
SetRedraw(True);
Invalidate;
Handled := True;
end;
constructor TSysCheckBoxStyleHook.Create(AHandle: THandle);
begin
inherited;
OverridePaint := True;
OverrideEraseBkgnd := True;
// DoubleBuffered := True;
end;
function TSysCheckBoxStyleHook.GetDrawState(State: TSysCheckBoxState)
: TThemedButton;
begin
Result := tbButtonDontCare;
if not SysControl.Enabled then
case State of
cbUnchecked:
Result := tbCheckBoxUncheckedDisabled;
cbChecked:
Result := tbCheckBoxCheckedDisabled;
cbGrayed:
Result := tbCheckBoxMixedDisabled;
end
else if Pressed and MouseInControl then
case State of
cbUnchecked:
Result := tbCheckBoxUncheckedPressed;
cbChecked:
Result := tbCheckBoxCheckedPressed;
cbGrayed:
Result := tbCheckBoxMixedPressed;
end
else if MouseInControl then
case State of
cbUnchecked:
Result := tbCheckBoxUncheckedHot;
cbChecked:
Result := tbCheckBoxCheckedHot;
cbGrayed:
Result := tbCheckBoxMixedHot;
end
else
case State of
cbUnchecked:
Result := tbCheckBoxUncheckedNormal;
cbChecked:
Result := tbCheckBoxCheckedNormal;
cbGrayed:
Result := tbCheckBoxMixedNormal;
end;
end;
procedure TSysCheckBoxStyleHook.MouseEnter;
begin
inherited;
Invalidate;
Handled := True;
end;
procedure TSysCheckBoxStyleHook.MouseLeave;
begin
inherited;
Invalidate;
Handled := True;
end;
procedure TSysCheckBoxStyleHook.Paint(Canvas: TCanvas);
var
State: TSysCheckBoxState;
Details: TThemedElementDetails;
R: TRect;
Spacing: Integer;
BoxSize: TSize;
LCaption: string;
LRect: TRect;
ElementSize: TElementSize;
begin
if StyleServices.Available then
begin
State := TSysCheckBoxState(SendMessage(Handle, BM_GETCHECK, 0, 0));
Details := StyleServices.GetElementDetails(GetDrawState(State));
Spacing := 3;
LRect := System.Classes.Rect(0, 0, 20, 20);
ElementSize := esActual;
R := SysControl.ClientRect;
with StyleServices do
begin
{$IF (CompilerVersion >= 33)}
if not (Assigned(Application.Mainform) and GetElementSize(Canvas.Handle, GetElementDetails(tbCheckBoxCheckedNormal), LRect, ElementSize, BoxSize, Application.MainForm.Monitor.PixelsPerInch)) then
{$ELSE}
if not GetElementSize(Canvas.Handle, GetElementDetails(tbCheckBoxCheckedNormal), LRect, ElementSize, BoxSize) then
{$ENDIF}
begin
BoxSize.cx := GetSysMetrics(SM_CXMENUCHECK);
BoxSize.cy := GetSysMetrics(SM_CYMENUCHECK);
end;
end;
if not RightAlignment then
begin
R := Rect(0, 0, BoxSize.cx, BoxSize.cy);
RectVCenter(R, Rect(0, 0, SysControl.Width, SysControl.Height));
end
else
begin
R := Rect(SysControl.Width - BoxSize.cx - 1, 0, SysControl.Width,
SysControl.Height);
RectVCenter(R, Rect(SysControl.Width - BoxSize.cy - 1, 0,
SysControl.Width, SysControl.Height));
end;
DrawStyleElement(Canvas.Handle, Details, R);
Canvas.Font := SysControl.Font;
R := Rect(0, 0, SysControl.Width - BoxSize.cx - 10, SysControl.Height);
LCaption := Text;
Winapi.Windows.DrawText(Canvas.Handle, PWideChar(LCaption),
Length(LCaption), R, SysControl.DrawTextBiDiModeFlags(DT_CALCRECT or
DT_EXPANDTABS));
if not RightAlignment then
RectVCenter(R, Rect(BoxSize.cx + Spacing, 0, SysControl.Width,
SysControl.Height))
else
begin
if SysControl.BiDiMode <> bmRightToLeft then
RectVCenter(R, Rect(3, 0, SysControl.Width - BoxSize.cx - Spacing,
SysControl.Height))
else
RectVCenter(R, Rect(SysControl.Width - BoxSize.cx - Spacing - R.Right,
0, SysControl.Width - BoxSize.cx - Spacing, SysControl.Height));
end;
DrawControlText(Canvas, Details, LCaption, R,
SysControl.DrawTextBiDiModeFlags(DT_LEFT or DT_VCENTER or DT_EXPANDTABS));
if Focused then
begin
InflateRect(R, 2, 1);
if R.Top < 0 then
R.Top := 0;
if R.Bottom > SysControl.Height then
R.Bottom := SysControl.Height;
Canvas.Brush.Color := StyleServices.GetSystemColor(clBtnFace);
Canvas.DrawFocusRect(R);
end;
end;
end;
procedure TSysCheckBoxStyleHook.PaintBackground(Canvas: TCanvas);
var
Details: TThemedElementDetails;
begin
if StyleServices.Available then
begin
Details.Element := teButton;
if StyleServices.HasTransparentParts(Details) then
StyleServices.DrawParentBackground(Handle, Canvas.Handle, Details, False);
end;
end;
function TSysCheckBoxStyleHook.RightAlignment: Boolean;
begin
Result := (SysControl.BiDiMode = bmRightToLeft) or
(GetWindowLong(Handle, GWL_STYLE) and BS_RIGHTBUTTON = BS_RIGHTBUTTON);
end;
procedure TSysCheckBoxStyleHook.WMKeyDown(var Message: TWMKeyDown);
begin
if Message.CharCode = VK_SPACE then
SetRedraw(False);
CallDefaultProc(TMessage(Message));
if Message.CharCode = VK_SPACE then
begin
SetRedraw(True);
Invalidate;
end;
Handled := True;
end;
procedure TSysCheckBoxStyleHook.WMKeyUp(var Message: TWMKeyUp);
begin
if Message.CharCode = VK_SPACE then
SetRedraw(False);
CallDefaultProc(TMessage(Message));
if Message.CharCode = VK_SPACE then
begin
SetRedraw(True);
Invalidate;
end;
Handled := True;
end;
procedure TSysCheckBoxStyleHook.WMLButtonDblClk(var Message: TWMMouse);
begin
SetRedraw(False);
CallDefaultProc(TMessage(Message));
SetRedraw(True);
Invalidate;
Handled := True;
end;
procedure TSysCheckBoxStyleHook.WMLButtonDown(var Message: TWMMouse);
begin
SetRedraw(False);
CallDefaultProc(TMessage(Message));
SetRedraw(True);
FPressed := True;
Invalidate;
Handled := True;
end;
procedure TSysCheckBoxStyleHook.WMLButtonUp(var Message: TWMMouse);
begin
SetRedraw(False);
CallDefaultProc(TMessage(Message));
SetRedraw(True);
FPressed := False;
Invalidate;
Handled := True;
end;
procedure TSysCheckBoxStyleHook.WndProc(var Message: TMessage);
begin
inherited;
end;
{ TSysRadioButtonStyleHook }
constructor TSysRadioButtonStyleHook.Create(AHandle: THandle);
begin
inherited;
OverridePaint := True;
OverrideEraseBkgnd := True;
// DoubleBuffered := True;
end;
function TSysRadioButtonStyleHook.GetDrawState(State: TSysCheckBoxState)
: TThemedButton;
begin
Result := tbButtonDontCare;
if not SysControl.Enabled then
case State of
cbUnchecked:
Result := tbRadioButtonUncheckedDisabled;
cbChecked:
Result := tbRadioButtonCheckedDisabled;
end
else if Pressed and MouseInControl then
case State of
cbUnchecked:
Result := tbRadioButtonUncheckedPressed;
cbChecked:
Result := tbRadioButtonCheckedPressed;
end
else if MouseInControl then
case State of
cbUnchecked:
Result := tbRadioButtonUncheckedHot;
cbChecked:
Result := tbRadioButtonCheckedHot;
end
else
case State of
cbUnchecked:
Result := tbRadioButtonUncheckedNormal;
cbChecked:
Result := tbRadioButtonCheckedNormal;
end;
end;
procedure TSysRadioButtonStyleHook.WndProc(var Message: TMessage);
begin
inherited;
end;
initialization
if StyleServices.Available then
begin
with TSysStyleManager do
begin
RegisterSysStyleHook(WC_BUTTON, TSysButtonStyleHook);
RegisterSysStyleHook(WC_EDIT, TSysEditStyleHook);
RegisterSysStyleHook('ComboLBox', TSysListBoxStyleHook);
RegisterSysStyleHook(WC_COMBOBOX, TSysComboBoxStyleHook);
RegisterSysStyleHook( 'ListBox', TSysListBoxStyleHook);
RegisterSysStyleHook( 'Static', TSysStaticStyleHook);
end;
end;
finalization
with TSysStyleManager do
begin
UnRegisterSysStyleHook(WC_BUTTON, TSysButtonStyleHook);
UnRegisterSysStyleHook(WC_EDIT, TSysEditStyleHook);
UnRegisterSysStyleHook('ComboLBox', TSysListBoxStyleHook);
UnRegisterSysStyleHook(WC_COMBOBOX, TSysComboBoxStyleHook);
UnRegisterSysStyleHook('ListBox', TSysListBoxStyleHook);
UnRegisterSysStyleHook('Static', TSysStaticStyleHook);
end;
end.