// **************************************************************************************************
//
// Unit Vcl.Styles.NC
// 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.
//
// The Original Code is Vcl.Styles.NC.pas.
//
// The Initial Developer of the Original Code is Rodrigo Ruz V.
// Portions created by Rodrigo Ruz V. are Copyright (C) 2014-2020 Rodrigo Ruz V.
// All Rights Reserved.
//
// **************************************************************************************************
unit Vcl.Styles.NC;
interface
{$IF RTLVersion>=24}
{$LEGACYIFEND ON}
{$IFEND}
uses
System.Classes,
System.Generics.Collections,
System.Types,
Winapi.Windows,
Winapi.Messages,
Vcl.ImgList,
System.UITypes,
Vcl.Graphics,
Vcl.Themes,
Vcl.Styles,
Vcl.Controls,
Vcl.Menus,
Vcl.StdCtrls,
Vcl.GraphUtil,
Vcl.Forms,
Vcl.Styles.Utils.Misc;
type
TNCControl = class;
// TListNCButtons = TObjectList<TNCButton>;
TNCControls = class;
TListNCControls = class(TCollection)
private
FOwner: TNCControls;
function GetItem(Index: Integer): TNCControl;
procedure SetItem(Index: Integer; Value: TNCControl);
function Add: TNCControl;
protected
function GetOwner: TPersistent; override;
public
constructor Create(AOwner: TPersistent);
destructor Destroy; override;
function AddEx<T: TCollectionItem>: T;
function Insert(Index: Integer): TNCControl;
property Items[Index: Integer]: TNCControl read GetItem write SetItem; default;
end;
TNCControls = class(TComponent)
private
FControls: TListNCControls;
FStyleServices: TCustomStyleServices;
FVisible: Boolean;
FForm: TCustomForm;
FShowSystemMenu: Boolean;
FFormBorderSize: TRect;
FImages: TCustomImageList;
FShowCaption: Boolean;
FLastPoint: TPoint;
FActiveTabControlIndex, FHotControlIndex, FPressedControlIndex, FControlUpIndex: Integer;
function GetStyleServices: TCustomStyleServices;
procedure SetStyleServices(const Value: TCustomStyleServices);
procedure SetVisible(const Value: Boolean);
function GetControl(Index: Integer): TNCControl;
function GetCount: Integer;
procedure SetImages(const Value: TCustomImageList);
procedure SetShowSystemMenu(const Value: Boolean);
procedure SetShowCaption(const Value: Boolean);
function GetActiveTabButtonIndex: Integer;
procedure SetActiveTabButtonIndex(const Value: Integer);
property FormBorderSize: TRect read FFormBorderSize write FFormBorderSize;
property Form: TCustomForm read FForm;
protected
function GetNCControlIndex(P: TPoint): Integer;
function PointInNCControl(P: TPoint): Boolean;
property LastPoint: TPoint read FLastPoint;
public
property Controls: TListNCControls read FControls;
property ControlsList[index: Integer]: TNCControl read GetControl; default;
property ControlsCount: Integer read GetCount;
property StyleServices: TCustomStyleServices read GetStyleServices write SetStyleServices;
procedure Invalidate;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property ActiveTabButtonIndex: Integer read GetActiveTabButtonIndex write SetActiveTabButtonIndex;
property LNCControl: TListNCControls read FControls;
property Visible: Boolean read FVisible write SetVisible default True;
property Images: TCustomImageList read FImages write SetImages;
property ShowSystemMenu: Boolean read FShowSystemMenu write SetShowSystemMenu default True;
property ShowCaption: Boolean read FShowCaption write SetShowCaption default True;
end;
TNCControl = class(TCollectionItem)
private
FFont: TFont;
FEnabled: Boolean;
FWidth: Integer;
FVisible: Boolean;
FTop: Integer;
FHeight: Integer;
FLeft: Integer;
FNCControls: TNCControls;
FCaption: string;
FHint: string;
FShowHint: Boolean;
FName: TComponentName;
FTag: NativeInt;
FCaptionAligmentFlags: Cardinal;
function GetEnabled: Boolean;
procedure SetEnabled(const Value: Boolean);
function GetBoundsRect: TRect;
procedure SetBoundsRect(const Value: TRect);
procedure SetHeight(const Value: Integer);
procedure SetLeft(const Value: Integer);
procedure SetTop(const Value: Integer);
procedure SetWidth(const Value: Integer);
procedure SetVisible(const Value: Boolean);
procedure SetFont(const Value: TFont);
procedure SetShowHint(const Value: Boolean);
procedure SetName(const Value: TComponentName);
procedure DrawControl(ACanvas: TCanvas; AMouseInControl, Pressed: Boolean); virtual;
protected
procedure Handle_WMNCLButtonDown(var Message: TWMNCHitMessage); virtual;
procedure Handle_WMNCLButtonUp(var Message: TWMNCHitMessage); virtual;
procedure Handle_WMNCMouseMove(var Message: TWMNCHitMessage); virtual;
published
procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); virtual;
property Left: Integer read FLeft write SetLeft;
property Top: Integer read FTop write SetTop;
property Width: Integer read FWidth write SetWidth;
property Height: Integer read FHeight write SetHeight;
property Font: TFont read FFont write SetFont;
property Enabled: Boolean read GetEnabled write SetEnabled default True;
property Visible: Boolean read FVisible write SetVisible default True;
property Hint: string read FHint write FHint;
property ShowHint: Boolean read FShowHint write SetShowHint;
property Name: TComponentName read FName write SetName stored False;
property Tag: NativeInt read FTag write FTag default 0;
property CaptionAligmentFlags: Cardinal read FCaptionAligmentFlags write FCaptionAligmentFlags;
property Caption: string read FCaption write FCaption;
function GetAs<T>: T;
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
property NCControls: TNCControls read FNCControls;
property BoundsRect: TRect read GetBoundsRect write SetBoundsRect;
end;
TNCButton = class(TNCControl)
public type
TNCButtonStyle = (nsPushButton, nsTranparent, nsSplitButton, nsSplitTrans, nsAlpha, nsGradient, nsTab, nsEdge, nsFrame);
TNCImageStyle = (isNormal, isGray, isGrayHot);
private
FDropDown: Boolean;
FStyle: TNCButtonStyle;
FImageAlignment: TImageAlignment;
FPressedImageIndex: TImageIndex;
FDropDownMenu: TPopupMenu;
FOnDropDownClick: TNotifyEvent;
FDisabledImageIndex: TImageIndex;
FImageMargins: TImageMargins;
FImageIndex: TImageIndex;
FHotImageIndex: TImageIndex;
FImageStyle: TNCImageStyle;
FOnClick: TNotifyEvent;
FHintWindow: THintWindow;
FAlphaColor: TColor;
FAlphaHotColor: TColor;
FFontColor: TColor;
FHotFontColor: TColor;
FStartColor: TColor;
FEndColor: TColor;
FDirection: TGradientDirection;
FDefaultFontAwesomeSize: Integer;
FUseFontAwesome: Boolean;
FAwesomeHotFontColor: TColor;
FAwesomeFontColor: TColor;
FOnClose: TNotifyEvent;
procedure DrawControl(ACanvas: TCanvas; AMouseInControl, Pressed: Boolean); override;
procedure SetStyle(const Value: TNCButtonStyle);
procedure SetDisabledImageIndex(const Value: TImageIndex);
procedure SetDropDownMenu(const Value: TPopupMenu);
procedure SetHotImageIndex(const Value: TImageIndex);
procedure SetImageAlignment(const Value: TImageAlignment);
procedure SetImageIndex(const Value: TImageIndex);
procedure SetImageMargins(const Value: TImageMargins);
procedure SetPressedImageIndex(const Value: TImageIndex);
procedure DrawControlText(Canvas: TCanvas; Details: TThemedElementDetails; const S: string; var R: TRect;
Flags: Cardinal; AColor: TColor = clNone);
procedure SetImageStyle(const Value: TNCImageStyle);
procedure ShowHintWindow(X, Y: Integer);
procedure HideHintWindow;
function GetTabIndex: Integer;
procedure SetUseFontAwesome(const Value: Boolean);
protected
procedure Handle_WMNCLButtonDown(var Message: TWMNCHitMessage); override;
procedure Handle_WMNCLButtonUp(var Message: TWMNCHitMessage); override;
procedure Handle_WMNCMouseMove(var Message: TWMNCHitMessage); override;
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
property TabIndex: Integer read GetTabIndex;
published
property Style: TNCButtonStyle read FStyle write SetStyle;
property ImageStyle: TNCImageStyle read FImageStyle write SetImageStyle;
property DisabledImageIndex: TImageIndex read FDisabledImageIndex write SetDisabledImageIndex;
property DropDownMenu: TPopupMenu read FDropDownMenu write SetDropDownMenu;
property HotImageIndex: TImageIndex read FHotImageIndex write SetHotImageIndex;
property ImageAlignment: TImageAlignment read FImageAlignment write SetImageAlignment;
property ImageIndex: TImageIndex read FImageIndex write SetImageIndex;
property ImageMargins: TImageMargins read FImageMargins write SetImageMargins;
property PressedImageIndex: TImageIndex read FPressedImageIndex write SetPressedImageIndex;
property AlphaColor: TColor read FAlphaColor write FAlphaColor;
property AlphaHotColor: TColor read FAlphaHotColor write FAlphaHotColor;
property FontColor: TColor read FFontColor write FFontColor;
property HotFontColor: TColor read FHotFontColor write FHotFontColor;
property StartColor: TColor read FStartColor write FStartColor;
property EndColor: TColor read FEndColor write FEndColor;
property Direction: TGradientDirection read FDirection write FDirection;
property UseFontAwesome: Boolean read FUseFontAwesome write SetUseFontAwesome;
property DefaultFontAwesomeSize: Integer read FDefaultFontAwesomeSize write FDefaultFontAwesomeSize;
property AwesomeFontColor: TColor read FAwesomeFontColor write FAwesomeFontColor;
property AwesomeHotFontColor: TColor read FAwesomeHotFontColor write FAwesomeHotFontColor;
property OnDropDownClick: TNotifyEvent read FOnDropDownClick write FOnDropDownClick;
property OnClick: TNotifyEvent read FOnClick write FOnClick;
property OnClose: TNotifyEvent read FOnClose write FOnClose;
end;
TFormStyleNCControls = class(TFormStyleHook)
strict private
FNCControls: TNCControls;
private
function GetNCControls: TNCControls;
protected
procedure WMNCMouseMove(var Message: TWMNCHitMessage); message WM_NCMOUSEMOVE;
procedure WMNCLButtonDown(var Message: TWMNCHitMessage); message WM_NCLBUTTONDOWN;
procedure WMNCLButtonUp(var Message: TWMNCHitMessage); message WM_NCLBUTTONUP;
procedure WMNCLButtonDblClk(var Message: TWMNCHitMessage); message WM_NCLBUTTONDBLCLK;
procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
procedure PaintNCControls(Canvas: TCanvas; ARect: TRect);
procedure PaintNC(Canvas: TCanvas); override;
strict protected
procedure MouseLeave; override;
procedure MouseEnter; override;
procedure Restore; override;
procedure Maximize; override;
procedure Minimize; override;
public
property NCControls: TNCControls read GetNCControls;
constructor Create(AControl: TWinControl); override;
destructor Destroy; override;
end;
TFormStyleNCSettings = class
private
class var FUseThinBorder: Boolean;
public
class property UseThinBorder: Boolean read FUseThinBorder write FUseThinBorder;
end;
{
TODO
Add more buttons styles (colors, gradient, glow, link)
Add hot effects (glow, menu sel)
Add support for TAction
}
implementation
uses
DDetours,
Winapi.CommCtrl,
System.SysUtils,
System.Rtti,
Winapi.UxTheme,
Vcl.Styles.Utils.Graphics,
Vcl.Styles.FontAwesome,
Vcl.Styles.FormStyleHooks;
type
THintWindowClass = class(THintWindow);
TCustomFormClass = class(TCustomForm);
TFormStyleHookClass = class(TFormStyleHook);
TStyleHookList = TList<TStyleHookClass>;
TStyleHookDictionary = TDictionary<TClass, TStyleHookList>;
TCustomStyleEngineHelper = Class Helper for TCustomStyleEngine
public
class function GetRegisteredStyleHooks: TStyleHookDictionary;
end;
var
Trampoline_TFormStyleHook_GetBorderSize: function(Self: TFormStyleHook): TRect;
Trampoline_TFormStyleHook_GetRegion: function(Self: TFormStyleHook): HRgn;
class function TCustomStyleEngineHelper.GetRegisteredStyleHooks: TStyleHookDictionary;
begin
with Self do
Result := FRegisteredStyleHooks;
end;
function IsStyleHookRegistered(ControlClass: TClass; StyleHookClass: TStyleHookClass): Boolean;
var
List: TStyleHookList;
begin
Result := False;
if TCustomStyleEngine.GetRegisteredStyleHooks.ContainsKey(ControlClass) then
begin
List := TCustomStyleEngine.GetRegisteredStyleHooks[ControlClass];
Result := List.IndexOf(StyleHookClass) <> -1;
end;
end;
function GetRegisteredStylesHooks(ControlClass: TClass): TStyleHookList;
begin
Result := nil;
if TCustomStyleEngine.GetRegisteredStyleHooks.ContainsKey(ControlClass) then
Result := TCustomStyleEngine.GetRegisteredStyleHooks[ControlClass];
end;
{ TNCControls }
constructor TNCControls.Create(AOwner: TComponent);
begin
if not(AOwner is TCustomForm) then
Raise EAbort.Create('TNCControls only must be created in forms');
inherited Create(AOwner);
FForm := TCustomForm(AOwner);
FControls := TListNCControls.Create(Self);
FHotControlIndex := -1;
FControlUpIndex := -1;
FPressedControlIndex := -1;
FStyleServices := nil;
FImages := nil;
FVisible := True;
FShowCaption := True;
FShowSystemMenu := True;
if not IsStyleHookRegistered(AOwner.ClassType, TFormStyleNCControls) then
TStyleManager.Engine.RegisterStyleHook(AOwner.ClassType, TFormStyleNCControls);
FForm.Perform(CM_RECREATEWND, 0, 0);
FActiveTabControlIndex := 0;
end;
destructor TNCControls.Destroy;
begin
FControls.Free;
inherited;
end;
function TNCControls.GetActiveTabButtonIndex: Integer;
begin
Result := FActiveTabControlIndex;
end;
function TNCControls.GetControl(Index: Integer): TNCControl;
begin
Result := FControls[Index];
end;
function TNCControls.GetCount: Integer;
begin
Result := FControls.Count;
end;
function TNCControls.GetStyleServices: TCustomStyleServices;
begin
Result := FStyleServices;
if (Result = nil) then
Result := Vcl.Themes.StyleServices;
end;
procedure TNCControls.Invalidate;
begin
if FForm.HandleAllocated then
SendMessage(FForm.Handle, WM_NCPAINT, 0, 0);
end;
procedure TNCControls.SetActiveTabButtonIndex(const Value: Integer);
// Refactor This -> TNCButton can't be called from here
function GetMaxTabIndex: Integer;
var
i: Integer;
begin
Result := -1;
For i := 0 to (FControls.Count - 1) do
if (FControls[i] is TNCButton) and (FControls[i].GetAs<TNCButton>.Style = nsTab) then
Inc(Result);
end;
var
lmax: Integer;
begin
lmax := GetMaxTabIndex;
if (Value <> FActiveTabControlIndex) and (Value >= 0) and (lmax >= 0) and (Value <= lmax) then
begin
FActiveTabControlIndex := Value;
Invalidate;
end;
end;
procedure TNCControls.SetImages(const Value: TCustomImageList);
begin
FImages := Value;
end;
procedure TNCControls.SetShowCaption(const Value: Boolean);
begin
if Value <> FShowCaption then
begin
FShowCaption := Value;
Invalidate;
end;
end;
procedure TNCControls.SetShowSystemMenu(const Value: Boolean);
begin
if Value <> FShowSystemMenu then
begin
FShowSystemMenu := Value;
Invalidate;
end;
end;
procedure TNCControls.SetStyleServices(const Value: TCustomStyleServices);
begin
if Value <> FStyleServices then
begin
FStyleServices := Value;
if IsWindowVisible(TCustomFormClass(FForm).Handle) then
PostMessage(TCustomFormClass(FForm).Handle, CM_CUSTOMSTYLECHANGED, 0, 0)
else
SendMessage(TCustomFormClass(FForm).Handle, CM_CUSTOMSTYLECHANGED, 0, 0);
end;
end;
procedure TNCControls.SetVisible(const Value: Boolean);
begin
if Value <> FVisible then
begin
FVisible := Value;
Invalidate;
end;
end;
function TNCControls.GetNCControlIndex(P: TPoint): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to FControls.Count - 1 do
if FControls[i].Visible and PtInRect(FControls[i].BoundsRect, P) then
Exit(i);
end;
function TNCControls.PointInNCControl(P: TPoint): Boolean;
begin
Result := GetNCControlIndex(P) >= 0;
end;
{ TNCButton }
constructor TNCButton.Create(Collection: TCollection);
begin
inherited Create(Collection);
FDropDown := False;
FImageMargins := TImageMargins.Create;
FDisabledImageIndex := -1;
FPressedImageIndex := -1;
FImageIndex := -1;
FUseFontAwesome := False;
FDefaultFontAwesomeSize := 16; // 16
FHotImageIndex := -1;
FImageAlignment := iaLeft;
FStyle := nsPushButton;
FImageStyle := isNormal;
FDropDownMenu := nil;
FOnDropDownClick := nil;
FOnClick := nil;
FOnClose := nil;
FHintWindow := THintWindow.Create(nil);
FAlphaColor := FNCControls.StyleServices.GetSystemColor(clBtnFace);
FDirection := TGradientDirection.gdHorizontal;
FFontColor := StyleServices.GetSystemColor(clBtnText);
FHotFontColor := StyleServices.GetSystemColor(clHighlight);
FAwesomeFontColor := StyleServices.GetSystemColor(clBtnText);
FAwesomeHotFontColor := StyleServices.GetSystemColor(clHighlight);
end;
destructor TNCButton.Destroy;
begin
FreeAndNil(FHintWindow);
FreeAndNil(FImageMargins);
inherited;
end;
procedure TNCButton.DrawControlText(Canvas: TCanvas; Details: TThemedElementDetails; const S: string; var R: TRect;
Flags: Cardinal; AColor: TColor = clNone);
var
ThemeTextColor: TColor;
TextFormat: TTextFormatFlags;
LStyleServices: TCustomStyleServices;
begin
Canvas.Font := Font;
LStyleServices := NCControls.StyleServices;
TextFormat := TTextFormatFlags(Flags);
if LStyleServices.GetElementColor(Details, ecTextColor, ThemeTextColor) then
begin
if AColor <> clNone then
Canvas.Font.Color := AColor
else
Canvas.Font.Color := ThemeTextColor;
LStyleServices.DrawText(Canvas.Handle, Details, S, R, TextFormat, Canvas.Font.Color);
end
else
begin
Canvas.Refresh;
LStyleServices.DrawText(Canvas.Handle, Details, S, R, TextFormat);
end;
end;
function TNCButton.GetTabIndex: Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to NCControls.ControlsCount - 1 do
if NCControls.LNCControl[i] is TNCButton then
begin
if NCControls.LNCControl[i].GetAs<TNCButton>.Style = nsTab then
Inc(Result);
if NCControls[i] = Self then
Break;
end;
end;
procedure DoDrawGrayImage(hdcDst: HDC; himl: HIMAGELIST; ImageIndex, X, Y: Integer);
var
pimldp: TImageListDrawParams;
begin
FillChar(pimldp, SizeOf(pimldp), #0);
pimldp.fState := ILS_SATURATE;
pimldp.cbSize := SizeOf(pimldp);
pimldp.hdcDst := hdcDst;
pimldp.himl := himl;
pimldp.i := ImageIndex;
pimldp.X := X;
pimldp.Y := Y;
ImageList_DrawIndirect(@pimldp);
end;
procedure FrameRect(ACanvas: TCanvas; const R: TRect; Color1, Color2: TColor);
begin
with ACanvas do
begin
Pen.Color := Color1;
PolyLine([Point(R.Left, R.Bottom), Point(R.Left, R.Top), Point(R.Right, R.Top)]);
Pen.Color := Color2;
PolyLine([Point(R.Right, R.Top), Point(R.Right, R.Bottom), Point(R.Left, R.Bottom)]);
end;
end;
procedure TNCButton.Handle_WMNCLButtonDown(var Message: TWMNCHitMessage);
var
i: Integer;
begin
// process click on buttton with the nstab style
if (FNCControls.FPressedControlIndex >= 0) and (FNCControls[FNCControls.FPressedControlIndex] is TNCButton) and
(FNCControls[FNCControls.FPressedControlIndex].GetAs<TNCButton>.Style = nsTab) then
begin
FNCControls.FActiveTabControlIndex := -1;
For i := 0 to FNCControls.FPressedControlIndex do
if (FNCControls[i] is TNCButton) and (FNCControls[i].GetAs<TNCButton>.Style = nsTab) then
Inc(FNCControls.FActiveTabControlIndex);
end;
end;
procedure TNCButton.Handle_WMNCLButtonUp(var Message: TWMNCHitMessage);
var
LNCButtton: TNCButton;
LRect: TRect;
P: TPoint;
i, X, Y: Integer;
begin
i := FNCControls.FControlUpIndex;
if ((Message.HitTest = HTTOP) or (Message.HitTest = HTCAPTION)) and (i >= 0) and
(NCControls.LNCControl[i] is TNCButton) then
begin
LRect := Rect(0, 0, 0, 0);
if (NCControls <> nil) then
begin
LRect := NCControls.LNCControl[i].BoundsRect;
LRect.Left := LRect.Right - 15;
end;
P := NCControls.LastPoint;
LNCButtton := NCControls.LNCControl[i].GetAs<TNCButton>;
if (LNCButtton.Enabled) and Assigned(LNCButtton.FOnDropDownClick) and
(LNCButtton.Style in [nsSplitButton, nsSplitTrans]) and PtInRect(LRect, P) then
LNCButtton.FOnDropDownClick(LNCButtton)
else if (LNCButtton.Enabled) and Assigned(LNCButtton.FDropDownMenu) and PtInRect(LRect, P) then
begin
X := NCControls.Form.Left + LNCButtton.BoundsRect.Left;
if NCControls.Form.BiDiMode = TBiDiMode.bdRightToLeft then
Inc(X, 250);
Y := NCControls.Form.Top + LNCButtton.BoundsRect.Bottom;
// OutputDebugString(PChar(Format('Popup X %d Y %d', [X, Y])));
LNCButtton.FDropDownMenu.Popup(X, Y);
// if LNCButtton.FDropDownMenu.BiDiMode = bdLeftToRight then
// LNCButtton.FDropDownMenu.Popup(X, Y)
// else
// begin
// LPoint := Point(X, Y);
// TrackPopupMenu(LNCButtton.FDropDownMenu.Handle, TPM_RIGHTALIGN or TPM_TOPALIGN, LPoint.X, LPoint.Y, 0, PopupList.Window, nil);
// end;
end
else if (LNCButtton.Style = nsTab) and Assigned(LNCButtton.FOnClose) and PtInRect(LRect, P) then
begin
if LNCButtton.ShowHint then
LNCButtton.HideHintWindow();
if not IsIconic(TCustomFormClass(NCControls.Form).Handle) then
LNCButtton.FOnClose(LNCButtton);
end
else if (LNCButtton.Enabled) and Assigned(LNCButtton.FOnClick) then
begin
if LNCButtton.ShowHint then
LNCButtton.HideHintWindow();
if not IsIconic(TCustomFormClass(NCControls.Form).Handle) then
LNCButtton.FOnClick(LNCButtton);
end;
end;
end;
procedure TNCButton.Handle_WMNCMouseMove(var Message: TWMNCHitMessage);
var
P: TPoint;
i: Integer;
begin
P := NCControls.LastPoint;
if ((Message.HitTest = HTTOP) or (Message.HitTest = HTCAPTION) or (not NCControls.ShowSystemMenu and
(Message.HitTest = HTSYSMENU))) and NCControls.PointInNCControl(P) then
begin
if NCControls.FHotControlIndex <> NCControls.GetNCControlIndex(P) then
begin
NCControls.FHotControlIndex := NCControls.GetNCControlIndex(P);
for i := 0 to NCControls.ControlsCount - 1 do
if (NCControls.FHotControlIndex <> i) and NCControls.LNCControl[i].ShowHint and
(NCControls.LNCControl[i] is TNCButton) then
NCControls.LNCControl[i].GetAs<TNCButton>.HideHintWindow();
if not IsIconic(TCustomFormClass(NCControls.Form).Handle) then
if NCControls.LNCControl[NCControls.FHotControlIndex].ShowHint and
(NCControls.LNCControl[NCControls.FHotControlIndex] is TNCButton) then
NCControls.LNCControl[NCControls.FHotControlIndex].GetAs<TNCButton>.ShowHintWindow(Message.XCursor,
Message.YCursor);
NCControls.Invalidate();
end;
end
else
// if NCControls.FHotControlIndex <> -1 then
begin
for i := 0 to NCControls.ControlsCount - 1 do
if NCControls.LNCControl[i].ShowHint and (NCControls.LNCControl[i] is TNCButton) then
NCControls.LNCControl[i].GetAs<TNCButton>.HideHintWindow();
NCControls.FHotControlIndex := -1;
NCControls.Invalidate();
// OutputDebugString(PChar('Ping '+FormatDateTime('hh:nn:ss.zzz', Now)));
end;
end;
procedure TNCButton.DrawControl(ACanvas: TCanvas; AMouseInControl, Pressed: Boolean);
var
Details, Details2: TThemedElementDetails;
ButtonRect, DrawRect, LRect, LRectAwesome: TRect;
IW, IH, IX, IY: Integer;
SaveIndex: Integer;
X, Y, i, LImgIndex: Integer;
BCaption: String;
LStyleServices: TCustomStyleServices;
LColor, LColor1, LColor2, ThemeTextColor: TColor;
FButtonState: TThemedWindow;
function GetBorderSize: TRect;
var
Size: TSize;
Details: TThemedElementDetails;
Detail: TThemedWindow;
begin
Result := Rect(0, 0, 0, 0);
if NCControls.Form.BorderStyle = bsNone then
Exit;
if not LStyleServices.Available then
Exit;
{ caption height }
if (NCControls.Form.BorderStyle <> bsToolWindow) and (NCControls.Form.BorderStyle <> bsSizeToolWin) then
Detail := twCaptionActive
else
Detail := twSmallCaptionActive;
Details := LStyleServices.GetElementDetails(Detail);
LStyleServices.GetElementSize(0, Details, esActual, Size);
Result.Top := Size.cy;
{ left border width }
if (NCControls.Form.BorderStyle <> bsToolWindow) and (NCControls.Form.BorderStyle <> bsSizeToolWin) then
Detail := twFrameLeftActive
else
Detail := twSmallFrameLeftActive;
Details := LStyleServices.GetElementDetails(Detail);
LStyleServices.GetElementSize(0, Details, esActual, Size);
Result.Left := Size.cx;
{ right border width }
if (NCControls.Form.BorderStyle <> bsToolWindow) and (NCControls.Form.BorderStyle <> bsSizeToolWin) then
Detail := twFrameRightActive
else
Detail := twSmallFrameRightActive;
Details := LStyleServices.GetElementDetails(Detail);
LStyleServices.GetElementSize(0, Details, esActual, Size);
Result.Right := Size.cx;
{ bottom border height }
if (FNCControls.Form.BorderStyle <> bsToolWindow) and (NCControls.Form.BorderStyle <> bsSizeToolWin) then
Detail := twFrameBottomActive
else
Detail := twSmallFrameBottomActive;
Details := LStyleServices.GetElementDetails(Detail);
LStyleServices.GetElementSize(0, Details, esActual, Size);
Result.Bottom := Size.cy;
end;
function GetTopOffset: Integer;
var
P: TPoint;
begin
P.X := NCControls.Form.Left + NCControls.Form.Width div 2;
P.Y := NCControls.Form.Top + NCControls.Form.Height div 2;
Result := Screen.MonitorFromPoint(P).WorkareaRect.Top;
if NCControls.Form.Top < Result then
Result := Result - NCControls.Form.Top
else
Result := 0;
end;
procedure CorrectRightButtonRect(var AButtonRect: TRect);
var
TopOffset, RightOffset: Integer;
BS: TRect;
begin
if (NCControls.Form.WindowState = wsMaximized) and (TCustomFormClass(NCControls.Form).FormStyle <> fsMDIChild) and
(ButtonRect.Width > 0) then
begin
BS := GetBorderSize;
TopOffset := GetTopOffset;
RightOffset := -BS.Right;
if ButtonRect.Top < TopOffset then
begin
TopOffset := TopOffset - ButtonRect.Top;
OffsetRect(ButtonRect, RightOffset, TopOffset);
TopOffset := ButtonRect.Bottom - BS.Top;
if TopOffset > 0 then
OffsetRect(ButtonRect, 0, -TopOffset);
end;
end;
end;
procedure CorrectLeftButtonRect(var AButtonRect: TRect);
var
TopOffset, LeftOffset: Integer;
BS: TRect;
begin
if (NCControls.Form.WindowState = wsMaximized) and (TCustomFormClass(NCControls.Form).FormStyle <> fsMDIChild) and
(ButtonRect.Width > 0) then
begin
BS := GetBorderSize;
TopOffset := GetTopOffset;
LeftOffset := BS.Left;
if ButtonRect.Top < TopOffset then
begin
TopOffset := TopOffset - ButtonRect.Top;
OffsetRect(ButtonRect, LeftOffset, TopOffset);
TopOffset := ButtonRect.Bottom - BS.Top;
if TopOffset > 0 then
OffsetRect(ButtonRect, 0, -TopOffset);
end;
end;
end;
function GetButtonCloseRect(Index: Integer): TRect;
var
Details: TThemedElementDetails;
R, ButtonR: TRect;
begin
R := BoundsRect;
if R.Left < 0 then
Exit;
if Index = TabIndex then
InflateRect(R, 0, 2);
Result := R;
Details := LStyleServices.GetElementDetails(twSmallCloseButtonNormal);
if not LStyleServices.GetElementContentRect(0, Details, Result, ButtonR) then
ButtonR := Rect(0, 0, 0, 0);
Result.Left := Result.Right - (ButtonR.Width) - 3;
Result.Width := ButtonR.Width;
Result.Top := Result.Top + 3;
end;
begin
LStyleServices := NCControls.StyleServices;
BCaption := FCaption;
LImgIndex := FImageIndex;
if not Enabled then
begin
Details := LStyleServices.GetElementDetails(tbPushButtonDisabled);
if DisabledImageIndex <> -1 then
LImgIndex := FDisabledImageIndex;
end
else if Pressed then
begin
Details := LStyleServices.GetElementDetails(tbPushButtonPressed);
if PressedImageIndex <> -1 then
LImgIndex := FPressedImageIndex;
end
else if AMouseInControl then
begin
Details := LStyleServices.GetElementDetails(tbPushButtonHot);
if HotImageIndex <> -1 then
LImgIndex := FHotImageIndex;
end
else if Enabled then
Details := LStyleServices.GetElementDetails(tbPushButtonNormal);
DrawRect := BoundsRect; // ClientRect;
if FStyle = nsTab then
if (NCControls.Form.WindowState = wsMaximized) and (TCustomFormClass(NCControls.Form).FormStyle <> fsMDIChild) then
else
DrawRect.Height := NCControls.FormBorderSize.Top - DrawRect.Top;
if FStyle = nsAlpha then
begin
LColor := ACanvas.Pen.Color;
try
ButtonRect := DrawRect;
{$IF CompilerVersion > 23}
if not StyleServices.HasElementFixedPosition(Details) then
{$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
ACanvas.Pen.Color := clNone;
if (AMouseInControl) and (FAlphaHotColor <> clNone) then
begin
LRect := DrawRect;
InflateRect(LRect, -1, -1);
AlphaBlendFillCanvas(ACanvas.Handle, FAlphaHotColor, LRect, 96);
ACanvas.Pen.Color := FAlphaHotColor;
end
else if FAlphaColor <> clNone then
begin
LRect := DrawRect;
InflateRect(LRect, -1, -1);
AlphaBlendFillCanvas(ACanvas.Handle, FAlphaColor, LRect, 96);
ACanvas.Pen.Color := FAlphaColor;
end;
if ACanvas.Pen.Color <> clNone then
begin
LRect := DrawRect;
ACanvas.Brush.Style := bsSolid;
ACanvas.Rectangle(LRect.Left, LRect.Top, LRect.Left + LRect.Width, LRect.Top + LRect.Height);
end;
finally
ACanvas.Pen.Color := LColor;
end;
end
else if FStyle = nsGradient then
begin
LColor := ACanvas.Pen.Color;
try
ButtonRect := DrawRect;
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
if AMouseInControl then
GradientFillCanvas(ACanvas, FEndColor, FStartColor, DrawRect, FDirection)
else
GradientFillCanvas(ACanvas, FStartColor, FEndColor, DrawRect, FDirection);
if AMouseInControl then
ACanvas.Pen.Color := FEndColor
else
ACanvas.Pen.Color := FStartColor;
ACanvas.Brush.Style := bsClear;
LRect := DrawRect;
ACanvas.Rectangle(LRect.Left, LRect.Top, LRect.Left + LRect.Width, LRect.Top + LRect.Height);
finally
ACanvas.Pen.Color := LColor;
end;
end
else if FStyle = nsTab then
begin
// if AMouseInControl then
// Details := LStyleServices.GetElementDetails(ttTabItemHot)
// else
if Pressed or (NCControls.FActiveTabControlIndex = TabIndex) then
Details := LStyleServices.GetElementDetails(ttTabItemSelected)
else if not Enabled then
Details := LStyleServices.GetElementDetails(ttTabItemDisabled)
else
Details := LStyleServices.GetElementDetails(ttTabItemNormal);
ButtonRect := DrawRect;
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
LStyleServices.DrawElement(ACanvas.Handle, Details, DrawRect);
if @FOnClose <> nil then
begin
if AMouseInControl then
FButtonState := twSmallCloseButtonHot
else if Index = TabIndex then
FButtonState := twSmallCloseButtonNormal
else
FButtonState := twSmallCloseButtonDisabled;
Details2 := LStyleServices.GetElementDetails(FButtonState);
LRect := GetButtonCloseRect(Index);
if LRect.Bottom - LRect.Top > 0 then
LStyleServices.DrawElement(ACanvas.Handle, Details2, LRect);
end;
end
else if FStyle = nsEdge then
begin
ButtonRect := DrawRect;
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
LStyleServices.DrawElement(ACanvas.Handle, LStyleServices.GetElementDetails(tbGroupBoxNormal), DrawRect);
end
else if FStyle = nsFrame then
begin
ButtonRect := DrawRect;
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
LColor1 := LStyleServices.GetSystemColor(clBtnShadow);
LColor2 := LStyleServices.GetSystemColor(clBtnHighlight);
LColor := LColor1;
LColor1 := LColor2;
with DrawRect do
FrameRect(ACanvas, Rect(Left + 1, Top + 1, Left + Width - 1, Top + Height - 1), LColor1, LColor2);
LColor2 := LColor;
LColor1 := LColor;
with DrawRect do
FrameRect(ACanvas, Rect(Left + 0, Top + 0, Left + Width - 2, Top + Height - 2), LColor1, LColor2);
end
else if Enabled and (FStyle in [ { nsTranparent, } nsSplitTrans]) and AMouseInControl then
begin
ButtonRect := DrawRect;
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
Details := LStyleServices.GetElementDetails(tmMenuBarItemHot);
LStyleServices.DrawElement(ACanvas.Handle, Details, DrawRect);
end
else if (FStyle <> nsTranparent) and (FStyle <> nsSplitTrans) then
begin
ButtonRect := DrawRect;
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
LStyleServices.DrawElement(ACanvas.Handle, Details, DrawRect);
end;
if FUseFontAwesome and (LImgIndex >= 0) then
begin
IW := FDefaultFontAwesomeSize;
IH := FDefaultFontAwesomeSize;
ButtonRect := DrawRect;
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
if FStyle = nsSplitButton then
IX := DrawRect.Left + ((DrawRect.Width - 15) - IW) div 2
else
IX := DrawRect.Left + (DrawRect.Width - IW) div 2;
IY := DrawRect.Top + (DrawRect.Height - IH) div 2;
case FImageAlignment of
iaLeft:
begin
IX := DrawRect.Left + 2;
Inc(IX, ImageMargins.Left);
Inc(IY, ImageMargins.Top);
Dec(IY, ImageMargins.Bottom);
Inc(DrawRect.Left, { IX + } IW + ImageMargins.Right);
end;
iaRight:
begin
IX := DrawRect.Right - IW - 2;
Dec(IX, ImageMargins.Right);
Dec(IX, ImageMargins.Left);
Inc(IY, ImageMargins.Top);
Dec(IY, ImageMargins.Bottom);
DrawRect.Right := IX;
end;
iaTop:
begin
IX := { DrawRect.Left + } ( { DrawRect.Width - } IW) div 2;
Inc(IX, ImageMargins.Left);
Dec(IX, ImageMargins.Right);
IY := DrawRect.Top + 2;
Inc(IY, ImageMargins.Top);
Inc(DrawRect.Top, IY + IH + ImageMargins.Bottom);
end;
iaBottom:
begin
IX := { DrawRect.Left + } ( { DrawRect.Width - } IW) div 2;
Inc(IX, ImageMargins.Left);
Dec(IX, ImageMargins.Right);
IY := DrawRect.Bottom - IH - 2;
Dec(IY, ImageMargins.Bottom);
Dec(IY, ImageMargins.Top);
DrawRect.Bottom := IY;
end;
end;
// if AMouseInControl then
// Dec(IY);
LRectAwesome := Rect(IX, IY, IX + IW + 2, IY + IH + 2);
end
else if (LImgIndex >= 0) and (NCControls.FImages <> nil) and (NCControls.FImages.Handle <> 0) and
ImageList_GetIconSize(NCControls.FImages.Handle, IW, IH) then
begin
ButtonRect := DrawRect;
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
IX := DrawRect.Left + (DrawRect.Width - IW) div 2;
IY := DrawRect.Top + (DrawRect.Height - IH) div 2;
case FImageAlignment of
iaLeft:
begin
IX := DrawRect.Left + 2;
Inc(IX, ImageMargins.Left);
Inc(IY, ImageMargins.Top);
Dec(IY, ImageMargins.Bottom);
Inc(DrawRect.Left, { IX + } IW + ImageMargins.Right);
end;
iaRight:
begin
IX := DrawRect.Right - IW - 2;
Dec(IX, ImageMargins.Right);
Dec(IX, ImageMargins.Left);
Inc(IY, ImageMargins.Top);
Dec(IY, ImageMargins.Bottom);
DrawRect.Right := IX;
end;
iaTop:
begin
IX := { DrawRect.Left + } ( { DrawRect.Width - } IW) div 2;
Inc(IX, ImageMargins.Left);
Dec(IX, ImageMargins.Right);
IY := DrawRect.Top + 2;
Inc(IY, ImageMargins.Top);
Inc(DrawRect.Top, IY + IH + ImageMargins.Bottom);
end;
iaBottom:
begin
IX := { DrawRect.Left + } ( { DrawRect.Width - } IW) div 2;
Inc(IX, ImageMargins.Left);
Dec(IX, ImageMargins.Right);
IY := DrawRect.Bottom - IH - 2;
Dec(IY, ImageMargins.Bottom);
Dec(IY, ImageMargins.Top);
DrawRect.Bottom := IY;
end;
end;
// if AMouseInControl then
// Dec(IY);
if Enabled and ((FImageStyle = isNormal) or ((FImageStyle = isGrayHot) and AMouseInControl)) then
ImageList_Draw(NCControls.FImages.Handle, LImgIndex, ACanvas.Handle, IX, IY, ILD_NORMAL)
else
DoDrawGrayImage(ACanvas.Handle, NCControls.FImages.Handle, LImgIndex, IX, IY);
end;
if (FStyle in [nsSplitButton, nsSplitTrans]) then
begin
LRect := DrawRect;
Dec(DrawRect.Right, 15);
if AMouseInControl then
ThemeTextColor := FHotFontColor
else
ThemeTextColor := FFontColor;
if Length(BCaption) > 0 then
begin
ButtonRect := DrawRect;
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
DrawControlText(ACanvas, Details, BCaption, DrawRect, DT_VCENTER or DT_CENTER, ThemeTextColor);
end;
if FUseFontAwesome and (FImageIndex >= 0) then
begin
if AMouseInControl then
ThemeTextColor := FAwesomeHotFontColor
else
ThemeTextColor := FAwesomeFontColor;
FontAwesome.DrawChar(ACanvas.Handle, LImgIndex, LRectAwesome, FDefaultFontAwesomeSize, ThemeTextColor, 0,
FImageAlignment);
end;
if FDropDown then
begin
Details := LStyleServices.GetElementDetails(tbPushButtonPressed);
SaveIndex := SaveDC(ACanvas.Handle);
try
IntersectClipRect(ACanvas.Handle, Width - 15, 0, Width, Height);
DrawRect := Rect(Width - 30, 0, Width, Height);
ButtonRect := DrawRect;
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectLeftButtonRect(ButtonRect);
DrawRect := ButtonRect;
LStyleServices.DrawElement(ACanvas.Handle, Details, DrawRect);
finally
RestoreDC(ACanvas.Handle, SaveIndex);
end;
end;
with ACanvas do
begin
LColor := Pen.Color;
// draw split line
if FStyle <> nsSplitTrans then
begin
Pen.Color := LStyleServices.GetSystemColor(clBtnShadow);
MoveTo(LRect.Right - 15, LRect.Top + 3);
LineTo(LRect.Right - 15, LRect.Bottom - 3);
if Enabled then
Pen.Color := LStyleServices.GetSystemColor(clBtnHighlight)
else
Pen.Color := Font.Color;
MoveTo(LRect.Right - 14, LRect.Top + 3);
LineTo(LRect.Right - 14, LRect.Bottom - 3);
end;
// draw arrow
if (FStyle = nsSplitTrans) and (not AMouseInControl) then
Pen.Color := FFontColor
else
Pen.Color := FHotFontColor;
X := LRect.Right - 8;
Y := LRect.Top + (Height div 2) + 1;
for i := 3 downto 0 do
begin
MoveTo(X - i, Y - i);
LineTo(X + i + 1, Y - i);
end;
Pen.Color := LColor;
end;
end
else
begin
if AMouseInControl then
ThemeTextColor := FHotFontColor
else
ThemeTextColor := FFontColor;
// ButtonRect := DrawRect;
// if not StyleServices.HasElementFixedPosition(Details) then
// CorrectLeftButtonRect(ButtonRect);
// DrawRect := ButtonRect;
if (FCaptionAligmentFlags and DT_CENTER) <> DT_CENTER then
DrawRect.Left := DrawRect.Left + 5;
DrawControlText(ACanvas, Details, BCaption, DrawRect, FCaptionAligmentFlags, ThemeTextColor);
if FUseFontAwesome and (FImageIndex >= 0) then
begin
if AMouseInControl then
ThemeTextColor := FAwesomeHotFontColor
else
ThemeTextColor := FAwesomeFontColor;
// InflateRect(LRectAwesome, 2, 2);
FontAwesome.DrawChar(ACanvas.Handle, LImgIndex, LRectAwesome, FDefaultFontAwesomeSize, ThemeTextColor, 0,
FImageAlignment);
end;
end;
end;
procedure TNCButton.SetDisabledImageIndex(const Value: TImageIndex);
begin
FDisabledImageIndex := Value;
end;
procedure TNCButton.SetDropDownMenu(const Value: TPopupMenu);
begin
FDropDownMenu := Value;
end;
procedure TNCButton.SetHotImageIndex(const Value: TImageIndex);
begin
FHotImageIndex := Value;
end;
procedure TNCButton.SetImageAlignment(const Value: TImageAlignment);
begin
FImageAlignment := Value;
end;
procedure TNCButton.SetImageIndex(const Value: TImageIndex);
begin
FImageIndex := Value;
end;
procedure TNCButton.SetImageMargins(const Value: TImageMargins);
begin
FImageMargins := Value;
end;
procedure TNCButton.SetImageStyle(const Value: TNCImageStyle);
begin
FImageStyle := Value;
end;
procedure TNCButton.SetPressedImageIndex(const Value: TImageIndex);
begin
FPressedImageIndex := Value;
end;
procedure TNCButton.SetStyle(const Value: TNCButtonStyle);
begin
FStyle := Value;
end;
procedure TNCButton.SetUseFontAwesome(const Value: Boolean);
begin
FUseFontAwesome := Value;
end;
procedure TNCButton.ShowHintWindow(X, Y: Integer);
begin
if (THintWindowClass(FHintWindow).WindowHandle = 0) then
begin
FHintWindow.Visible := False;
FHintWindow.Color := NCControls.StyleServices.GetSystemColor(clInfoBk);
FHintWindow.Font.Color := NCControls.StyleServices.GetSystemColor(clInfoText);
FHintWindow.Caption := Hint;
FHintWindow.ParentWindow := Application.Handle;
FHintWindow.Left := NCControls.FForm.Left + BoundsRect.Left;
FHintWindow.Top := NCControls.FForm.Top + BoundsRect.Bottom + 5;
FHintWindow.Show;
end;
end;
procedure TNCButton.HideHintWindow;
begin
if THintWindowClass(FHintWindow).WindowHandle <> 0 then
FHintWindow.ReleaseHandle;
end;
{ TFormStyleNCControls }
constructor TFormStyleNCControls.Create(AControl: TWinControl);
begin
inherited;
FNCControls := nil;
end;
destructor TFormStyleNCControls.Destroy;
begin
inherited;
end;
function TFormStyleNCControls.GetNCControls: TNCControls;
var
i: Integer;
begin
Result := FNCControls;
if Result = nil then
for i := 0 to Form.ComponentCount - 1 do
if Form.Components[i] is TNCControls then
begin
FNCControls := TNCControls(Form.Components[i]);
Exit(FNCControls);
end;
end;
procedure TFormStyleNCControls.Maximize;
begin
if Handle <> 0 then
begin
FNCControls.FPressedControlIndex := -1;
FNCControls.FHotControlIndex := -1;
end;
inherited;
end;
procedure TFormStyleNCControls.Minimize;
begin
if Handle <> 0 then
begin
FNCControls.FPressedControlIndex := -1;
FNCControls.FHotControlIndex := -1;
end;
inherited;
end;
procedure TFormStyleNCControls.MouseEnter;
begin
inherited;
FNCControls.FPressedControlIndex := -1;
end;
procedure TFormStyleNCControls.MouseLeave;
begin
inherited;
if FNCControls.FHotControlIndex <> -1 then
begin
FNCControls.FHotControlIndex := -1;
FNCControls.FPressedControlIndex := -1;
if Form.BorderStyle <> bsNone then
InvalidateNC;
end;
end;
procedure TFormStyleNCControls.Restore;
begin
FNCControls.FPressedControlIndex := -1;
FNCControls.FHotControlIndex := -1;
inherited;
end;
procedure TFormStyleNCControls.PaintNCControls(Canvas: TCanvas; ARect: TRect);
var
LCurrent: Integer;
LNCControl: TNCControl;
begin
if (NCControls <> nil) and (NCControls.ControlsCount > 0) and (NCControls.Visible)
{ and (NCControls.Form.Visible) } and (NCControls.FControls.UpdateCount = 0) then
for LCurrent := 0 to NCControls.ControlsCount - 1 do
begin
LNCControl := NCControls.Controls[LCurrent];
if LNCControl.Visible and (LNCControl.BoundsRect.Right <= ARect.Right) then
LNCControl.DrawControl(Canvas, FNCControls.FHotControlIndex = LCurrent,
FNCControls.FPressedControlIndex = LCurrent);
end
else;
end;
procedure TFormStyleNCControls.WMNCHitTest(var Message: TWMNCHitTest);
var
P: TPoint;
LHitTest: Integer;
begin
if (NCControls <> nil) and (NCControls.Visible) then
begin
{$IF CompilerVersion>23}
if (TStyleManager.FormBorderStyle = fbsCurrentStyle) and (seBorder in Form.StyleElements) then
{$IFEND}
begin
P := _NormalizePoint(Point(Message.XPos, Message.YPos));
LHitTest := _GetHitTest(P);
if (LHitTest <> HTSYSMENU) or ((LHitTest = HTSYSMENU) and NCControls.ShowSystemMenu) then
begin
Message.Result := LHitTest;
Handled := True;
end
else
begin
Message.Result := WM_NULL;
Handled := True;
end;
end;
end
else
inherited;
end;
// Avoid maximize or restore on DblClk
procedure TFormStyleNCControls.WMNCLButtonDblClk(var Message: TWMNCHitMessage);
var
P: TPoint;
begin
if (NCControls <> nil) and (NCControls.Visible) then
begin
P := _NormalizePoint(Point(Message.XCursor, Message.YCursor));
if ((Message.HitTest = HTTOP) or (Message.HitTest = HTCAPTION)) and NCControls.PointInNCControl(P) then
begin
Message.Result := 0;
Message.Msg := WM_NULL;
Handled := True;
Exit;
end;
end;
inherited;
end;
procedure TFormStyleNCControls.WMNCLButtonDown(var Message: TWMNCHitMessage);
var
P: TPoint;
begin
inherited;
{$IF CompilerVersion>23}
if not((TStyleManager.FormBorderStyle = fbsCurrentStyle) and (seBorder in Form.StyleElements)) then
begin
Handled := False;
Exit;
end;
{$IFEND}
if (NCControls <> nil) and (NCControls.Visible) then
begin
P := _NormalizePoint(Point(Message.XCursor, Message.YCursor));
if ((Message.HitTest = HTTOP) or (Message.HitTest = HTCAPTION)) and FNCControls.PointInNCControl(P) then
begin
FNCControls.FPressedControlIndex := FNCControls.GetNCControlIndex(P);
if (FNCControls.FPressedControlIndex >= 0) then
FNCControls[FNCControls.FPressedControlIndex].Handle_WMNCLButtonDown(Message);
InvalidateNC;
Message.Result := 0;
Message.Msg := WM_NULL;
Handled := True;
end;
end;
end;
procedure TFormStyleNCControls.WMNCLButtonUp(var Message: TWMNCHitMessage);
var
OldIndex: Integer;
P: TPoint;
LNCControl: TNCControl;
begin
inherited;
if (NCControls <> nil) and (NCControls.Visible) then
begin
{$IF CompilerVersion>23}
if not((TStyleManager.FormBorderStyle = fbsCurrentStyle) and (seBorder in Form.StyleElements)) then
begin
Handled := False;
Exit;
end;
{$IFEND}
OldIndex := FNCControls.FPressedControlIndex;
if FNCControls.FPressedControlIndex <> -1 then
begin
FNCControls.FPressedControlIndex := -1;
InvalidateNC;
end;
if OldIndex = FNCControls.FHotControlIndex then
begin
P := _NormalizePoint(Point(Message.XCursor, Message.YCursor));
NCControls.FLastPoint := P;
NCControls.FControlUpIndex := NCControls.GetNCControlIndex(P);
if NCControls.FControlUpIndex > -1 then
begin
LNCControl := NCControls.Controls[NCControls.FControlUpIndex];
LNCControl.Handle_WMNCLButtonUp(Message);
end;
end;
Message.Result := 0;
Message.Msg := WM_NULL;
Handled := True;
end;
end;
procedure TFormStyleNCControls.WMNCMouseMove(var Message: TWMNCHitMessage);
var
i: Integer;
LNCControl: TNCControl;
begin
inherited;
if (NCControls <> nil) and (NCControls.Visible) then
begin
NCControls.FLastPoint := _NormalizePoint(Point(Message.XCursor, Message.YCursor));
// OutputDebugString(PChar(Format('Message.HitTest %d XCursor %d YCursor %d P.X %d P.Y %d',[Message.HitTest, Message.XCursor, Message.YCursor, P.X, P.Y])));
{$IF CompilerVersion>23}
if not((TStyleManager.FormBorderStyle = fbsCurrentStyle) and (seBorder in Form.StyleElements)) then
begin
Handled := False;
Exit;
end;
{$IFEND}
i := NCControls.GetNCControlIndex(NCControls.LastPoint);
if (i >= 0) then
begin
LNCControl := NCControls[i];
LNCControl.Handle_WMNCMouseMove(Message);
end
else
// notify to the controls the mouse leave.
if NCControls.ControlsCount > 0 then
begin
LNCControl := NCControls[0];
LNCControl.Handle_WMNCMouseMove(Message);
end;
end;
end;
procedure TFormStyleNCControls.PaintNC(Canvas: TCanvas);
var
Details, CaptionDetails, IconDetails: TThemedElementDetails;
Detail: TThemedWindow;
R, R1, R2, DrawRect, ButtonRect, TextRect: TRect;
CaptionBuffer: TBitmap;
FButtonState: TThemedWindow;
TextFormat: TTextFormat;
LText: string;
LStyleServices: TCustomStyleServices;
TextTopOffset: Integer;
function GetTopOffset: Integer;
var
P: TPoint;
begin
P.X := Form.Left + Form.Width div 2;
P.Y := Form.Top + Form.Height div 2;
Result := Screen.MonitorFromPoint(P).WorkareaRect.Top;
if Form.Top < Result then
Result := Result - Form.Top
else
Result := 0;
end;
procedure CorrectRightButtonRect(var AButtonRect: TRect);
var
TopOffset, RightOffset: Integer;
BS: TRect;
begin
if (Form.WindowState = wsMaximized) and (TCustomFormClass(Form).FormStyle <> fsMDIChild) and (ButtonRect.Width > 0)
then
begin
BS := _GetBorderSize;
TopOffset := GetTopOffset;
RightOffset := -BS.Right;
if ButtonRect.Top < TopOffset then
begin
TopOffset := TopOffset - ButtonRect.Top;
OffsetRect(ButtonRect, RightOffset, TopOffset);
TopOffset := ButtonRect.Bottom - BS.Top;
if TopOffset > 0 then
OffsetRect(ButtonRect, 0, -TopOffset);
end;
end;
end;
procedure CorrectLeftButtonRect(var AButtonRect: TRect);
var
TopOffset, LeftOffset: Integer;
BS: TRect;
begin
if (Form.WindowState = wsMaximized) and (TCustomFormClass(Form).FormStyle <> fsMDIChild) and (ButtonRect.Width > 0)
then
begin
BS := _GetBorderSize;
TopOffset := GetTopOffset;
LeftOffset := BS.Left;
if ButtonRect.Top < TopOffset then
begin
TopOffset := TopOffset - ButtonRect.Top;
OffsetRect(ButtonRect, LeftOffset, TopOffset);
TopOffset := ButtonRect.Bottom - BS.Top;
if TopOffset > 0 then
OffsetRect(ButtonRect, 0, -TopOffset);
end;
end;
end;
begin
if Form.BorderStyle = bsNone then
begin
MainMenuBarHookPaint(Canvas);
Exit;
end;
if NCControls <> nil then
LStyleServices := NCControls.StyleServices
else
LStyleServices := StyleServices;
_FCloseButtonRect := Rect(0, 0, 0, 0);
_FMaxButtonRect := Rect(0, 0, 0, 0);
_FMinButtonRect := Rect(0, 0, 0, 0);
_FHelpButtonRect := Rect(0, 0, 0, 0);
_FSysMenuButtonRect := Rect(0, 0, 0, 0);
_FCaptionRect := Rect(0, 0, 0, 0);
if not LStyleServices.Available then
Exit;
R := _GetBorderSize;
if (NCControls <> nil) then
NCControls.FormBorderSize := R;
if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then
begin
if _FFormActive then
Detail := twCaptionActive
else
Detail := twCaptionInActive
end
else
begin
if _FFormActive then
Detail := twSmallCaptionActive
else
Detail := twSmallCaptionInActive
end;
CaptionBuffer := TBitmap.Create;
try
CaptionBuffer.SetSize(_FWidth, R.Top);
// caption
DrawRect := Rect(0, 0, CaptionBuffer.Width, CaptionBuffer.Height);
Details := LStyleServices.GetElementDetails(Detail);
LStyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, DrawRect);
TextRect := DrawRect;
CaptionDetails := Details;
TextTopOffset := 3;
// icon
if ((NCControls <> nil) and NCControls.ShowSystemMenu) and (biSystemMenu in TCustomFormClass(Form).BorderIcons) and
(Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then
begin
IconDetails := LStyleServices.GetElementDetails(twSysButtonNormal);
if not LStyleServices.GetElementContentRect(0, IconDetails, DrawRect, ButtonRect) then
ButtonRect := Rect(0, 0, 0, 0);
R1 := ButtonRect;
{$IF CompilerVersion > 23}
if not StyleServices.HasElementFixedPosition(Details) then
begin
{$IFEND}
CorrectLeftButtonRect(ButtonRect);
TextTopOffset := Abs(R1.Top - ButtonRect.Top);
if TextTopOffset > R.Top then
TextTopOffset := 3;
{$IF CompilerVersion > 23}
end
else
TextTopOffset := 0;
{$IFEND}
R1 := Rect(0, 0, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
RectVCenter(R1, ButtonRect);
if ButtonRect.Width > 0 then
DrawIconEx(CaptionBuffer.Canvas.Handle, R1.Left, R1.Top, _GetIconFast.Handle, 0, 0, 0, 0, DI_NORMAL);
Inc(TextRect.Left, ButtonRect.Width + 5);
_FSysMenuButtonRect := ButtonRect;
end
else
Inc(TextRect.Left, R.Left);
// buttons
if (biSystemMenu in TCustomFormClass(Form).BorderIcons) then
begin
if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then
begin
if (_FPressedButton = HTCLOSE) and (_FHotButton = HTCLOSE) then
FButtonState := twCloseButtonPushed
else if _FHotButton = HTCLOSE then
FButtonState := twCloseButtonHot
else if _FFormActive then
FButtonState := twCloseButtonNormal
else
FButtonState := twCloseButtonDisabled;
end
else
begin
if (_FPressedButton = HTCLOSE) and (_FHotButton = HTCLOSE) then
FButtonState := twSmallCloseButtonPushed
else if _FHotButton = HTCLOSE then
FButtonState := twSmallCloseButtonHot
else if _FFormActive then
FButtonState := twSmallCloseButtonNormal
else
FButtonState := twSmallCloseButtonDisabled;
end;
Details := LStyleServices.GetElementDetails(FButtonState);
if not LStyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) then
ButtonRect := Rect(0, 0, 0, 0);
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectRightButtonRect(ButtonRect);
LStyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, ButtonRect);
if ButtonRect.Left > 0 then
TextRect.Right := ButtonRect.Left;
_FCloseButtonRect := ButtonRect;
end;
if (biMaximize in TCustomFormClass(Form).BorderIcons) and (biSystemMenu in TCustomFormClass(Form).BorderIcons) and
(Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then
begin
if Form.WindowState = wsMaximized then
begin
if (_FPressedButton = HTMAXBUTTON) and (_FHotButton = HTMAXBUTTON) then
FButtonState := twRestoreButtonPushed
else if _FHotButton = HTMAXBUTTON then
FButtonState := twRestoreButtonHot
else if _FFormActive then
FButtonState := twRestoreButtonNormal
else
FButtonState := twRestoreButtonDisabled;
end
else
begin
if (_FPressedButton = HTMAXBUTTON) and (_FHotButton = HTMAXBUTTON) then
FButtonState := twMaxButtonPushed
else if _FHotButton = HTMAXBUTTON then
FButtonState := twMaxButtonHot
else if _FFormActive then
FButtonState := twMaxButtonNormal
else
FButtonState := twMaxButtonDisabled;
end;
Details := LStyleServices.GetElementDetails(FButtonState);
if not LStyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) then
ButtonRect := Rect(0, 0, 0, 0);
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectRightButtonRect(ButtonRect);
if ButtonRect.Width > 0 then
LStyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, ButtonRect);
if ButtonRect.Left > 0 then
TextRect.Right := ButtonRect.Left;
_FMaxButtonRect := ButtonRect;
end;
if (biMinimize in TCustomFormClass(Form).BorderIcons) and (biSystemMenu in TCustomFormClass(Form).BorderIcons) and
(Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then
begin
if (_FPressedButton = HTMINBUTTON) and (_FHotButton = HTMINBUTTON) then
FButtonState := twMinButtonPushed
else if _FHotButton = HTMINBUTTON then
FButtonState := twMinButtonHot
else if _FFormActive then
FButtonState := twMinButtonNormal
else
FButtonState := twMinButtonDisabled;
Details := LStyleServices.GetElementDetails(FButtonState);
if not LStyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) then
ButtonRect := Rect(0, 0, 0, 0);
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectRightButtonRect(ButtonRect);
if ButtonRect.Width > 0 then
LStyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, ButtonRect);
if ButtonRect.Left > 0 then
TextRect.Right := ButtonRect.Left;
_FMinButtonRect := ButtonRect;
end;
if (biHelp in TCustomFormClass(Form).BorderIcons) and (biSystemMenu in TCustomFormClass(Form).BorderIcons) and
((not(biMaximize in TCustomFormClass(Form).BorderIcons) and not(biMinimize in TCustomFormClass(Form).BorderIcons))
or (Form.BorderStyle = bsDialog)) then
begin
if (_FPressedButton = HTHELP) and (_FHotButton = HTHELP) then
FButtonState := twHelpButtonPushed
else if _FHotButton = HTHELP then
FButtonState := twHelpButtonHot
else if _FFormActive then
FButtonState := twHelpButtonNormal
else
FButtonState := twHelpButtonDisabled;
Details := LStyleServices.GetElementDetails(FButtonState);
if not LStyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) then
ButtonRect := Rect(0, 0, 0, 0);
{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND}
CorrectRightButtonRect(ButtonRect);
if ButtonRect.Width > 0 then
LStyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, ButtonRect);
if ButtonRect.Left > 0 then
TextRect.Right := ButtonRect.Left;
_FHelpButtonRect := ButtonRect;
end;
R2 := TextRect;
if (NCControls <> nil) and (NCControls.ControlsCount > 0) and (NCControls.Visible) then
Inc(TextRect.Left, NCControls.Controls[NCControls.ControlsCount - 1].BoundsRect.Right - NCControls.Controls[0]
.BoundsRect.Left + 10);
// text
if (NCControls <> nil) and (IsIconic(TCustomFormClass(Form).Handle) or (NCControls.ShowCaption)) then
begin
TextFormat := [tfLeft, tfSingleLine, tfVerticalCenter];
if Control.UseRightToLeftReading then
Include(TextFormat, tfRtlReading);
LText := Text;
if (TCustomFormClass(Form).WindowState = wsMaximized) and (TCustomFormClass(Form).FormStyle <> fsMDIChild) and
(TextTopOffset <> 0) and (biSystemMenu in TCustomFormClass(Form).BorderIcons) then
begin
Inc(TextRect.Left, R.Left);
MoveWindowOrg(CaptionBuffer.Canvas.Handle, 0, TextTopOffset);
LStyleServices.DrawText(CaptionBuffer.Canvas.Handle, CaptionDetails, LText, TextRect, TextFormat);
MoveWindowOrg(CaptionBuffer.Canvas.Handle, 0, -TextTopOffset);
end
else
LStyleServices.DrawText(CaptionBuffer.Canvas.Handle, CaptionDetails, LText, TextRect, TextFormat);
end;
if (NCControls <> nil) and (NCControls.ControlsCount > 0) and (NCControls.Visible) then
Dec(TextRect.Left, NCControls.Controls[NCControls.ControlsCount - 1].BoundsRect.Right - NCControls.Controls[0]
.BoundsRect.Left + 10);
_FCaptionRect := TextRect;
if not IsIconic(TCustomFormClass(Form).Handle) then
PaintNCControls(CaptionBuffer.Canvas, R2);
// caption
Canvas.Draw(0, 0, CaptionBuffer);
finally
CaptionBuffer.Free;
end;
// menubar
MainMenuBarHookPaint(Canvas);
// left
if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then
begin
if _FFormActive then
Detail := twFrameLeftActive
else
Detail := twFrameLeftInActive
end
else
begin
if _FFormActive then
Detail := twSmallFrameLeftActive
else
Detail := twSmallFrameLeftInActive
end;
DrawRect := Rect(0, R.Top, R.Left, _FHeight - R.Bottom);
Details := LStyleServices.GetElementDetails(Detail);
if DrawRect.Bottom - DrawRect.Top > 0 then
LStyleServices.DrawElement(Canvas.Handle, Details, DrawRect);
// right
if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then
begin
if _FFormActive then
Detail := twFrameRightActive
else
Detail := twFrameRightInActive
end
else
begin
if _FFormActive then
Detail := twSmallFrameRightActive
else
Detail := twSmallFrameRightInActive
end;
DrawRect := Rect(_FWidth - R.Right, R.Top, _FWidth, _FHeight - R.Bottom);
Details := LStyleServices.GetElementDetails(Detail);
if DrawRect.Bottom - DrawRect.Top > 0 then
LStyleServices.DrawElement(Canvas.Handle, Details, DrawRect);
// Bottom
if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then
begin
if _FFormActive then
Detail := twFrameBottomActive
else
Detail := twFrameBottomInActive
end
else
begin
if _FFormActive then
Detail := twSmallFrameBottomActive
else
Detail := twSmallFrameBottomInActive
end;
DrawRect := Rect(0, _FHeight - R.Bottom, _FWidth, _FHeight);
Details := LStyleServices.GetElementDetails(Detail);
if DrawRect.Bottom - DrawRect.Top > 0 then
LStyleServices.DrawElement(Canvas.Handle, Details, DrawRect);
end;
// This custom GetBorderSize method is necessary to allow to the NC controls use a custom Style in the title and border area.
function Detour_TFormStyleHook_GetBorderSize(Self: TFormStyleHook): TRect;
var
Size: TSize;
Details: TThemedElementDetails;
Detail: TThemedWindow;
LStylesServices: TCustomStyleServices;
LForm: TCustomForm;
begin
if not(ExecutingInMainThread) then
Exit(Trampoline_TFormStyleHook_GetBorderSize(Self));
if (Self is TFormStyleNCControls) and (TFormStyleNCControls(Self).NCControls <> nil) then
begin
LStylesServices := TFormStyleNCControls(Self).NCControls.StyleServices;
LForm := TFormStyleHookClass(Self)._Form;
Result := Rect(0, 0, 0, 0);
if LForm.BorderStyle = bsNone then
Exit;
if not LStylesServices.Available then
Exit;
{ caption height }
if (LForm.BorderStyle <> bsToolWindow) and (LForm.BorderStyle <> bsSizeToolWin) then
Detail := twCaptionActive
else
Detail := twSmallCaptionActive;
Details := LStylesServices.GetElementDetails(Detail);
LStylesServices.GetElementSize(0, Details, esActual, Size);
Result.Top := Size.cy;
{ left border width }
if (LForm.BorderStyle <> bsToolWindow) and (LForm.BorderStyle <> bsSizeToolWin) then
Detail := twFrameLeftActive
else
Detail := twSmallFrameLeftActive;
Details := LStylesServices.GetElementDetails(Detail);
LStylesServices.GetElementSize(0, Details, esActual, Size);
Result.Left := Size.cx;
{ right border width }
if (LForm.BorderStyle <> bsToolWindow) and (LForm.BorderStyle <> bsSizeToolWin) then
Detail := twFrameRightActive
else
Detail := twSmallFrameRightActive;
Details := LStylesServices.GetElementDetails(Detail);
LStylesServices.GetElementSize(0, Details, esActual, Size);
Result.Right := Size.cx;
{ bottom border height }
if (LForm.BorderStyle <> bsToolWindow) and (LForm.BorderStyle <> bsSizeToolWin) then
Detail := twFrameBottomActive
else
Detail := twSmallFrameBottomActive;
Details := LStylesServices.GetElementDetails(Detail);
LStylesServices.GetElementSize(0, Details, esActual, Size);
Result.Bottom := Size.cy;
// //Result.Top := Result.Top + 5;
// Result.Left := 0;
// Result.Right := 0;
// Result.Bottom := 0;
if TFormStyleNCSettings.UseThinBorder then
begin
// Don't use 0, because the native resize feature is lost if the border is 0.
Result.Left := 1;
Result.Right := 1;
Result.Bottom := 1;
end;
end
else
Exit(Trampoline_TFormStyleHook_GetBorderSize(Self));
end;
// This custom GetRegion method is necessary to allow to the NC controls use a custom Style in the title and border area.
function Detour_TFormStyleHook_GetRegion(Self: TFormStyleHook): HRgn;
var
R: TRect;
Details: TThemedElementDetails;
Detail: TThemedWindow;
LStylesServices: TCustomStyleServices;
LForm: TCustomForm;
begin
if not(ExecutingInMainThread) then
Exit(Trampoline_TFormStyleHook_GetRegion(Self));
if (Self is TFormStyleNCControls) and (TFormStyleNCControls(Self).NCControls <> nil) then
begin
LStylesServices := TFormStyleNCControls(Self).NCControls.StyleServices;
LForm := TFormStyleHookClass(Self)._Form;
Result := 0;
if not LStylesServices.Available then
Exit;
R := Rect(0, 0, TFormStyleHookClass(Self)._FWidth, TFormStyleHookClass(Self)._FHeight);
if (LForm.BorderStyle <> bsToolWindow) and (LForm.BorderStyle <> bsSizeToolWin) then
Detail := twCaptionActive
else
Detail := twSmallCaptionActive;
Details := LStylesServices.GetElementDetails(Detail);
LStylesServices.GetElementRegion(Details, R, Result);
end
else
Exit(Trampoline_TFormStyleHook_GetRegion(Self));
end;
{ TListNCButtons }
function TListNCControls.Add: TNCControl;
begin
Result := TNCControl(inherited Add);
end;
function RttiMethodInvokeEx(const MethodName: string; RttiType: TRttiType; Instance: TValue;
const Args: array of TValue): TValue;
var
Found: Boolean;
LMethod: TRttiMethod;
LIndex: Integer;
LParams: TArray<TRttiParameter>;
begin
Result := nil;
LMethod := nil;
Found := False;
for LMethod in RttiType.GetMethods do
if SameText(LMethod.Name, MethodName) then
begin
LParams := LMethod.GetParameters;
if Length(Args) = Length(LParams) then
begin
Found := True;
for LIndex := 0 to Length(LParams) - 1 do
if LParams[LIndex].ParamType.Handle <> Args[LIndex].TypeInfo then
begin
Found := False;
Break;
end;
end;
if Found then
Break;
end;
if (LMethod <> nil) and Found then
Result := LMethod.Invoke(Instance, Args)
else
raise Exception.CreateFmt('method %s not found', [MethodName]);
end;
function TListNCControls.AddEx<T>: T;
var
LRttiContext: TRttiContext;
LRttiType: TRttiType;
LRttiInstanceType: TRttiInstanceType;
LValue: TValue;
begin
LRttiContext := TRttiContext.Create;
LRttiType := LRttiContext.GetType(TypeInfo(T));
if (LRttiType <> nil) then
begin
LRttiInstanceType := LRttiType.AsInstance;
LValue := LRttiInstanceType.GetMethod('Create').Invoke(LRttiInstanceType.MetaclassType, [Self]);
// LValue := RttiMethodInvokeEx('Create', LRttiInstanceType, LRttiInstanceType.MetaclassType, [Self]);
end;
Result := LValue.AsType<T>;
end;
constructor TListNCControls.Create(AOwner: TPersistent);
begin
FOwner := TNCControls(AOwner);
inherited Create(TNCControl);
end;
destructor TListNCControls.Destroy;
begin
inherited;
end;
function TListNCControls.GetItem(Index: Integer): TNCControl;
begin
Result := TNCControl(inherited GetItem(Index));
end;
function TListNCControls.GetOwner: TPersistent;
begin
Result := FOwner;
end;
function TListNCControls.Insert(Index: Integer): TNCControl;
begin
Result := TNCControl(inherited Insert(Index));
end;
procedure TListNCControls.SetItem(Index: Integer; Value: TNCControl);
begin
inherited SetItem(Index, Value);
end;
{ TNCControl }
constructor TNCControl.Create(Collection: TCollection);
begin
inherited Create(Collection);
FNCControls := TNCControls(Collection.Owner);
FEnabled := True;
FVisible := True;
FFont := TFont.Create;
FWidth := 80;
FTop := 5;
FCaptionAligmentFlags := DT_VCENTER or DT_CENTER or DT_WORDBREAK;
end;
destructor TNCControl.Destroy;
begin
FFont.Free;
inherited;
end;
function TNCControl.GetAs<T>: T;
var
LValue: TValue;
begin
LValue := TValue.From(Self);
Result := LValue.AsType<T>;
end;
function TNCControl.GetBoundsRect: TRect;
begin
Result.Left := Left;
Result.Top := Top;
Result.Right := Left + Width;
Result.Bottom := Top + Height;
end;
function TNCControl.GetEnabled: Boolean;
begin
Result := FEnabled;
end;
procedure TNCControl.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
FLeft := ALeft;
FTop := ATop;
FWidth := AWidth;
FHeight := AHeight;
end;
procedure TNCControl.SetBoundsRect(const Value: TRect);
begin
with Value do
SetBounds(Left, Top, Right - Left, Bottom - Top);
end;
procedure TNCControl.SetEnabled(const Value: Boolean);
begin
if Value <> FEnabled then
FEnabled := Value;
end;
procedure TNCControl.SetFont(const Value: TFont);
begin
FFont := Value;
end;
procedure TNCControl.SetHeight(const Value: Integer);
begin
FHeight := Value;
end;
procedure TNCControl.SetLeft(const Value: Integer);
begin
FLeft := Value;
end;
procedure TNCControl.SetName(const Value: TComponentName);
begin
FName := Value;
end;
procedure TNCControl.SetShowHint(const Value: Boolean);
begin
FShowHint := Value;
end;
procedure TNCControl.SetTop(const Value: Integer);
begin
FTop := Value;
end;
procedure TNCControl.SetVisible(const Value: Boolean);
begin
if FVisible <> Value then
FVisible := Value;
// TODO : Add parent notification
end;
procedure TNCControl.SetWidth(const Value: Integer);
begin
FWidth := Value;
end;
procedure TNCControl.DrawControl(ACanvas: TCanvas; AMouseInControl, Pressed: Boolean);
begin
end;
procedure TNCControl.Handle_WMNCLButtonDown(var Message: TWMNCHitMessage);
begin
end;
procedure TNCControl.Handle_WMNCLButtonUp(var Message: TWMNCHitMessage);
begin
end;
procedure TNCControl.Handle_WMNCMouseMove(var Message: TWMNCHitMessage);
begin
end;
initialization
TFormStyleNCSettings.UseThinBorder := False;
{$IFDEF CPUX86}
Trampoline_TFormStyleHook_GetBorderSize := InterceptCreate(TFormStyleHookClass(nil)._GetBorderSizeAddr,
@Detour_TFormStyleHook_GetBorderSize);
{$ENDIF}
Trampoline_TFormStyleHook_GetRegion := InterceptCreate(TFormStyleHookClass(nil)._GetRegionAddr,
@Detour_TFormStyleHook_GetRegion);
finalization
{$IFDEF CPUX86}
InterceptRemove(@Trampoline_TFormStyleHook_GetBorderSize);
{$ENDIF}
InterceptRemove(@Trampoline_TFormStyleHook_GetRegion);
end.