mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-26 11:17:57 +08:00
1147 lines
36 KiB
ObjectPascal
1147 lines
36 KiB
ObjectPascal
|
|
{*****************************************************************************}
|
|
{ }
|
|
{ Tnt Delphi Unicode Controls }
|
|
{ http://www.tntware.com/delphicontrols/unicode/ }
|
|
{ Version: 2.3.0 }
|
|
{ }
|
|
{ Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) }
|
|
{ }
|
|
{*****************************************************************************}
|
|
|
|
unit TntMenus;
|
|
|
|
{$INCLUDE compilers.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Classes, Menus, Graphics, Messages;
|
|
|
|
type
|
|
{TNT-WARN TMenuItem}
|
|
TTntMenuItem = class(TMenuItem{TNT-ALLOW TMenuItem})
|
|
private
|
|
FIgnoreMenuChanged: Boolean;
|
|
FCaption: WideString;
|
|
FHint: WideString;
|
|
FKeyboardLayout: HKL;
|
|
function GetCaption: WideString;
|
|
procedure SetInheritedCaption(const Value: AnsiString);
|
|
procedure SetCaption(const Value: WideString);
|
|
function IsCaptionStored: Boolean;
|
|
procedure UpdateMenuString(ParentMenu: TMenu);
|
|
function GetAlignmentDrawStyle: Word;
|
|
function MeasureItemTextWidth(ACanvas: TCanvas; const Text: WideString): Integer;
|
|
function GetHint: WideString;
|
|
procedure SetInheritedHint(const Value: AnsiString);
|
|
procedure SetHint(const Value: WideString);
|
|
function IsHintStored: Boolean;
|
|
protected
|
|
procedure DefineProperties(Filer: TFiler); override;
|
|
function GetActionLinkClass: TMenuActionLinkClass; override;
|
|
procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override;
|
|
procedure MenuChanged(Rebuild: Boolean); override;
|
|
procedure AdvancedDrawItem(ACanvas: TCanvas; ARect: TRect;
|
|
State: TOwnerDrawState; TopLevel: Boolean); override;
|
|
procedure DoDrawText(ACanvas: TCanvas; const ACaption: WideString;
|
|
var Rect: TRect; Selected: Boolean; Flags: Integer);
|
|
procedure MeasureItem(ACanvas: TCanvas; var Width, Height: Integer); override;
|
|
public
|
|
procedure InitiateAction; override;
|
|
procedure Loaded; override;
|
|
function Find(ACaption: WideString): TMenuItem{TNT-ALLOW TMenuItem};
|
|
published
|
|
property Caption: WideString read GetCaption write SetCaption stored IsCaptionStored;
|
|
property Hint: WideString read GetHint write SetHint stored IsHintStored;
|
|
end;
|
|
|
|
{TNT-WARN TMainMenu}
|
|
TTntMainMenu = class(TMainMenu{TNT-ALLOW TMainMenu})
|
|
protected
|
|
procedure DoChange(Source: TMenuItem{TNT-ALLOW TMenuItem}; Rebuild: Boolean); override;
|
|
public
|
|
{$IFDEF COMPILER_9_UP}
|
|
function CreateMenuItem: TMenuItem{TNT-ALLOW TMenuItem}; override;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{TNT-WARN TPopupMenu}
|
|
TTntPopupMenu = class(TPopupMenu{TNT-ALLOW TPopupMenu})
|
|
protected
|
|
procedure DoChange(Source: TMenuItem{TNT-ALLOW TMenuItem}; Rebuild: Boolean); override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
{$IFDEF COMPILER_9_UP}
|
|
function CreateMenuItem: TMenuItem{TNT-ALLOW TMenuItem}; override;
|
|
{$ENDIF}
|
|
destructor Destroy; override;
|
|
procedure Popup(X, Y: Integer); override;
|
|
end;
|
|
|
|
{TNT-WARN NewSubMenu}
|
|
function WideNewSubMenu(const ACaption: WideString; hCtx: THelpContext;
|
|
const AName: TComponentName; const Items: array of TTntMenuItem;
|
|
AEnabled: Boolean): TTntMenuItem;
|
|
{TNT-WARN NewItem}
|
|
function WideNewItem(const ACaption: WideString; AShortCut: TShortCut;
|
|
AChecked, AEnabled: Boolean; AOnClick: TNotifyEvent; hCtx: THelpContext;
|
|
const AName: TComponentName): TTntMenuItem;
|
|
|
|
function MessageToShortCut(Msg: TWMKeyDown): TShortCut;
|
|
|
|
{TNT-WARN ShortCutToText}
|
|
function WideShortCutToText(WordShortCut: Word): WideString;
|
|
{TNT-WARN TextToShortCut}
|
|
function WideTextToShortCut(Text: WideString): TShortCut;
|
|
{TNT-WARN GetHotKey}
|
|
function WideGetHotkey(const Text: WideString): WideString;
|
|
{TNT-WARN StripHotkey}
|
|
function WideStripHotkey(const Text: WideString): WideString;
|
|
{TNT-WARN AnsiSameCaption}
|
|
function WideSameCaption(const Text1, Text2: WideString): Boolean;
|
|
|
|
function WideGetMenuItemCaption(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): WideString;
|
|
function WideGetMenuItemHint(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): WideString;
|
|
|
|
procedure NoOwnerDrawTopLevelItems(Menu: TMainMenu{TNT-ALLOW TMainMenu});
|
|
|
|
procedure FixMenuBiDiProblem(Menu: TMenu);
|
|
|
|
function MenuItemHasBitmap(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): Boolean;
|
|
|
|
type
|
|
TTntPopupList = class(TPopupList)
|
|
private
|
|
SavedPopupList: TPopupList;
|
|
protected
|
|
procedure WndProc(var Message: TMessage); override;
|
|
end;
|
|
|
|
var
|
|
TntPopupList: TTntPopupList;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Forms, SysUtils, Consts, ActnList, ImgList, TntControls, TntGraphics,
|
|
TntActnList, TntClasses, TntForms, TntSysUtils, TntWindows;
|
|
|
|
function WideNewSubMenu(const ACaption: WideString; hCtx: THelpContext;
|
|
const AName: TComponentName; const Items: array of TTntMenuItem;
|
|
AEnabled: Boolean): TTntMenuItem;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := TTntMenuItem.Create(nil);
|
|
for I := Low(Items) to High(Items) do
|
|
Result.Add(Items[I]);
|
|
Result.Caption := ACaption;
|
|
Result.HelpContext := hCtx;
|
|
Result.Name := AName;
|
|
Result.Enabled := AEnabled;
|
|
end;
|
|
|
|
function WideNewItem(const ACaption: WideString; AShortCut: TShortCut;
|
|
AChecked, AEnabled: Boolean; AOnClick: TNotifyEvent; hCtx: THelpContext;
|
|
const AName: TComponentName): TTntMenuItem;
|
|
begin
|
|
Result := TTntMenuItem.Create(nil);
|
|
with Result do
|
|
begin
|
|
Caption := ACaption;
|
|
ShortCut := AShortCut;
|
|
OnClick := AOnClick;
|
|
HelpContext := hCtx;
|
|
Checked := AChecked;
|
|
Enabled := AEnabled;
|
|
Name := AName;
|
|
end;
|
|
end;
|
|
|
|
function MessageToShortCut(Msg: TWMKeyDown): TShortCut;
|
|
var
|
|
ShiftState: TShiftState;
|
|
begin
|
|
ShiftState := Forms.KeyDataToShiftState(TWMKeyDown(Msg).KeyData);
|
|
Result := Menus.ShortCut(TWMKeyDown(Msg).CharCode, ShiftState);
|
|
end;
|
|
|
|
function WideGetSpecialName(WordShortCut: Word): WideString;
|
|
var
|
|
ScanCode: Integer;
|
|
KeyName: array[0..255] of WideChar;
|
|
begin
|
|
Assert(Win32PlatformIsUnicode);
|
|
Result := '';
|
|
ScanCode := MapVirtualKeyW(WordRec(WordShortCut).Lo, 0) shl 16;
|
|
if ScanCode <> 0 then
|
|
begin
|
|
GetKeyNameTextW(ScanCode, KeyName, SizeOf(KeyName));
|
|
Result := KeyName;
|
|
end;
|
|
end;
|
|
|
|
function WideGetKeyboardChar(Key: Word): WideChar;
|
|
var
|
|
LatinNumChar: WideChar;
|
|
begin
|
|
Assert(Win32PlatformIsUnicode);
|
|
Result := WideChar(MapVirtualKeyW(Key, 2));
|
|
if (Key in [$30..$39]) then
|
|
begin
|
|
// Check to see if "0" - "9" can be used if all that differs is shift state
|
|
LatinNumChar := WideChar(Key - $30 + Ord('0'));
|
|
if (Result <> LatinNumChar)
|
|
and (Byte(Key) = WordRec(VkKeyScanW(LatinNumChar)).Lo) then // .Hi would be the shift state
|
|
Result := LatinNumChar;
|
|
end;
|
|
end;
|
|
|
|
function WideShortCutToText(WordShortCut: Word): WideString;
|
|
var
|
|
Name: WideString;
|
|
begin
|
|
if (not Win32PlatformIsUnicode)
|
|
or (WordRec(WordShortCut).Lo in [$08..$09 {BKSP, TAB}, $0D {ENTER}, $1B {ESC}, $20..$28 {Misc Nav},
|
|
$2D..$2E {INS, DEL}, $70..$87 {F1 - F24}])
|
|
then
|
|
Result := ShortCutToText{TNT-ALLOW ShortCutToText}(WordShortCut)
|
|
else begin
|
|
case WordRec(WordShortCut).Lo of
|
|
$30..$39: Name := WideGetKeyboardChar(WordRec(WordShortCut).Lo); {1-9,0}
|
|
$41..$5A: Name := WideGetKeyboardChar(WordRec(WordShortCut).Lo); {A-Z}
|
|
$60..$69: Name := WideGetKeyboardChar(WordRec(WordShortCut).Lo); {numpad 1-9,0}
|
|
else
|
|
Name := WideGetSpecialName(WordShortCut);
|
|
end;
|
|
if Name <> '' then
|
|
begin
|
|
Result := '';
|
|
if WordShortCut and scShift <> 0 then Result := Result + SmkcShift;
|
|
if WordShortCut and scCtrl <> 0 then Result := Result + SmkcCtrl;
|
|
if WordShortCut and scAlt <> 0 then Result := Result + SmkcAlt;
|
|
Result := Result + Name;
|
|
end
|
|
else Result := '';
|
|
end;
|
|
end;
|
|
|
|
{ This function is *very* slow. Use sparingly. Return 0 if no VK code was
|
|
found for the text }
|
|
|
|
function WideTextToShortCut(Text: WideString): TShortCut;
|
|
|
|
{ If the front of Text is equal to Front then remove the matching piece
|
|
from Text and return True, otherwise return False }
|
|
|
|
function CompareFront(var Text: WideString; const Front: WideString): Boolean;
|
|
begin
|
|
Result := (Pos(Front, Text) = 1);
|
|
if Result then
|
|
Delete(Text, 1, Length(Front));
|
|
end;
|
|
|
|
var
|
|
Key: TShortCut;
|
|
Shift: TShortCut;
|
|
begin
|
|
Result := 0;
|
|
Shift := 0;
|
|
while True do
|
|
begin
|
|
if CompareFront(Text, SmkcShift) then Shift := Shift or scShift
|
|
else if CompareFront(Text, '^') then Shift := Shift or scCtrl
|
|
else if CompareFront(Text, SmkcCtrl) then Shift := Shift or scCtrl
|
|
else if CompareFront(Text, SmkcAlt) then Shift := Shift or scAlt
|
|
else Break;
|
|
end;
|
|
if Text = '' then Exit;
|
|
for Key := $08 to $255 do { Copy range from table in ShortCutToText }
|
|
if WideSameText(Text, WideShortCutToText(Key)) then
|
|
begin
|
|
Result := Key or Shift;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
function WideGetHotkeyPos(const Text: WideString): Integer;
|
|
var
|
|
I, L: Integer;
|
|
begin
|
|
Result := 0;
|
|
I := 1;
|
|
L := Length(Text);
|
|
while I <= L do
|
|
begin
|
|
if (Text[I] = cHotkeyPrefix) and (L - I >= 1) then
|
|
begin
|
|
Inc(I);
|
|
if Text[I] <> cHotkeyPrefix then
|
|
Result := I; // this might not be the last
|
|
end;
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
|
|
function WideGetHotkey(const Text: WideString): WideString;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I := WideGetHotkeyPos(Text);
|
|
if I = 0 then
|
|
Result := ''
|
|
else
|
|
Result := Text[I];
|
|
end;
|
|
|
|
function WideStripHotkey(const Text: WideString): WideString;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := Text;
|
|
I := 1;
|
|
while I <= Length(Result) do
|
|
begin
|
|
if Result[I] = cHotkeyPrefix then
|
|
if SysLocale.FarEast
|
|
and ((I > 1) and (Length(Result) - I >= 2)
|
|
and (Result[I - 1] = '(') and (Result[I + 2] = ')')) then begin
|
|
Delete(Result, I - 1, 4);
|
|
Dec(I, 2);
|
|
end else
|
|
Delete(Result, I, 1);
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
|
|
function WideSameCaption(const Text1, Text2: WideString): Boolean;
|
|
begin
|
|
Result := WideSameText(WideStripHotkey(Text1), WideStripHotkey(Text2));
|
|
end;
|
|
|
|
function WideSameCaptionStr(const Text1, Text2: WideString): Boolean;
|
|
begin
|
|
Result := WideSameStr(WideStripHotkey(Text1), WideStripHotkey(Text2));
|
|
end;
|
|
|
|
function WideGetMenuItemCaption(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): WideString;
|
|
begin
|
|
if MenuItem is TTntMenuItem then
|
|
Result := TTntMenuItem(MenuItem).Caption
|
|
else
|
|
Result := MenuItem.Caption;
|
|
end;
|
|
|
|
function WideGetMenuItemHint(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): WideString;
|
|
begin
|
|
if MenuItem is TTntMenuItem then
|
|
Result := TTntMenuItem(MenuItem).Hint
|
|
else
|
|
Result := MenuItem.Hint;
|
|
end;
|
|
|
|
procedure NoOwnerDrawTopLevelItems(Menu: TMainMenu{TNT-ALLOW TMainMenu});
|
|
{If top-level items are created as owner-drawn, they will not appear as raised
|
|
buttons when the mouse hovers over them. The VCL will often create top-level
|
|
items as owner-drawn even when they don't need to be (owner-drawn state can be
|
|
set on an item-by-item basis). This routine turns off the owner-drawn flag for
|
|
top-level items if it appears unnecessary}
|
|
|
|
function ItemHasValidImage(Item: TMenuItem{TNT-ALLOW TMenuItem}): boolean;
|
|
var
|
|
Images: TCustomImageList;
|
|
begin
|
|
Assert(Item <> nil, 'TNT Internal Error: ItemHasValidImage: item = nil');
|
|
Images := Item.GetImageList;
|
|
Result := (Assigned(Images) and (Item.ImageIndex >= 0) and (Item.ImageIndex < Images.Count))
|
|
or (MenuItemHasBitmap(Item) and (not Item.Bitmap.Empty))
|
|
end;
|
|
|
|
var
|
|
HM: HMenu;
|
|
i: integer;
|
|
Info: TMenuItemInfoA;
|
|
Item: TMenuItem{TNT-ALLOW TMenuItem};
|
|
Win98Plus: boolean;
|
|
begin
|
|
if Assigned(Menu) then begin
|
|
Win98Plus:= (Win32MajorVersion > 4)
|
|
or((Win32MajorVersion = 4) and (Win32MinorVersion > 0));
|
|
if not Win98Plus then
|
|
Exit; {exit if Windows 95 or NT 4.0}
|
|
HM:= Menu.Handle;
|
|
Info.cbSize:= sizeof(Info);
|
|
for i := 0 to GetMenuItemCount(HM) - 1 do begin
|
|
Info.fMask:= MIIM_FTYPE or MIIM_ID;
|
|
if not GetMenuItemInfo(HM, i, true, Info) then
|
|
Break;
|
|
if Info.fType and MFT_OWNERDRAW <> 0 then begin
|
|
Item:= Menu.FindItem(Info.wID, fkCommand);
|
|
if not Assigned(Item) then
|
|
continue;
|
|
if Assigned(Item.OnDrawItem)
|
|
or Assigned(Item.OnAdvancedDrawItem)
|
|
or ItemHasValidImage(Item) then
|
|
Continue;
|
|
Info.fMask:= MIIM_FTYPE or MIIM_STRING;
|
|
Info.fType:= (Info.fType and not MFT_OWNERDRAW) or MFT_STRING;
|
|
if Win32PlatformIsUnicode and (Item is TTntMenuItem) then begin
|
|
// Unicode
|
|
TMenuItemInfoW(Info).dwTypeData:= PWideChar(TTntMenuItem(Item).Caption);
|
|
SetMenuItemInfoW(HM, i, true, TMenuItemInfoW(Info));
|
|
end else begin
|
|
// Ansi
|
|
Info.dwTypeData:= PAnsiChar(Item.Caption);
|
|
SetMenuItemInfoA(HM, i, true, Info);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TTntMenuItem's utility procs }
|
|
|
|
procedure SyncHotKeyPosition(const Source: WideString; var Dest: WideString);
|
|
var
|
|
I: Integer;
|
|
FarEastHotString: WideString;
|
|
begin
|
|
if (AnsiString(Source) <> AnsiString(Dest))
|
|
and WideSameCaptionStr(AnsiString(Source), AnsiString(Dest)) then begin
|
|
// when reduced to ansi, the only difference is hot key positions
|
|
Dest := WideStripHotkey(Dest);
|
|
I := 1;
|
|
while I <= Length(Source) do
|
|
begin
|
|
if Source[I] = cHotkeyPrefix then begin
|
|
if SysLocale.FarEast
|
|
and ((I > 1) and (Length(Source) - I >= 2)
|
|
and (Source[I - 1] = '(') and (Source[I + 2] = ')')) then begin
|
|
FarEastHotString := Copy(Source, I - 1, 4);
|
|
Dec(I);
|
|
Insert(FarEastHotString, Dest, I);
|
|
Inc(I, 3);
|
|
end else begin
|
|
Insert(cHotkeyPrefix, Dest, I);
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
Inc(I);
|
|
end;
|
|
// test work
|
|
if AnsiString(Source) <> AnsiString(Dest) then
|
|
raise ETntInternalError.CreateFmt('Internal Error: SyncHotKeyPosition Failed ("%s" <> "%s").',
|
|
[AnsiString(Source), AnsiString(Dest)]);
|
|
end;
|
|
end;
|
|
|
|
procedure UpdateMenuItems(Items: TMenuItem{TNT-ALLOW TMenuItem}; ParentMenu: TMenu);
|
|
var
|
|
i: integer;
|
|
begin
|
|
if (Items.ComponentState * [csReading, csDestroying] = []) then begin
|
|
for i := Items.Count - 1 downto 0 do
|
|
UpdateMenuItems(Items[i], ParentMenu);
|
|
if Items is TTntMenuItem then
|
|
TTntMenuItem(Items).UpdateMenuString(ParentMenu);
|
|
end;
|
|
end;
|
|
|
|
procedure FixMenuBiDiProblem(Menu: TMenu);
|
|
var
|
|
i: integer;
|
|
begin
|
|
// TMenu sometimes sets bidi on first visible item which can convert caption to ansi
|
|
if (SysLocale.MiddleEast)
|
|
and (Menu <> nil)
|
|
and (Menu.Items.Count > 0) then
|
|
begin
|
|
for i := 0 to Menu.Items.Count - 1 do begin
|
|
if Menu.Items[i].Visible then begin
|
|
if (Menu.Items[i] is TTntMenuItem) then
|
|
(Menu.Items[i] as TTntMenuItem).UpdateMenuString(Menu);
|
|
break; // found first visible menu item!
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
{$IFDEF COMPILER_6} // verified against VCL source in Delphi 6 and BCB 6
|
|
type
|
|
THackMenuItem = class(TComponent)
|
|
protected
|
|
FxxxxCaption: Ansistring;
|
|
FxxxxHandle: HMENU;
|
|
FxxxxChecked: Boolean;
|
|
FxxxxEnabled: Boolean;
|
|
FxxxxDefault: Boolean;
|
|
FxxxxAutoHotkeys: TMenuItemAutoFlag;
|
|
FxxxxAutoLineReduction: TMenuItemAutoFlag;
|
|
FxxxxRadioItem: Boolean;
|
|
FxxxxVisible: Boolean;
|
|
FxxxxGroupIndex: Byte;
|
|
FxxxxImageIndex: TImageIndex;
|
|
FxxxxActionLink: TMenuActionLink{TNT-ALLOW TMenuActionLink};
|
|
FxxxxBreak: TMenuBreak;
|
|
FBitmap: TBitmap;
|
|
FxxxxCommand: Word;
|
|
FxxxxHelpContext: THelpContext;
|
|
FxxxxHint: AnsiString;
|
|
FxxxxItems: TList;
|
|
FxxxxShortCut: TShortCut;
|
|
FxxxxParent: TMenuItem{TNT-ALLOW TMenuItem};
|
|
FMerged: TMenuItem{TNT-ALLOW TMenuItem};
|
|
FMergedWith: TMenuItem{TNT-ALLOW TMenuItem};
|
|
end;
|
|
{$ENDIF}
|
|
{$IFDEF DELPHI_7} // verified against VCL source in Delphi 7
|
|
type
|
|
THackMenuItem = class(TComponent)
|
|
protected
|
|
FxxxxCaption: AnsiString;
|
|
FxxxxHandle: HMENU;
|
|
FxxxxChecked: Boolean;
|
|
FxxxxEnabled: Boolean;
|
|
FxxxxDefault: Boolean;
|
|
FxxxxAutoHotkeys: TMenuItemAutoFlag;
|
|
FxxxxAutoLineReduction: TMenuItemAutoFlag;
|
|
FxxxxRadioItem: Boolean;
|
|
FxxxxVisible: Boolean;
|
|
FxxxxGroupIndex: Byte;
|
|
FxxxxImageIndex: TImageIndex;
|
|
FxxxxActionLink: TMenuActionLink{TNT-ALLOW TMenuActionLink};
|
|
FxxxxBreak: TMenuBreak;
|
|
FBitmap: TBitmap;
|
|
FxxxxCommand: Word;
|
|
FxxxxHelpContext: THelpContext;
|
|
FxxxxHint: AnsiString;
|
|
FxxxxItems: TList;
|
|
FxxxxShortCut: TShortCut;
|
|
FxxxxParent: TMenuItem{TNT-ALLOW TMenuItem};
|
|
FMerged: TMenuItem{TNT-ALLOW TMenuItem};
|
|
FMergedWith: TMenuItem{TNT-ALLOW TMenuItem};
|
|
end;
|
|
{$ENDIF}
|
|
{$IFDEF DELPHI_9} // verified against VCL source in Delphi 9
|
|
type
|
|
THackMenuItem = class(TComponent)
|
|
protected
|
|
FxxxxCaption: AnsiString;
|
|
FxxxxHandle: HMENU;
|
|
FxxxxChecked: Boolean;
|
|
FxxxxEnabled: Boolean;
|
|
FxxxxDefault: Boolean;
|
|
FxxxxAutoHotkeys: TMenuItemAutoFlag;
|
|
FxxxxAutoLineReduction: TMenuItemAutoFlag;
|
|
FxxxxRadioItem: Boolean;
|
|
FxxxxVisible: Boolean;
|
|
FxxxxGroupIndex: Byte;
|
|
FxxxxImageIndex: TImageIndex;
|
|
FxxxxActionLink: TMenuActionLink{TNT-ALLOW TMenuActionLink};
|
|
FxxxxBreak: TMenuBreak;
|
|
FBitmap: TBitmap;
|
|
FxxxxCommand: Word;
|
|
FxxxxHelpContext: THelpContext;
|
|
FxxxxHint: AnsiString;
|
|
FxxxxItems: TList;
|
|
FxxxxShortCut: TShortCut;
|
|
FxxxxParent: TMenuItem{TNT-ALLOW TMenuItem};
|
|
FMerged: TMenuItem{TNT-ALLOW TMenuItem};
|
|
FMergedWith: TMenuItem{TNT-ALLOW TMenuItem};
|
|
end;
|
|
{$ENDIF}
|
|
{$IFDEF DELPHI_10} // verified against VCL source in Delphi 10
|
|
type
|
|
THackMenuItem = class(TComponent)
|
|
protected
|
|
FxxxxCaption: AnsiString;
|
|
FxxxxHandle: HMENU;
|
|
FxxxxChecked: Boolean;
|
|
FxxxxEnabled: Boolean;
|
|
FxxxxDefault: Boolean;
|
|
FxxxxAutoHotkeys: TMenuItemAutoFlag;
|
|
FxxxxAutoLineReduction: TMenuItemAutoFlag;
|
|
FxxxxRadioItem: Boolean;
|
|
FxxxxVisible: Boolean;
|
|
FxxxxGroupIndex: Byte;
|
|
FxxxxImageIndex: TImageIndex;
|
|
FxxxxActionLink: TMenuActionLink{TNT-ALLOW TMenuActionLink};
|
|
FxxxxBreak: TMenuBreak;
|
|
FBitmap: TBitmap;
|
|
FxxxxCommand: Word;
|
|
FxxxxHelpContext: THelpContext;
|
|
FxxxxHint: AnsiString;
|
|
FxxxxItems: TList;
|
|
FxxxxShortCut: TShortCut;
|
|
FxxxxParent: TMenuItem{TNT-ALLOW TMenuItem};
|
|
FMerged: TMenuItem{TNT-ALLOW TMenuItem};
|
|
FMergedWith: TMenuItem{TNT-ALLOW TMenuItem};
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function MenuItemHasBitmap(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): Boolean;
|
|
begin
|
|
Result := Assigned(THackMenuItem(MenuItem).FBitmap);
|
|
end;
|
|
|
|
{ TTntMenuItem }
|
|
|
|
procedure TTntMenuItem.DefineProperties(Filer: TFiler);
|
|
begin
|
|
inherited;
|
|
TntPersistent_AfterInherited_DefineProperties(Filer, Self);
|
|
end;
|
|
|
|
type TAccessActionlink = class(TActionLink);
|
|
|
|
procedure TTntMenuItem.InitiateAction;
|
|
begin
|
|
if GetKeyboardLayout(0) <> FKeyboardLayout then
|
|
MenuChanged(False);
|
|
inherited;
|
|
end;
|
|
|
|
function TTntMenuItem.IsCaptionStored: Boolean;
|
|
begin
|
|
Result := (ActionLink = nil) or (not TAccessActionlink(ActionLink).IsCaptionLinked);
|
|
end;
|
|
|
|
procedure TTntMenuItem.SetInheritedCaption(const Value: AnsiString);
|
|
begin
|
|
inherited Caption := Value;
|
|
end;
|
|
|
|
function TTntMenuItem.GetCaption: WideString;
|
|
begin
|
|
if (AnsiString(FCaption) <> inherited Caption)
|
|
and WideSameCaptionStr(AnsiString(FCaption), inherited Caption) then
|
|
begin
|
|
// only difference is hotkey position, update caption with new hotkey position
|
|
SyncHotKeyPosition(inherited Caption, FCaption);
|
|
end;
|
|
Result := GetSyncedWideString(FCaption, (inherited Caption));
|
|
end;
|
|
|
|
procedure TTntMenuItem.SetCaption(const Value: WideString);
|
|
begin
|
|
GetCaption; // auto adjust for hot key changes
|
|
SetSyncedWideString(Value, FCaption, (inherited Caption), SetInheritedCaption);
|
|
end;
|
|
|
|
function TTntMenuItem.GetHint: WideString;
|
|
begin
|
|
Result := GetSyncedWideString(FHint, inherited Hint);
|
|
end;
|
|
|
|
procedure TTntMenuItem.SetInheritedHint(const Value: AnsiString);
|
|
begin
|
|
inherited Hint := Value;
|
|
end;
|
|
|
|
procedure TTntMenuItem.SetHint(const Value: WideString);
|
|
begin
|
|
SetSyncedWideString(Value, FHint, inherited Hint, SetInheritedHint);
|
|
end;
|
|
|
|
function TTntMenuItem.IsHintStored: Boolean;
|
|
begin
|
|
Result := (ActionLink = nil) or not TAccessActionlink(ActionLink).IsHintLinked;
|
|
end;
|
|
|
|
procedure TTntMenuItem.Loaded;
|
|
begin
|
|
inherited;
|
|
UpdateMenuString(GetParentMenu);
|
|
end;
|
|
|
|
procedure TTntMenuItem.MenuChanged(Rebuild: Boolean);
|
|
begin
|
|
if (not FIgnoreMenuChanged) then begin
|
|
inherited;
|
|
UpdateMenuItems(Self, GetParentMenu);
|
|
FixMenuBiDiProblem(GetParentMenu);
|
|
end;
|
|
end;
|
|
|
|
procedure TTntMenuItem.UpdateMenuString(ParentMenu: TMenu);
|
|
var
|
|
ParentHandle: THandle;
|
|
|
|
function NativeMenuTypeIsString: Boolean;
|
|
var
|
|
MenuItemInfo: TMenuItemInfoW;
|
|
Buffer: array[0..79] of WideChar;
|
|
begin
|
|
MenuItemInfo.cbSize := 44; // Required for Windows NT 4.0
|
|
MenuItemInfo.fMask := MIIM_TYPE;
|
|
MenuItemInfo.dwTypeData := Buffer; // ??
|
|
MenuItemInfo.cch := Length(Buffer); // ??
|
|
Result := GetMenuItemInfoW(ParentHandle, Command, False, MenuItemInfo)
|
|
and ((MenuItemInfo.fType and (MFT_BITMAP or MFT_SEPARATOR or MFT_OWNERDRAW)) = 0)
|
|
end;
|
|
|
|
function NativeMenuString: WideString;
|
|
var
|
|
Len: Integer;
|
|
begin
|
|
Assert(Win32PlatformIsUnicode);
|
|
Len := GetMenuStringW(ParentHandle, Command, nil, 0, MF_BYCOMMAND);
|
|
if Len = 0 then
|
|
Result := ''
|
|
else begin
|
|
SetLength(Result, Len + 1);
|
|
Len := GetMenuStringW(ParentHandle, Command, PWideChar(Result), Len + 1, MF_BYCOMMAND);
|
|
SetLength(Result, Len);
|
|
end;
|
|
end;
|
|
|
|
procedure SetMenuString(const Value: WideString);
|
|
var
|
|
MenuItemInfo: TMenuItemInfoW;
|
|
Buffer: array[0..79] of WideChar;
|
|
begin
|
|
MenuItemInfo.cbSize := 44; // Required for Windows NT 4.0
|
|
MenuItemInfo.fMask := MIIM_TYPE;
|
|
MenuItemInfo.dwTypeData := Buffer; // ??
|
|
MenuItemInfo.cch := Length(Buffer); // ??
|
|
if GetMenuItemInfoW(ParentHandle, Command, False, MenuItemInfo)
|
|
and ((MenuItemInfo.fType and (MFT_BITMAP or MFT_SEPARATOR or MFT_OWNERDRAW)) = 0) then
|
|
begin
|
|
MenuItemInfo.dwTypeData := PWideChar(Value);
|
|
MenuItemInfo.cch := Length(Value);
|
|
TntWin32Check(SetMenuItemInfoW(ParentHandle, Command, False, MenuItemInfo));
|
|
end;
|
|
end;
|
|
|
|
function SameEvent(A, B: TMenuMeasureItemEvent): Boolean;
|
|
begin
|
|
Result := @A = @B;
|
|
end;
|
|
|
|
var
|
|
MenuCaption: WideString;
|
|
begin
|
|
FKeyboardLayout := GetKeyboardLayout(0);
|
|
if Parent = nil then
|
|
ParentHandle := 0
|
|
else if (THackMenuItem(Self.Parent).FMergedWith <> nil) then
|
|
ParentHandle := THackMenuItem(Self.Parent).FMergedWith.Handle
|
|
else
|
|
ParentHandle := Parent.Handle;
|
|
|
|
if (Win32PlatformIsUnicode)
|
|
and (Parent <> nil) and (ParentMenu <> nil)
|
|
and (ComponentState * [csReading, csDestroying] = [])
|
|
and (Visible)
|
|
and (NativeMenuTypeIsString) then begin
|
|
MenuCaption := Caption;
|
|
if (Count = 0)
|
|
and ((ShortCut <> scNone)
|
|
and ((Parent = nil) or (Parent.Parent <> nil) or not (Parent.Owner is TMainMenu{TNT-ALLOW TMainMenu}))) then
|
|
MenuCaption := MenuCaption + #9 + WideShortCutToText(ShortCut);
|
|
if (NativeMenuString <> MenuCaption) then
|
|
begin
|
|
SetMenuString(MenuCaption);
|
|
if ((Parent = ParentMenu.Items) or (THackMenuItem(Self.Parent).FMergedWith <> nil))
|
|
and (ParentMenu is TMainMenu{TNT-ALLOW TMainMenu})
|
|
and (ParentMenu.WindowHandle <> 0) then
|
|
DrawMenuBar(ParentMenu.WindowHandle) {top level menu bar items}
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TTntMenuItem.GetAlignmentDrawStyle: Word;
|
|
const
|
|
Alignments: array[TPopupAlignment] of Word = (DT_LEFT, DT_RIGHT, DT_CENTER);
|
|
var
|
|
ParentMenu: TMenu;
|
|
Alignment: TPopupAlignment;
|
|
begin
|
|
ParentMenu := GetParentMenu;
|
|
if ParentMenu is TMenu then
|
|
Alignment := paLeft
|
|
else if ParentMenu is TPopupMenu{TNT-ALLOW TPopupMenu} then
|
|
Alignment := TPopupMenu{TNT-ALLOW TPopupMenu}(ParentMenu).Alignment
|
|
else
|
|
Alignment := paLeft;
|
|
Result := Alignments[Alignment];
|
|
end;
|
|
|
|
procedure TTntMenuItem.AdvancedDrawItem(ACanvas: TCanvas; ARect: TRect;
|
|
State: TOwnerDrawState; TopLevel: Boolean);
|
|
|
|
procedure DrawMenuText(BiDi: Boolean);
|
|
var
|
|
ImageList: TCustomImageList;
|
|
DrawImage, DrawGlyph: Boolean;
|
|
GlyphRect, SaveRect: TRect;
|
|
DrawStyle: Longint;
|
|
Selected: Boolean;
|
|
Win98Plus: Boolean;
|
|
Win2K: Boolean;
|
|
begin
|
|
ImageList := GetImageList;
|
|
Selected := odSelected in State;
|
|
Win98Plus := (Win32MajorVersion > 4) or
|
|
((Win32MajorVersion = 4) and (Win32MinorVersion > 0));
|
|
Win2K := (Win32MajorVersion > 4) and (Win32Platform = VER_PLATFORM_WIN32_NT);
|
|
with ACanvas do
|
|
begin
|
|
GlyphRect.Left := ARect.Left + 1;
|
|
DrawImage := (ImageList <> nil) and ((ImageIndex > -1) and
|
|
(ImageIndex < ImageList.Count) or Checked and ((not MenuItemHasBitmap(Self)) or
|
|
Bitmap.Empty));
|
|
if DrawImage or MenuItemHasBitmap(Self) and not Bitmap.Empty then
|
|
begin
|
|
DrawGlyph := True;
|
|
if DrawImage then
|
|
GlyphRect.Right := GlyphRect.Left + ImageList.Width
|
|
else begin
|
|
{ Need to add BitmapWidth/Height properties for TMenuItem if we're to
|
|
support them. Right now let's hardcode them to 16x16. }
|
|
GlyphRect.Right := GlyphRect.Left + 16;
|
|
end;
|
|
{ Draw background pattern brush if selected }
|
|
if Checked then
|
|
begin
|
|
Inc(GlyphRect.Right);
|
|
if not Selected then
|
|
Brush.Bitmap := AllocPatternBitmap(clBtnFace, clBtnHighlight);
|
|
Inc(GlyphRect.Left);
|
|
end;
|
|
if Checked then
|
|
Dec(GlyphRect.Right);
|
|
end else begin
|
|
if (ImageList <> nil) and (not TopLevel) then
|
|
GlyphRect.Right := GlyphRect.Left + ImageList.Width
|
|
else
|
|
GlyphRect.Right := GlyphRect.Left;
|
|
DrawGlyph := False;
|
|
end;
|
|
if BiDi then begin
|
|
SaveRect := GlyphRect;
|
|
GlyphRect.Left := ARect.Right - (SaveRect.Right - ARect.Left);
|
|
GlyphRect.Right := ARect.Right - (SaveRect.Left - ARect.Left);
|
|
end;
|
|
with GlyphRect do begin
|
|
Dec(Left);
|
|
Inc(Right, 2);
|
|
end;
|
|
if Selected then begin
|
|
if DrawGlyph then begin
|
|
if BiDi then
|
|
ARect.Right := GlyphRect.Left - 1
|
|
else
|
|
ARect.Left := GlyphRect.Right + 1;
|
|
end;
|
|
if not (Win98Plus and TopLevel) then
|
|
Brush.Color := clHighlight;
|
|
end;
|
|
if TopLevel and Win98Plus and (not Selected)
|
|
{$IFDEF COMPILER_7_UP}
|
|
and (not Win32PlatformIsXP)
|
|
{$ENDIF}
|
|
then
|
|
OffsetRect(ARect, 0, -1);
|
|
if not (Selected and DrawGlyph) then begin
|
|
if BiDi then
|
|
ARect.Right := GlyphRect.Left - 1
|
|
else
|
|
ARect.Left := GlyphRect.Right + 1;
|
|
end;
|
|
Inc(ARect.Left, 2);
|
|
Dec(ARect.Right, 1);
|
|
DrawStyle := DT_EXPANDTABS or DT_SINGLELINE or GetAlignmentDrawStyle;
|
|
if Win2K and (odNoAccel in State) then
|
|
DrawStyle := DrawStyle or DT_HIDEPREFIX;
|
|
{ Calculate vertical layout }
|
|
SaveRect := ARect;
|
|
if odDefault in State then
|
|
Font.Style := [fsBold];
|
|
DoDrawText(ACanvas, Caption, ARect, Selected, DrawStyle or DT_CALCRECT or DT_NOCLIP);
|
|
if BiDi then begin
|
|
{ the DT_CALCRECT does not take into account alignment }
|
|
ARect.Left := SaveRect.Left;
|
|
ARect.Right := SaveRect.Right;
|
|
end;
|
|
OffsetRect(ARect, 0, ((SaveRect.Bottom - SaveRect.Top) - (ARect.Bottom - ARect.Top)) div 2);
|
|
if TopLevel and Selected and Win98Plus
|
|
{$IFDEF COMPILER_7_UP}
|
|
and (not Win32PlatformIsXP)
|
|
{$ENDIF}
|
|
then
|
|
OffsetRect(ARect, 1, 0);
|
|
DoDrawText(ACanvas, Caption, ARect, Selected, DrawStyle);
|
|
if (ShortCut <> scNone) and not TopLevel then
|
|
begin
|
|
if BiDi then begin
|
|
ARect.Left := 10;
|
|
ARect.Right := ARect.Left + WideCanvasTextWidth(ACanvas, WideShortCutToText(ShortCut));
|
|
end else begin
|
|
ARect.Left := ARect.Right;
|
|
ARect.Right := SaveRect.Right - 10;
|
|
end;
|
|
DoDrawText(ACanvas, WideShortCutToText(ShortCut), ARect, Selected, DT_RIGHT);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
ParentMenu: TMenu;
|
|
SaveCaption: WideString;
|
|
SaveShortCut: TShortCut;
|
|
begin
|
|
ParentMenu := GetParentMenu;
|
|
if (not Win32PlatformIsUnicode)
|
|
or (Self.IsLine)
|
|
or ( (ParentMenu <> nil) and (ParentMenu.OwnerDraw or (GetImageList <> nil))
|
|
and (Assigned(OnAdvancedDrawItem) or Assigned(OnDrawItem)) ) then
|
|
inherited
|
|
else begin
|
|
SaveCaption := Caption;
|
|
SaveShortCut := ShortCut;
|
|
try
|
|
FIgnoreMenuChanged := True;
|
|
try
|
|
Caption := '';
|
|
ShortCut := scNone;
|
|
finally
|
|
FIgnoreMenuChanged := False;
|
|
end;
|
|
inherited;
|
|
finally
|
|
FIgnoreMenuChanged := True;
|
|
try
|
|
Caption := SaveCaption;
|
|
ShortCut := SaveShortcut;
|
|
finally
|
|
FIgnoreMenuChanged := False;
|
|
end;
|
|
end;
|
|
DrawMenuText((ParentMenu <> nil) and (ParentMenu.IsRightToLeft))
|
|
end;
|
|
end;
|
|
|
|
procedure TTntMenuItem.DoDrawText(ACanvas: TCanvas; const ACaption: WideString;
|
|
var Rect: TRect; Selected: Boolean; Flags: Longint);
|
|
var
|
|
Text: WideString;
|
|
ParentMenu: TMenu;
|
|
begin
|
|
if (not Win32PlatformIsUnicode)
|
|
or (IsLine) then
|
|
inherited DoDrawText(ACanvas, ACaption, Rect, Selected, Flags)
|
|
else begin
|
|
ParentMenu := GetParentMenu;
|
|
if (ParentMenu <> nil) and (ParentMenu.IsRightToLeft) then
|
|
begin
|
|
if Flags and DT_LEFT = DT_LEFT then
|
|
Flags := Flags and (not DT_LEFT) or DT_RIGHT
|
|
else if Flags and DT_RIGHT = DT_RIGHT then
|
|
Flags := Flags and (not DT_RIGHT) or DT_LEFT;
|
|
Flags := Flags or DT_RTLREADING;
|
|
end;
|
|
Text := ACaption;
|
|
if (Flags and DT_CALCRECT <> 0) and ((Text = '') or
|
|
(Text[1] = cHotkeyPrefix) and (Text[2] = #0)) then Text := Text + ' ';
|
|
with ACanvas do
|
|
begin
|
|
Brush.Style := bsClear;
|
|
if Default then
|
|
Font.Style := Font.Style + [fsBold];
|
|
if not Enabled then
|
|
begin
|
|
if not Selected then
|
|
begin
|
|
OffsetRect(Rect, 1, 1);
|
|
Font.Color := clBtnHighlight;
|
|
Tnt_DrawTextW(Handle, PWideChar(Text), Length(Text), Rect, Flags);
|
|
OffsetRect(Rect, -1, -1);
|
|
end;
|
|
if Selected and (ColorToRGB(clHighlight) = ColorToRGB(clBtnShadow)) then
|
|
Font.Color := clBtnHighlight else
|
|
Font.Color := clBtnShadow;
|
|
end;
|
|
Tnt_DrawTextW(Handle, PWideChar(Text), Length(Text), Rect, Flags);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TTntMenuItem.MeasureItemTextWidth(ACanvas: TCanvas; const Text: WideString): Integer;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
FillChar(R, SizeOf(R), 0);
|
|
DoDrawText(ACanvas, Text, R, False,
|
|
GetAlignmentDrawStyle or DT_EXPANDTABS or DT_SINGLELINE or DT_NOCLIP or DT_CALCRECT);
|
|
Result := R.Right - R.Left;
|
|
end;
|
|
|
|
procedure TTntMenuItem.MeasureItem(ACanvas: TCanvas; var Width, Height: Integer);
|
|
var
|
|
SaveMeasureItemEvent: TMenuMeasureItemEvent;
|
|
begin
|
|
if (not Win32PlatformIsUnicode)
|
|
or (Self.IsLine) then
|
|
inherited
|
|
else begin
|
|
SaveMeasureItemEvent := inherited OnMeasureItem;
|
|
try
|
|
inherited OnMeasureItem := nil;
|
|
inherited;
|
|
Inc(Width, MeasureItemTextWidth(ACanvas, Caption));
|
|
Dec(Width, MeasureItemTextWidth(ACanvas, inherited Caption));
|
|
if ShortCut <> scNone then begin
|
|
Inc(Width, MeasureItemTextWidth(ACanvas, WideShortCutToText(ShortCut)));
|
|
Dec(Width, MeasureItemTextWidth(ACanvas, ShortCutToText{TNT-ALLOW ShortCutToText}(ShortCut)));
|
|
end;
|
|
finally
|
|
inherited OnMeasureItem := SaveMeasureItemEvent;
|
|
end;
|
|
if Assigned(OnMeasureItem) then OnMeasureItem(Self, ACanvas, Width, Height);
|
|
end;
|
|
end;
|
|
|
|
function TTntMenuItem.Find(ACaption: WideString): TMenuItem{TNT-ALLOW TMenuItem};
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := nil;
|
|
ACaption := WideStripHotkey(ACaption);
|
|
for I := 0 to Count - 1 do
|
|
if WideSameText(ACaption, WideStripHotkey(WideGetMenuItemCaption(Items[I]))) then
|
|
begin
|
|
Result := Items[I];
|
|
System.Break;
|
|
end;
|
|
end;
|
|
|
|
function TTntMenuItem.GetActionLinkClass: TMenuActionLinkClass;
|
|
begin
|
|
Result := TTntMenuActionLink;
|
|
end;
|
|
|
|
procedure TTntMenuItem.ActionChange(Sender: TObject; CheckDefaults: Boolean);
|
|
begin
|
|
if (Sender is TCustomAction{TNT-ALLOW TCustomAction}) and Supports(Sender, ITntAction) then begin
|
|
if not CheckDefaults or (Caption = '') then
|
|
Caption := TntAction_GetCaption(TCustomAction{TNT-ALLOW TCustomAction}(Sender));
|
|
if not CheckDefaults or (Hint = '') then
|
|
Hint := TntAction_GetHint(TCustomAction{TNT-ALLOW TCustomAction}(Sender));
|
|
end;
|
|
inherited;
|
|
end;
|
|
|
|
{ TTntMainMenu }
|
|
|
|
{$IFDEF COMPILER_9_UP}
|
|
function TTntMainMenu.CreateMenuItem: TMenuItem{TNT-ALLOW TMenuItem};
|
|
begin
|
|
Result := TTntMenuItem.Create(Self);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TTntMainMenu.DoChange(Source: TMenuItem{TNT-ALLOW TMenuItem}; Rebuild: Boolean);
|
|
begin
|
|
inherited;
|
|
UpdateMenuItems(Items, Self);
|
|
if (THackMenuItem(Items).FMerged <> nil) then begin
|
|
UpdateMenuItems(THackMenuItem(Items).FMerged, Self);
|
|
end;
|
|
end;
|
|
|
|
{ TTntPopupMenu }
|
|
|
|
constructor TTntPopupMenu.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
PopupList.Remove(Self);
|
|
if TntPopupList <> nil then
|
|
TntPopupList.Add(Self);
|
|
end;
|
|
|
|
{$IFDEF COMPILER_9_UP}
|
|
function TTntPopupMenu.CreateMenuItem: TMenuItem{TNT-ALLOW TMenuItem};
|
|
begin
|
|
Result := TTntMenuItem.Create(Self);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
destructor TTntPopupMenu.Destroy;
|
|
begin
|
|
if TntPopupList <> nil then
|
|
TntPopupList.Remove(Self);
|
|
PopupList.Add(Self);
|
|
inherited;
|
|
end;
|
|
|
|
procedure TTntPopupMenu.DoChange(Source: TMenuItem{TNT-ALLOW TMenuItem}; Rebuild: Boolean);
|
|
begin
|
|
inherited;
|
|
UpdateMenuItems(Items, Self);
|
|
end;
|
|
|
|
procedure TTntPopupMenu.Popup(X, Y: Integer);
|
|
begin
|
|
Menus.PopupList := TntPopupList;
|
|
try
|
|
inherited;
|
|
finally
|
|
Menus.PopupList := TntPopupList.SavedPopupList;
|
|
end;
|
|
end;
|
|
|
|
{ TTntPopupList }
|
|
|
|
procedure TTntPopupList.WndProc(var Message: TMessage);
|
|
var
|
|
I, Item: Integer;
|
|
MenuItem: TMenuItem{TNT-ALLOW TMenuItem};
|
|
FindKind: TFindItemKind;
|
|
begin
|
|
case Message.Msg of
|
|
WM_ENTERMENULOOP:
|
|
begin
|
|
Menus.PopupList := SavedPopupList;
|
|
for i := 0 to Count - 1 do
|
|
FixMenuBiDiProblem(Items[i]);
|
|
end;
|
|
WM_MENUSELECT:
|
|
with TWMMenuSelect(Message) do
|
|
begin
|
|
FindKind := fkCommand;
|
|
if MenuFlag and MF_POPUP <> 0 then FindKind := fkHandle;
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
if FindKind = fkHandle then
|
|
begin
|
|
if Menu <> 0 then
|
|
Item := Integer(GetSubMenu(Menu, IDItem)) else
|
|
Item := -1;
|
|
end
|
|
else
|
|
Item := IDItem;
|
|
MenuItem := TPopupMenu{TNT-ALLOW TPopupMenu}(Items[I]).FindItem(Item, FindKind);
|
|
if MenuItem <> nil then
|
|
begin
|
|
TntApplication.Hint := WideGetLongHint(WideGetMenuItemHint(MenuItem));
|
|
Exit;
|
|
end;
|
|
end;
|
|
TntApplication.Hint := '';
|
|
end;
|
|
end;
|
|
inherited;
|
|
end;
|
|
|
|
initialization
|
|
TntPopupList := TTntPopupList.Create;
|
|
TntPopupList.SavedPopupList := Menus.PopupList;
|
|
|
|
finalization
|
|
FreeAndNil(TntPopupList);
|
|
|
|
end.
|