mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-29 19:02:52 +02:00
win32: draw popup menu in Vista style on vista/w7
git-svn-id: trunk@20606 -
This commit is contained in:
parent
d4702f28d9
commit
a7eca7b2d5
@ -1540,7 +1540,8 @@ begin
|
|||||||
begin
|
begin
|
||||||
DrawMenuItem(TMenuItem(menuItem), PDrawItemStruct(LParam)^._hDC,
|
DrawMenuItem(TMenuItem(menuItem), PDrawItemStruct(LParam)^._hDC,
|
||||||
PDrawItemStruct(LParam)^.rcItem,
|
PDrawItemStruct(LParam)^.rcItem,
|
||||||
PDrawItemStruct(LParam)^.itemState and ODS_SELECTED <> 0);
|
PDrawItemStruct(LParam)^.itemState and ODS_SELECTED <> 0,
|
||||||
|
PDrawItemStruct(LParam)^.itemState and ODS_NOACCEL <> 0);
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ type
|
|||||||
FThemeData: TThemeData; // Holds a list of theme data handles.
|
FThemeData: TThemeData; // Holds a list of theme data handles.
|
||||||
protected
|
protected
|
||||||
function GetTheme(Element: TThemedElement): HTHEME;
|
function GetTheme(Element: TThemedElement): HTHEME;
|
||||||
property Theme[Element: TThemedElement]: HTHEME read GetTheme;
|
|
||||||
function InitThemes: Boolean; override;
|
function InitThemes: Boolean; override;
|
||||||
procedure UnloadThemeData; override;
|
procedure UnloadThemeData; override;
|
||||||
function UseThemes: Boolean; override;
|
function UseThemes: Boolean; override;
|
||||||
@ -58,6 +57,7 @@ type
|
|||||||
function ContentRect(DC: HDC; Details: TThemedElementDetails; BoundingRect: TRect): TRect; override;
|
function ContentRect(DC: HDC; Details: TThemedElementDetails; BoundingRect: TRect): TRect; override;
|
||||||
function HasTransparentParts(Details: TThemedElementDetails): Boolean; override;
|
function HasTransparentParts(Details: TThemedElementDetails): Boolean; override;
|
||||||
procedure PaintBorder(Control: TObject; EraseLRCorner: Boolean); override;
|
procedure PaintBorder(Control: TObject; EraseLRCorner: Boolean); override;
|
||||||
|
property Theme[Element: TThemedElement]: HTHEME read GetTheme;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
@ -38,7 +38,7 @@ uses
|
|||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
WSMenus, WSLCLClasses, WSProc,
|
WSMenus, WSLCLClasses, WSProc,
|
||||||
Windows, Controls, Classes, SysUtils, Win32Int, Win32Proc, Win32WSImgList,
|
Windows, Controls, Classes, SysUtils, Win32Int, Win32Proc, Win32WSImgList,
|
||||||
InterfaceBase, LCLProc, Themes;
|
InterfaceBase, LCLProc, Themes, Win32UxTheme, TmSchema, Win32Themes;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
@ -79,10 +79,11 @@ type
|
|||||||
class procedure Popup(const APopupMenu: TPopupMenu; const X, Y: integer); override;
|
class procedure Popup(const APopupMenu: TPopupMenu; const X, Y: integer); override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function MenuItemSize(aMenuItem: TMenuItem; aHDC: HDC): TSize;
|
function MenuItemSize(AMenuItem: TMenuItem; AHDC: HDC): TSize;
|
||||||
procedure DrawMenuItem(const aMenuItem: TMenuItem; const aHDC: HDC; const aRect: Windows.RECT; const aSelected: boolean);
|
procedure DrawMenuItem(const AMenuItem: TMenuItem; const AHDC: HDC; const ARect: Windows.RECT; const ASelected, ANoAccel: boolean);
|
||||||
function FindMenuItemAccelerator(const ACharCode: char; const AMenuHandle: HMENU): integer;
|
function FindMenuItemAccelerator(const ACharCode: char; const AMenuHandle: HMENU): integer;
|
||||||
|
procedure DrawMenuItemIcon(const AMenuItem: TMenuItem; const AHDC: HDC;
|
||||||
|
const ImageRect: TRect; const ASelected: Boolean);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
@ -104,6 +105,24 @@ const
|
|||||||
MF_ENABLED
|
MF_ENABLED
|
||||||
);
|
);
|
||||||
|
|
||||||
|
PopupItemStates: array[{ Enabled } Boolean, { Selected } Boolean] of TThemedMenu =
|
||||||
|
(
|
||||||
|
(tmPopupItemDisabled, tmPopupItemDisabledHot),
|
||||||
|
(tmPopupItemNormal, tmPopupItemHot)
|
||||||
|
);
|
||||||
|
|
||||||
|
PopupCheckBgStates: array[{ Enabled } Boolean] of TThemedMenu =
|
||||||
|
(
|
||||||
|
tmPopupCheckBackgroundDisabled,
|
||||||
|
tmPopupCheckBackgroundNormal
|
||||||
|
);
|
||||||
|
|
||||||
|
PopupCheckStates: array[{ Enabled } Boolean, { RadioItem } Boolean] of TThemedMenu =
|
||||||
|
(
|
||||||
|
(tmPopupCheckMarkDisabled, tmPopupBulletDisabled),
|
||||||
|
(tmPopupCheckMarkNormal, tmPopupBulletNormal)
|
||||||
|
);
|
||||||
|
|
||||||
var
|
var
|
||||||
menuiteminfosize : DWORD = 0;
|
menuiteminfosize : DWORD = 0;
|
||||||
|
|
||||||
@ -111,6 +130,20 @@ type
|
|||||||
TCaptionFlags = (cfBold, cfUnderline);
|
TCaptionFlags = (cfBold, cfUnderline);
|
||||||
TCaptionFlagsSet = set of TCaptionFlags;
|
TCaptionFlagsSet = set of TCaptionFlags;
|
||||||
|
|
||||||
|
// metrics for vista drawing
|
||||||
|
TVistaMenuMetrics = record
|
||||||
|
ItemMargins: TMargins;
|
||||||
|
CheckSize: TSize;
|
||||||
|
CheckMargins: TMargins;
|
||||||
|
CheckBgMargins: TMargins;
|
||||||
|
GutterSize: TSize;
|
||||||
|
SubMenuSize: TSize;
|
||||||
|
TextSize: TSize;
|
||||||
|
TextMargins: TMargins;
|
||||||
|
ShortCustSize: TSize;
|
||||||
|
SeparatorSize: TSize;
|
||||||
|
end;
|
||||||
|
|
||||||
(* Returns index of the character in the menu item caption that is displayed
|
(* Returns index of the character in the menu item caption that is displayed
|
||||||
as underlined and is therefore the hot key of the menu item.
|
as underlined and is therefore the hot key of the menu item.
|
||||||
If the caption does not contain any underlined character, 0 is returned.
|
If the caption does not contain any underlined character, 0 is returned.
|
||||||
@ -164,34 +197,36 @@ begin
|
|||||||
else Result := MakeLResult(0, 0);
|
else Result := MakeLResult(0, 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function GetMenuItemFont(const aFlags: TCaptionFlagsSet): HFONT;
|
function GetMenuItemFont(const AFlags: TCaptionFlagsSet): HFONT;
|
||||||
var
|
var
|
||||||
lf: LOGFONT;
|
lf: LOGFONT;
|
||||||
ncm: NONCLIENTMETRICS;
|
ncm: NONCLIENTMETRICS;
|
||||||
begin
|
begin
|
||||||
ncm.cbSize:= sizeof(ncm);
|
ncm.cbSize := sizeof(ncm);
|
||||||
if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), @ncm, 0) then
|
if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), @ncm, 0) then
|
||||||
lf:= ncm.lfMenuFont
|
lf := ncm.lfMenuFont
|
||||||
else
|
else
|
||||||
GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), @lf);
|
GetObject(GetStockObject(DEFAULT_GUI_FONT), SizeOf(LOGFONT), @lf);
|
||||||
if cfUnderline in aFlags then lf.lfUnderline := 1
|
if cfUnderline in AFlags then
|
||||||
else lf.lfUnderline := 0;
|
lf.lfUnderline := 1
|
||||||
if cfBold in aFlags then
|
else
|
||||||
|
lf.lfUnderline := 0;
|
||||||
|
if cfBold in AFlags then
|
||||||
begin
|
begin
|
||||||
if lf.lfWeight<=400 then
|
if lf.lfWeight <= 400 then
|
||||||
lf.lfWeight:= lf.lfWeight + 300
|
lf.lfWeight := lf.lfWeight + 300
|
||||||
else
|
else
|
||||||
lf.lfWeight:= lf.lfWeight + 100;
|
lf.lfWeight := lf.lfWeight + 100;
|
||||||
end;
|
end;
|
||||||
Result := CreateFontIndirect(@lf);
|
Result := CreateFontIndirect(@lf);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
(* Get the menu item caption including shortcut *)
|
(* Get the menu item caption including shortcut *)
|
||||||
function CompleteMenuItemCaption(const aMenuItem: TMenuItem): string;
|
function CompleteMenuItemCaption(const AMenuItem: TMenuItem): string;
|
||||||
begin
|
begin
|
||||||
Result := aMenuItem.Caption;
|
Result := AMenuItem.Caption;
|
||||||
if aMenuItem.shortCut <> scNone then
|
if AMenuItem.ShortCut <> scNone then
|
||||||
Result := Result + ShortCutToText(aMenuItem.shortCut);
|
Result := Result + ' ' + ShortCutToText(AMenuItem.ShortCut);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
(* Get the maximum length of the given string in pixels *)
|
(* Get the maximum length of the given string in pixels *)
|
||||||
@ -206,7 +241,7 @@ var
|
|||||||
{$endif WindowsUnicodeSupport}
|
{$endif WindowsUnicodeSupport}
|
||||||
begin
|
begin
|
||||||
FillChar(tmpRect, SizeOf(tmpRect), 0);
|
FillChar(tmpRect, SizeOf(tmpRect), 0);
|
||||||
newFont := getMenuItemFont(aDecoration);
|
newFont := GetMenuItemFont(aDecoration);
|
||||||
oldFont := SelectObject(aHDC, newFont);
|
oldFont := SelectObject(aHDC, newFont);
|
||||||
{$ifdef WindowsUnicodeSupport}
|
{$ifdef WindowsUnicodeSupport}
|
||||||
if UnicodeEnabledOS then
|
if UnicodeEnabledOS then
|
||||||
@ -300,35 +335,262 @@ begin
|
|||||||
Result := (aMenuItemHeight - anElementHeight) div 2;
|
Result := (aMenuItemHeight - anElementHeight) div 2;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function MenuItemSize(aMenuItem: TMenuItem; aHDC: HDC): TSize;
|
function IsVistaMenu: Boolean; inline;
|
||||||
|
begin
|
||||||
|
Result := ThemeServices.ThemesAvailable and (WindowsVersion >= wvVista) and
|
||||||
|
(TWin32ThemeServices(ThemeServices).Theme[teMenu] <> 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetVistaMenuMetrics(const AMenuItem: TMenuItem; DC: HDC): TVistaMenuMetrics;
|
||||||
|
var
|
||||||
|
Theme: HTHEME;
|
||||||
|
TextRect: TRect;
|
||||||
|
W: WideString;
|
||||||
|
AFont, OldFont: HFONT;
|
||||||
|
begin
|
||||||
|
Theme := TWin32ThemeServices(ThemeServices).Theme[teMenu];
|
||||||
|
GetThemeMargins(Theme, 0, MENU_POPUPITEM, 0, TMT_CONTENTMARGINS, nil, Result.ItemMargins);
|
||||||
|
GetThemePartSize(Theme, 0, MENU_POPUPCHECK, 0, nil, TS_TRUE, Result.CheckSize);
|
||||||
|
GetThemeMargins(Theme, 0, MENU_POPUPCHECK, 0, TMT_CONTENTMARGINS, nil, Result.CheckMargins);
|
||||||
|
GetThemeMargins(Theme, 0, MENU_POPUPCHECKBACKGROUND, 0, TMT_CONTENTMARGINS, nil, Result.CheckBgMargins);
|
||||||
|
GetThemePartSize(Theme, 0, MENU_POPUPGUTTER, 0, nil, TS_TRUE, Result.GutterSize);
|
||||||
|
GetThemePartSize(Theme, 0, MENU_POPUPSUBMENU, 0, nil, TS_TRUE, Result.SubMenuSize);
|
||||||
|
|
||||||
|
if AMenuItem.IsLine then
|
||||||
|
begin
|
||||||
|
GetThemePartSize(Theme, 0, MENU_POPUPSEPARATOR, 0, nil, TS_TRUE, Result.SeparatorSize);
|
||||||
|
FillChar(Result.TextMargins, SizeOf(Result.TextMargins), 0);
|
||||||
|
FillChar(Result.TextSize, SizeOf(Result.TextSize), 0);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result.TextMargins := Result.ItemMargins;
|
||||||
|
GetThemeInt(Theme, MENU_POPUPITEM, 0, TMT_BORDERSIZE, Result.TextMargins.cxRightWidth);
|
||||||
|
GetThemeInt(Theme, MENU_POPUPBACKGROUND, 0, TMT_BORDERSIZE, Result.TextMargins.cxLeftWidth);
|
||||||
|
|
||||||
|
if AMenuItem.Default then
|
||||||
|
begin
|
||||||
|
AFont := GetMenuItemFont([cfBold]);
|
||||||
|
OldFont := SelectObject(DC, AFont);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
OldFont := 0;
|
||||||
|
|
||||||
|
W := UTF8ToUTF16(CompleteMenuItemCaption(AMenuItem));
|
||||||
|
GetThemeTextExtent(Theme, DC, MENU_POPUPITEM, 0, PWideChar(W), Length(W),
|
||||||
|
DT_SINGLELINE or DT_LEFT or DT_EXPANDTABS, nil, TextRect);
|
||||||
|
Result.TextSize.cx := TextRect.Right - TextRect.Left;
|
||||||
|
Result.TextSize.cy := TextRect.Bottom - TextRect.Top;
|
||||||
|
|
||||||
|
if AMenuItem.ShortCut <> scNone then
|
||||||
|
begin;
|
||||||
|
W := UTF8ToUTF16(ShortCutToText(AMenuItem.ShortCut));
|
||||||
|
GetThemeTextExtent(Theme, DC, MENU_POPUPITEM, 0, PWideChar(W), Length(W),
|
||||||
|
DT_SINGLELINE or DT_LEFT, nil, TextRect);
|
||||||
|
Result.ShortCustSize.cx := TextRect.Right - TextRect.Left;
|
||||||
|
Result.ShortCustSize.cy := TextRect.Bottom - TextRect.Top;
|
||||||
|
end;
|
||||||
|
if OldFont <> 0 then
|
||||||
|
DeleteObject(SelectObject(DC, OldFont));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function VistaPopupMenuItemSize(AMenuItem: TMenuItem; ADC: HDC): TSize;
|
||||||
|
var
|
||||||
|
Metrics: TVistaMenuMetrics;
|
||||||
|
begin
|
||||||
|
Metrics := GetVistaMenuMetrics(AMenuItem, ADC);
|
||||||
|
// count check
|
||||||
|
Result.cx := Metrics.CheckSize.cx + Metrics.CheckMargins.cxRightWidth + Metrics.CheckMargins.cxLeftWidth;
|
||||||
|
if AMenuItem.IsLine then
|
||||||
|
begin
|
||||||
|
Result.cx := Result.cx + Metrics.SeparatorSize.cx + Metrics.ItemMargins.cxLeftWidth + Metrics.ItemMargins.cxRightWidth;
|
||||||
|
Result.cy := Metrics.SeparatorSize.cy + Metrics.ItemMargins.cyTopHeight + Metrics.ItemMargins.cyBottomHeight;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result.cy := Metrics.CheckSize.cy + Metrics.CheckMargins.cyTopHeight + Metrics.CheckMargins.cyBottomHeight;
|
||||||
|
if AMenuItem.HasIcon then
|
||||||
|
begin
|
||||||
|
Result.cy := Max(Result.cy, AMenuItem.GetIconSize.y);
|
||||||
|
Result.cx := Max(Result.cx, AMenuItem.GetIconSize.x);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
// count gutter
|
||||||
|
Result.cx := Result.cx + (Metrics.CheckBgMargins.cxRightWidth - Metrics.CheckMargins.cxRightWidth) +
|
||||||
|
Metrics.GutterSize.cx;
|
||||||
|
// count text
|
||||||
|
Result.cx := Result.cx + Metrics.TextSize.cx;
|
||||||
|
Result.cx := Result.cx + Metrics.TextMargins.cxLeftWidth + Metrics.TextMargins.cxRightWidth;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawVistaPopupMenu(const AMenuItem: TMenuItem; const AHDC: HDC; const ARect: TRect; const ASelected, ANoAccel: boolean);
|
||||||
|
var
|
||||||
|
Details, Tmp: TThemedElementDetails;
|
||||||
|
Metrics: TVistaMenuMetrics;
|
||||||
|
CheckRect, GutterRect, TextRect, SeparatorRect, ImageRect: TRect;
|
||||||
|
IconSize: TPoint;
|
||||||
|
TextFlags: DWord;
|
||||||
|
AFont, OldFont: HFONT;
|
||||||
|
IsRightToLeft: Boolean;
|
||||||
|
begin
|
||||||
|
Metrics := GetVistaMenuMetrics(AMenuItem, AHDC);
|
||||||
|
// draw backgound
|
||||||
|
Details := ThemeServices.GetElementDetails(PopupItemStates[AMenuItem.Enabled, ASelected]);
|
||||||
|
if ThemeServices.HasTransparentParts(Details) then
|
||||||
|
begin
|
||||||
|
Tmp := ThemeServices.GetElementDetails(tmPopupBackground);
|
||||||
|
ThemeServices.DrawElement(AHDC, Tmp, ARect, nil);
|
||||||
|
end;
|
||||||
|
IsRightToLeft := AMenuItem.GetIsRightToLeft;
|
||||||
|
// calc check/image rect
|
||||||
|
CheckRect := ARect;
|
||||||
|
if IsRightToLeft then
|
||||||
|
CheckRect.left := CheckRect.Right - Metrics.CheckSize.cx - Metrics.CheckMargins.cxRightWidth - Metrics.CheckMargins.cxLeftWidth
|
||||||
|
else
|
||||||
|
CheckRect.Right := CheckRect.Left + Metrics.CheckSize.cx + Metrics.CheckMargins.cxRightWidth + Metrics.CheckMargins.cxLeftWidth;
|
||||||
|
CheckRect.Bottom := CheckRect.Top + Metrics.CheckSize.cy + Metrics.CheckMargins.cyTopHeight + Metrics.CheckMargins.cyBottomHeight;
|
||||||
|
// draw gutter
|
||||||
|
GutterRect := CheckRect;
|
||||||
|
if IsRightToLeft then
|
||||||
|
begin
|
||||||
|
GutterRect.Right := GutterRect.Left - Metrics.CheckBgMargins.cxRightWidth + Metrics.CheckMargins.cxRightWidth;
|
||||||
|
GutterRect.Left := GutterRect.Right - Metrics.GutterSize.cx;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
GutterRect.Left := GutterRect.Right + Metrics.CheckBgMargins.cxRightWidth - Metrics.CheckMargins.cxRightWidth;
|
||||||
|
GutterRect.Right := GutterRect.Left + Metrics.GutterSize.cx;
|
||||||
|
end;
|
||||||
|
Tmp := ThemeServices.GetElementDetails(tmPopupGutter);
|
||||||
|
ThemeServices.DrawElement(AHDC, Tmp, GutterRect, nil);
|
||||||
|
// draw menu item
|
||||||
|
ThemeServices.DrawElement(AHDC, Details, ARect, nil);
|
||||||
|
|
||||||
|
if AMenuItem.IsLine then
|
||||||
|
begin
|
||||||
|
// draw separator
|
||||||
|
if IsRightToLeft then
|
||||||
|
begin
|
||||||
|
SeparatorRect.Left := GutterRect.Left - Metrics.ItemMargins.cxLeftWidth;
|
||||||
|
SeparatorRect.Right := ARect.Left - Metrics.ItemMargins.cxRightWidth;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
SeparatorRect.Left := GutterRect.Right + Metrics.ItemMargins.cxLeftWidth;
|
||||||
|
SeparatorRect.Right := ARect.Right - Metrics.ItemMargins.cxRightWidth;
|
||||||
|
end;
|
||||||
|
SeparatorRect.Top := ARect.Top + Metrics.ItemMargins.cyTopHeight;
|
||||||
|
SeparatorRect.Bottom := ARect.Bottom - Metrics.ItemMargins.cyBottomHeight;
|
||||||
|
Tmp := ThemeServices.GetElementDetails(tmPopupSeparator);
|
||||||
|
ThemeServices.DrawElement(AHDC, Tmp, SeparatorRect, nil);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// draw check/image
|
||||||
|
if AMenuItem.HasIcon then
|
||||||
|
begin
|
||||||
|
ImageRect := CheckRect;
|
||||||
|
IconSize := AMenuItem.GetIconSize;
|
||||||
|
ImageRect.Left := (ImageRect.Left + ImageRect.Right - IconSize.x) div 2;
|
||||||
|
ImageRect.Top := (ImageRect.Top + ImageRect.Bottom - IconSize.y) div 2;
|
||||||
|
ImageRect.Right := IconSize.x;
|
||||||
|
ImageRect.Bottom := IconSize.y;
|
||||||
|
DrawMenuItemIcon(AMenuItem, AHDC, ImageRect, ASelected);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if AMenuItem.Checked then
|
||||||
|
begin
|
||||||
|
Tmp := ThemeServices.GetElementDetails(PopupCheckBgStates[AMenuItem.Enabled]);
|
||||||
|
ThemeServices.DrawElement(AHDC, Tmp, CheckRect, nil);
|
||||||
|
Tmp := ThemeServices.GetElementDetails(PopupCheckStates[AMenuItem.Enabled, AMenuItem.RadioItem]);
|
||||||
|
ThemeServices.DrawElement(AHDC, Tmp, CheckRect, nil);
|
||||||
|
end;
|
||||||
|
// draw text
|
||||||
|
TextRect := GutterRect;
|
||||||
|
if IsRightToLeft then
|
||||||
|
begin
|
||||||
|
TextRect.Right := TextRect.Left - Metrics.TextMargins.cxLeftWidth;
|
||||||
|
TextRect.Left := ARect.Left + Metrics.TextMargins.cxRightWidth;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
TextRect.Left := TextRect.Right + Metrics.TextMargins.cxLeftWidth;
|
||||||
|
TextRect.Right := ARect.Right - Metrics.TextMargins.cxRightWidth;
|
||||||
|
end;
|
||||||
|
TextRect.Top := (TextRect.Top + TextRect.Bottom - Metrics.TextSize.cy) div 2;
|
||||||
|
TextRect.Bottom := TextRect.Top + Metrics.TextSize.cy;
|
||||||
|
TextFlags := DT_SINGLELINE or DT_EXPANDTABS;
|
||||||
|
// todo: distinct UseRightToLeftAlignment and UseRightToLeftReading
|
||||||
|
if IsRightToLeft then
|
||||||
|
TextFlags := TextFlags or DT_RIGHT or DT_RTLREADING
|
||||||
|
else
|
||||||
|
TextFlags := TextFlags or DT_LEFT;
|
||||||
|
if ANoAccel then
|
||||||
|
TextFlags := TextFlags or DT_HIDEPREFIX;
|
||||||
|
if AMenuItem.Default then
|
||||||
|
begin
|
||||||
|
AFont := GetMenuItemFont([cfBold]);
|
||||||
|
OldFont := SelectObject(AHDC, AFont);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
OldFont := 0;
|
||||||
|
ThemeServices.DrawText(AHDC, Details, AMenuItem.Caption, TextRect, TextFlags, 0);
|
||||||
|
if AMenuItem.ShortCut <> scNone then
|
||||||
|
begin
|
||||||
|
if IsRightToLeft then
|
||||||
|
begin
|
||||||
|
TextRect.Right := TextRect.Left + Metrics.ShortCustSize.cx;
|
||||||
|
TextFlags := TextFlags xor DT_RIGHT or DT_LEFT;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
TextRect.Left := TextRect.Right - Metrics.ShortCustSize.cx;
|
||||||
|
TextFlags := TextFlags xor DT_LEFT or DT_RIGHT;
|
||||||
|
end;
|
||||||
|
ThemeServices.DrawText(AHDC, Details, ShortCutToText(AMenuItem.ShortCut), TextRect, TextFlags, 0);
|
||||||
|
end;
|
||||||
|
if OldFont <> 0 then
|
||||||
|
DeleteObject(SelectObject(AHDC, OldFont));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function MenuItemSize(AMenuItem: TMenuItem; AHDC: HDC): TSize;
|
||||||
var
|
var
|
||||||
decoration: TCaptionFlagsSet;
|
decoration: TCaptionFlagsSet;
|
||||||
minimumHeight: Integer;
|
minimumHeight: Integer;
|
||||||
begin
|
begin
|
||||||
if aMenuItem.Default then
|
// TODO: vista menubar
|
||||||
|
if IsVistaMenu and not AMenuItem.IsInMenuBar then
|
||||||
|
begin
|
||||||
|
Result := VistaPopupMenuItemSize(AMenuItem, AHDC);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if AMenuItem.Default then
|
||||||
decoration := [cfBold]
|
decoration := [cfBold]
|
||||||
else
|
else
|
||||||
decoration := [];
|
decoration := [];
|
||||||
|
|
||||||
Result := StringSize(CompleteMenuItemCaption(aMenuItem), aHDC, decoration);
|
Result := StringSize(CompleteMenuItemCaption(AMenuItem), AHDC, decoration);
|
||||||
inc(Result.cx, LeftCaptionPosition(aMenuItem));
|
inc(Result.cx, LeftCaptionPosition(AMenuItem));
|
||||||
|
|
||||||
if not aMenuItem.IsInMenuBar then
|
if not AMenuItem.IsInMenuBar then
|
||||||
inc(Result.cx, SpaceBetweenIcons)
|
inc(Result.cx, SpaceBetweenIcons)
|
||||||
else
|
else
|
||||||
dec(Result.cx, SpaceBetweenIcons);
|
dec(Result.cx, SpaceBetweenIcons);
|
||||||
|
|
||||||
if (aMenuItem.ShortCut <> scNone) then
|
if (AMenuItem.ShortCut <> scNone) then
|
||||||
Inc(Result.cx, SpaceBetweenIcons);
|
Inc(Result.cx, SpaceBetweenIcons);
|
||||||
|
|
||||||
minimumHeight := GetSystemMetrics(SM_CYMENU);
|
minimumHeight := GetSystemMetrics(SM_CYMENU);
|
||||||
if not aMenuItem.IsInMenuBar then
|
if not AMenuItem.IsInMenuBar then
|
||||||
Dec(minimumHeight, 2);
|
Dec(minimumHeight, 2);
|
||||||
if aMenuItem.IsLine then
|
if AMenuItem.IsLine then
|
||||||
Result.cy := 10 // it is a separator
|
Result.cy := 10 // it is a separator
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
if aMenuItem.hasIcon then
|
if AMenuItem.hasIcon then
|
||||||
Result.cy := Max(Result.cy, aMenuItem.GetIconSize.y);
|
Result.cy := Max(Result.cy, aMenuItem.GetIconSize.y);
|
||||||
Inc(Result.cy, 2);
|
Inc(Result.cy, 2);
|
||||||
if Result.cy < minimumHeight then
|
if Result.cy < minimumHeight then
|
||||||
@ -449,12 +711,12 @@ begin
|
|||||||
else
|
else
|
||||||
decoration := [];
|
decoration := [];
|
||||||
|
|
||||||
newFont := getMenuItemFont(decoration);
|
newFont := GetMenuItemFont(decoration);
|
||||||
oldFont := SelectObject(aHDC, newFont);
|
oldFont := SelectObject(aHDC, newFont);
|
||||||
IsRightToLeft := aMenuItem.GetIsRightToLeft;
|
IsRightToLeft := aMenuItem.GetIsRightToLeft;
|
||||||
|
|
||||||
etoFlags := ETO_OPAQUE;
|
etoFlags := ETO_OPAQUE;
|
||||||
dtFlags := 0;
|
dtFlags := DT_EXPANDTABS;
|
||||||
if IsRightToLeft then
|
if IsRightToLeft then
|
||||||
begin
|
begin
|
||||||
etoFlags := etoFlags or ETO_RTLREADING;
|
etoFlags := etoFlags or ETO_RTLREADING;
|
||||||
@ -527,73 +789,89 @@ begin
|
|||||||
DeleteObject(newFont);
|
DeleteObject(newFont);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure DrawMenuItemIcon(const aMenuItem: TMenuItem; const aHDC: HDC;
|
procedure DrawMenuItemIcon(const AMenuItem: TMenuItem; const AHDC: HDC;
|
||||||
const aRect: Windows.RECT; const aSelected, aChecked: boolean);
|
const ImageRect: TRect; const ASelected: Boolean);
|
||||||
var
|
var
|
||||||
x: Integer;
|
|
||||||
AEffect: TGraphicsDrawEffect;
|
AEffect: TGraphicsDrawEffect;
|
||||||
AImageList: TCustomImageList;
|
AImageList: TCustomImageList;
|
||||||
FreeImageList: Boolean;
|
FreeImageList: Boolean;
|
||||||
AImageIndex: Integer;
|
AImageIndex: Integer;
|
||||||
ImageRect: TRect;
|
|
||||||
begin
|
begin
|
||||||
AImageList := aMenuItem.GetImageList;
|
AImageList := AMenuItem.GetImageList;
|
||||||
if AImageList = nil then
|
if AImageList = nil then
|
||||||
begin
|
begin
|
||||||
AImageList := TImageList.Create(nil);
|
AImageList := TImageList.Create(nil);
|
||||||
AImageList.Width := aMenuItem.Bitmap.Width; // maybe height to prevent too wide bitmaps?
|
AImageList.Width := AMenuItem.Bitmap.Width; // maybe height to prevent too wide bitmaps?
|
||||||
AImageList.Height := aMenuItem.Bitmap.Height;
|
AImageList.Height := AMenuItem.Bitmap.Height;
|
||||||
AImageIndex := AImageList.Add(aMenuItem.Bitmap, nil);
|
AImageIndex := AImageList.Add(AMenuItem.Bitmap, nil);
|
||||||
FreeImageList := True;
|
FreeImageList := True;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
FreeImageList := False;
|
FreeImageList := False;
|
||||||
AImageIndex := aMenuItem.ImageIndex;
|
AImageIndex := AMenuItem.ImageIndex;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if not aMenuItem.Enabled then
|
if not AMenuItem.Enabled then
|
||||||
AEffect := gdeDisabled
|
AEffect := gdeDisabled
|
||||||
else
|
else
|
||||||
if aSelected then
|
if ASelected then
|
||||||
AEffect := gdeHighlighted
|
AEffect := gdeHighlighted
|
||||||
else
|
else
|
||||||
AEffect := gdeNormal;
|
AEffect := gdeNormal;
|
||||||
|
|
||||||
if aMenuItem.GetIsRightToLeft then
|
|
||||||
x := aRect.Right - AImageList.Width - spaceBetweenIcons
|
|
||||||
else
|
|
||||||
x := aRect.Left + spaceBetweenIcons;
|
|
||||||
|
|
||||||
ImageRect := Rect(x, aRect.top + TopPosition(aRect.bottom - aRect.top, AImageList.Height),
|
|
||||||
AImageList.Width, AImageList.Height);
|
|
||||||
|
|
||||||
if aChecked then // draw rectangle around
|
|
||||||
begin
|
|
||||||
FrameRect(aHDC,
|
|
||||||
Rect(ImageRect.Left - 1, ImageRect.Top - 1, ImageRect.Left + ImageRect.Right + 1, ImageRect.Top + ImageRect.Bottom + 1),
|
|
||||||
GetSysColorBrush(COLOR_HIGHLIGHT));
|
|
||||||
end;
|
|
||||||
|
|
||||||
if AImageIndex < AImageList.Count then
|
if AImageIndex < AImageList.Count then
|
||||||
TWin32WSCustomImageList.DrawToDC(AImageList, AImageIndex, aHDC,
|
TWin32WSCustomImageList.DrawToDC(AImageList, AImageIndex, AHDC,
|
||||||
ImageRect, AImageList.BkColor, AImageList.BlendColor,
|
ImageRect, AImageList.BkColor, AImageList.BlendColor,
|
||||||
AEffect, AImageList.DrawingStyle, AImageList.ImageType);
|
AEffect, AImageList.DrawingStyle, AImageList.ImageType);
|
||||||
if FreeImageList then
|
if FreeImageList then
|
||||||
AImageList.Free;
|
AImageList.Free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure DrawMenuItem(const aMenuItem: TMenuItem; const aHDC: HDC; const aRect: Windows.RECT; const aSelected: boolean);
|
procedure DrawClassicMenuItemIcon(const AMenuItem: TMenuItem; const AHDC: HDC;
|
||||||
|
const ARect: TRect; const ASelected, AChecked: boolean);
|
||||||
|
var
|
||||||
|
x: Integer;
|
||||||
|
ImageRect: TRect;
|
||||||
|
IconSize: TPoint;
|
||||||
begin
|
begin
|
||||||
|
IconSize := AMenuItem.GetIconSize;
|
||||||
|
if AMenuItem.GetIsRightToLeft then
|
||||||
|
x := ARect.Right - IconSize.x - spaceBetweenIcons
|
||||||
|
else
|
||||||
|
x := ARect.Left + spaceBetweenIcons;
|
||||||
|
|
||||||
|
ImageRect := Rect(x, ARect.top + TopPosition(ARect.Bottom - ARect.Top, IconSize.y),
|
||||||
|
IconSize.x, IconSize.y);
|
||||||
|
|
||||||
|
if AChecked then // draw rectangle around
|
||||||
|
begin
|
||||||
|
FrameRect(aHDC,
|
||||||
|
Rect(ImageRect.Left - 1, ImageRect.Top - 1, ImageRect.Left + ImageRect.Right + 1, ImageRect.Top + ImageRect.Bottom + 1),
|
||||||
|
GetSysColorBrush(COLOR_HIGHLIGHT));
|
||||||
|
end;
|
||||||
|
|
||||||
|
DrawMenuItemIcon(AMenuItem, AHDC, ImageRect, ASelected);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawMenuItem(const AMenuItem: TMenuItem; const AHDC: HDC; const ARect: Windows.RECT; const ASelected, ANoAccel: boolean);
|
||||||
|
begin
|
||||||
|
// TODO: vista menubar
|
||||||
|
if IsVistaMenu and not AMenuItem.IsInMenuBar then
|
||||||
|
begin
|
||||||
|
DrawVistaPopupMenu(AMenuItem, AHDC, ARect, ASelected, ANoAccel);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
if aMenuItem.IsLine then
|
if aMenuItem.IsLine then
|
||||||
DrawSeparator(aHDC, aRect)
|
DrawSeparator(AHDC, ARect)
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
DrawMenuItemText(aMenuItem, aHDC, aRect, aSelected);
|
DrawMenuItemText(AMenuItem, AHDC, ARect, ASelected);
|
||||||
if aMenuItem.hasIcon then
|
if aMenuItem.HasIcon then
|
||||||
DrawMenuItemIcon(aMenuItem, aHDC, aRect, aSelected, aMenuItem.Checked) else
|
DrawClassicMenuItemIcon(AMenuItem, AHDC, ARect, ASelected, AMenuItem.Checked) else
|
||||||
if aMenuItem.Checked then
|
if AMenuItem.Checked then
|
||||||
DrawMenuItemCheckMark(aMenuItem, aHDC, aRect, aSelected);
|
DrawMenuItemCheckMark(AMenuItem, AHDC, ARect, ASelected);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user