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

3754 lines
108 KiB
ObjectPascal

unit Vcl.Styles.Utils.Shadow;
interface
{$LEGACYIFEND ON}
{$IF (CompilerVersion >= 31)}
uses
System.UITypes,
Winapi.Windows,
Winapi.Messages,
Vcl.Menus,
Vcl.Forms,
Vcl.Graphics,
Vcl.Controls,
Vcl.Themes;
type
TFormStyleHook = class(TMouseTrackControlStyleHook)
strict private type
{$REGION 'TMainMenuBarStyleHook'}
TMainMenuBarStyleHook = class
strict private type
TMenuBarButton = record
Index: Integer;
State: TThemedWindow;
ItemRect: TRect;
end;
public type
TMenuBarItem = record
Index: Integer;
State: TThemedMenu;
MenuItem: TMenuItem;
ItemRect: TRect;
end;
strict private
class var FCurrentMenuItem: TMenuItem;
class var FMenuBarHook: TMainMenuBarStyleHook;
class function PopupMenuHook(Code: Integer; WParam: WPARAM; var Msg: TMsg): LRESULT; stdcall; static;
strict private
FActiveItem: Integer;
FBoundsRect: TRect;
FEnterWithKeyboard: Boolean;
FFormHook: TFormStyleHook;
FIcon: TIcon;
FIconHandle: HICON;
FInMenuLoop: Boolean;
FItemCount: Integer;
FItems: array of TMenuBarItem;
FHotMDIButton, FOldMDIHotButton: Integer;
FMDIButtons: array[0..2] of TMenuBarButton;
FMDIChildSysMenuActive: Boolean;
FMDIChildSystemMenuTracking: Boolean;
FMenuActive: Boolean;
FMenuHook: HHOOK;
FMenuPush: Boolean;
FMouseInMainMenu: Boolean;
FMustActivateMDIChildSysMenu: Boolean;
FMustActivateMenuItem: Boolean;
FMustActivateSysMenu: Boolean;
FOldActiveItem: Integer;
FOldCursorPos: TPoint;
FPressedMDIButton: Integer;
FSelectFirstItem: Boolean;
FShowMDIButtons: Boolean;
FSysMenuActive: Boolean;
FSystemMenuTracking: Boolean;
function CanFindPriorItem(AMenuItem: TMenuItem): Boolean;
function CanFindNextItem(AMenuItem: TMenuItem): Boolean;
function CanTrackMDISystemMenu: Boolean;
function CanTrackSystemMenu: Boolean;
procedure DrawItem(AItem: TMenuBarItem; ACanvas: TCanvas);
function FindFirstMenuItem(AUpdateMenu: Boolean): Integer;
function FindFirstRightMenuItem(AUpdateMenu: Boolean): Integer;
function FindHotKeyItem(CharCode: Integer; AUpdateMenu: Boolean): Integer;
function FindItem(Value: NativeUInt; Kind: TFindItemKind): TMenuItem;
function FindNextMenuItem(AUpdateMenu: Boolean): Integer;
function FindPriorMenuItem(AUpdateMenu: Boolean): Integer;
function GetIcon: TIcon;
function GetIconFast: TIcon;
function GetMenuItemWidth(AMenuItem: TMenuItem; ACanvas: TCanvas): Integer;
function GetTrackMenuPos(AItem: TMenuBarItem): TPoint;
procedure HookMenus;
function IsSubMenuItem(AMenuItem: TMenuItem): Boolean;
function ItemFromCursorPos: Integer;
function ItemFromPoint(X, Y: Integer): Integer;
function MainMenu: TMainMenu;
procedure MenuExit;
function MDIButtonFromPoint(X, Y: Integer): Integer;
procedure MDIChildClose;
procedure MDIChildMinimize;
procedure MDIChildRestore;
procedure SetBoundsRect(const ABoundsRect: TRect);
procedure SetShowMDIButtons(Value: Boolean);
procedure TrackMenuFromItem;
procedure UnHookMenus;
public
constructor Create(FormHook: TFormStyleHook);
destructor Destroy; override;
function CheckHotKeyItem(ACharCode: Word): Boolean;
function GetMenuHeight(AWidth: Integer): Integer;
procedure Invalidate;
procedure MenuEnter(ATrackMenu: Boolean);
procedure MouseDown(X, Y: Integer);
procedure MouseMove(X, Y: Integer);
procedure MouseUp(X, Y: Integer);
procedure Paint(Canvas: TCanvas);
procedure ProcessMenuLoop(ATrackMenu: Boolean);
procedure TrackSystemMenu;
procedure TrackMDIChildSystemMenu;
property BoundsRect: TRect read FBoundsRect write SetBoundsRect;
property InMenuLoop: Boolean read FInMenuLoop write FInMenuLoop;
property EnterWithKeyboard: Boolean read FEnterWithKeyboard write FEnterWithKeyboard;
property MenuActive: Boolean read FMenuActive write FMenuActive;
property MustActivateMDIChildSysMenu: Boolean read FMustActivateMDIChildSysMenu write FMustActivateMDIChildSysMenu;
property MustActivateSysMenu: Boolean read FMustActivateSysMenu write FMustActivateSysMenu;
property MustActivateMenuItem: Boolean read FMustActivateMenuItem write FMustActivateMenuItem;
property ShowMDIButtons: Boolean read FShowMDIButtons write SetShowMDIButtons;
property MouseInMainMenu: Boolean read FMouseInMainMenu;
end;
{$ENDREGION}
strict private const
WM_NCUAHDRAWCAPTION = $00AE;
strict protected
FCaptionRect: TRect;
FChangeSizeCalled: Boolean;
FChangeVisibleChildHandle: HWND;
FCloseButtonRect: TRect;
FFormActive: Boolean;
FHotButton: Integer;
FHeight: Integer;
FHelpButtonRect: TRect;
FIcon: TIcon;
FIconHandle: HICON;
FMainMenuBarHook: TMainMenuBarStyleHook;
FMaxButtonRect: TRect;
FMDIClientInstance: Pointer;
FMDIHorzScrollBar: TWinControl; { TScrollBar }
FMDIPrevClientProc: Pointer;
FMDIScrollSizeBox: TWinControl;
FMDIStopHorzScrollBar: Boolean;
FMDIStopVertScrollBar: Boolean;
FMDIVertScrollBar: TWinControl; { TScrollBar }
FMinButtonRect: TRect;
FLeft: Integer;
FNeedsUpdate: Boolean;
FOldHorzSrollBarPosition: Integer;
FOldVertSrollBarPosition: Integer;
FPressedButton: Integer;
FRegion: HRGN;
FStopCheckChildMove: Boolean;
FSysMenuButtonRect: TRect;
FTop: Integer;
FWidth: Integer;
FCaptionEmulation: Boolean;
FRestoring: Boolean;
FRestoringConstraints: TSizeConstraints;
procedure AdjustMDIScrollBars;
procedure ChangeSize;
function IsStyleBorder: Boolean;
function GetBorderSize: TRect;
function GetForm: TCustomForm; inline;
function GetIconFast: TIcon;
function GetIcon: TIcon;
function GetHitTest(P: TPoint): Integer;
procedure GetMDIScrollInfo(SetRange: Boolean);
function GetMDIWorkArea: TRect;
function GetRegion: HRgn;
procedure InitMDIScrollBars;
function MDIChildMaximized: Boolean;
procedure MDIHorzScroll(Offset: Integer);
procedure MDIVertScroll(Offset: Integer);
function NormalizePoint(P: TPoint): TPoint;
procedure UpdateForm;
procedure OnMDIHScroll(Sender: TObject; ScrollCode: System.UITypes.TScrollCode; var ScrollPos: Integer);
procedure OnMDIVScroll(Sender: TObject; ScrollCode: System.UITypes.TScrollCode; var ScrollPos: Integer);
procedure CMDialogChar(var Message: TWMKey); message CM_DIALOGCHAR;
procedure CMMenuChanged(var Message: TMessage); message CM_MENUCHANGED;
procedure WMInitMenu(var Message: TMessage); message WM_INITMENU;
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
procedure WMNCActivate(var Message: TMessage); message WM_NCACTIVATE;
procedure WMWindowPosChanging(var Message: TWMWindowPosChanging); message WM_WINDOWPOSCHANGING;
procedure WMSize(var Message: TWMSIZE); message WM_SIZE;
procedure WMMove(var Message: TWMMOVE); message WM_MOVE;
procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
procedure WMNCMouseMove(var Message: TWMNCHitMessage); message WM_NCMOUSEMOVE;
procedure WMNCLButtonDown(var Message: TWMNCHitMessage); message WM_NCLBUTTONDOWN;
procedure WMNCRButtonDown(var Message: TWMNCHitMessage); message WM_NCRBUTTONDOWN;
procedure WMNCLButtonUp(var Message: TWMNCHitMessage); message WM_NCLBUTTONUP;
procedure WMNCRButtonUp(var Message: TWMNCHitMessage); message WM_NCRBUTTONUP;
procedure WMNCLButtonDblClk(var Message: TWMNCHitMessage); message WM_NCLBUTTONDBLCLK;
procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE;
procedure WMNCUAHDrawCaption(var Message: TMessage); message WM_NCUAHDRAWCAPTION;
procedure WMShowWindow(var Message: TWMShowWindow); message WM_SHOWWINDOW;
procedure WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo); message WM_GETMINMAXINFO;
procedure WMSetText(var Message: TMessage); message WM_SETTEXT;
procedure WMMDIChildMove(var Message: TMessage); message WM_MDICHILDMOVE;
procedure WMMDIChildClose(var Message: TMessage); message WM_MDICHILDCLOSE;
procedure WMSysCommand(var Message: TMessage); message WM_SYSCOMMAND;
procedure WMDestroy(var Message: TMessage); message WM_DESTROY;
strict protected
procedure Close; virtual;
procedure Help; virtual;
procedure Maximize; virtual;
procedure MDIClientWndProc(var Message: TMessage); virtual;
procedure Minimize; virtual;
procedure MouseEnter; override;
procedure MouseLeave; override;
procedure PaintBackground(Canvas: TCanvas); override;
procedure PaintNC(Canvas: TCanvas); override;
procedure Restore; virtual;
procedure WndProc(var Message: TMessage); override;
property Form: TCustomForm read GetForm;
public
constructor Create(AControl: TWinControl); override;
destructor Destroy; override;
procedure Invalidate; override;
property Handle;
end;
{$IFEND}
implementation
{$IF (CompilerVersion >= 31)}
uses
System.Types,
System.Classes,
System.SysUtils,
Winapi.CommCtrl,
Vcl.StdCtrls;
type
TFormClass = Class(TForm);
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;
{ TFormStyleHook }
constructor TFormStyleHook.Create(AControl: TWinControl);
begin
inherited;
FocusUpdate := False;
if seClient in Form.StyleElements then
OverrideEraseBkgnd := True;
if IsStyleBorder then
OverridePaintNC := True;
FMainMenuBarHook := nil;
FMDIHorzScrollBar := nil;
FMDIVertScrollBar := nil;
FMDIScrollSizeBox := nil;
FMDIClientInstance := nil;
FMDIPrevClientProc := nil;
FChangeVisibleChildHandle := 0;
FStopCheckChildMove := False;
FOldHorzSrollBarPosition := 0;
FOldVertSrollBarPosition := 0;
FMDIStopHorzScrollBar := False;
FMDIStopVertScrollBar := False;
MouseInNCArea := True;
FFormActive := False;
FChangeSizeCalled := False;
FRegion := 0;
FLeft := Control.Left;
FTop := Control.Top;
FWidth := Control.Width;
FHeight := Control.Height;
FNeedsUpdate := True;
FIcon := nil;
FIconHandle := 0;
FHotButton := 0;
FPressedButton := 0;
FCaptionEmulation := False;
FRestoring := False;
end;
destructor TFormStyleHook.Destroy;
begin
if FIcon <> nil then
FreeAndNil(FIcon);
if FMDIClientInstance <> nil then
begin
SetWindowLong(TForm(Control).ClientHandle, GWL_WNDPROC,
IntPtr(FMDIPrevClientProc));
FreeObjectInstance(FMDIClientInstance);
end;
if FMainMenuBarHook <> nil then
FreeAndNil(FMainMenuBarHook);
if FMDIHorzScrollBar <> nil then
FreeAndNil(FMDIHorzScrollBar);
if FMDIVertScrollBar <> nil then
FreeAndNil(FMDIVertScrollBar);
if FMDIScrollSizeBox <> nil then
FreeAndNil(FMDIScrollSizeBox);
inherited;
end;
function TFormStyleHook.IsStyleBorder: Boolean;
begin
Result := (TStyleManager.FormBorderStyle = fbsCurrentStyle) and
(seBorder in Form.StyleElements);
end;
procedure TFormStyleHook.Invalidate;
begin
// Prevent ancestor's Invalidate from executing
end;
procedure TFormStyleHook.MDIHorzScroll(Offset: Integer);
var
I: Integer;
begin
FStopCheckChildMove := True;
try
for I := 0 to TFormClass(Form).MDIChildCount - 1 do
if TFormClass(Form).MDIChildren[I].Visible then
TFormClass(Form).MDIChildren[I].Left := TFormClass(Form).MDIChildren[I]
.Left + Offset;
finally
FStopCheckChildMove := False;
end;
GetMDIScrollInfo(False);
end;
procedure TFormStyleHook.MDIVertScroll(Offset: Integer);
var
I: Integer;
begin
FStopCheckChildMove := True;
try
for I := 0 to TFormClass(Form).MDIChildCount - 1 do
if TFormClass(Form).MDIChildren[I].Visible then
TFormClass(Form).MDIChildren[I].Top := TFormClass(Form).MDIChildren[I]
.Top + Offset;
finally
FStopCheckChildMove := False;
end;
GetMDIScrollInfo(False);
end;
procedure TFormStyleHook.OnMDIHScroll(Sender: TObject;
ScrollCode: System.UITypes.TScrollCode; var ScrollPos: Integer);
var
Offset: Integer;
begin
if (FMDIStopHorzScrollBar) or
(ScrollCode <> System.UITypes.TScrollCode.scEndScroll) then
Exit;
Offset := TScrollBar(FMDIHorzScrollBar).Position - FOldHorzSrollBarPosition;
if Offset <> 0 then
MDIHorzScroll(-Offset);
FOldHorzSrollBarPosition := TScrollBar(FMDIHorzScrollBar).Position;
end;
procedure TFormStyleHook.OnMDIVScroll(Sender: TObject;
ScrollCode: System.UITypes.TScrollCode; var ScrollPos: Integer);
var
Offset: Integer;
begin
if (FMDIStopVertScrollBar) or
(ScrollCode <> System.UITypes.TScrollCode.scEndScroll) then
Exit;
Offset := TScrollBar(FMDIVertScrollBar).Position - FOldVertSrollBarPosition;
if Offset <> 0 then
MDIVertScroll(-Offset);
FOldVertSrollBarPosition := TScrollBar(FMDIVertScrollBar).Position;
end;
function TFormStyleHook.MDIChildMaximized: Boolean;
begin
Result := (TFormClass(Form).ActiveMDIChild <> nil) and
(TFormClass(Form).ActiveMDIChild.WindowState = wsMaximized);
end;
procedure TFormStyleHook.GetMDIScrollInfo(SetRange: Boolean);
var
I, MinX, MinY, MaxX, MaxY, HPage, VPage: Integer;
R, MDIR, MDICLR: TRect;
ReCalcInfo: Boolean;
LHorzScrollVisible, LVertScrollVisible: Boolean;
LMDIHorzScrollBar: TScrollBar;
LMDIVertScrollBar: TScrollBar;
begin
LMDIHorzScrollBar := TScrollBar(FMDIHorzScrollBar);
LMDIVertScrollBar := TScrollBar(FMDIVertScrollBar);
if (LMDIHorzScrollBar = nil) or (LMDIVertScrollBar = nil) then
Exit;
if (not(LMDIVertScrollBar.HandleAllocated)) or
(not LMDIHorzScrollBar.HandleAllocated) then
Exit;
if MDIChildMaximized then
begin
if IsWindowVisible(LMDIHorzScrollBar.Handle) then
ShowWindow(LMDIHorzScrollBar.Handle, SW_HIDE);
if IsWindowVisible(LMDIVertScrollBar.Handle) then
ShowWindow(LMDIVertScrollBar.Handle, SW_HIDE);
if IsWindowVisible(FMDIScrollSizeBox.Handle) then
ShowWindow(FMDIScrollSizeBox.Handle, SW_HIDE);
Exit;
end;
ReCalcInfo := False;
R := GetMDIWorkArea;
MinX := MaxInt;
MinY := MaxInt;
MaxX := -MaxInt;
MaxY := -MaxInt;
for I := 0 to TFormClass(Form).MDIChildCount - 1 do
if (TFormClass(Form).MDIChildren[I].Visible) and
(TFormClass(Form).MDIChildren[I].Handle <> FChangeVisibleChildHandle) then
with TFormClass(Form) do
begin
GetWindowRect(MDIChildren[I].Handle, MDIR);
GetWindowRect(TForm(Control).ClientHandle, MDICLR);
OffsetRect(MDIR, -MDICLR.Left, -MDICLR.Top);
if MinX > MDIR.Left then
MinX := MDIR.Left;
if MinY > MDIR.Top then
MinY := MDIR.Top;
if MaxX < MDIR.Left + MDIR.Width then
MaxX := MDIR.Left + MDIR.Width;
if MaxY < MDIR.Top + MDIR.Height then
MaxY := MDIR.Top + MDIR.Height;
end;
LHorzScrollVisible := (MinX < 0) or (MaxX > R.Width);
LVertScrollVisible := (MinY < 0) or (MaxY > R.Height);
if LVertScrollVisible and not LHorzScrollVisible then
LHorzScrollVisible := (MinX < 0) or
(MaxX > R.Width - LMDIVertScrollBar.Width);
if LHorzScrollVisible and not LVertScrollVisible then
LVertScrollVisible := (MinY < 0) or
(MaxY > R.Height - LMDIHorzScrollBar.Height);
if LHorzScrollVisible and not IsWindowVisible(LMDIHorzScrollBar.Handle) then
begin
SetWindowPos(LMDIHorzScrollBar.Handle, HWND_TOP, R.Left,
R.Bottom - LMDIHorzScrollBar.Height, R.Width, LMDIHorzScrollBar.Height,
SWP_SHOWWINDOW);
ShowWindow(LMDIHorzScrollBar.Handle, SW_SHOW);
ReCalcInfo := True;
end
else if not LHorzScrollVisible and IsWindowVisible(LMDIHorzScrollBar.Handle)
then
begin
ShowWindow(LMDIHorzScrollBar.Handle, SW_HIDE);
ReCalcInfo := True;
end;
if LVertScrollVisible and not IsWindowVisible(LMDIVertScrollBar.Handle) then
begin
if LHorzScrollVisible then
SetWindowPos(LMDIVertScrollBar.Handle, HWND_TOP,
R.Right - LMDIVertScrollBar.Width, R.Top, LMDIVertScrollBar.Width,
R.Height - LMDIHorzScrollBar.Height, SWP_SHOWWINDOW)
else
SetWindowPos(LMDIVertScrollBar.Handle, HWND_TOP,
R.Right - LMDIVertScrollBar.Width, R.Top, LMDIVertScrollBar.Width,
R.Height, SWP_SHOWWINDOW);
ShowWindow(LMDIVertScrollBar.Handle, SW_SHOW);
ReCalcInfo := True;
end
else if not LVertScrollVisible and IsWindowVisible(LMDIVertScrollBar.Handle)
then
begin
ShowWindow(LMDIVertScrollBar.Handle, SW_HIDE);
ReCalcInfo := True;
end;
HPage := R.Width;
VPage := R.Height;
AdjustMDIScrollBars;
if IsWindowVisible(LMDIHorzScrollBar.Handle) then
begin
if MinX > 0 then
MinX := 0;
if MaxX < R.Width then
MaxX := R.Width;
if SetRange then
begin
FMDIStopHorzScrollBar := True;
if IsWindowVisible(LMDIVertScrollBar.Handle) then
LMDIHorzScrollBar.PageSize := HPage - LMDIVertScrollBar.Width
else
LMDIHorzScrollBar.PageSize := HPage;
LMDIHorzScrollBar.SetParams(-MinX, 0, MaxX - MinX - 1);
FOldHorzSrollBarPosition := LMDIHorzScrollBar.Position;
FMDIStopHorzScrollBar := False;
end;
LMDIHorzScrollBar.LargeChange := LMDIHorzScrollBar.PageSize;
end;
if IsWindowVisible(LMDIVertScrollBar.Handle) then
begin
if MinY > 0 then
MinY := 0;
if MaxY < R.Height then
MaxY := R.Height;
if SetRange then
begin
FMDIStopVertScrollBar := True;
if IsWindowVisible(LMDIHorzScrollBar.Handle) then
LMDIVertScrollBar.PageSize := VPage - LMDIHorzScrollBar.Height
else
LMDIVertScrollBar.PageSize := VPage;
LMDIVertScrollBar.SetParams(-MinY, 0, MaxY - MinY - 1);
FOldVertSrollBarPosition := LMDIVertScrollBar.Position;
FMDIStopVertScrollBar := False;
end;
LMDIVertScrollBar.LargeChange := LMDIVertScrollBar.PageSize;
end;
if (not IsWindowVisible(LMDIHorzScrollBar.Handle)) and
(not IsWindowVisible(LMDIVertScrollBar.Handle)) then
ReCalcInfo := False;
if IsWindowVisible(LMDIHorzScrollBar.Handle) and
IsWindowVisible(LMDIVertScrollBar.Handle) and
not IsWindowVisible(FMDIScrollSizeBox.Handle) then
begin
SetWindowPos(FMDIScrollSizeBox.Handle, HWND_TOP,
R.Right - LMDIVertScrollBar.Width, R.Bottom - LMDIHorzScrollBar.Height,
LMDIVertScrollBar.Width, LMDIHorzScrollBar.Height, SWP_SHOWWINDOW);
ShowWindow(FMDIScrollSizeBox.Handle, SW_SHOW);
end
else if not IsWindowVisible(LMDIHorzScrollBar.Handle) or
not IsWindowVisible(LMDIVertScrollBar.Handle) and
IsWindowVisible(FMDIScrollSizeBox.Handle) then
ShowWindow(FMDIScrollSizeBox.Handle, SW_HIDE);
if ReCalcInfo then
GetMDIScrollInfo(SetRange);
end;
procedure TFormStyleHook.InitMDIScrollBars;
begin
if FMDIHorzScrollBar = nil then
begin
FMDIHorzScrollBar := TScrollBar.CreateParented(Control.Handle);
with TScrollBar(FMDIHorzScrollBar) do
begin
Kind := sbHorizontal;
OnScroll := OnMDIHScroll;
SetWindowPos(FMDIHorzScrollBar.Handle, HWND_TOP, 0, 0, 0,
GetSystemMetrics(SM_CYHSCROLL), SWP_NOREDRAW);
ShowWindow(FMDIHorzScrollBar.Handle, SW_HIDE);
end;
end;
if FMDIVertScrollBar = nil then
begin
FMDIVertScrollBar := TScrollBar.CreateParented(Control.Handle);
with TScrollBar(FMDIVertScrollBar) do
begin
Kind := sbVertical;
OnScroll := OnMDIVScroll;
SetWindowPos(FMDIVertScrollBar.Handle, HWND_TOP, 0, 0,
GetSystemMetrics(SM_CXVSCROLL), 0, SWP_NOREDRAW);
ShowWindow(FMDIVertScrollBar.Handle, SW_HIDE);
end;
end;
if FMDIScrollSizeBox = nil then
begin
FMDIScrollSizeBox := TScrollBarStyleHook.TScrollWindow.CreateParented
(Control.Handle);
with TScrollBarStyleHook.TScrollWindow(FMDIScrollSizeBox) do
begin
SizeBox := True;
SetWindowPos(FMDIScrollSizeBox.Handle, HWND_TOP, 0, 0,
GetSystemMetrics(SM_CXVSCROLL), GetSystemMetrics(SM_CYHSCROLL),
SWP_NOREDRAW);
ShowWindow(FMDIScrollSizeBox.Handle, SW_HIDE);
end;
end;
end;
procedure TFormStyleHook.AdjustMDIScrollBars;
var
R: TRect;
begin
R := GetMDIWorkArea;
if (FMDIHorzScrollBar <> nil) and IsWindowVisible(FMDIHorzScrollBar.Handle)
then
begin
if (FMDIVertScrollBar <> nil) and IsWindowVisible(FMDIVertScrollBar.Handle)
then
SetWindowPos(FMDIHorzScrollBar.Handle, HWND_TOP, R.Left,
R.Bottom - FMDIHorzScrollBar.Height, R.Width - FMDIVertScrollBar.Width,
FMDIHorzScrollBar.Height, SWP_SHOWWINDOW)
else
SetWindowPos(FMDIHorzScrollBar.Handle, HWND_TOP, R.Left,
R.Bottom - FMDIHorzScrollBar.Height, R.Width, FMDIHorzScrollBar.Height,
SWP_SHOWWINDOW);
end;
if (FMDIVertScrollBar <> nil) and IsWindowVisible(FMDIVertScrollBar.Handle)
then
begin
if (FMDIHorzScrollBar <> nil) and IsWindowVisible(FMDIHorzScrollBar.Handle)
then
SetWindowPos(FMDIVertScrollBar.Handle, HWND_TOP,
R.Right - FMDIVertScrollBar.Width, R.Top, FMDIVertScrollBar.Width,
R.Height - FMDIHorzScrollBar.Height, SWP_SHOWWINDOW)
else
SetWindowPos(FMDIVertScrollBar.Handle, HWND_TOP,
R.Right - FMDIVertScrollBar.Width, R.Top, FMDIVertScrollBar.Width,
R.Height, SWP_SHOWWINDOW)
end;
if (FMDIScrollSizeBox <> nil) and IsWindowVisible(FMDIScrollSizeBox.Handle)
and (FMDIVertScrollBar <> nil) and IsWindowVisible(FMDIVertScrollBar.Handle)
and (FMDIHorzScrollBar <> nil) and IsWindowVisible(FMDIHorzScrollBar.Handle)
then
SetWindowPos(FMDIScrollSizeBox.Handle, HWND_TOP,
R.Right - FMDIVertScrollBar.Width, R.Bottom - FMDIHorzScrollBar.Height,
FMDIVertScrollBar.Width, FMDIHorzScrollBar.Height, SWP_SHOWWINDOW);
end;
function TFormStyleHook.GetMDIWorkArea: TRect;
var
P: TPoint;
begin
Result := Control.ClientRect;
if TForm(Control).ClientHandle <> 0 then
begin
GetWindowRect(TForm(Control).ClientHandle, Result);
P := Control.ClientToScreen(Point(0, 0));
OffsetRect(Result, -P.X, -P.Y);
end;
end;
procedure TFormStyleHook.MDIClientWndProc(var Message: TMessage);
var
FCallOldProc: Boolean;
R: TRect;
Details: TThemedElementDetails;
begin
FCallOldProc := True;
case Message.Msg of
WM_NCACTIVATE:
begin
if TForm(Control).ActiveMDIChild <> nil then
SendMessage(TForm(Control).ActiveMDIChild.Handle, Message.Msg,
Message.WParam, Message.LParam);
FCallOldProc := False;
Message.Result := 1;
end;
WM_NCCALCSIZE:
FCallOldProc := False;
WM_NCPAINT:
FCallOldProc := False;
WM_ERASEBKGND:
if StyleServices.Available then
begin
Details.Element := teWindow;
Details.Part := 0;
R := Rect(0, 0, TForm(Control).ClientWidth,
TForm(Control).ClientHeight);
if StyleServices.Available then
StyleServices.DrawElement(Message.WParam, Details, R);
FCallOldProc := False;
end;
end;
if FCallOldProc then
with Message do
Result := CallWindowProc(FMDIPrevClientProc,
TFormClass(Form).ClientHandle, Msg, WParam, LParam);
end;
procedure TFormStyleHook.PaintBackground(Canvas: TCanvas);
var
Details: TThemedElementDetails;
R: TRect;
begin
if StyleServices.Available then
begin
Details.Element := teWindow;
Details.Part := 0;
R := Rect(0, 0, Control.ClientWidth, Control.ClientHeight);
StyleServices.DrawElement(Canvas.Handle, Details, R);
end;
end;
function TFormStyleHook.GetBorderSize: TRect;
var
Size: TSize;
Details: TThemedElementDetails;
Detail: TThemedWindow;
begin
Result := Rect(0, 0, 0, 0);
if Form.BorderStyle = bsNone then
Exit;
if not StyleServices.Available then
Exit;
{ caption height }
if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin)
then
Detail := twCaptionActive
else
Detail := twSmallCaptionActive;
Details := StyleServices.GetElementDetails(Detail);
StyleServices.GetElementSize(0, Details, esActual, Size);
Result.Top := Size.cy;
{ left border width }
if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin)
then
Detail := twFrameLeftActive
else
Detail := twSmallFrameLeftActive;
Details := StyleServices.GetElementDetails(Detail);
StyleServices.GetElementSize(0, Details, esActual, Size);
Result.Left := Size.cx;
{ right border width }
if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin)
then
Detail := twFrameRightActive
else
Detail := twSmallFrameRightActive;
Details := StyleServices.GetElementDetails(Detail);
StyleServices.GetElementSize(0, Details, esActual, Size);
Result.Right := Size.cx;
{ bottom border height }
if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin)
then
Detail := twFrameBottomActive
else
Detail := twSmallFrameBottomActive;
Details := StyleServices.GetElementDetails(Detail);
StyleServices.GetElementSize(0, Details, esActual, Size);
Result.Bottom := Size.cy;
end;
function TFormStyleHook.GetForm: TCustomForm;
begin
Result := TCustomForm(Control);
end;
function TFormStyleHook.NormalizePoint(P: TPoint): TPoint;
var
WindowPos, ClientPos: TPoint;
HandleParent: HWND;
begin
if (TFormClass(Form).FormStyle = fsMDIChild) or (Form.Parent <> nil) then
begin
HandleParent := GetParent(Control.Handle);
WindowPos := Point(FLeft, FTop);
ClientToScreen(HandleParent, WindowPos);
ClientPos := Point(0, 0);
ClientToScreen(Handle, ClientPos);
Result := P;
ScreenToClient(Handle, Result);
Inc(Result.X, ClientPos.X - WindowPos.X);
Inc(Result.Y, ClientPos.Y - WindowPos.Y);
end
else
begin
WindowPos := Point(FLeft, FTop);
ClientPos := Point(0, 0);
ClientToScreen(Handle, ClientPos);
Result := P;
ScreenToClient(Handle, Result);
Inc(Result.X, ClientPos.X - WindowPos.X);
Inc(Result.Y, ClientPos.Y - WindowPos.Y);
end;
end;
function TFormStyleHook.GetHitTest(P: TPoint): Integer;
var
FBorderSize: TRect;
FTopLeftRect, FTopRightRect, FBottomLeftRect, FBottomRightRect, FTopRect,
FLeftRect, FRightRect, FBottomRect, FHitCaptionRect: TRect;
begin
Result := HTCLIENT;
if Form.BorderStyle = bsNone then
begin
if (FMainMenuBarHook <> nil) and FMainMenuBarHook.BoundsRect.Contains(P)
then
Exit(HTMENU)
else
Exit;
end;
FBorderSize := GetBorderSize;
FHitCaptionRect := FCaptionRect;
FHitCaptionRect.Top := FBorderSize.Left;
FBorderSize.Top := FHitCaptionRect.Top;
{ check buttons }
if (FMainMenuBarHook <> nil) and FMainMenuBarHook.BoundsRect.Contains(P) then
Exit(HTMENU)
else if FHitCaptionRect.Contains(P) then
Exit(HTCAPTION)
else if FCloseButtonRect.Contains(P) then
Exit(HTCLOSE)
else if FMaxButtonRect.Contains(P) then
Exit(HTMAXBUTTON)
else if FMinButtonRect.Contains(P) then
Exit(HTMINBUTTON)
else if FHelpButtonRect.Contains(P) then
Exit(HTHELP)
else if FSysMenuButtonRect.Contains(P) then
Exit(HTSYSMENU);
{ check window state }
if (Form.WindowState = wsMaximized) or (Form.WindowState = wsMinimized) then
Exit;
{ check border }
if (Form.BorderStyle = bsDialog) or (Form.BorderStyle = bsSingle) or
(Form.BorderStyle = bsToolWindow) then
begin
if Rect(FBorderSize.Left, FBorderSize.Top, FWidth - FBorderSize.Right,
FHeight - FBorderSize.Bottom).Contains(P) then
Exit(HTCLIENT)
else
Exit(HTBORDER);
end;
FTopLeftRect := Rect(0, 0, FBorderSize.Left, FBorderSize.Top);
FTopRightRect := Rect(FWidth - FBorderSize.Right, 0, FWidth, FBorderSize.Top);
FBottomLeftRect := Rect(0, FHeight - FBorderSize.Bottom,
FBorderSize.Left, FHeight);
FBottomRightRect := Rect(FWidth - FBorderSize.Right,
FHeight - FBorderSize.Bottom, FWidth, FHeight);
FTopRect := Rect(FTopLeftRect.Right, 0, FTopRightRect.Left, FBorderSize.Top);
FLeftRect := Rect(0, FTopLeftRect.Bottom, FBorderSize.Left,
FBottomLeftRect.Top);
FRightRect := Rect(FWidth - FBorderSize.Right, FTopRightRect.Bottom, FWidth,
FBottomRightRect.Top);
FBottomRect := Rect(FBottomLeftRect.Right, FHeight - FBorderSize.Bottom,
FBottomRightRect.Left, FHeight);
if FTopLeftRect.Contains(P) then
Result := HTTOPLEFT
else if FTopRightRect.Contains(P) then
Result := HTTOPRIGHT
else if FBottomLeftRect.Contains(P) then
Result := HTBOTTOMLEFT
else if FBottomRightRect.Contains(P) then
Result := HTBOTTOMRIGHT
else if FLeftRect.Contains(P) then
Result := HTLEFT
else if FRightRect.Contains(P) then
Result := HTRIGHT
else if FBottomRect.Contains(P) then
Result := HTBOTTOM
else if FTopRect.Contains(P) then
Result := HTTOP;
end;
procedure TFormStyleHook.CMDialogChar(var Message: TWMKey);
begin
if (FMainMenuBarHook <> nil) and
(KeyDataToShiftState(Message.KeyData) = [ssAlt]) and
FMainMenuBarHook.CheckHotKeyItem(Message.CharCode) then
begin
Message.Result := 1;
Handled := True;
end;
end;
procedure TFormStyleHook.WMSetText(var Message: TMessage);
begin
if not IsStyleBorder then
begin
Handled := False;
Exit;
end;
Form.DefaultHandler(Message);
InvalidateNC;
Handled := True;
end;
procedure TFormStyleHook.WMMDIChildClose(var Message: TMessage);
function IsAnyMDIChildMaximized: Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to TFormClass(Form).MDIChildCount - 1 do
if (FChangeVisibleChildHandle <> TFormClass(Form).MDIChildren[I].Handle)
and (TFormClass(Form).MDIChildren[I].Visible) and
(TFormClass(Form).MDIChildren[I].WindowState = wsMaximized) then
begin
Result := True;
Break;
end;
end;
begin
FChangeVisibleChildHandle := Message.WParam;
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) then
begin
if IsAnyMDIChildMaximized and not FMainMenuBarHook.ShowMDIButtons then
FMainMenuBarHook.ShowMDIButtons := True
else if not IsAnyMDIChildMaximized and FMainMenuBarHook.ShowMDIButtons then
FMainMenuBarHook.ShowMDIButtons := False;
InvalidateNC;
end;
GetMDIScrollInfo(True);
end;
procedure TFormStyleHook.WMDestroy(var Message: TMessage);
begin
if not(csRecreating in Form.ControlState) and
(TFormClass(Form).FormStyle = fsMDIChild) then
PostMessage(Application.MainForm.Handle, WM_MDICHILDCLOSE, 0, 0);
end;
procedure TFormStyleHook.WMSysCommand(var Message: TMessage);
begin
if IsStyleBorder then
case Message.WParam of
SC_RESTORE:
begin
FRestoring := True;
FRestoringConstraints := Form.Constraints;
end;
SC_CLOSE:
if TFormClass(Form).FormStyle = fsMDIChild then
PostMessage(Application.MainForm.Handle, WM_MDICHILDCLOSE,
Winapi.Windows.WParam(Form.Handle), 0);
SC_MINIMIZE:
if TFormClass(Form).FormStyle = fsMDIChild then
FFormActive := False;
SC_KEYMENU:
begin
if TMainMenuBarStyleHook(FMainMenuBarHook) <> nil then
begin
if TWMSYSCOMMAND(Message).Key = VK_SPACE then
FMainMenuBarHook.TrackSystemMenu
else
begin
FMainMenuBarHook.MenuActive := True;
FMainMenuBarHook.EnterWithKeyboard := True;
FMainMenuBarHook.MenuEnter(False);
end;
Handled := True;
end;
end;
end;
end;
procedure TFormStyleHook.WMInitMenu(var Message: TMessage);
begin
if (WParam(GetMenu(Control.Handle)) = Message.WParam) and IsStyleBorder then
SetMenu(Control.Handle, 0);
end;
procedure TFormStyleHook.CMMenuChanged(var Message: TMessage);
begin
if IsStyleBorder then
begin
if GetMenu(Control.Handle) <> 0 then
SetMenu(Control.Handle, 0);
Handled := True;
end;
end;
procedure TFormStyleHook.WMNCHitTest(var Message: TWMNCHitTest);
var
P: TPoint;
begin
if IsStyleBorder then
begin
P := NormalizePoint(Point(Message.XPos, Message.YPos));
Message.Result := GetHitTest(P);
Handled := True;
end;
end;
procedure TFormStyleHook.WMNCCalcSize(var Message: TWMNCCalcSize);
var
Params: PNCCalcSizeParams;
R, MenuRect: TRect;
MenuHeight: Integer;
begin
if not IsStyleBorder then
begin
Handled := False;
Exit;
end;
{ check menu info }
if (TFormClass(Form).FormStyle = fsMDIChild) then
TMainMenuBarStyleHook(FMainMenuBarHook) := nil
else if (Form.Menu <> nil) and not Form.Menu.AutoMerge and
(Form.Menu.Items.Count > 0) and
(TMainMenuBarStyleHook(FMainMenuBarHook) = nil) then
TMainMenuBarStyleHook(FMainMenuBarHook) :=
TFormStyleHook.TMainMenuBarStyleHook.Create(Self)
else if ((Form.Menu = nil) or ((Form.Menu <> nil) and
(Form.Menu.Items.Count = 0))) and
(TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) then
TMainMenuBarStyleHook(FMainMenuBarHook) := nil;
{ calc NC info }
if (Message.CalcValidRects and (Form.BorderStyle <> bsNone)) or
((Form.BorderStyle = bsNone) and (TMainMenuBarStyleHook(FMainMenuBarHook) <>
nil)) then
begin
R := GetBorderSize;
if TMainMenuBarStyleHook(FMainMenuBarHook) <> nil then
begin
MenuHeight := FMainMenuBarHook.GetMenuHeight(FWidth - R.Left - R.Right);
MenuRect := Rect(R.Left, R.Top, FWidth - R.Right, R.Top + MenuHeight);
FMainMenuBarHook.BoundsRect := MenuRect;
end
else
MenuHeight := 0;
Params := Message.CalcSize_Params;
with Params^.rgrc[0] do
begin
Inc(Left, R.Left);
Inc(Top, R.Top + MenuHeight);
Dec(Right, R.Right);
Dec(Bottom, R.Bottom);
if TFormClass(Form).BorderWidth <> 0 then
begin
Inc(Left, TFormClass(Form).BorderWidth);
Inc(Top, TFormClass(Form).BorderWidth);
Dec(Right, TFormClass(Form).BorderWidth);
Dec(Bottom, TFormClass(Form).BorderWidth);
end;
end;
Handled := True;
end;
end;
function TFormStyleHook.GetIconFast: TIcon;
begin
if (FIcon = nil) or (FIconHandle = 0) then
Result := GetIcon
else
Result := FIcon;
end;
function TFormStyleHook.GetIcon: TIcon;
var
IconX, IconY: Integer;
TmpHandle: THandle;
Info: TWndClassEx;
Buffer: array [0 .. 255] of Char;
begin
TmpHandle := THandle(SendMessage(Handle, WM_GETICON, ICON_SMALL, 0));
if TmpHandle = 0 then
TmpHandle := THandle(SendMessage(Handle, WM_GETICON, ICON_BIG, 0));
if TmpHandle = 0 then
begin
{ Get instance }
GetClassName(Handle, Buffer, Length(Buffer));
FillChar(Info, SizeOf(Info), 0);
Info.cbSize := SizeOf(Info);
if GetClassInfoEx(GetWindowLong(Handle, GWL_HINSTANCE), @Buffer, Info) then
begin
TmpHandle := Info.hIconSm;
if TmpHandle = 0 then
TmpHandle := Info.HICON;
end
end;
if FIcon = nil then
FIcon := TIcon.Create;
if TmpHandle <> 0 then
begin
IconX := GetSystemMetrics(SM_CXSMICON);
if IconX = 0 then
IconX := GetSystemMetrics(SM_CXSIZE);
IconY := GetSystemMetrics(SM_CYSMICON);
if IconY = 0 then
IconY := GetSystemMetrics(SM_CYSIZE);
FIcon.Handle := CopyImage(TmpHandle, IMAGE_ICON, IconX, IconY, 0);
FIconHandle := TmpHandle;
end;
Result := FIcon;
end;
procedure TFormStyleHook.PaintNC(Canvas: TCanvas);
var
Details, CaptionDetails, IconDetails: TThemedElementDetails;
Detail: TThemedWindow;
R, R1, DrawRect, ButtonRect, TextRect: TRect;
CaptionBuffer: TBitmap;
FButtonState: TThemedWindow;
TextFormat: TTextFormat;
LText: string;
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
(TFormClass(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
(TFormClass(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;
procedure DrawBorder;
function CheckRectInRect(const R1: TRect; var R2: TRect): Boolean;
begin
if R2.Top < R1.Top then
R2.Top := R1.Top;
if R2.Bottom > R1.Bottom then
R2.Bottom := R1.Bottom;
if R2.Left < R1.Left then
R2.Left := R1.Left;
if R2.Bottom > R1.Bottom then
R2.Bottom := R1.Bottom;
Result := (R2.Top <= R2.Bottom) and (R2.Left <= R2.Right);
end;
var
BSize: TRect;
begin
if TFormClass(Form).BorderWidth = 0 then
Exit;
Canvas.Brush.Color := StyleServices.GetStyleColor(scWindow);
Canvas.Brush.Style := bsSolid;
if Form.BorderStyle = bsNone then
BSize := Rect(0, 0, 0, 0)
else
BSize := GetBorderSize;
R := Rect(BSize.Left, BSize.Top, FWidth - BSize.Right,
FHeight - BSize.Bottom);
if TMainMenuBarStyleHook(FMainMenuBarHook) <> nil then
Inc(R.Top, FMainMenuBarHook.GetMenuHeight(FWidth - BSize.Left -
BSize.Right));
DrawRect := Rect(R.Left, R.Top, R.Left + TFormClass(Form).BorderWidth,
R.Bottom);
if CheckRectInRect(R, DrawRect) then
Canvas.FillRect(DrawRect);
DrawRect := Rect(R.Right - TFormClass(Form).BorderWidth, R.Top, R.Right,
R.Bottom);
if CheckRectInRect(R, DrawRect) then
Canvas.FillRect(DrawRect);
DrawRect := Rect(R.Left + TFormClass(Form).BorderWidth, R.Top,
R.Right - TFormClass(Form).BorderWidth, R.Top + TFormClass(Form)
.BorderWidth);
if CheckRectInRect(R, DrawRect) then
Canvas.FillRect(DrawRect);
DrawRect := Rect(R.Left + TFormClass(Form).BorderWidth,
R.Bottom - TFormClass(Form).BorderWidth, R.Right - TFormClass(Form)
.BorderWidth, R.Bottom);
if CheckRectInRect(R, DrawRect) then
Canvas.FillRect(DrawRect);
end;
begin
if Form.BorderStyle = bsNone then
begin
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) then
FMainMenuBarHook.Paint(Canvas);
DrawBorder;
Exit;
end;
{ init some parameters }
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 StyleServices.Available then
Exit;
R := GetBorderSize;
{ draw caption }
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;
CaptionBuffer.SetSize(FWidth, R.Top);
{ draw caption border }
DrawRect := Rect(0, 0, CaptionBuffer.Width, CaptionBuffer.Height);
Details := StyleServices.GetElementDetails(Detail);
StyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, DrawRect);
TextRect := DrawRect;
CaptionDetails := Details;
TextTopOffset := 3;
{ draw icon }
if (biSystemMenu in TFormClass(Form).BorderIcons) and
(Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and
(Form.BorderStyle <> bsSizeToolWin) then
begin
IconDetails := StyleServices.GetElementDetails(twSysButtonNormal);
if not StyleServices.GetElementContentRect(0, IconDetails, DrawRect,
ButtonRect) then
ButtonRect := Rect(0, 0, 0, 0);
R1 := ButtonRect;
if not StyleServices.HasElementFixedPosition(Details) then
begin
CorrectLeftButtonRect(ButtonRect);
TextTopOffset := Abs(R1.Top - ButtonRect.Top);
if TextTopOffset > R.Top then
TextTopOffset := 3;
end
else
TextTopOffset := 0;
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);
{ draw buttons }
if (biSystemMenu in TFormClass(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 := StyleServices.GetElementDetails(FButtonState);
if not StyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect)
then
ButtonRect := Rect(0, 0, 0, 0);
if not StyleServices.HasElementFixedPosition(Details) then
CorrectRightButtonRect(ButtonRect);
if ButtonRect.Width > 0 then
StyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details,
ButtonRect);
if ButtonRect.Left > 0 then
TextRect.Right := ButtonRect.Left;
FCloseButtonRect := ButtonRect;
end;
if (biMaximize in TFormClass(Form).BorderIcons) and
(biSystemMenu in TFormClass(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 := StyleServices.GetElementDetails(FButtonState);
if not StyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect)
then
ButtonRect := Rect(0, 0, 0, 0);
if not StyleServices.HasElementFixedPosition(Details) then
CorrectRightButtonRect(ButtonRect);
if ButtonRect.Width > 0 then
StyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details,
ButtonRect);
if ButtonRect.Left > 0 then
TextRect.Right := ButtonRect.Left;
FMaxButtonRect := ButtonRect;
end;
if (biMinimize in TFormClass(Form).BorderIcons) and
(biSystemMenu in TFormClass(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 := StyleServices.GetElementDetails(FButtonState);
if not StyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect)
then
ButtonRect := Rect(0, 0, 0, 0);
if not StyleServices.HasElementFixedPosition(Details) then
CorrectRightButtonRect(ButtonRect);
if ButtonRect.Width > 0 then
StyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details,
ButtonRect);
if ButtonRect.Left > 0 then
TextRect.Right := ButtonRect.Left;
FMinButtonRect := ButtonRect;
end;
if (biHelp in TFormClass(Form).BorderIcons) and
(biSystemMenu in TFormClass(Form).BorderIcons) and
((not(biMaximize in TFormClass(Form).BorderIcons) and
not(biMinimize in TFormClass(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 := StyleServices.GetElementDetails(FButtonState);
if not StyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect)
then
ButtonRect := Rect(0, 0, 0, 0);
if not StyleServices.HasElementFixedPosition(Details) then
CorrectRightButtonRect(ButtonRect);
if ButtonRect.Width > 0 then
StyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details,
ButtonRect);
if ButtonRect.Left > 0 then
TextRect.Right := ButtonRect.Left;
FHelpButtonRect := ButtonRect;
end;
{ draw text }
TextFormat := [tfLeft, tfSingleLine, tfVerticalCenter];
if Control.UseRightToLeftReading then
Include(TextFormat, tfRtlReading);
// Important: Must retrieve Text prior to calling DrawText as it causes
// CaptionBuffer.Canvas to free its handle, making the outcome of the call
// to DrawText dependent on parameter evaluation order.
LText := Text;
if (Form.WindowState = wsMaximized) and
(TFormClass(Form).FormStyle <> fsMDIChild) and (TextTopOffset <> 0) and
(biSystemMenu in TFormClass(Form).BorderIcons) then
begin
Inc(TextRect.Left, R.Left);
MoveWindowOrg(CaptionBuffer.Canvas.Handle, 0, TextTopOffset);
StyleServices.DrawText(CaptionBuffer.Canvas.Handle, CaptionDetails, LText,
TextRect, TextFormat);
MoveWindowOrg(CaptionBuffer.Canvas.Handle, 0, -TextTopOffset);
end
else
StyleServices.DrawText(CaptionBuffer.Canvas.Handle, CaptionDetails, LText,
TextRect, TextFormat);
FCaptionRect := TextRect;
{ draw caption buffer }
Canvas.Draw(0, 0, CaptionBuffer);
CaptionBuffer.Free;
{ draw menubar }
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and
(FMainMenuBarHook.BoundsRect.Right < FWidth - R.Right) then
FMainMenuBarHook.BoundsRect := Rect(FMainMenuBarHook.BoundsRect.Left,
FMainMenuBarHook.BoundsRect.Top, FWidth - R.Right,
FMainMenuBarHook.BoundsRect.Bottom);
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) then
FMainMenuBarHook.Paint(Canvas);
{ draw left border }
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 := StyleServices.GetElementDetails(Detail);
if DrawRect.Bottom - DrawRect.Top > 0 then
StyleServices.DrawElement(Canvas.Handle, Details, DrawRect);
{ draw right border }
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 := StyleServices.GetElementDetails(Detail);
if DrawRect.Bottom - DrawRect.Top > 0 then
StyleServices.DrawElement(Canvas.Handle, Details, DrawRect);
{ draw Bottom border }
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 := StyleServices.GetElementDetails(Detail);
if DrawRect.Bottom - DrawRect.Top > 0 then
StyleServices.DrawElement(Canvas.Handle, Details, DrawRect);
DrawBorder;
end;
procedure TFormStyleHook.WMNCActivate(var Message: TMessage);
begin
if not IsStyleBorder then
begin
Handled := False;
Exit;
end;
FFormActive := Message.WParam > 0;
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and FMainMenuBarHook.InMenuLoop
then
FMainMenuBarHook.InMenuLoop := False;
if (TFormClass(Form).FormStyle = fsMDIChild) then
begin
if (TFormClass(Form).FormStyle = fsMDIChild) and (Win32MajorVersion >= 6)
then
SetRedraw(False);
CallDefaultProc(Message);
if (TFormClass(Form).FormStyle = fsMDIChild) and (Win32MajorVersion >= 6)
then
begin
SetRedraw(True);
if not(csDestroying in Control.ComponentState) and
not(csLoading in Control.ComponentState) then
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE + RDW_ALLCHILDREN +
RDW_UPDATENOW);
end;
end
else
Message.Result := 1;
if TFormClass(Form).ClientHandle <> 0 then
PostMessage(TForm(Control).ClientHandle, WM_NCACTIVATE, Message.WParam,
Message.LParam);
if (Form.BorderStyle <> bsNone) and
not((TFormClass(Form).FormStyle = fsMDIChild) and
(Form.WindowState = wsMaximized)) then
InvalidateNC;
Handled := True;
end;
function TFormStyleHook.GetRegion: HRGN;
var
WR, R, R1, ScrR: TRect;
Details: TThemedElementDetails;
Detail: TThemedWindow;
P: TPoint;
LeftOffset, TopOffset, RightOffset, BottomOffset: Integer;
begin
Result := 0;
if not StyleServices.Available then
Exit;
R := Rect(0, 0, FWidth, FHeight);
if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin)
then
Detail := twCaptionActive
else
Detail := twSmallCaptionActive;
Details := StyleServices.GetElementDetails(Detail);
StyleServices.GetElementRegion(Details, R, Result);
if (Form.WindowState = wsMaximized) and
(TFormClass(Form).FormStyle <> fsMDIChild) and (Form.BorderStyle <> bsNone)
then
begin
P.X := FLeft + FWidth div 2;
P.Y := FTop + FHeight div 2;
WR := Screen.WorkareaRect;
R := Screen.MonitorFromPoint(P).WorkareaRect;
R1 := Screen.MonitorFromPoint(P).BoundsRect;
ScrR := Rect(R1.Left, R1.Top, R1.Left + R1.Right, R1.Top + R1.Bottom);
LeftOffset := 0;
TopOffset := 0;
RightOffset := 0;
BottomOffset := 0;
if (R.Top <> R1.Top) and (R.Top > 0) and (FTop < 0) and (Abs(FTop) < 100)
then
TopOffset := Abs(FTop)
else if (FTop < R.Top) and (R.Top - FTop < 100) then
TopOffset := R.Top - FTop
else if (FTop < ScrR.Top) and (ScrR.Top - FTop < 100) then
TopOffset := ScrR.Top - FTop
else if (FTop < WR.Top) and (WR.Top - FTop < 100) then
TopOffset := WR.Top - FTop;
if (R.Left <> R1.Left) and (R.Left > 0) and (FLeft < 0) and
(Abs(FLeft) < 100) then
LeftOffset := Abs(FLeft)
else if (FLeft < R.Left) and (R.Left - FLeft < 100) then
LeftOffset := R.Left - FLeft
else if (FLeft < ScrR.Left) and (ScrR.Left - FLeft < 100) then
LeftOffset := ScrR.Left - FLeft
else if (FLeft < WR.Left) and (WR.Left - FLeft < 100) then
LeftOffset := WR.Left - FLeft;
if (FLeft + FWidth > R.Right) and (FLeft + FWidth - R.Right < 100) then
RightOffset := FLeft + FWidth - R.Right
else if (FLeft + FWidth > ScrR.Right) and (FLeft + FWidth - ScrR.Right < 100)
then
RightOffset := FLeft + FWidth - ScrR.Right
else if (FLeft + FWidth > WR.Right) and (FLeft + FWidth - WR.Right < 100)
then
RightOffset := FLeft + FWidth - WR.Right;
if (FTop + FHeight > R.Bottom) and (FTop + FHeight - R.Bottom < 100) then
BottomOffset := FTop + FHeight - R.Bottom
else if (FTop + FHeight > ScrR.Bottom) and
(FTop + FHeight - ScrR.Bottom < 100) then
BottomOffset := FTop + FHeight - ScrR.Bottom
else if (FTop + FHeight > WR.Bottom) and (FTop + FHeight - WR.Bottom < 100)
then
BottomOffset := FTop + FHeight - WR.Bottom;
if (LeftOffset <> 0) or (RightOffset <> 0) or (TopOffset <> 0) or
(BottomOffset <> 0) then
SetRectRgn(Result, LeftOffset, TopOffset, FWidth - RightOffset,
FHeight - BottomOffset);
end;
end;
procedure TFormStyleHook.ChangeSize;
var
R: TRect;
begin
FChangeSizeCalled := True;
try
if IsIconic(Handle) then
begin
R := GetBorderSize;
FHeight := R.Top + R.Bottom;
end;
if Form.BorderStyle <> bsNone then
begin
FRegion := GetRegion;
SetWindowRgn(Handle, FRegion, True);
end
else if (Form.BorderStyle = bsNone) and (FRegion <> 0) then
begin
SetWindowRgn(Handle, 0, True);
FRegion := 0;
end;
finally
FChangeSizeCalled := False;
end;
end;
procedure TFormStyleHook.WMMove(var Message: TWMMOVE);
begin
if TFormClass(Form).FormStyle = fsMDIChild then
begin
CallDefaultProc(TMessage(Message));
SendMessage(Application.MainForm.Handle, WM_MDICHILDMOVE, 0, 0);
Handled := True;
end;
end;
procedure TFormStyleHook.WMMDIChildMove(var Message: TMessage);
begin
if (TFormClass(Form).FormStyle = fsMDIForm) and not FStopCheckChildMove then
begin
FChangeVisibleChildHandle := Message.WParam;
GetMDIScrollInfo(True);
FChangeVisibleChildHandle := 0;
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and IsStyleBorder then
begin
if MDIChildMaximized and not FMainMenuBarHook.ShowMDIButtons then
FMainMenuBarHook.ShowMDIButtons := True
else if not MDIChildMaximized and FMainMenuBarHook.ShowMDIButtons then
FMainMenuBarHook.ShowMDIButtons := False;
end;
Handled := True;
end;
end;
procedure TFormStyleHook.WMSize(var Message: TWMSIZE);
begin
if IsIconic(Handle) and (Application.MainForm.Handle <> Handle) and IsStyleBorder
then
InvalidateNC;
if (FMDIClientInstance <> nil) then
begin
CallDefaultProc(TMessage(Message));
GetMDIScrollInfo(True);
Handled := True;
Exit;
end;
if TFormClass(Form).FormStyle = fsMDIChild then
begin
CallDefaultProc(TMessage(Message));
SendMessage(Application.MainForm.Handle, WM_MDICHILDMOVE, 0, 0);
if IsIconic(Handle) and IsStyleBorder then
InvalidateNC;
Handled := True;
end;
end;
procedure TFormStyleHook.WMWindowPosChanging(var Message: TWMWindowPosChanging);
var
Changed: Boolean;
begin
if not IsStyleBorder then
begin
Handled := False;
Exit;
end;
CallDefaultProc(TMessage(Message));
if (Message.WindowPos^.flags and SWP_SHOWWINDOW <> 0) and FNeedsUpdate then
begin
FNeedsUpdate := False;
if (Control is TForm) and (TForm(Control).FormStyle = fsMDIForm) and
(FMDIClientInstance = nil) then
begin
FMDIPrevClientProc := Pointer(GetWindowLong(TForm(Control).ClientHandle,
GWL_WNDPROC));
FMDIClientInstance := MakeObjectInstance(MDIClientWndProc);
SetWindowLong(TForm(Control).ClientHandle, GWL_WNDPROC,
IntPtr(FMDIClientInstance));
InitMDIScrollBars;
AdjustMDIScrollBars;
end;
if IsStyleBorder and not TStyleManager.SystemStyle.Enabled and
(GetWindowLong(Handle, GWL_STYLE) and WS_CAPTION <> 0) and
not(TFormClass(Form).FormStyle = fsMDIChild) then
begin
FCaptionEmulation := True;
SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) and
not WS_CAPTION);
end;
end;
Handled := True;
Changed := False;
if FChangeSizeCalled then
begin
if FRestoring then
begin
FRestoring := False;
if (FRestoringConstraints.MinHeight <> 0) or
(FRestoringConstraints.MinWidth <> 0) or
(FRestoringConstraints.MaxWidth <> 0) or
(FRestoringConstraints.MaxHeight <> 0) then
Form.Constraints := FRestoringConstraints;
end;
Exit;
end;
if (Message.WindowPos^.flags and SWP_NOSIZE = 0) or
(Message.WindowPos^.flags and SWP_NOMOVE = 0) then
begin
if (Message.WindowPos^.flags and SWP_NOMOVE = 0) then
begin
FLeft := Message.WindowPos^.X;
FTop := Message.WindowPos^.Y;
end;
if (Message.WindowPos^.flags and SWP_NOSIZE = 0) then
begin
Changed := ((Message.WindowPos^.cx <> FWidth) or
(Message.WindowPos^.cy <> FHeight)) and
(Message.WindowPos^.flags and SWP_NOSIZE = 0);
FWidth := Message.WindowPos^.cx;
FHeight := Message.WindowPos^.cy;
end;
end;
if (Message.WindowPos^.flags and SWP_FRAMECHANGED <> 0) then
Changed := True;
if Changed then
begin
ChangeSize;
if Form.BorderStyle <> bsNone then
InvalidateNC;
end;
end;
procedure TFormStyleHook.WndProc(var Message: TMessage);
begin
// Reserved for potential updates
inherited;
case Message.Msg of
WM_WINDOWPOSCHANGED:
if IsStyleBorder and (Form.WindowState = wsMaximized) then
with TWMWindowPosChanged(Message) do
if (WindowPos^.flags and SWP_NOSIZE = 0) or
(WindowPos^.flags and SWP_NOMOVE = 0) then
begin
if (WindowPos^.flags and SWP_NOMOVE = 0) then
begin
FLeft := WindowPos^.X;
FTop := WindowPos^.Y;
end;
if (WindowPos^.flags and SWP_NOSIZE = 0) then
begin
FWidth := WindowPos^.cx;
FHeight := WindowPos^.cy;
end;
end;
end;
end;
procedure TFormStyleHook.UpdateForm;
begin
if Form.BorderStyle = bsNone then
Exit;
Control.Width := Control.Width - 1;
Control.Width := Control.Width + 1;
end;
procedure TFormStyleHook.WMNCMouseMove(var Message: TWMNCHitMessage);
var
P: TPoint;
begin
if not IsStyleBorder then
begin
Handled := False;
Exit;
end;
inherited;
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and
(Message.HitTest = HTMENU) then
begin
P := NormalizePoint(Point(Message.XCursor, Message.YCursor));
P.X := P.X - FMainMenuBarHook.BoundsRect.Left;
P.Y := P.Y - FMainMenuBarHook.BoundsRect.Top;
FMainMenuBarHook.MouseMove(P.X, P.Y);
Handled := True;
end
else if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and
FMainMenuBarHook.MouseInMainMenu and (Message.HitTest <> HTMENU) then
FMainMenuBarHook.MouseMove(-1, -1);
if (Message.HitTest = HTCLOSE) or (Message.HitTest = HTMAXBUTTON) or
(Message.HitTest = HTMINBUTTON) or (Message.HitTest = HTHELP) then
begin
if FHotButton <> Message.HitTest then
begin
FHotButton := Message.HitTest;
InvalidateNC;
end;
Message.Result := 0;
Message.Msg := WM_NULL;
Handled := True;
end
else if FHotButton <> 0 then
begin
FHotButton := 0;
InvalidateNC;
end;
end;
procedure TFormStyleHook.WMNCRButtonDown(var Message: TWMNCHitMessage);
begin
if not IsStyleBorder then
begin
Handled := False;
Exit;
end;
inherited;
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and
(Message.HitTest = HTMENU) then
Handled := True;
end;
procedure TFormStyleHook.WMNCLButtonDown(var Message: TWMNCHitMessage);
var
P: TPoint;
begin
if not IsStyleBorder then
begin
Handled := False;
Exit;
end;
inherited;
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and FMainMenuBarHook.MustActivateMDIChildSysMenu
then
begin
FMainMenuBarHook.InMenuLoop := False;
FMainMenuBarHook.MustActivateMDIChildSysMenu := False;
FMainMenuBarHook.TrackMDIChildSystemMenu;
Handled := True;
Exit;
end;
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and FMainMenuBarHook.MustActivateSysMenu
then
begin
FMainMenuBarHook.InMenuLoop := False;
FMainMenuBarHook.MustActivateSysMenu := False;
FMainMenuBarHook.TrackSystemMenu;
Handled := True;
Exit;
end;
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and FMainMenuBarHook.MustActivateMenuItem
then
begin
FMainMenuBarHook.InMenuLoop := False;
FMainMenuBarHook.MustActivateMenuItem := False;
FMainMenuBarHook.ProcessMenuLoop(True);
Handled := True;
Exit;
end;
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and
(Message.HitTest = HTMENU) then
begin
P := NormalizePoint(Point(Message.XCursor, Message.YCursor));
P.X := P.X - FMainMenuBarHook.BoundsRect.Left;
P.Y := P.Y - FMainMenuBarHook.BoundsRect.Top;
FMainMenuBarHook.MouseDown(P.X, P.Y);
Handled := True;
end;
if (Message.HitTest = HTCLOSE) or (Message.HitTest = HTMAXBUTTON) or
(Message.HitTest = HTMINBUTTON) or (Message.HitTest = HTHELP) then
begin
FPressedButton := Message.HitTest;
InvalidateNC;
Message.Result := 0;
Message.Msg := WM_NULL;
Handled := True;
end;
end;
procedure TFormStyleHook.WMNCRButtonUp(var Message: TWMNCHitMessage);
begin
if not IsStyleBorder then
begin
Handled := False;
Exit;
end;
// call system menu
if (Message.HitTest = HTCAPTION) and FCaptionEmulation then
begin
SendMessage(Handle, $313, 0, MakeLong(Message.XCursor, Message.YCursor));
end;
end;
procedure TFormStyleHook.WMNCLButtonUp(var Message: TWMNCHitMessage);
var
FWasPressedButton: Integer;
P: TPoint;
begin
if not IsStyleBorder then
begin
Handled := False;
Exit;
end;
FWasPressedButton := FPressedButton;
if FPressedButton <> 0 then
begin
FPressedButton := 0;
InvalidateNC;
end;
if (TMainMenuBarStyleHook(FMainMenuBarHook) <> nil) and
(Message.HitTest = HTMENU) then
begin
P := NormalizePoint(Point(Message.XCursor, Message.YCursor));
P.X := P.X - FMainMenuBarHook.BoundsRect.Left;
P.Y := P.Y - FMainMenuBarHook.BoundsRect.Top;
FMainMenuBarHook.MouseUp(P.X, P.Y);
Handled := True;
end;
if (Message.HitTest = HTTOP) or (Message.HitTest = HTBOTTOM) or
(Message.HitTest = HTLEFT) or (Message.HitTest = HTRIGHT) or
(Message.HitTest = HTCAPTION) or (Message.HitTest = HTTOPLEFT) or
(Message.HitTest = HTTOPRIGHT) or (Message.HitTest = HTBOTTOMRIGHT) or
(Message.HitTest = HTBOTTOMLEFT) or (Message.HitTest = HTSYSMENU) then
begin
Exit;
end;
if FWasPressedButton = FHotButton then
if Message.HitTest = HTCLOSE then
Close
else if (Message.HitTest = HTMAXBUTTON) and
(biMaximize in TFormClass(Form).BorderIcons) then
begin
if Form.WindowState <> wsMaximized then
Maximize
else
Restore;
end
else if (Message.HitTest = HTMINBUTTON) and
(biMinimize in TFormClass(Form).BorderIcons) then
begin
if Form.WindowState <> wsMinimized then
Minimize
else
Restore;
end
else if (Message.HitTest = HTHELP) and
(biHelp in TFormClass(Form).BorderIcons) then
Help;
Message.Result := 0;
Message.Msg := WM_NULL;
Handled := True;
end;
procedure TFormStyleHook.WMNCLButtonDblClk(var Message: TWMNCHitMessage);
begin
inherited;
if (Message.HitTest = HTTOP) or (Message.HitTest = HTBOTTOM) or
(Message.HitTest = HTLEFT) or (Message.HitTest = HTRIGHT) or
(Message.HitTest = HTCAPTION) or (Message.HitTest = HTTOPLEFT) or
(Message.HitTest = HTTOPRIGHT) or (Message.HitTest = HTBOTTOMRIGHT) or
(Message.HitTest = HTBOTTOMLEFT) then
begin
Exit;
end;
Message.Result := 0;
Message.Msg := WM_NULL;
Handled := True;
end;
procedure TFormStyleHook.MouseEnter;
begin
inherited;
FPressedButton := 0;
end;
procedure TFormStyleHook.MouseLeave;
begin
inherited;
if FHotButton <> 0 then
begin
FHotButton := 0;
FPressedButton := 0;
if Form.BorderStyle <> bsNone then
InvalidateNC;
end;
if TMainMenuBarStyleHook(FMainMenuBarHook) <> nil then
FMainMenuBarHook.MouseMove(-1, -1);
end;
procedure TFormStyleHook.WMActivate(var Message: TWMActivate);
begin
if IsStyleBorder then
begin
CallDefaultProc(TMessage(Message));
FFormActive := Message.Active > 0;
Handled := True;
end;
end;
procedure TFormStyleHook.WMNCUAHDrawCaption(var Message: TMessage);
begin
if IsStyleBorder then
begin
InvalidateNC;
Handled := True;
end;
end;
procedure TFormStyleHook.Close;
begin
if Handle <> 0 then
SendMessage(Handle, WM_SYSCOMMAND, SC_CLOSE, 0);
end;
procedure TFormStyleHook.Restore;
begin
FPressedButton := 0;
FHotButton := 0;
if Handle <> 0 then
SendMessage(Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
end;
procedure TFormStyleHook.Maximize;
begin
if Handle <> 0 then
begin
FPressedButton := 0;
FHotButton := 0;
if IsZoomed(Handle) then
SendMessage(Handle, WM_SYSCOMMAND, SC_RESTORE, 0)
else
SendMessage(Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
end;
end;
procedure TFormStyleHook.Minimize;
begin
if Handle <> 0 then
begin
FPressedButton := 0;
FHotButton := 0;
if IsIconic(Handle) then
SendMessage(Handle, WM_SYSCOMMAND, SC_RESTORE, 0)
else
SendMessage(Handle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
end;
end;
procedure TFormStyleHook.Help;
begin
SendMessage(Handle, WM_SYSCOMMAND, SC_CONTEXTHELP, 0)
end;
procedure TFormStyleHook.WMShowWindow(var Message: TWMShowWindow);
begin
if Message.Show and FNeedsUpdate then
begin
FNeedsUpdate := False;
if (Control is TForm) and (TForm(Control).FormStyle = fsMDIForm) and
(FMDIClientInstance = nil) then
begin
FMDIPrevClientProc := Pointer(GetWindowLong(TForm(Control).ClientHandle,
GWL_WNDPROC));
FMDIClientInstance := MakeObjectInstance(MDIClientWndProc);
SetWindowLong(TForm(Control).ClientHandle, GWL_WNDPROC,
IntPtr(FMDIClientInstance));
InitMDIScrollBars;
AdjustMDIScrollBars;
end;
if IsStyleBorder and not TStyleManager.SystemStyle.Enabled and
(GetWindowLong(Handle, GWL_STYLE) and WS_CAPTION <> 0) and
not(TFormClass(Form).FormStyle = fsMDIChild) then
begin
FCaptionEmulation := True;
SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) and
not WS_CAPTION);
end;
UpdateForm;
end;
end;
procedure TFormStyleHook.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
var
R: TRect;
MM: PMinMaxInfo;
begin
if IsStyleBorder then
begin
CallDefaultProc(TMessage(Message));
R := GetBorderSize;
MM := Message.MinMaxInfo;
MM^.ptMinTrackSize.Y := R.Top + R.Bottom;
Handled := True;
end;
end;
{ TFormStyleHook.TMainMenuBarStyleHook }
constructor TFormStyleHook.TMainMenuBarStyleHook.Create
(FormHook: TFormStyleHook);
begin
FFormHook := FormHook;
FBoundsRect := Rect(0, 0, 0, 0);
FIcon := nil;
FItemCount := 0;
FMenuActive := False;
FMenuPush := False;
FActiveItem := -1;
FOldActiveItem := -1;
FMouseInMainMenu := False;
FMenuBarHook := nil;
FOldCursorPos := Point(-1, -1);
FEnterWithKeyboard := False;
FSystemMenuTracking := False;
FMDIChildSystemMenuTracking := False;
FShowMDIButtons := False;
FHotMDIButton := -1;
FPressedMDIButton := -1;
FOldMDIHotButton := -1;
FMustActivateSysMenu := False;
FMustActivateMenuItem := False;
FMustActivateMDIChildSysMenu := False;
FSysMenuActive := False;
FMDIChildSysMenuActive := False;
end;
destructor TFormStyleHook.TMainMenuBarStyleHook.Destroy;
begin
if FIcon <> nil then
FreeAndNil(FIcon);
inherited;
end;
function TFormStyleHook.TMainMenuBarStyleHook.GetIconFast: TIcon;
begin
if (FIcon = nil) or (FIconHandle = 0) then
Result := GetIcon
else
Result := FIcon;
end;
function TFormStyleHook.TMainMenuBarStyleHook.GetIcon: TIcon;
var
IconX, IconY: Integer;
TmpHandle: Integer;
Inst: Cardinal;
Info: TWndClassEx;
Handle: HWND;
StrBuf: array [0 .. 300] of Char;
begin
if not CanTrackMDISystemMenu then
begin
Result := nil;
Exit;
end;
Handle := TFormClass(FFormHook.Form).ActiveMDIChild.Handle;
TmpHandle := 0;
if TmpHandle = 0 then
TmpHandle := SendMessage(Handle, WM_GETICON, ICON_SMALL, 0);
if TmpHandle = 0 then
TmpHandle := SendMessage(Handle, WM_GETICON, ICON_BIG, 0);
if TmpHandle = 0 then
begin
{ Get instance }
GetClassName(Handle, StrBuf, Length(StrBuf));
FillChar(Info, SizeOf(Info), 0);
Info.cbSize := SizeOf(Info);
Inst := GetWindowLong(Handle, GWL_HINSTANCE);
if GetClassInfoEx(Inst, @StrBuf, Info) then
begin
TmpHandle := Info.hIconSm;
if TmpHandle = 0 then
TmpHandle := Info.HICON;
end
end;
if FIcon = nil then
FIcon := TIcon.Create;
if TmpHandle <> 0 then
begin
IconX := GetSystemMetrics(SM_CXSMICON);
if IconX = 0 then
IconX := GetSystemMetrics(SM_CXSIZE);
IconY := GetSystemMetrics(SM_CYSMICON);
if IconY = 0 then
IconY := GetSystemMetrics(SM_CYSIZE);
FIcon.Handle := CopyImage(TmpHandle, IMAGE_ICON, IconX, IconY, 0);
FIconHandle := TmpHandle;
end;
Result := FIcon;
end;
function TFormStyleHook.TMainMenuBarStyleHook.CanTrackMDISystemMenu: Boolean;
begin
Result := (TFormClass(FFormHook.Form).FormStyle = fsMDIForm) and
(TFormClass(FFormHook.Form).ActiveMDIChild <> nil) and
(biSystemMenu in TFormClass(FFormHook.Form).ActiveMDIChild.BorderIcons);
end;
function TFormStyleHook.TMainMenuBarStyleHook.CanTrackSystemMenu: Boolean;
begin
Result := (biSystemMenu in TFormClass(FFormHook.Form).BorderIcons) and
(FFormHook.Form.BorderStyle <> bsNone);
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.SetShowMDIButtons
(Value: Boolean);
begin
if FShowMDIButtons <> Value then
begin
FShowMDIButtons := Value;
FHotMDIButton := -1;
FPressedMDIButton := -1;
FOldMDIHotButton := -1;
if not Value and (FIcon <> nil) then
FreeAndNil(FIcon);
Invalidate;
end;
end;
function TFormStyleHook.TMainMenuBarStyleHook.IsSubMenuItem
(AMenuItem: TMenuItem): Boolean;
var
I: Integer;
begin
Result := True;
for I := 0 to FItemCount - 1 do
if AMenuItem.Parent = FItems[I].MenuItem then
Exit(False);
end;
function TFormStyleHook.TMainMenuBarStyleHook.CanFindPriorItem
(AMenuItem: TMenuItem): Boolean;
begin
Result := (AMenuItem = nil) or not IsSubMenuItem(AMenuItem);
end;
function TFormStyleHook.TMainMenuBarStyleHook.CanFindNextItem
(AMenuItem: TMenuItem): Boolean;
begin
Result := (AMenuItem = nil) or (AMenuItem.Count = 0);
end;
function TFormStyleHook.TMainMenuBarStyleHook.FindItem(Value: NativeUInt;
Kind: TFindItemKind): TMenuItem;
begin
Result := MainMenu.FindItem(Value, Kind);
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.MenuEnter;
begin
HideCaret(0);
FMDIChildSysMenuActive := False;
FSysMenuActive := False;
if not ATrackMenu then
FindFirstMenuItem(True);
ProcessMenuLoop(ATrackMenu);
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.MenuExit;
begin
ShowCaret(0);
FInMenuLoop := False;
FMenuPush := False;
FMenuActive := False;
FEnterWithKeyboard := False;
FMDIChildSysMenuActive := False;
FSysMenuActive := False;
if (FActiveItem <> -1) and
(WindowFromPoint(Mouse.CursorPos) = FFormHook.Handle) and
(ItemFromCursorPos <> -1) then
begin
FActiveItem := ItemFromCursorPos;
FOldActiveItem := FActiveItem;
end
else
begin
FActiveItem := -1;
FOldActiveItem := -1;
end;
Invalidate;
end;
function TFormStyleHook.TMainMenuBarStyleHook.CheckHotKeyItem
(ACharCode: Word): Boolean;
var
I: Integer;
begin
Result := False;
I := FindHotKeyItem(ACharCode, True);
if (I <> -1) and (FActiveItem = I) then
begin
Result := True;
if FItems[FActiveItem].MenuItem.Count = 0 then
begin
MenuExit;
if FItems[I].MenuItem.GetParentMenu <> nil then
FItems[I].MenuItem.GetParentMenu.DispatchCommand
(FItems[I].MenuItem.Command);
end
else
begin
FEnterWithKeyboard := True;
TrackMenuFromItem;
end;
end;
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.ProcessMenuLoop;
var
Msg: TMsg;
FDispatchMessage: Boolean;
I: Integer;
begin
if FInMenuLoop then
Exit;
FInMenuLoop := True;
repeat
if ATrackMenu then
TrackMenuFromItem;
FDispatchMessage := False;
if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
case Msg.Message of
WM_MOUSEMOVE:
begin
end;
WM_SYSKEYDOWN:
begin
if Msg.WParam = VK_MENU then
begin
FInMenuLoop := False;
FDispatchMessage := True;
end;
end;
WM_QUIT:
begin
FInMenuLoop := False;
PostQuitMessage(Msg.WParam);
end;
WM_CLOSE, CM_RELEASE:
begin
FInMenuLoop := False;
FDispatchMessage := True;
end;
WM_KEYDOWN:
begin
if not FEnterWithKeyboard then
begin
FEnterWithKeyboard := True;
Invalidate;
end;
I := FindHotKeyItem(Msg.WParam, True);
if (I <> -1) and (FActiveItem = I) then
begin
if FItems[FActiveItem].MenuItem.Count = 0 then
begin
MenuExit;
if FItems[I].MenuItem.GetParentMenu <> nil then
FItems[I].MenuItem.GetParentMenu.DispatchCommand
(FItems[I].MenuItem.Command);
end
else
TrackMenuFromItem;
end
else
case Msg.WParam of
VK_ESCAPE:
MenuExit;
VK_RIGHT:
if FFormHook.Control.BiDiMode = bdRightToLeft then
FindPriorMenuItem(True)
else
FindNextMenuItem(True);
VK_LEFT:
if FFormHook.Control.BiDiMode = bdRightToLeft then
FindNextMenuItem(True)
else
FindPriorMenuItem(True);
VK_RETURN, VK_DOWN:
if FMDIChildSysMenuActive then
begin
MenuExit;
TrackMDIChildSystemMenu;
end
else if FSysMenuActive then
begin
MenuExit;
TrackSystemMenu;
end
else if FActiveItem <> -1 then
begin
if FItems[FActiveItem].MenuItem.Count = 0 then
begin
I := FActiveItem;
MenuExit;
if FItems[I].MenuItem.GetParentMenu <> nil then
FItems[I].MenuItem.GetParentMenu.DispatchCommand
(FItems[I].MenuItem.Command);
end
else
TrackMenuFromItem;
end;
end;
end;
WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN, WM_NCLBUTTONDOWN,
WM_NCRBUTTONDOWN, WM_NCMBUTTONDOWN, WM_LBUTTONUP, WM_RBUTTONUP,
WM_MBUTTONUP, WM_NCLBUTTONUP, WM_NCRBUTTONUP, WM_NCMBUTTONUP,
WM_ACTIVATE, WM_NCACTIVATE, WM_SETFOCUS, WM_KILLFOCUS, WM_CANCELMODE:
begin
FInMenuLoop := False;
FDispatchMessage := True;
end;
else
DispatchMessage(Msg);
end;
until not FInMenuLoop;
if not FMustActivateMenuItem then
MenuExit;
if FDispatchMessage then
DispatchMessage(Msg);
end;
function TFormStyleHook.TMainMenuBarStyleHook.FindFirstMenuItem;
var
I: Integer;
begin
Result := -1;
for I := 0 to FItemCount - 1 do
begin
if FItems[I].MenuItem.Visible and FItems[I].MenuItem.Enabled then
begin
Result := I;
if AUpdateMenu then
begin
FActiveItem := I;
Invalidate;
end;
Break;
end;
end;
end;
function TFormStyleHook.TMainMenuBarStyleHook.FindFirstRightMenuItem;
var
I: Integer;
begin
Result := -1;
for I := FItemCount - 1 downto 0 do
begin
if FItems[I].MenuItem.Visible and FItems[I].MenuItem.Enabled then
begin
Result := I;
if AUpdateMenu then
begin
FActiveItem := I;
Invalidate;
end;
Break;
end;
end;
end;
function TFormStyleHook.TMainMenuBarStyleHook.FindHotKeyItem;
var
I: Integer;
begin
Result := -1;
for I := 0 to FItemCount - 1 do
begin
if FItems[I].MenuItem.Visible and FItems[I].MenuItem.Enabled and
IsAccel(CharCode, FItems[I].MenuItem.Caption) then
begin
Result := I;
if AUpdateMenu then
begin
FActiveItem := I;
Invalidate;
end;
Break;
end;
end;
end;
function TFormStyleHook.TMainMenuBarStyleHook.FindNextMenuItem;
var
I, J: Integer;
begin
Result := -1;
if FActiveItem = -1 then
J := 0
else
J := FActiveItem + 1;
for I := J to FItemCount - 1 do
begin
if FItems[I].MenuItem.Visible and FItems[I].MenuItem.Enabled then
begin
Result := I;
if AUpdateMenu then
begin
FActiveItem := I;
Invalidate;
end;
Break;
end;
end;
if (Result = -1) and not CanTrackSystemMenu then
Result := FindFirstMenuItem(AUpdateMenu)
else if (Result = -1) and CanTrackSystemMenu and not FMenuPush then
begin
if not FSysMenuActive and not FMDIChildSysMenuActive then
begin
FSysMenuActive := True;
FMDIChildSysMenuActive := False;
if AUpdateMenu then
Invalidate;
end
else if CanTrackMDISystemMenu and not FMDIChildSysMenuActive then
begin
FSysMenuActive := False;
FMDIChildSysMenuActive := True;
if AUpdateMenu then
Invalidate;
end
else
begin
FSysMenuActive := False;
FMDIChildSysMenuActive := False;
Result := FindFirstMenuItem(AUpdateMenu);
end;
end
else if (Result = -1) and FMenuPush then
begin
if CanTrackSystemMenu and AUpdateMenu then
begin
MenuExit;
TrackSystemMenu;
end
else if CanTrackMDISystemMenu and AUpdateMenu then
begin
MenuExit;
TrackMDIChildSystemMenu;
end
else if FMenuHook = 0 then
Result := FindFirstMenuItem(AUpdateMenu);
end;
end;
function TFormStyleHook.TMainMenuBarStyleHook.FindPriorMenuItem;
var
I, J: Integer;
begin
Result := -1;
if FActiveItem = -1 then
J := FItemCount
else
J := FActiveItem - 1;
for I := J downto 0 do
begin
if FItems[I].MenuItem.Visible and FItems[I].MenuItem.Enabled then
begin
Result := I;
if AUpdateMenu then
begin
FActiveItem := I;
Invalidate;
end;
Break;
end;
end;
if (Result = -1) and not CanTrackSystemMenu then
Result := FindFirstRightMenuItem(AUpdateMenu)
else if (Result = -1) and CanTrackSystemMenu and not FMenuPush then
begin
if CanTrackMDISystemMenu and not FMDIChildSysMenuActive and not FSysMenuActive
then
begin
FSysMenuActive := False;
FMDIChildSysMenuActive := True;
if AUpdateMenu then
Invalidate;
end
else if not FSysMenuActive then
begin
FSysMenuActive := True;
FMDIChildSysMenuActive := False;
if AUpdateMenu then
Invalidate;
end
else
begin
FSysMenuActive := False;
FMDIChildSysMenuActive := False;
Result := FindFirstRightMenuItem(AUpdateMenu);
end;
end
else if (Result = -1) and FMenuPush then
begin
if CanTrackMDISystemMenu and AUpdateMenu then
begin
MenuExit;
TrackMDIChildSystemMenu;
end
else if CanTrackSystemMenu and AUpdateMenu then
begin
MenuExit;
TrackSystemMenu;
end
else if FMenuHook = 0 then
Result := FindFirstRightMenuItem(AUpdateMenu);
end;
end;
function TFormStyleHook.TMainMenuBarStyleHook.GetTrackMenuPos
(AItem: TMenuBarItem): TPoint;
var
RightPoint: TPoint;
begin
Result := Point(AItem.ItemRect.Left, AItem.ItemRect.Top +
AItem.ItemRect.Height);
Result.X := Result.X + FFormHook.FLeft + FBoundsRect.Left;
Result.Y := Result.Y + FFormHook.FTop + FBoundsRect.Top;
RightPoint := Point(Result.X + AItem.ItemRect.Width, Result.Y);
if Screen.MonitorFromPoint(Result) <> Screen.MonitorFromPoint(RightPoint) then
begin
if FFormHook.Control.BiDiMode <> bdRightToLeft then
Result.X := Screen.MonitorFromPoint(RightPoint).WorkareaRect.Left
else
Result.X := Screen.MonitorFromPoint(Result).WorkareaRect.Right -
AItem.ItemRect.Width - 1;
end;
if FFormHook.Control.BiDiMode = bdRightToLeft then
Result.X := Result.X + AItem.ItemRect.Width;
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.HookMenus;
begin
FSelectFirstItem := True;
FMenuBarHook := Self;
FCurrentMenuItem := nil;
if FMenuHook = 0 then
FMenuHook := SetWindowsHookEx(WH_MSGFILTER, @PopupMenuHook, 0,
GetCurrentThreadID);
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.UnHookMenus;
begin
if FMenuHook <> 0 then
UnhookWindowsHookEx(FMenuHook);
FMenuBarHook := nil;
FCurrentMenuItem := nil;
FMenuHook := 0;
FSelectFirstItem := False;
end;
function TFormStyleHook.TMainMenuBarStyleHook.ItemFromCursorPos: Integer;
var
P: TPoint;
begin
P := Mouse.CursorPos;
P.X := P.X - FFormHook.FLeft - FBoundsRect.Left;
P.Y := P.Y - FFormHook.FTop - FBoundsRect.Top;
Result := ItemFromPoint(P.X, P.Y);
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.MDIChildClose;
begin
if (TFormClass(FFormHook.Form).ActiveMDIChild <> nil) then
SendMessage(TFormClass(FFormHook.Form).ActiveMDIChild.Handle, WM_SYSCOMMAND,
SC_CLOSE, 0);
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.MDIChildRestore;
begin
if (TFormClass(FFormHook.Form).ActiveMDIChild <> nil) then
SendMessage(TFormClass(FFormHook.Form).ActiveMDIChild.Handle, WM_SYSCOMMAND,
SC_RESTORE, 0);
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.MDIChildMinimize;
begin
if (TFormClass(FFormHook.Form).ActiveMDIChild <> nil) then
SendMessage(TFormClass(FFormHook.Form).ActiveMDIChild.Handle, WM_SYSCOMMAND,
SC_MINIMIZE, 0);
end;
function TFormStyleHook.TMainMenuBarStyleHook.MDIButtonFromPoint(X,
Y: Integer): Integer;
var
I: Integer;
begin
Result := -1;
for I := 0 to 2 do
if FMDIButtons[I].ItemRect.Contains(Point(X, Y)) then
Exit(FMDIButtons[I].Index);
end;
function TFormStyleHook.TMainMenuBarStyleHook.ItemFromPoint(X,
Y: Integer): Integer;
var
I: Integer;
begin
Result := -1;
for I := 0 to FItemCount - 1 do
if FItems[I].MenuItem.Visible and FItems[I].MenuItem.Enabled and
FItems[I].ItemRect.Contains(Point(X, Y)) then
Exit(FItems[I].Index);
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.Invalidate;
begin
FFormHook.InvalidateNC;
end;
function TFormStyleHook.TMainMenuBarStyleHook.MainMenu: TMainMenu;
begin
if TFormClass(FFormHook.Form).FormStyle = fsMDIChild then
begin
Result := nil;
Exit;
end;
Result := FFormHook.Form.Menu;
end;
function TFormStyleHook.TMainMenuBarStyleHook.GetMenuHeight
(AWidth: Integer): Integer;
function GetItemCount(AMenu, AChildMenu: TMainMenu): Integer;
procedure Insert(APos: Integer; var ACount: Integer; AItem: TMenuItem);
var
I: Integer;
begin
Inc(ACount);
if APos = ACount - 1 then
FItems[APos].MenuItem := AItem
else
begin
for I := ACount - 1 downto APos + 1 do
FItems[I].MenuItem := FItems[I - 1].MenuItem;
FItems[APos].MenuItem := AItem;
end;
end;
function CanAddItem(AItem: TMenuItem): Boolean;
var
I: Integer;
begin
Result := True;
for I := 0 to AChildMenu.Items.Count - 1 do
if AItem.GroupIndex = AChildMenu.Items[I].GroupIndex then
begin
Result := False;
Break;
end;
end;
var
I, J, Count, Index: Integer;
begin
if AMenu = nil then
Exit(0);
if AChildMenu <> nil then
begin
Count := AMenu.Items.Count + AChildMenu.Items.Count;
SetLength(FItems, Count);
Result := AChildMenu.Items.Count;
{ add items from child menu }
for I := 0 to Result - 1 do
FItems[I].MenuItem := AChildMenu.Items[I];
{ add items from menu }
for I := AMenu.Items.Count - 1 downto 0 do
if CanAddItem(AMenu.Items[I]) then
begin
Index := -1;
for J := 0 to Result - 1 do
if AMenu.Items[I].GroupIndex <= FItems[J].MenuItem.GroupIndex then
begin
Index := J;
Break;
end;
if Index = -1 then
Index := Result;
Insert(Index, Result, AMenu.Items[I]);
end;
end
else
begin
{ add items from menu }
Result := AMenu.Items.Count;
SetLength(FItems, Result);
for I := 0 to Result - 1 do
FItems[I].MenuItem := AMenu.Items[I];
end;
end;
var
Buffer: TBitmap;
I, LHeight: Integer;
LWidth, LButtonWidth: Integer;
LIconDraw: Boolean;
FMenu, FChildMenu: TMainMenu;
begin
Result := GetSystemMetrics(SM_CYMENU);
if MainMenu = nil then
Exit;
if FShowMDIButtons then
LButtonWidth := Result * 3
else
LButtonWidth := 0;
{ get menu }
FMenu := MainMenu;
{ get mdi child menu }
FChildMenu := nil;
if TFormClass(FFormHook.Form).FormStyle = fsMDIForm then
with TFormClass(FFormHook.Form) do
if (ActiveMDIChild <> nil) and (ActiveMDIChild.Menu <> nil) and
(ActiveMDIChild.Menu.Items.Count > 0) and
(ActiveMDIChild.Handle <> FFormHook.FChangeVisibleChildHandle) then
FChildMenu := ActiveMDIChild.Menu;
{ initialize array of items }
FItemCount := GetItemCount(FMenu, FChildMenu);
{ calculation sizes }
Buffer := TBitmap.Create;
try
Buffer.Canvas.Font.Assign(Screen.MenuFont);
LIconDraw := FShowMDIButtons and CanTrackMDISystemMenu;
if LIconDraw then
LHeight := GetSystemMetrics(SM_CYMENU)
else
LHeight := 0;
for I := 0 to FItemCount - 1 do
begin
LWidth := GetMenuItemWidth(FItems[I].MenuItem, Buffer.Canvas);
LHeight := LHeight + LWidth;
if (LHeight > AWidth) and (LHeight <> 0) then
begin
LHeight := LWidth;
Result := Result + GetSystemMetrics(SM_CYMENU);
end;
end;
finally
Buffer.Free;
end;
if (LButtonWidth <> 0) and (LHeight + LButtonWidth > AWidth) then
Result := Result + GetSystemMetrics(SM_CYMENU);
end;
function TFormStyleHook.TMainMenuBarStyleHook.GetMenuItemWidth
(AMenuItem: TMenuItem; ACanvas: TCanvas): Integer;
var
R: TRect;
begin
if (AMenuItem.GetParentMenu = nil) or not AMenuItem.Visible then
Exit(0);
R := Rect(0, 0, 0, 0);
DrawText(ACanvas.Handle, PChar(AMenuItem.Caption), Length(AMenuItem.Caption),
R, DT_CALCRECT);
Result := R.Width + 10;
if (AMenuItem.GetParentMenu.Images <> nil) and (AMenuItem.ImageIndex >= 0) and
(AMenuItem.ImageIndex < AMenuItem.GetParentMenu.Images.Count) then
Result := Result + MainMenu.Images.Width + 6;
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.DrawItem(AItem: TMenuBarItem;
ACanvas: TCanvas);
var
Details: TThemedElementDetails;
SaveIndex: Integer;
LWidth, LHeight: Integer;
R: TRect;
LTextColor: TColor;
ItemMainMenu: TMenu;
LStyle: TCustomStyleServices;
begin
if AItem.MenuItem.GetParentMenu = nil then
Exit;
LStyle := StyleServices;
ItemMainMenu := AItem.MenuItem.GetParentMenu;
{ check item state }
if FActiveItem = AItem.Index then
begin
if FMenuPush then
AItem.State := tmMenuBarItemPushed
else if not FSysMenuActive and not FMDIChildSysMenuActive then
AItem.State := tmMenuBarItemHot
else
AItem.State := tmMenuBarItemNormal;
end
else if AItem.MenuItem.Enabled then
AItem.State := tmMenuBarItemNormal
else
AItem.State := tmMenuBarItemDisabled;
Details := LStyle.GetElementDetails(AItem.State);
{ draw item body }
SaveIndex := SaveDC(ACanvas.Handle);
try
LStyle.DrawElement(ACanvas.Handle, Details, AItem.ItemRect);
finally
RestoreDC(ACanvas.Handle, SaveIndex);
end;
R := AItem.ItemRect;
if FFormHook.Control.BiDiMode <> bdRightToLeft then
Inc(R.Left, 5)
else
Dec(R.Right, 5);
{ draw item image }
if (ItemMainMenu.Images <> nil) and (AItem.MenuItem.ImageIndex >= 0) and
(AItem.MenuItem.ImageIndex < MainMenu.Images.Count) then
begin
if FFormHook.Control.BiDiMode <> bdRightToLeft then
LWidth := R.Left
else
LWidth := R.Right - ItemMainMenu.Images.Width;
LHeight := R.Top + R.Height div 2 - ItemMainMenu.Images.Height div 2;
ImageList_Draw(MainMenu.Images.Handle, AItem.MenuItem.ImageIndex,
ACanvas.Handle, LWidth, LHeight, ILD_TRANSPARENT);
if FFormHook.Control.BiDiMode <> bdRightToLeft then
R.Left := R.Left + ItemMainMenu.Images.Width + 3
else
R.Right := R.Right - ItemMainMenu.Images.Width - 3;
end;
{ draw item text }
if LStyle.GetElementColor(Details, ecTextColor, LTextColor) then
ACanvas.Font.Color := TColor(LTextColor);
if (FMenuPush or FMenuActive) and FEnterWithKeyboard then
DrawText(ACanvas.Handle, PChar(AItem.MenuItem.Caption),
Length(AItem.MenuItem.Caption), R, FFormHook.Control.DrawTextBiDiModeFlags
(DT_LEFT or DT_VCENTER or DT_SINGLELINE))
else
DrawText(ACanvas.Handle, PChar(AItem.MenuItem.Caption),
Length(AItem.MenuItem.Caption), R, FFormHook.Control.DrawTextBiDiModeFlags
(DT_LEFT or DT_VCENTER or DT_HIDEPREFIX or DT_SINGLELINE));
end;
type
TMenuItemClass = class(TMenuItem);
procedure TFormStyleHook.TMainMenuBarStyleHook.Paint(Canvas: TCanvas);
function GetItemCount(AMenu, AMergedMenu: TMainMenu): Integer;
procedure Insert(APos: Integer; var ACount: Integer; AItem: TMenuItem);
var
I: Integer;
begin
Inc(ACount);
if APos = ACount - 1 then
FItems[APos].MenuItem := AItem
else
begin
for I := ACount - 1 downto APos + 1 do
FItems[I].MenuItem := FItems[I - 1].MenuItem;
FItems[APos].MenuItem := AItem;
end;
end;
function CanAddItem(AItem: TMenuItem): Boolean;
var
I: Integer;
begin
Result := True;
for I := 0 to AMergedMenu.Items.Count - 1 do
if AItem.GroupIndex = AMergedMenu.Items[I].GroupIndex then
begin
Result := False;
Break;
end;
end;
var
I, J, Count, Index: Integer;
begin
if AMenu = nil then
Exit(0);
if AMergedMenu <> nil then
begin
Count := AMenu.Items.Count + AMergedMenu.Items.Count;
SetLength(FItems, Count);
Result := AMergedMenu.Items.Count;
{ add items from child menu }
for I := 0 to Result - 1 do
FItems[I].MenuItem := AMergedMenu.Items[I];
{ add items from menu }
for I := AMenu.Items.Count - 1 downto 0 do
if CanAddItem(AMenu.Items[I]) then
begin
Index := -1;
for J := 0 to Result - 1 do
if AMenu.Items[I].GroupIndex <= FItems[J].MenuItem.GroupIndex then
begin
Index := J;
Break;
end;
if Index = -1 then
Index := Result;
Insert(Index, Result, AMenu.Items[I]);
end;
end
else
begin
{ add items from menu }
Result := AMenu.Items.Count;
SetLength(FItems, Result);
for I := 0 to Result - 1 do
FItems[I].MenuItem := AMenu.Items[I];
end;
end;
function IsRightJustify(AMenu: HMenu; AIndex: Integer): Boolean;
var
Info: TMenuItemInfo;
begin
FillChar(Info, SizeOf(Info), 0);
Info.cbSize := SizeOf(TMenuItemInfo);
Info.fMask := MIIM_TYPE;
GetMenuItemInfo(AMenu, FItems[AIndex].MenuItem.Command, False, Info);
Result := Info.fType and MFT_RIGHTJUSTIFY = MFT_RIGHTJUSTIFY;
end;
var
Details: TThemedElementDetails;
Buffer: TBitmap;
FMenu, FMergedMenu: TMainMenu;
I, X, Y, W, BW: Integer;
SaveIndex: Integer;
FIconDraw, FRightAlign: Boolean;
LStyle: TCustomStyleServices;
FMerged: TMenuItem;
RX: Integer;
FPrevIndex: Integer;
begin
if (FBoundsRect.Width = 0) or (FBoundsRect.Height = 0) then
Exit;
LStyle := StyleServices;
if not LStyle.Available then
Exit;
{ get main menu }
FMenu := MainMenu;
if FMenu = nil then
Exit;
{ get merged menu }
FMergedMenu := nil;
FMerged := TMenuItemClass(FFormHook.Form.Menu.Items).Merged;
if (FMerged <> nil) and (FMerged.Count > 0) and
(FMerged.GetParentMenu is TMainMenu) then
FMergedMenu := TMainMenu(FMerged.GetParentMenu);
Buffer := TBitmap.Create;
try
Buffer.SetSize(FBoundsRect.Width, FBoundsRect.Height);
{ draw menu bar }
SaveIndex := SaveDC(Buffer.Canvas.Handle);
try
Details := LStyle.GetElementDetails(tmMenuBarBackgroundActive);
LStyle.DrawElement(Buffer.Canvas.Handle, Details,
Rect(0, 0, Buffer.Width, Buffer.Height));
finally
RestoreDC(Buffer.Canvas.Handle, SaveIndex);
end;
Buffer.Canvas.Font.Assign(Screen.MenuFont);
Buffer.Canvas.Brush.Style := bsClear;
{ draw mdi child icon }
FIconDraw := FShowMDIButtons and CanTrackMDISystemMenu;
if FIconDraw then
DrawIconEx(Buffer.Canvas.Handle, 2, 2, GetIconFast.Handle, 0, 0, 0, 0,
DI_NORMAL);
{ initialize array of items }
FItemCount := GetItemCount(FMenu, FMergedMenu);
{ draw items }
FRightAlign := FFormHook.Control.BiDiMode = bdRightToLeft;
BW := GetSystemMetrics(SM_CYMENU);
Y := 0;
if FShowMDIButtons then
RX := FBoundsRect.Width - BW * 3
else
RX := FBoundsRect.Width;
if not FRightAlign then
begin
if FIconDraw then
X := BW
else
X := 0;
end
else
X := RX;
for I := 0 to FItemCount - 1 do
begin
FItems[I].Index := I;
W := GetMenuItemWidth(FItems[I].MenuItem, Buffer.Canvas);
if W = 0 then
begin
FItems[I].ItemRect := Rect(0, 0, 0, 0);
Continue;
end;
if not FRightAlign then
begin
FItems[I].ItemRect.Left := X;
FItems[I].ItemRect.Right := FItems[I].ItemRect.Left + W;
if (FItems[I].ItemRect.Right > FBoundsRect.Width) and (X <> 0) then
begin
Y := Y + GetSystemMetrics(SM_CYMENU);
FItems[I].ItemRect.Left := 0;
FItems[I].ItemRect.Right := W;
end;
X := FItems[I].ItemRect.Right;
end
else
begin
FItems[I].ItemRect.Left := X - W;
FItems[I].ItemRect.Right := FItems[I].ItemRect.Left + W;
if (FItems[I].ItemRect.Left < 0) and (X <> 0) then
begin
Y := Y + GetSystemMetrics(SM_CYMENU);
if FShowMDIButtons then
FItems[I].ItemRect.Right := FBoundsRect.Width - BW * 3
else
FItems[I].ItemRect.Right := FBoundsRect.Width;
FItems[I].ItemRect.Left := FItems[I].ItemRect.Right - W;
end;
X := FItems[I].ItemRect.Left;
end;
FItems[I].ItemRect.Top := Y;
FItems[I].ItemRect.Bottom := FItems[I].ItemRect.Top +
GetSystemMetrics(SM_CYMENU);
end;
if not FRightAlign then
begin
FPrevIndex := -1;
for I := FItemCount - 1 downto 0 do
if IsRightJustify(FMenu.Handle, I) then
begin
FItems[I].Index := I;
W := FItems[I].ItemRect.Width;
if (W > 0) and
((FPrevIndex = -1) or ((FPrevIndex >= 0) and
(FItems[I].ItemRect.Top = FItems[FPrevIndex].ItemRect.Top))) then
begin
FItems[I].ItemRect.Left := RX - W;
FItems[I].ItemRect.Right := RX;
RX := FItems[I].ItemRect.Left;
FPrevIndex := I;
end;
end;
end;
for I := 0 to FItemCount - 1 do
if FItems[I].ItemRect.Width > 0 then
DrawItem(FItems[I], Buffer.Canvas);
{ draw mdi buttons }
X := Buffer.Width;
Y := Buffer.Height - BW;
if FShowMDIButtons then
begin
for I := 0 to 2 do
begin
FMDIButtons[I].Index := I;
case I of
0:
begin
if (I = FHotMDIButton) and (I = FPressedMDIButton) then
FMDIButtons[I].State := twMDICloseButtonPushed
else if (I = FHotMDIButton) then
FMDIButtons[I].State := twMDICloseButtonHot
else
FMDIButtons[I].State := twMDICloseButtonNormal;
end;
1:
begin
if (I = FHotMDIButton) and (I = FPressedMDIButton) then
FMDIButtons[I].State := twMDIRestoreButtonPushed
else if (I = FHotMDIButton) then
FMDIButtons[I].State := twMDIRestoreButtonHot
else
FMDIButtons[I].State := twMDIRestoreButtonNormal;
end;
2:
begin
if (I = FHotMDIButton) and (I = FPressedMDIButton) then
FMDIButtons[I].State := twMDIMinButtonPushed
else if (I = FHotMDIButton) then
FMDIButtons[I].State := twMDIMinButtonHot
else
FMDIButtons[I].State := twMDIMinButtonNormal;
end;
end;
FMDIButtons[I].ItemRect := Rect(X - BW, Y, X, Y + BW);
Details := LStyle.GetElementDetails(FMDIButtons[I].State);
LStyle.DrawElement(Buffer.Canvas.Handle, Details,
FMDIButtons[I].ItemRect);
X := X - BW;
end;
end;
{ draw buffer }
Canvas.Draw(FBoundsRect.Left, FBoundsRect.Top, Buffer);
finally
Buffer.Free;
end;
end;
class function TFormStyleHook.TMainMenuBarStyleHook.PopupMenuHook(Code: Integer;
WParam: WParam; var Msg: TMsg): LRESULT;
var
FItem: Integer;
FFindItemKind: TFindItemKind;
P: TPoint;
FOldActiveItem: Integer;
I: Integer;
CanFindItem: Boolean;
begin
if (FMenuBarHook = nil) or
((FMenuBarHook <> nil) and (FMenuBarHook.MainMenu = nil)) then
Exit(0);
Result := CallNextHookEx(FMenuBarHook.FMenuHook, Code, WParam, IntPtr(@Msg));
if Result <> 0 then
Exit;
if FMenuBarHook.FSelectFirstItem then
begin
FMenuBarHook.FSelectFirstItem := False;
if not(shMenus in TStyleManager.SystemHooks) and
(Msg.Message <> WM_MENUSELECT) and FMenuBarHook.FEnterWithKeyboard then
PostMessage(Msg.HWND, WM_KEYDOWN, VK_DOWN, 0);
end;
if Code = MSGF_MENU then
case Msg.Message of
WM_MOUSEMOVE:
if (WindowFromPoint(Mouse.CursorPos) = FMenuBarHook.FFormHook.Handle)
and not FMenuBarHook.FMustActivateMenuItem then
begin
P := Mouse.CursorPos;
P.X := P.X - FMenuBarHook.FFormHook.Control.Left -
FMenuBarHook.FBoundsRect.Left;
P.Y := P.Y - FMenuBarHook.FFormHook.Control.Top -
FMenuBarHook.FBoundsRect.Top;
FOldActiveItem := FMenuBarHook.FActiveItem;
FMenuBarHook.MouseMove(P.X, P.Y);
if (FOldActiveItem <> FMenuBarHook.FActiveItem) and
(FMenuBarHook.FActiveItem <> -1) then
begin
P := Mouse.CursorPos;
FMenuBarHook.FMustActivateMenuItem := True;
PostMessage(FMenuBarHook.FFormHook.Handle, WM_NCLBUTTONDOWN,
MK_LBUTTON, Integer(PointToSmallPoint(P)));
// 64-bit safe Integer cast
end;
end;
WM_SYSKEYDOWN:
if Msg.WParam = VK_MENU then
begin
FMenuBarHook.FMustActivateMenuItem := False;
FMenuBarHook.MenuExit;
end;
WM_MENUSELECT:
begin
FFindItemKind := fkCommand;
if (Msg.WParam shr 16) and MF_POPUP <> 0 then
FFindItemKind := fkHandle;
if FFindItemKind = fkHandle then
FItem := GetSubMenu(HMenu(Msg.LParam), LoWord(Msg.WParam))
else
FItem := LoWord(Msg.WParam);
FCurrentMenuItem := FMenuBarHook.FindItem(FItem, FFindItemKind);
end;
WM_KEYDOWN:
begin
if FMenuBarHook.FFormHook.Control.BiDiMode = bdRightToLeft then
begin
if Msg.WParam = VK_RIGHT then
Msg.WParam := VK_LEFT
else if Msg.WParam = VK_LEFT then
Msg.WParam := VK_RIGHT;
end;
CanFindItem := False;
if Msg.WParam = VK_RIGHT then
CanFindItem := FMenuBarHook.CanFindNextItem(FCurrentMenuItem)
else if Msg.WParam = VK_LEFT then
CanFindItem := FMenuBarHook.CanFindPriorItem(FCurrentMenuItem);
case Msg.WParam of
VK_RIGHT:
if CanFindItem then
begin
FMenuBarHook.FEnterWithKeyboard := True;
if FMenuBarHook.FSystemMenuTracking and FMenuBarHook.CanTrackMDISystemMenu
then
begin
P := Mouse.CursorPos;
FMenuBarHook.FMustActivateMDIChildSysMenu := True;
EndMenu;
PostMessage(FMenuBarHook.FFormHook.Handle, WM_NCLBUTTONDOWN,
MK_LBUTTON, Integer(PointToSmallPoint(P)));
// 64-bit safe Integer cast
Exit;
end
else if not FMenuBarHook.FSystemMenuTracking then
I := FMenuBarHook.FindNextMenuItem(False)
else
I := FMenuBarHook.FindFirstMenuItem(False);
if I <> -1 then
begin
FMenuBarHook.FActiveItem := I;
P := Mouse.CursorPos;
FMenuBarHook.FMustActivateMenuItem := True;
EndMenu;
PostMessage(FMenuBarHook.FFormHook.Handle, WM_NCLBUTTONDOWN,
MK_LBUTTON, Integer(PointToSmallPoint(P)));
end
else if not FMenuBarHook.FSystemMenuTracking then
begin
P := Mouse.CursorPos;
FMenuBarHook.FMustActivateSysMenu := True;
EndMenu;
PostMessage(FMenuBarHook.FFormHook.Handle, WM_NCLBUTTONDOWN,
MK_LBUTTON, Integer(PointToSmallPoint(P)));
// 64-bit safe Integer cast
end;
end;
VK_LEFT:
if CanFindItem then
begin
FMenuBarHook.FEnterWithKeyboard := True;
if FMenuBarHook.FMDIChildSystemMenuTracking then
I := -1
else if not FMenuBarHook.FSystemMenuTracking then
I := FMenuBarHook.FindPriorMenuItem(False)
else
I := FMenuBarHook.FindFirstRightMenuItem(False);
if I <> -1 then
begin
FMenuBarHook.FActiveItem := I;
P := Mouse.CursorPos;
FMenuBarHook.FMustActivateMenuItem := True;
EndMenu;
PostMessage(FMenuBarHook.FFormHook.Handle, WM_NCLBUTTONDOWN,
MK_LBUTTON, Integer(PointToSmallPoint(P)));
// 64-bit safe Integer cast
end
else if FMenuBarHook.CanTrackMDISystemMenu and not FMenuBarHook.FMDIChildSystemMenuTracking
then
begin
P := Mouse.CursorPos;
FMenuBarHook.FMustActivateMDIChildSysMenu := True;
EndMenu;
PostMessage(FMenuBarHook.FFormHook.Handle, WM_NCLBUTTONDOWN,
MK_LBUTTON, Integer(PointToSmallPoint(P)));
// 64-bit safe Integer cast
end
else if not FMenuBarHook.FSystemMenuTracking then
begin
P := Mouse.CursorPos;
FMenuBarHook.FMustActivateSysMenu := True;
EndMenu;
PostMessage(FMenuBarHook.FFormHook.Handle, WM_NCLBUTTONDOWN,
MK_LBUTTON, Integer(PointToSmallPoint(P)));
// 64-bit safe Integer cast
end;
end;
end;
end;
end;
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.SetBoundsRect
(const ABoundsRect: TRect);
begin
FBoundsRect := ABoundsRect;
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.MouseUp(X, Y: Integer);
begin
FActiveItem := ItemFromPoint(X, Y);
if FActiveItem <> -1 then
begin
Invalidate;
if FItems[FActiveItem].MenuItem.Count = 0 then
MainMenu.DispatchCommand(FItems[FActiveItem].MenuItem.Command);
end;
if FShowMDIButtons then
begin
FHotMDIButton := MDIButtonFromPoint(X, Y);
if (FHotMDIButton <> -1) and (FPressedMDIButton = FHotMDIButton) then
begin
FPressedMDIButton := -1;
Invalidate;
case FMDIButtons[FHotMDIButton].Index of
0:
MDIChildClose;
1:
MDIChildRestore;
2:
MDIChildMinimize;
end;
end
else
FPressedMDIButton := -1;
end;
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.MouseDown(X, Y: Integer);
begin
FActiveItem := ItemFromPoint(X, Y);
if FActiveItem <> -1 then
MenuEnter(True)
else
begin
if FShowMDIButtons and CanTrackMDISystemMenu and
Rect(0, 0, GetSystemMetrics(SM_CYMENU), GetSystemMetrics(SM_CYMENU))
.Contains(Point(X, Y)) then
TrackMDIChildSystemMenu;
end;
if FShowMDIButtons then
begin
FHotMDIButton := MDIButtonFromPoint(X, Y);
FPressedMDIButton := FHotMDIButton;
if FPressedMDIButton <> -1 then
Invalidate;
end;
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.MouseMove(X, Y: Integer);
begin
if FMustActivateMenuItem or ((FOldCursorPos = Mouse.CursorPos) and
(FMenuActive or FMenuPush)) then
Exit;
FOldCursorPos := Mouse.CursorPos;
FMouseInMainMenu := not((X < 0) or (Y < 0));
if FMenuPush then
begin
if ItemFromPoint(X, Y) <> -1 then
FActiveItem := ItemFromPoint(X, Y);
end
else
FActiveItem := ItemFromPoint(X, Y);
if FActiveItem <> FOldActiveItem then
begin
Invalidate;
FOldActiveItem := FActiveItem;
if FMenuPush and (FMenuHook = 0) and
(FItems[FActiveItem].MenuItem.Count <> 0) then
TrackMenuFromItem;
end;
if FShowMDIButtons then
begin
FHotMDIButton := MDIButtonFromPoint(X, Y);
if FHotMDIButton <> FOldMDIHotButton then
begin
Invalidate;
FOldMDIHotButton := FHotMDIButton;
end;
if FHotMDIButton = -1 then
FPressedMDIButton := -1;
end;
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.TrackMDIChildSystemMenu;
var
X, Y: Integer;
Child: TCustomForm;
P: TPoint;
R: TRect;
begin
FMDIChildSysMenuActive := False;
FSysMenuActive := False;
if TFormClass(FFormHook.Form).FormStyle <> fsMDIForm then
Exit;
Child := TFormClass(FFormHook.Form).ActiveMDIChild;
if Child = nil then
Exit;
FMDIChildSystemMenuTracking := True;
if Child.WindowState = wsMaximized then
begin
X := FFormHook.FLeft + FBoundsRect.Left;
Y := FFormHook.FTop + FBoundsRect.Bottom;
end
else
begin
P := FFormHook.Control.ClientToScreen(Point(0, 0));
R := FFormHook.GetMDIWorkArea;
X := P.X + R.Left + Child.Left + FBoundsRect.Left;
Y := P.Y + R.Top + Child.Top + FBoundsRect.Top;
end;
HookMenus;
SendMessage(Child.Handle, $313, 0, MakeLong(X, Y));
UnHookMenus;
FMDIChildSystemMenuTracking := False;
Invalidate;
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.TrackSystemMenu;
var
X, Y: Integer;
LeftPoint, RightPoint: TPoint;
begin
FMDIChildSysMenuActive := False;
FSysMenuActive := False;
FSystemMenuTracking := True;
X := FFormHook.FLeft + FBoundsRect.Left;
Y := FFormHook.FTop + FBoundsRect.Top;
LeftPoint := Point(X, Y);
RightPoint := Point(X + 50, Y);
if Screen.MonitorFromPoint(LeftPoint) <> Screen.MonitorFromPoint(RightPoint)
then
X := Screen.MonitorFromPoint(RightPoint).WorkareaRect.Left;
HookMenus;
SendMessage(FFormHook.Handle, $313, 0, MakeLong(X, Y));
UnHookMenus;
FSystemMenuTracking := False;
Invalidate;
end;
procedure TFormStyleHook.TMainMenuBarStyleHook.TrackMenuFromItem;
var
P: TPoint;
Cmd: Bool;
FItem: TMenuItem;
begin
FMDIChildSysMenuActive := False;
FSysMenuActive := False;
FMenuPush := True;
Invalidate;
if FItems[FActiveItem].MenuItem.Count = 0 then
Exit;
P := GetTrackMenuPos(FItems[FActiveItem]);
HookMenus;
if FFormHook.Control.BiDiMode <> bdRightToLeft then
Cmd := TrackPopupMenu(FItems[FActiveItem].MenuItem.Handle, TPM_LEFTBUTTON or
TPM_RIGHTBUTTON or TPM_RETURNCMD or TPM_NOANIMATION, P.X, P.Y, 0,
FFormHook.Handle, nil)
else
Cmd := TrackPopupMenu(FItems[FActiveItem].MenuItem.Handle, TPM_LEFTBUTTON or
TPM_RIGHTBUTTON or TPM_RETURNCMD or TPM_NOANIMATION or TPM_RIGHTALIGN,
P.X, P.Y, 0, FFormHook.Handle, nil);
UnHookMenus;
FMenuPush := False;
if Cmd then
begin
FItem := FindItem(IntPtr(Cmd), fkCommand);
if FItem <> nil then
FItem.GetParentMenu.DispatchCommand(FItem.Command)
else
PostMessage(FFormHook.Handle, WM_COMMAND, WParam(Cmd), 0);
MenuExit;
end
else if not FMustActivateMenuItem then
begin
FMenuActive := True;
FInMenuLoop := False;
ProcessMenuLoop(False);
end;
Invalidate;
end;
{$IFEND}
end.