1 |
|
---|
2 | {*****************************************************************************}
|
---|
3 | { }
|
---|
4 | { Tnt Delphi Unicode Controls }
|
---|
5 | { http://www.tntware.com/delphicontrols/unicode/ }
|
---|
6 | { Version: 2.3.0 }
|
---|
7 | { }
|
---|
8 | { Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) }
|
---|
9 | { }
|
---|
10 | {*****************************************************************************}
|
---|
11 |
|
---|
12 | unit TntMenus;
|
---|
13 |
|
---|
14 | {$INCLUDE TntCompilers.inc}
|
---|
15 |
|
---|
16 | interface
|
---|
17 |
|
---|
18 | uses
|
---|
19 | Windows, Classes, Menus, Graphics, Messages;
|
---|
20 |
|
---|
21 | type
|
---|
22 | {TNT-WARN TMenuItem}
|
---|
23 | TTntMenuItem = class(TMenuItem{TNT-ALLOW TMenuItem})
|
---|
24 | private
|
---|
25 | FIgnoreMenuChanged: Boolean;
|
---|
26 | FCaption: WideString;
|
---|
27 | FHint: WideString;
|
---|
28 | FKeyboardLayout: HKL;
|
---|
29 | function GetCaption: WideString;
|
---|
30 | procedure SetInheritedCaption(const Value: AnsiString);
|
---|
31 | procedure SetCaption(const Value: WideString);
|
---|
32 | function IsCaptionStored: Boolean;
|
---|
33 | procedure UpdateMenuString(ParentMenu: TMenu);
|
---|
34 | function GetAlignmentDrawStyle: Word;
|
---|
35 | function MeasureItemTextWidth(ACanvas: TCanvas; const Text: WideString): Integer;
|
---|
36 | function GetHint: WideString;
|
---|
37 | procedure SetInheritedHint(const Value: AnsiString);
|
---|
38 | procedure SetHint(const Value: WideString);
|
---|
39 | function IsHintStored: Boolean;
|
---|
40 | protected
|
---|
41 | procedure DefineProperties(Filer: TFiler); override;
|
---|
42 | function GetActionLinkClass: TMenuActionLinkClass; override;
|
---|
43 | procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override;
|
---|
44 | procedure MenuChanged(Rebuild: Boolean); override;
|
---|
45 | procedure AdvancedDrawItem(ACanvas: TCanvas; ARect: TRect;
|
---|
46 | State: TOwnerDrawState; TopLevel: Boolean); override;
|
---|
47 | procedure DoDrawText(ACanvas: TCanvas; const ACaption: WideString;
|
---|
48 | var Rect: TRect; Selected: Boolean; Flags: Integer);
|
---|
49 | procedure MeasureItem(ACanvas: TCanvas; var Width, Height: Integer); override;
|
---|
50 | public
|
---|
51 | procedure InitiateAction; override;
|
---|
52 | procedure Loaded; override;
|
---|
53 | function Find(ACaption: WideString): TMenuItem{TNT-ALLOW TMenuItem};
|
---|
54 | published
|
---|
55 | property Caption: WideString read GetCaption write SetCaption stored IsCaptionStored;
|
---|
56 | property Hint: WideString read GetHint write SetHint stored IsHintStored;
|
---|
57 | end;
|
---|
58 |
|
---|
59 | {TNT-WARN TMainMenu}
|
---|
60 | TTntMainMenu = class(TMainMenu{TNT-ALLOW TMainMenu})
|
---|
61 | protected
|
---|
62 | procedure DoChange(Source: TMenuItem{TNT-ALLOW TMenuItem}; Rebuild: Boolean); override;
|
---|
63 | public
|
---|
64 | {$IFDEF COMPILER_9_UP}
|
---|
65 | function CreateMenuItem: TMenuItem{TNT-ALLOW TMenuItem}; override;
|
---|
66 | {$ENDIF}
|
---|
67 | end;
|
---|
68 |
|
---|
69 | {TNT-WARN TPopupMenu}
|
---|
70 | TTntPopupMenu = class(TPopupMenu{TNT-ALLOW TPopupMenu})
|
---|
71 | protected
|
---|
72 | procedure DoChange(Source: TMenuItem{TNT-ALLOW TMenuItem}; Rebuild: Boolean); override;
|
---|
73 | public
|
---|
74 | constructor Create(AOwner: TComponent); override;
|
---|
75 | {$IFDEF COMPILER_9_UP}
|
---|
76 | function CreateMenuItem: TMenuItem{TNT-ALLOW TMenuItem}; override;
|
---|
77 | {$ENDIF}
|
---|
78 | destructor Destroy; override;
|
---|
79 | procedure Popup(X, Y: Integer); override;
|
---|
80 | end;
|
---|
81 |
|
---|
82 | {TNT-WARN NewSubMenu}
|
---|
83 | function WideNewSubMenu(const ACaption: WideString; hCtx: THelpContext;
|
---|
84 | const AName: TComponentName; const Items: array of TTntMenuItem;
|
---|
85 | AEnabled: Boolean): TTntMenuItem;
|
---|
86 | {TNT-WARN NewItem}
|
---|
87 | function WideNewItem(const ACaption: WideString; AShortCut: TShortCut;
|
---|
88 | AChecked, AEnabled: Boolean; AOnClick: TNotifyEvent; hCtx: THelpContext;
|
---|
89 | const AName: TComponentName): TTntMenuItem;
|
---|
90 |
|
---|
91 | function MessageToShortCut(Msg: TWMKeyDown): TShortCut;
|
---|
92 |
|
---|
93 | {TNT-WARN ShortCutToText}
|
---|
94 | function WideShortCutToText(WordShortCut: Word): WideString;
|
---|
95 | {TNT-WARN TextToShortCut}
|
---|
96 | function WideTextToShortCut(Text: WideString): TShortCut;
|
---|
97 | {TNT-WARN GetHotKey}
|
---|
98 | function WideGetHotkey(const Text: WideString): WideString;
|
---|
99 | {TNT-WARN StripHotkey}
|
---|
100 | function WideStripHotkey(const Text: WideString): WideString;
|
---|
101 | {TNT-WARN AnsiSameCaption}
|
---|
102 | function WideSameCaption(const Text1, Text2: WideString): Boolean;
|
---|
103 |
|
---|
104 | function WideGetMenuItemCaption(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): WideString;
|
---|
105 | function WideGetMenuItemHint(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): WideString;
|
---|
106 |
|
---|
107 | procedure NoOwnerDrawTopLevelItems(Menu: TMainMenu{TNT-ALLOW TMainMenu});
|
---|
108 |
|
---|
109 | procedure FixMenuBiDiProblem(Menu: TMenu);
|
---|
110 |
|
---|
111 | function MenuItemHasBitmap(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): Boolean;
|
---|
112 |
|
---|
113 | type
|
---|
114 | TTntPopupList = class(TPopupList)
|
---|
115 | private
|
---|
116 | SavedPopupList: TPopupList;
|
---|
117 | protected
|
---|
118 | procedure WndProc(var Message: TMessage); override;
|
---|
119 | end;
|
---|
120 |
|
---|
121 | var
|
---|
122 | TntPopupList: TTntPopupList;
|
---|
123 |
|
---|
124 | implementation
|
---|
125 |
|
---|
126 | uses
|
---|
127 | Forms, SysUtils, Consts, ActnList, ImgList, TntControls, TntGraphics,
|
---|
128 | TntActnList, TntClasses, TntForms, TntSysUtils, TntWindows;
|
---|
129 |
|
---|
130 | function WideNewSubMenu(const ACaption: WideString; hCtx: THelpContext;
|
---|
131 | const AName: TComponentName; const Items: array of TTntMenuItem;
|
---|
132 | AEnabled: Boolean): TTntMenuItem;
|
---|
133 | var
|
---|
134 | I: Integer;
|
---|
135 | begin
|
---|
136 | Result := TTntMenuItem.Create(nil);
|
---|
137 | for I := Low(Items) to High(Items) do
|
---|
138 | Result.Add(Items[I]);
|
---|
139 | Result.Caption := ACaption;
|
---|
140 | Result.HelpContext := hCtx;
|
---|
141 | Result.Name := AName;
|
---|
142 | Result.Enabled := AEnabled;
|
---|
143 | end;
|
---|
144 |
|
---|
145 | function WideNewItem(const ACaption: WideString; AShortCut: TShortCut;
|
---|
146 | AChecked, AEnabled: Boolean; AOnClick: TNotifyEvent; hCtx: THelpContext;
|
---|
147 | const AName: TComponentName): TTntMenuItem;
|
---|
148 | begin
|
---|
149 | Result := TTntMenuItem.Create(nil);
|
---|
150 | with Result do
|
---|
151 | begin
|
---|
152 | Caption := ACaption;
|
---|
153 | ShortCut := AShortCut;
|
---|
154 | OnClick := AOnClick;
|
---|
155 | HelpContext := hCtx;
|
---|
156 | Checked := AChecked;
|
---|
157 | Enabled := AEnabled;
|
---|
158 | Name := AName;
|
---|
159 | end;
|
---|
160 | end;
|
---|
161 |
|
---|
162 | function MessageToShortCut(Msg: TWMKeyDown): TShortCut;
|
---|
163 | var
|
---|
164 | ShiftState: TShiftState;
|
---|
165 | begin
|
---|
166 | ShiftState := Forms.KeyDataToShiftState(TWMKeyDown(Msg).KeyData);
|
---|
167 | Result := Menus.ShortCut(TWMKeyDown(Msg).CharCode, ShiftState);
|
---|
168 | end;
|
---|
169 |
|
---|
170 | function WideGetSpecialName(WordShortCut: Word): WideString;
|
---|
171 | var
|
---|
172 | ScanCode: Integer;
|
---|
173 | KeyName: array[0..255] of WideChar;
|
---|
174 | begin
|
---|
175 | Assert(Win32PlatformIsUnicode);
|
---|
176 | Result := '';
|
---|
177 | ScanCode := MapVirtualKeyW(WordRec(WordShortCut).Lo, 0) shl 16;
|
---|
178 | if ScanCode <> 0 then
|
---|
179 | begin
|
---|
180 | GetKeyNameTextW(ScanCode, KeyName, SizeOf(KeyName));
|
---|
181 | Result := KeyName;
|
---|
182 | end;
|
---|
183 | end;
|
---|
184 |
|
---|
185 | function WideGetKeyboardChar(Key: Word): WideChar;
|
---|
186 | var
|
---|
187 | LatinNumChar: WideChar;
|
---|
188 | begin
|
---|
189 | Assert(Win32PlatformIsUnicode);
|
---|
190 | Result := WideChar(MapVirtualKeyW(Key, 2));
|
---|
191 | if (Key in [$30..$39]) then
|
---|
192 | begin
|
---|
193 | // Check to see if "0" - "9" can be used if all that differs is shift state
|
---|
194 | LatinNumChar := WideChar(Key - $30 + Ord('0'));
|
---|
195 | if (Result <> LatinNumChar)
|
---|
196 | and (Byte(Key) = WordRec(VkKeyScanW(LatinNumChar)).Lo) then // .Hi would be the shift state
|
---|
197 | Result := LatinNumChar;
|
---|
198 | end;
|
---|
199 | end;
|
---|
200 |
|
---|
201 | function WideShortCutToText(WordShortCut: Word): WideString;
|
---|
202 | var
|
---|
203 | Name: WideString;
|
---|
204 | begin
|
---|
205 | if (not Win32PlatformIsUnicode)
|
---|
206 | or (WordRec(WordShortCut).Lo in [$08..$09 {BKSP, TAB}, $0D {ENTER}, $1B {ESC}, $20..$28 {Misc Nav},
|
---|
207 | $2D..$2E {INS, DEL}, $70..$87 {F1 - F24}])
|
---|
208 | then
|
---|
209 | Result := ShortCutToText{TNT-ALLOW ShortCutToText}(WordShortCut)
|
---|
210 | else begin
|
---|
211 | case WordRec(WordShortCut).Lo of
|
---|
212 | $30..$39: Name := WideGetKeyboardChar(WordRec(WordShortCut).Lo); {1-9,0}
|
---|
213 | $41..$5A: Name := WideGetKeyboardChar(WordRec(WordShortCut).Lo); {A-Z}
|
---|
214 | $60..$69: Name := WideGetKeyboardChar(WordRec(WordShortCut).Lo); {numpad 1-9,0}
|
---|
215 | else
|
---|
216 | Name := WideGetSpecialName(WordShortCut);
|
---|
217 | end;
|
---|
218 | if Name <> '' then
|
---|
219 | begin
|
---|
220 | Result := '';
|
---|
221 | if WordShortCut and scShift <> 0 then Result := Result + SmkcShift;
|
---|
222 | if WordShortCut and scCtrl <> 0 then Result := Result + SmkcCtrl;
|
---|
223 | if WordShortCut and scAlt <> 0 then Result := Result + SmkcAlt;
|
---|
224 | Result := Result + Name;
|
---|
225 | end
|
---|
226 | else Result := '';
|
---|
227 | end;
|
---|
228 | end;
|
---|
229 |
|
---|
230 | { This function is *very* slow. Use sparingly. Return 0 if no VK code was
|
---|
231 | found for the text }
|
---|
232 |
|
---|
233 | function WideTextToShortCut(Text: WideString): TShortCut;
|
---|
234 |
|
---|
235 | { If the front of Text is equal to Front then remove the matching piece
|
---|
236 | from Text and return True, otherwise return False }
|
---|
237 |
|
---|
238 | function CompareFront(var Text: WideString; const Front: WideString): Boolean;
|
---|
239 | begin
|
---|
240 | Result := (Pos(Front, Text) = 1);
|
---|
241 | if Result then
|
---|
242 | Delete(Text, 1, Length(Front));
|
---|
243 | end;
|
---|
244 |
|
---|
245 | var
|
---|
246 | Key: TShortCut;
|
---|
247 | Shift: TShortCut;
|
---|
248 | begin
|
---|
249 | Result := 0;
|
---|
250 | Shift := 0;
|
---|
251 | while True do
|
---|
252 | begin
|
---|
253 | if CompareFront(Text, SmkcShift) then Shift := Shift or scShift
|
---|
254 | else if CompareFront(Text, '^') then Shift := Shift or scCtrl
|
---|
255 | else if CompareFront(Text, SmkcCtrl) then Shift := Shift or scCtrl
|
---|
256 | else if CompareFront(Text, SmkcAlt) then Shift := Shift or scAlt
|
---|
257 | else Break;
|
---|
258 | end;
|
---|
259 | if Text = '' then Exit;
|
---|
260 | for Key := $08 to $255 do { Copy range from table in ShortCutToText }
|
---|
261 | if WideSameText(Text, WideShortCutToText(Key)) then
|
---|
262 | begin
|
---|
263 | Result := Key or Shift;
|
---|
264 | Exit;
|
---|
265 | end;
|
---|
266 | end;
|
---|
267 |
|
---|
268 | function WideGetHotkeyPos(const Text: WideString): Integer;
|
---|
269 | var
|
---|
270 | I, L: Integer;
|
---|
271 | begin
|
---|
272 | Result := 0;
|
---|
273 | I := 1;
|
---|
274 | L := Length(Text);
|
---|
275 | while I <= L do
|
---|
276 | begin
|
---|
277 | if (Text[I] = cHotkeyPrefix) and (L - I >= 1) then
|
---|
278 | begin
|
---|
279 | Inc(I);
|
---|
280 | if Text[I] <> cHotkeyPrefix then
|
---|
281 | Result := I; // this might not be the last
|
---|
282 | end;
|
---|
283 | Inc(I);
|
---|
284 | end;
|
---|
285 | end;
|
---|
286 |
|
---|
287 | function WideGetHotkey(const Text: WideString): WideString;
|
---|
288 | var
|
---|
289 | I: Integer;
|
---|
290 | begin
|
---|
291 | I := WideGetHotkeyPos(Text);
|
---|
292 | if I = 0 then
|
---|
293 | Result := ''
|
---|
294 | else
|
---|
295 | Result := Text[I];
|
---|
296 | end;
|
---|
297 |
|
---|
298 | function WideStripHotkey(const Text: WideString): WideString;
|
---|
299 | var
|
---|
300 | I: Integer;
|
---|
301 | begin
|
---|
302 | Result := Text;
|
---|
303 | I := 1;
|
---|
304 | while I <= Length(Result) do
|
---|
305 | begin
|
---|
306 | if Result[I] = cHotkeyPrefix then
|
---|
307 | if SysLocale.FarEast
|
---|
308 | and ((I > 1) and (Length(Result) - I >= 2)
|
---|
309 | and (Result[I - 1] = '(') and (Result[I + 2] = ')')) then begin
|
---|
310 | Delete(Result, I - 1, 4);
|
---|
311 | Dec(I, 2);
|
---|
312 | end else
|
---|
313 | Delete(Result, I, 1);
|
---|
314 | Inc(I);
|
---|
315 | end;
|
---|
316 | end;
|
---|
317 |
|
---|
318 | function WideSameCaption(const Text1, Text2: WideString): Boolean;
|
---|
319 | begin
|
---|
320 | Result := WideSameText(WideStripHotkey(Text1), WideStripHotkey(Text2));
|
---|
321 | end;
|
---|
322 |
|
---|
323 | function WideSameCaptionStr(const Text1, Text2: WideString): Boolean;
|
---|
324 | begin
|
---|
325 | Result := WideSameStr(WideStripHotkey(Text1), WideStripHotkey(Text2));
|
---|
326 | end;
|
---|
327 |
|
---|
328 | function WideGetMenuItemCaption(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): WideString;
|
---|
329 | begin
|
---|
330 | if MenuItem is TTntMenuItem then
|
---|
331 | Result := TTntMenuItem(MenuItem).Caption
|
---|
332 | else
|
---|
333 | Result := MenuItem.Caption;
|
---|
334 | end;
|
---|
335 |
|
---|
336 | function WideGetMenuItemHint(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): WideString;
|
---|
337 | begin
|
---|
338 | if MenuItem is TTntMenuItem then
|
---|
339 | Result := TTntMenuItem(MenuItem).Hint
|
---|
340 | else
|
---|
341 | Result := MenuItem.Hint;
|
---|
342 | end;
|
---|
343 |
|
---|
344 | procedure NoOwnerDrawTopLevelItems(Menu: TMainMenu{TNT-ALLOW TMainMenu});
|
---|
345 | {If top-level items are created as owner-drawn, they will not appear as raised
|
---|
346 | buttons when the mouse hovers over them. The VCL will often create top-level
|
---|
347 | items as owner-drawn even when they don't need to be (owner-drawn state can be
|
---|
348 | set on an item-by-item basis). This routine turns off the owner-drawn flag for
|
---|
349 | top-level items if it appears unnecessary}
|
---|
350 |
|
---|
351 | function ItemHasValidImage(Item: TMenuItem{TNT-ALLOW TMenuItem}): boolean;
|
---|
352 | var
|
---|
353 | Images: TCustomImageList;
|
---|
354 | begin
|
---|
355 | Assert(Item <> nil, 'TNT Internal Error: ItemHasValidImage: item = nil');
|
---|
356 | Images := Item.GetImageList;
|
---|
357 | Result := (Assigned(Images) and (Item.ImageIndex >= 0) and (Item.ImageIndex < Images.Count))
|
---|
358 | or (MenuItemHasBitmap(Item) and (not Item.Bitmap.Empty))
|
---|
359 | end;
|
---|
360 |
|
---|
361 | var
|
---|
362 | HM: HMenu;
|
---|
363 | i: integer;
|
---|
364 | Info: TMenuItemInfoA;
|
---|
365 | Item: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
366 | Win98Plus: boolean;
|
---|
367 | begin
|
---|
368 | if Assigned(Menu) then begin
|
---|
369 | Win98Plus:= (Win32MajorVersion > 4)
|
---|
370 | or((Win32MajorVersion = 4) and (Win32MinorVersion > 0));
|
---|
371 | if not Win98Plus then
|
---|
372 | Exit; {exit if Windows 95 or NT 4.0}
|
---|
373 | HM:= Menu.Handle;
|
---|
374 | Info.cbSize:= sizeof(Info);
|
---|
375 | for i := 0 to GetMenuItemCount(HM) - 1 do begin
|
---|
376 | Info.fMask:= MIIM_FTYPE or MIIM_ID;
|
---|
377 | if not GetMenuItemInfo(HM, i, true, Info) then
|
---|
378 | Break;
|
---|
379 | if Info.fType and MFT_OWNERDRAW <> 0 then begin
|
---|
380 | Item:= Menu.FindItem(Info.wID, fkCommand);
|
---|
381 | if not Assigned(Item) then
|
---|
382 | continue;
|
---|
383 | if Assigned(Item.OnDrawItem)
|
---|
384 | or Assigned(Item.OnAdvancedDrawItem)
|
---|
385 | or ItemHasValidImage(Item) then
|
---|
386 | Continue;
|
---|
387 | Info.fMask:= MIIM_FTYPE or MIIM_STRING;
|
---|
388 | Info.fType:= (Info.fType and not MFT_OWNERDRAW) or MFT_STRING;
|
---|
389 | if Win32PlatformIsUnicode and (Item is TTntMenuItem) then begin
|
---|
390 | // Unicode
|
---|
391 | TMenuItemInfoW(Info).dwTypeData:= PWideChar(TTntMenuItem(Item).Caption);
|
---|
392 | SetMenuItemInfoW(HM, i, true, TMenuItemInfoW(Info));
|
---|
393 | end else begin
|
---|
394 | // Ansi
|
---|
395 | Info.dwTypeData:= PAnsiChar(Item.Caption);
|
---|
396 | SetMenuItemInfoA(HM, i, true, Info);
|
---|
397 | end;
|
---|
398 | end;
|
---|
399 | end;
|
---|
400 | end;
|
---|
401 | end;
|
---|
402 |
|
---|
403 | { TTntMenuItem's utility procs }
|
---|
404 |
|
---|
405 | procedure SyncHotKeyPosition(const Source: WideString; var Dest: WideString);
|
---|
406 | var
|
---|
407 | I: Integer;
|
---|
408 | FarEastHotString: WideString;
|
---|
409 | begin
|
---|
410 | if (AnsiString(Source) <> AnsiString(Dest))
|
---|
411 | and WideSameCaptionStr(AnsiString(Source), AnsiString(Dest)) then begin
|
---|
412 | // when reduced to ansi, the only difference is hot key positions
|
---|
413 | Dest := WideStripHotkey(Dest);
|
---|
414 | I := 1;
|
---|
415 | while I <= Length(Source) do
|
---|
416 | begin
|
---|
417 | if Source[I] = cHotkeyPrefix then begin
|
---|
418 | if SysLocale.FarEast
|
---|
419 | and ((I > 1) and (Length(Source) - I >= 2)
|
---|
420 | and (Source[I - 1] = '(') and (Source[I + 2] = ')')) then begin
|
---|
421 | FarEastHotString := Copy(Source, I - 1, 4);
|
---|
422 | Dec(I);
|
---|
423 | Insert(FarEastHotString, Dest, I);
|
---|
424 | Inc(I, 3);
|
---|
425 | end else begin
|
---|
426 | Insert(cHotkeyPrefix, Dest, I);
|
---|
427 | Inc(I);
|
---|
428 | end;
|
---|
429 | end;
|
---|
430 | Inc(I);
|
---|
431 | end;
|
---|
432 | // test work
|
---|
433 | if AnsiString(Source) <> AnsiString(Dest) then
|
---|
434 | raise ETntInternalError.CreateFmt('Internal Error: SyncHotKeyPosition Failed ("%s" <> "%s").',
|
---|
435 | [AnsiString(Source), AnsiString(Dest)]);
|
---|
436 | end;
|
---|
437 | end;
|
---|
438 |
|
---|
439 | procedure UpdateMenuItems(Items: TMenuItem{TNT-ALLOW TMenuItem}; ParentMenu: TMenu);
|
---|
440 | var
|
---|
441 | i: integer;
|
---|
442 | begin
|
---|
443 | if (Items.ComponentState * [csReading, csDestroying] = []) then begin
|
---|
444 | for i := Items.Count - 1 downto 0 do
|
---|
445 | UpdateMenuItems(Items[i], ParentMenu);
|
---|
446 | if Items is TTntMenuItem then
|
---|
447 | TTntMenuItem(Items).UpdateMenuString(ParentMenu);
|
---|
448 | end;
|
---|
449 | end;
|
---|
450 |
|
---|
451 | procedure FixMenuBiDiProblem(Menu: TMenu);
|
---|
452 | var
|
---|
453 | i: integer;
|
---|
454 | begin
|
---|
455 | // TMenu sometimes sets bidi on first visible item which can convert caption to ansi
|
---|
456 | if (SysLocale.MiddleEast)
|
---|
457 | and (Menu <> nil)
|
---|
458 | and (Menu.Items.Count > 0) then
|
---|
459 | begin
|
---|
460 | for i := 0 to Menu.Items.Count - 1 do begin
|
---|
461 | if Menu.Items[i].Visible then begin
|
---|
462 | if (Menu.Items[i] is TTntMenuItem) then
|
---|
463 | (Menu.Items[i] as TTntMenuItem).UpdateMenuString(Menu);
|
---|
464 | break; // found first visible menu item!
|
---|
465 | end;
|
---|
466 | end;
|
---|
467 | end;
|
---|
468 | end;
|
---|
469 |
|
---|
470 |
|
---|
471 | {$IFDEF COMPILER_6} // verified against VCL source in Delphi 6 and BCB 6
|
---|
472 | type
|
---|
473 | THackMenuItem = class(TComponent)
|
---|
474 | protected
|
---|
475 | FxxxxCaption: Ansistring;
|
---|
476 | FxxxxHandle: HMENU;
|
---|
477 | FxxxxChecked: Boolean;
|
---|
478 | FxxxxEnabled: Boolean;
|
---|
479 | FxxxxDefault: Boolean;
|
---|
480 | FxxxxAutoHotkeys: TMenuItemAutoFlag;
|
---|
481 | FxxxxAutoLineReduction: TMenuItemAutoFlag;
|
---|
482 | FxxxxRadioItem: Boolean;
|
---|
483 | FxxxxVisible: Boolean;
|
---|
484 | FxxxxGroupIndex: Byte;
|
---|
485 | FxxxxImageIndex: TImageIndex;
|
---|
486 | FxxxxActionLink: TMenuActionLink{TNT-ALLOW TMenuActionLink};
|
---|
487 | FxxxxBreak: TMenuBreak;
|
---|
488 | FBitmap: TBitmap;
|
---|
489 | FxxxxCommand: Word;
|
---|
490 | FxxxxHelpContext: THelpContext;
|
---|
491 | FxxxxHint: AnsiString;
|
---|
492 | FxxxxItems: TList;
|
---|
493 | FxxxxShortCut: TShortCut;
|
---|
494 | FxxxxParent: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
495 | FMerged: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
496 | FMergedWith: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
497 | end;
|
---|
498 | {$ENDIF}
|
---|
499 | {$IFDEF DELPHI_7} // verified against VCL source in Delphi 7
|
---|
500 | type
|
---|
501 | THackMenuItem = class(TComponent)
|
---|
502 | protected
|
---|
503 | FxxxxCaption: AnsiString;
|
---|
504 | FxxxxHandle: HMENU;
|
---|
505 | FxxxxChecked: Boolean;
|
---|
506 | FxxxxEnabled: Boolean;
|
---|
507 | FxxxxDefault: Boolean;
|
---|
508 | FxxxxAutoHotkeys: TMenuItemAutoFlag;
|
---|
509 | FxxxxAutoLineReduction: TMenuItemAutoFlag;
|
---|
510 | FxxxxRadioItem: Boolean;
|
---|
511 | FxxxxVisible: Boolean;
|
---|
512 | FxxxxGroupIndex: Byte;
|
---|
513 | FxxxxImageIndex: TImageIndex;
|
---|
514 | FxxxxActionLink: TMenuActionLink{TNT-ALLOW TMenuActionLink};
|
---|
515 | FxxxxBreak: TMenuBreak;
|
---|
516 | FBitmap: TBitmap;
|
---|
517 | FxxxxCommand: Word;
|
---|
518 | FxxxxHelpContext: THelpContext;
|
---|
519 | FxxxxHint: AnsiString;
|
---|
520 | FxxxxItems: TList;
|
---|
521 | FxxxxShortCut: TShortCut;
|
---|
522 | FxxxxParent: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
523 | FMerged: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
524 | FMergedWith: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
525 | end;
|
---|
526 | {$ENDIF}
|
---|
527 | {$IFDEF DELPHI_9} // verified against VCL source in Delphi 9
|
---|
528 | type
|
---|
529 | THackMenuItem = class(TComponent)
|
---|
530 | protected
|
---|
531 | FxxxxCaption: AnsiString;
|
---|
532 | FxxxxHandle: HMENU;
|
---|
533 | FxxxxChecked: Boolean;
|
---|
534 | FxxxxEnabled: Boolean;
|
---|
535 | FxxxxDefault: Boolean;
|
---|
536 | FxxxxAutoHotkeys: TMenuItemAutoFlag;
|
---|
537 | FxxxxAutoLineReduction: TMenuItemAutoFlag;
|
---|
538 | FxxxxRadioItem: Boolean;
|
---|
539 | FxxxxVisible: Boolean;
|
---|
540 | FxxxxGroupIndex: Byte;
|
---|
541 | FxxxxImageIndex: TImageIndex;
|
---|
542 | FxxxxActionLink: TMenuActionLink{TNT-ALLOW TMenuActionLink};
|
---|
543 | FxxxxBreak: TMenuBreak;
|
---|
544 | FBitmap: TBitmap;
|
---|
545 | FxxxxCommand: Word;
|
---|
546 | FxxxxHelpContext: THelpContext;
|
---|
547 | FxxxxHint: AnsiString;
|
---|
548 | FxxxxItems: TList;
|
---|
549 | FxxxxShortCut: TShortCut;
|
---|
550 | FxxxxParent: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
551 | FMerged: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
552 | FMergedWith: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
553 | end;
|
---|
554 | {$ENDIF}
|
---|
555 | {$IFDEF DELPHI_10} // verified against VCL source in Delphi 10
|
---|
556 | type
|
---|
557 | THackMenuItem = class(TComponent)
|
---|
558 | protected
|
---|
559 | FxxxxCaption: AnsiString;
|
---|
560 | FxxxxHandle: HMENU;
|
---|
561 | FxxxxChecked: Boolean;
|
---|
562 | FxxxxEnabled: Boolean;
|
---|
563 | FxxxxDefault: Boolean;
|
---|
564 | FxxxxAutoHotkeys: TMenuItemAutoFlag;
|
---|
565 | FxxxxAutoLineReduction: TMenuItemAutoFlag;
|
---|
566 | FxxxxRadioItem: Boolean;
|
---|
567 | FxxxxVisible: Boolean;
|
---|
568 | FxxxxGroupIndex: Byte;
|
---|
569 | FxxxxImageIndex: TImageIndex;
|
---|
570 | FxxxxActionLink: TMenuActionLink{TNT-ALLOW TMenuActionLink};
|
---|
571 | FxxxxBreak: TMenuBreak;
|
---|
572 | FBitmap: TBitmap;
|
---|
573 | FxxxxCommand: Word;
|
---|
574 | FxxxxHelpContext: THelpContext;
|
---|
575 | FxxxxHint: AnsiString;
|
---|
576 | FxxxxItems: TList;
|
---|
577 | FxxxxShortCut: TShortCut;
|
---|
578 | FxxxxParent: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
579 | FMerged: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
580 | FMergedWith: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
581 | end;
|
---|
582 | {$ENDIF}
|
---|
583 |
|
---|
584 | function MenuItemHasBitmap(MenuItem: TMenuItem{TNT-ALLOW TMenuItem}): Boolean;
|
---|
585 | begin
|
---|
586 | Result := Assigned(THackMenuItem(MenuItem).FBitmap);
|
---|
587 | end;
|
---|
588 |
|
---|
589 | { TTntMenuItem }
|
---|
590 |
|
---|
591 | procedure TTntMenuItem.DefineProperties(Filer: TFiler);
|
---|
592 | begin
|
---|
593 | inherited;
|
---|
594 | TntPersistent_AfterInherited_DefineProperties(Filer, Self);
|
---|
595 | end;
|
---|
596 |
|
---|
597 | type TAccessActionlink = class(TActionLink);
|
---|
598 |
|
---|
599 | procedure TTntMenuItem.InitiateAction;
|
---|
600 | begin
|
---|
601 | if GetKeyboardLayout(0) <> FKeyboardLayout then
|
---|
602 | MenuChanged(False);
|
---|
603 | inherited;
|
---|
604 | end;
|
---|
605 |
|
---|
606 | function TTntMenuItem.IsCaptionStored: Boolean;
|
---|
607 | begin
|
---|
608 | Result := (ActionLink = nil) or (not TAccessActionlink(ActionLink).IsCaptionLinked);
|
---|
609 | end;
|
---|
610 |
|
---|
611 | procedure TTntMenuItem.SetInheritedCaption(const Value: AnsiString);
|
---|
612 | begin
|
---|
613 | inherited Caption := Value;
|
---|
614 | end;
|
---|
615 |
|
---|
616 | function TTntMenuItem.GetCaption: WideString;
|
---|
617 | begin
|
---|
618 | if (AnsiString(FCaption) <> inherited Caption)
|
---|
619 | and WideSameCaptionStr(AnsiString(FCaption), inherited Caption) then
|
---|
620 | begin
|
---|
621 | // only difference is hotkey position, update caption with new hotkey position
|
---|
622 | SyncHotKeyPosition(inherited Caption, FCaption);
|
---|
623 | end;
|
---|
624 | Result := GetSyncedWideString(FCaption, (inherited Caption));
|
---|
625 | end;
|
---|
626 |
|
---|
627 | procedure TTntMenuItem.SetCaption(const Value: WideString);
|
---|
628 | begin
|
---|
629 | GetCaption; // auto adjust for hot key changes
|
---|
630 | SetSyncedWideString(Value, FCaption, (inherited Caption), SetInheritedCaption);
|
---|
631 | end;
|
---|
632 |
|
---|
633 | function TTntMenuItem.GetHint: WideString;
|
---|
634 | begin
|
---|
635 | Result := GetSyncedWideString(FHint, inherited Hint);
|
---|
636 | end;
|
---|
637 |
|
---|
638 | procedure TTntMenuItem.SetInheritedHint(const Value: AnsiString);
|
---|
639 | begin
|
---|
640 | inherited Hint := Value;
|
---|
641 | end;
|
---|
642 |
|
---|
643 | procedure TTntMenuItem.SetHint(const Value: WideString);
|
---|
644 | begin
|
---|
645 | SetSyncedWideString(Value, FHint, inherited Hint, SetInheritedHint);
|
---|
646 | end;
|
---|
647 |
|
---|
648 | function TTntMenuItem.IsHintStored: Boolean;
|
---|
649 | begin
|
---|
650 | Result := (ActionLink = nil) or not TAccessActionlink(ActionLink).IsHintLinked;
|
---|
651 | end;
|
---|
652 |
|
---|
653 | procedure TTntMenuItem.Loaded;
|
---|
654 | begin
|
---|
655 | inherited;
|
---|
656 | UpdateMenuString(GetParentMenu);
|
---|
657 | end;
|
---|
658 |
|
---|
659 | procedure TTntMenuItem.MenuChanged(Rebuild: Boolean);
|
---|
660 | begin
|
---|
661 | if (not FIgnoreMenuChanged) then begin
|
---|
662 | inherited;
|
---|
663 | UpdateMenuItems(Self, GetParentMenu);
|
---|
664 | FixMenuBiDiProblem(GetParentMenu);
|
---|
665 | end;
|
---|
666 | end;
|
---|
667 |
|
---|
668 | procedure TTntMenuItem.UpdateMenuString(ParentMenu: TMenu);
|
---|
669 | var
|
---|
670 | ParentHandle: THandle;
|
---|
671 |
|
---|
672 | function NativeMenuTypeIsString: Boolean;
|
---|
673 | var
|
---|
674 | MenuItemInfo: TMenuItemInfoW;
|
---|
675 | Buffer: array[0..79] of WideChar;
|
---|
676 | begin
|
---|
677 | MenuItemInfo.cbSize := 44; // Required for Windows NT 4.0
|
---|
678 | MenuItemInfo.fMask := MIIM_TYPE;
|
---|
679 | MenuItemInfo.dwTypeData := Buffer; // ??
|
---|
680 | MenuItemInfo.cch := Length(Buffer); // ??
|
---|
681 | Result := GetMenuItemInfoW(ParentHandle, Command, False, MenuItemInfo)
|
---|
682 | and ((MenuItemInfo.fType and (MFT_BITMAP or MFT_SEPARATOR or MFT_OWNERDRAW)) = 0)
|
---|
683 | end;
|
---|
684 |
|
---|
685 | function NativeMenuString: WideString;
|
---|
686 | var
|
---|
687 | Len: Integer;
|
---|
688 | begin
|
---|
689 | Assert(Win32PlatformIsUnicode);
|
---|
690 | Len := GetMenuStringW(ParentHandle, Command, nil, 0, MF_BYCOMMAND);
|
---|
691 | if Len = 0 then
|
---|
692 | Result := ''
|
---|
693 | else begin
|
---|
694 | SetLength(Result, Len + 1);
|
---|
695 | Len := GetMenuStringW(ParentHandle, Command, PWideChar(Result), Len + 1, MF_BYCOMMAND);
|
---|
696 | SetLength(Result, Len);
|
---|
697 | end;
|
---|
698 | end;
|
---|
699 |
|
---|
700 | procedure SetMenuString(const Value: WideString);
|
---|
701 | var
|
---|
702 | MenuItemInfo: TMenuItemInfoW;
|
---|
703 | Buffer: array[0..79] of WideChar;
|
---|
704 | begin
|
---|
705 | MenuItemInfo.cbSize := 44; // Required for Windows NT 4.0
|
---|
706 | MenuItemInfo.fMask := MIIM_TYPE;
|
---|
707 | MenuItemInfo.dwTypeData := Buffer; // ??
|
---|
708 | MenuItemInfo.cch := Length(Buffer); // ??
|
---|
709 | if GetMenuItemInfoW(ParentHandle, Command, False, MenuItemInfo)
|
---|
710 | and ((MenuItemInfo.fType and (MFT_BITMAP or MFT_SEPARATOR or MFT_OWNERDRAW)) = 0) then
|
---|
711 | begin
|
---|
712 | MenuItemInfo.dwTypeData := PWideChar(Value);
|
---|
713 | MenuItemInfo.cch := Length(Value);
|
---|
714 | Win32Check(SetMenuItemInfoW(ParentHandle, Command, False, MenuItemInfo));
|
---|
715 | end;
|
---|
716 | end;
|
---|
717 |
|
---|
718 | function SameEvent(A, B: TMenuMeasureItemEvent): Boolean;
|
---|
719 | begin
|
---|
720 | Result := @A = @B;
|
---|
721 | end;
|
---|
722 |
|
---|
723 | var
|
---|
724 | MenuCaption: WideString;
|
---|
725 | begin
|
---|
726 | FKeyboardLayout := GetKeyboardLayout(0);
|
---|
727 | if Parent = nil then
|
---|
728 | ParentHandle := 0
|
---|
729 | else if (THackMenuItem(Self.Parent).FMergedWith <> nil) then
|
---|
730 | ParentHandle := THackMenuItem(Self.Parent).FMergedWith.Handle
|
---|
731 | else
|
---|
732 | ParentHandle := Parent.Handle;
|
---|
733 |
|
---|
734 | if (Win32PlatformIsUnicode)
|
---|
735 | and (Parent <> nil) and (ParentMenu <> nil)
|
---|
736 | and (ComponentState * [csReading, csDestroying] = [])
|
---|
737 | and (Visible)
|
---|
738 | and (NativeMenuTypeIsString) then begin
|
---|
739 | MenuCaption := Caption;
|
---|
740 | if (Count = 0)
|
---|
741 | and ((ShortCut <> scNone)
|
---|
742 | and ((Parent = nil) or (Parent.Parent <> nil) or not (Parent.Owner is TMainMenu{TNT-ALLOW TMainMenu}))) then
|
---|
743 | MenuCaption := MenuCaption + #9 + WideShortCutToText(ShortCut);
|
---|
744 | if (NativeMenuString <> MenuCaption) then
|
---|
745 | begin
|
---|
746 | SetMenuString(MenuCaption);
|
---|
747 | if ((Parent = ParentMenu.Items) or (THackMenuItem(Self.Parent).FMergedWith <> nil))
|
---|
748 | and (ParentMenu is TMainMenu{TNT-ALLOW TMainMenu})
|
---|
749 | and (ParentMenu.WindowHandle <> 0) then
|
---|
750 | DrawMenuBar(ParentMenu.WindowHandle) {top level menu bar items}
|
---|
751 | end;
|
---|
752 | end;
|
---|
753 | end;
|
---|
754 |
|
---|
755 | function TTntMenuItem.GetAlignmentDrawStyle: Word;
|
---|
756 | const
|
---|
757 | Alignments: array[TPopupAlignment] of Word = (DT_LEFT, DT_RIGHT, DT_CENTER);
|
---|
758 | var
|
---|
759 | ParentMenu: TMenu;
|
---|
760 | Alignment: TPopupAlignment;
|
---|
761 | begin
|
---|
762 | ParentMenu := GetParentMenu;
|
---|
763 | if ParentMenu is TMenu then
|
---|
764 | Alignment := paLeft
|
---|
765 | else if ParentMenu is TPopupMenu{TNT-ALLOW TPopupMenu} then
|
---|
766 | Alignment := TPopupMenu{TNT-ALLOW TPopupMenu}(ParentMenu).Alignment
|
---|
767 | else
|
---|
768 | Alignment := paLeft;
|
---|
769 | Result := Alignments[Alignment];
|
---|
770 | end;
|
---|
771 |
|
---|
772 | procedure TTntMenuItem.AdvancedDrawItem(ACanvas: TCanvas; ARect: TRect;
|
---|
773 | State: TOwnerDrawState; TopLevel: Boolean);
|
---|
774 |
|
---|
775 | procedure DrawMenuText(BiDi: Boolean);
|
---|
776 | var
|
---|
777 | ImageList: TCustomImageList;
|
---|
778 | DrawImage, DrawGlyph: Boolean;
|
---|
779 | GlyphRect, SaveRect: TRect;
|
---|
780 | DrawStyle: Longint;
|
---|
781 | Selected: Boolean;
|
---|
782 | Win98Plus: Boolean;
|
---|
783 | Win2K: Boolean;
|
---|
784 | begin
|
---|
785 | ImageList := GetImageList;
|
---|
786 | Selected := odSelected in State;
|
---|
787 | Win98Plus := (Win32MajorVersion > 4) or
|
---|
788 | ((Win32MajorVersion = 4) and (Win32MinorVersion > 0));
|
---|
789 | Win2K := (Win32MajorVersion > 4) and (Win32Platform = VER_PLATFORM_WIN32_NT);
|
---|
790 | with ACanvas do
|
---|
791 | begin
|
---|
792 | GlyphRect.Left := ARect.Left + 1;
|
---|
793 | DrawImage := (ImageList <> nil) and ((ImageIndex > -1) and
|
---|
794 | (ImageIndex < ImageList.Count) or Checked and ((not MenuItemHasBitmap(Self)) or
|
---|
795 | Bitmap.Empty));
|
---|
796 | if DrawImage or MenuItemHasBitmap(Self) and not Bitmap.Empty then
|
---|
797 | begin
|
---|
798 | DrawGlyph := True;
|
---|
799 | if DrawImage then
|
---|
800 | GlyphRect.Right := GlyphRect.Left + ImageList.Width
|
---|
801 | else begin
|
---|
802 | { Need to add BitmapWidth/Height properties for TMenuItem if we're to
|
---|
803 | support them. Right now let's hardcode them to 16x16. }
|
---|
804 | GlyphRect.Right := GlyphRect.Left + 16;
|
---|
805 | end;
|
---|
806 | { Draw background pattern brush if selected }
|
---|
807 | if Checked then
|
---|
808 | begin
|
---|
809 | Inc(GlyphRect.Right);
|
---|
810 | if not Selected then
|
---|
811 | Brush.Bitmap := AllocPatternBitmap(clBtnFace, clBtnHighlight);
|
---|
812 | Inc(GlyphRect.Left);
|
---|
813 | end;
|
---|
814 | if Checked then
|
---|
815 | Dec(GlyphRect.Right);
|
---|
816 | end else begin
|
---|
817 | if (ImageList <> nil) and (not TopLevel) then
|
---|
818 | GlyphRect.Right := GlyphRect.Left + ImageList.Width
|
---|
819 | else
|
---|
820 | GlyphRect.Right := GlyphRect.Left;
|
---|
821 | DrawGlyph := False;
|
---|
822 | end;
|
---|
823 | if BiDi then begin
|
---|
824 | SaveRect := GlyphRect;
|
---|
825 | GlyphRect.Left := ARect.Right - (SaveRect.Right - ARect.Left);
|
---|
826 | GlyphRect.Right := ARect.Right - (SaveRect.Left - ARect.Left);
|
---|
827 | end;
|
---|
828 | with GlyphRect do begin
|
---|
829 | Dec(Left);
|
---|
830 | Inc(Right, 2);
|
---|
831 | end;
|
---|
832 | if Selected then begin
|
---|
833 | if DrawGlyph then begin
|
---|
834 | if BiDi then
|
---|
835 | ARect.Right := GlyphRect.Left - 1
|
---|
836 | else
|
---|
837 | ARect.Left := GlyphRect.Right + 1;
|
---|
838 | end;
|
---|
839 | if not (Win98Plus and TopLevel) then
|
---|
840 | Brush.Color := clHighlight;
|
---|
841 | end;
|
---|
842 | if TopLevel and Win98Plus and (not Selected)
|
---|
843 | {$IFDEF COMPILER_7_UP}
|
---|
844 | and (not Win32PlatformIsXP)
|
---|
845 | {$ENDIF}
|
---|
846 | then
|
---|
847 | OffsetRect(ARect, 0, -1);
|
---|
848 | if not (Selected and DrawGlyph) then begin
|
---|
849 | if BiDi then
|
---|
850 | ARect.Right := GlyphRect.Left - 1
|
---|
851 | else
|
---|
852 | ARect.Left := GlyphRect.Right + 1;
|
---|
853 | end;
|
---|
854 | Inc(ARect.Left, 2);
|
---|
855 | Dec(ARect.Right, 1);
|
---|
856 | DrawStyle := DT_EXPANDTABS or DT_SINGLELINE or GetAlignmentDrawStyle;
|
---|
857 | if Win2K and (odNoAccel in State) then
|
---|
858 | DrawStyle := DrawStyle or DT_HIDEPREFIX;
|
---|
859 | { Calculate vertical layout }
|
---|
860 | SaveRect := ARect;
|
---|
861 | if odDefault in State then
|
---|
862 | Font.Style := [fsBold];
|
---|
863 | DoDrawText(ACanvas, Caption, ARect, Selected, DrawStyle or DT_CALCRECT or DT_NOCLIP);
|
---|
864 | if BiDi then begin
|
---|
865 | { the DT_CALCRECT does not take into account alignment }
|
---|
866 | ARect.Left := SaveRect.Left;
|
---|
867 | ARect.Right := SaveRect.Right;
|
---|
868 | end;
|
---|
869 | OffsetRect(ARect, 0, ((SaveRect.Bottom - SaveRect.Top) - (ARect.Bottom - ARect.Top)) div 2);
|
---|
870 | if TopLevel and Selected and Win98Plus
|
---|
871 | {$IFDEF COMPILER_7_UP}
|
---|
872 | and (not Win32PlatformIsXP)
|
---|
873 | {$ENDIF}
|
---|
874 | then
|
---|
875 | OffsetRect(ARect, 1, 0);
|
---|
876 | DoDrawText(ACanvas, Caption, ARect, Selected, DrawStyle);
|
---|
877 | if (ShortCut <> scNone) and not TopLevel then
|
---|
878 | begin
|
---|
879 | if BiDi then begin
|
---|
880 | ARect.Left := 10;
|
---|
881 | ARect.Right := ARect.Left + WideCanvasTextWidth(ACanvas, WideShortCutToText(ShortCut));
|
---|
882 | end else begin
|
---|
883 | ARect.Left := ARect.Right;
|
---|
884 | ARect.Right := SaveRect.Right - 10;
|
---|
885 | end;
|
---|
886 | DoDrawText(ACanvas, WideShortCutToText(ShortCut), ARect, Selected, DT_RIGHT);
|
---|
887 | end;
|
---|
888 | end;
|
---|
889 | end;
|
---|
890 |
|
---|
891 | var
|
---|
892 | ParentMenu: TMenu;
|
---|
893 | SaveCaption: WideString;
|
---|
894 | SaveShortCut: TShortCut;
|
---|
895 | begin
|
---|
896 | ParentMenu := GetParentMenu;
|
---|
897 | if (not Win32PlatformIsUnicode)
|
---|
898 | or (Self.IsLine)
|
---|
899 | or ( (ParentMenu <> nil) and (ParentMenu.OwnerDraw or (GetImageList <> nil))
|
---|
900 | and (Assigned(OnAdvancedDrawItem) or Assigned(OnDrawItem)) ) then
|
---|
901 | inherited
|
---|
902 | else begin
|
---|
903 | SaveCaption := Caption;
|
---|
904 | SaveShortCut := ShortCut;
|
---|
905 | try
|
---|
906 | FIgnoreMenuChanged := True;
|
---|
907 | try
|
---|
908 | Caption := '';
|
---|
909 | ShortCut := scNone;
|
---|
910 | finally
|
---|
911 | FIgnoreMenuChanged := False;
|
---|
912 | end;
|
---|
913 | inherited;
|
---|
914 | finally
|
---|
915 | FIgnoreMenuChanged := True;
|
---|
916 | try
|
---|
917 | Caption := SaveCaption;
|
---|
918 | ShortCut := SaveShortcut;
|
---|
919 | finally
|
---|
920 | FIgnoreMenuChanged := False;
|
---|
921 | end;
|
---|
922 | end;
|
---|
923 | DrawMenuText((ParentMenu <> nil) and (ParentMenu.IsRightToLeft))
|
---|
924 | end;
|
---|
925 | end;
|
---|
926 |
|
---|
927 | procedure TTntMenuItem.DoDrawText(ACanvas: TCanvas; const ACaption: WideString;
|
---|
928 | var Rect: TRect; Selected: Boolean; Flags: Longint);
|
---|
929 | var
|
---|
930 | Text: WideString;
|
---|
931 | ParentMenu: TMenu;
|
---|
932 | begin
|
---|
933 | if (not Win32PlatformIsUnicode)
|
---|
934 | or (IsLine) then
|
---|
935 | inherited DoDrawText(ACanvas, ACaption, Rect, Selected, Flags)
|
---|
936 | else begin
|
---|
937 | ParentMenu := GetParentMenu;
|
---|
938 | if (ParentMenu <> nil) and (ParentMenu.IsRightToLeft) then
|
---|
939 | begin
|
---|
940 | if Flags and DT_LEFT = DT_LEFT then
|
---|
941 | Flags := Flags and (not DT_LEFT) or DT_RIGHT
|
---|
942 | else if Flags and DT_RIGHT = DT_RIGHT then
|
---|
943 | Flags := Flags and (not DT_RIGHT) or DT_LEFT;
|
---|
944 | Flags := Flags or DT_RTLREADING;
|
---|
945 | end;
|
---|
946 | Text := ACaption;
|
---|
947 | if (Flags and DT_CALCRECT <> 0) and ((Text = '') or
|
---|
948 | (Text[1] = cHotkeyPrefix) and (Text[2] = #0)) then Text := Text + ' ';
|
---|
949 | with ACanvas do
|
---|
950 | begin
|
---|
951 | Brush.Style := bsClear;
|
---|
952 | if Default then
|
---|
953 | Font.Style := Font.Style + [fsBold];
|
---|
954 | if not Enabled then
|
---|
955 | begin
|
---|
956 | if not Selected then
|
---|
957 | begin
|
---|
958 | OffsetRect(Rect, 1, 1);
|
---|
959 | Font.Color := clBtnHighlight;
|
---|
960 | Tnt_DrawTextW(Handle, PWideChar(Text), Length(Text), Rect, Flags);
|
---|
961 | OffsetRect(Rect, -1, -1);
|
---|
962 | end;
|
---|
963 | if Selected and (ColorToRGB(clHighlight) = ColorToRGB(clBtnShadow)) then
|
---|
964 | Font.Color := clBtnHighlight else
|
---|
965 | Font.Color := clBtnShadow;
|
---|
966 | end;
|
---|
967 | Tnt_DrawTextW(Handle, PWideChar(Text), Length(Text), Rect, Flags);
|
---|
968 | end;
|
---|
969 | end;
|
---|
970 | end;
|
---|
971 |
|
---|
972 | function TTntMenuItem.MeasureItemTextWidth(ACanvas: TCanvas; const Text: WideString): Integer;
|
---|
973 | var
|
---|
974 | R: TRect;
|
---|
975 | begin
|
---|
976 | FillChar(R, SizeOf(R), 0);
|
---|
977 | DoDrawText(ACanvas, Text, R, False,
|
---|
978 | GetAlignmentDrawStyle or DT_EXPANDTABS or DT_SINGLELINE or DT_NOCLIP or DT_CALCRECT);
|
---|
979 | Result := R.Right - R.Left;
|
---|
980 | end;
|
---|
981 |
|
---|
982 | procedure TTntMenuItem.MeasureItem(ACanvas: TCanvas; var Width, Height: Integer);
|
---|
983 | var
|
---|
984 | SaveMeasureItemEvent: TMenuMeasureItemEvent;
|
---|
985 | begin
|
---|
986 | if (not Win32PlatformIsUnicode)
|
---|
987 | or (Self.IsLine) then
|
---|
988 | inherited
|
---|
989 | else begin
|
---|
990 | SaveMeasureItemEvent := inherited OnMeasureItem;
|
---|
991 | try
|
---|
992 | inherited OnMeasureItem := nil;
|
---|
993 | inherited;
|
---|
994 | Inc(Width, MeasureItemTextWidth(ACanvas, Caption));
|
---|
995 | Dec(Width, MeasureItemTextWidth(ACanvas, inherited Caption));
|
---|
996 | if ShortCut <> scNone then begin
|
---|
997 | Inc(Width, MeasureItemTextWidth(ACanvas, WideShortCutToText(ShortCut)));
|
---|
998 | Dec(Width, MeasureItemTextWidth(ACanvas, ShortCutToText{TNT-ALLOW ShortCutToText}(ShortCut)));
|
---|
999 | end;
|
---|
1000 | finally
|
---|
1001 | inherited OnMeasureItem := SaveMeasureItemEvent;
|
---|
1002 | end;
|
---|
1003 | if Assigned(OnMeasureItem) then OnMeasureItem(Self, ACanvas, Width, Height);
|
---|
1004 | end;
|
---|
1005 | end;
|
---|
1006 |
|
---|
1007 | function TTntMenuItem.Find(ACaption: WideString): TMenuItem{TNT-ALLOW TMenuItem};
|
---|
1008 | var
|
---|
1009 | I: Integer;
|
---|
1010 | begin
|
---|
1011 | Result := nil;
|
---|
1012 | ACaption := WideStripHotkey(ACaption);
|
---|
1013 | for I := 0 to Count - 1 do
|
---|
1014 | if WideSameText(ACaption, WideStripHotkey(WideGetMenuItemCaption(Items[I]))) then
|
---|
1015 | begin
|
---|
1016 | Result := Items[I];
|
---|
1017 | System.Break;
|
---|
1018 | end;
|
---|
1019 | end;
|
---|
1020 |
|
---|
1021 | function TTntMenuItem.GetActionLinkClass: TMenuActionLinkClass;
|
---|
1022 | begin
|
---|
1023 | Result := TTntMenuActionLink;
|
---|
1024 | end;
|
---|
1025 |
|
---|
1026 | procedure TTntMenuItem.ActionChange(Sender: TObject; CheckDefaults: Boolean);
|
---|
1027 | begin
|
---|
1028 | if (Sender is TCustomAction{TNT-ALLOW TCustomAction}) and Supports(Sender, ITntAction) then begin
|
---|
1029 | if not CheckDefaults or (Caption = '') then
|
---|
1030 | Caption := TntAction_GetCaption(TCustomAction{TNT-ALLOW TCustomAction}(Sender));
|
---|
1031 | if not CheckDefaults or (Hint = '') then
|
---|
1032 | Hint := TntAction_GetHint(TCustomAction{TNT-ALLOW TCustomAction}(Sender));
|
---|
1033 | end;
|
---|
1034 | inherited;
|
---|
1035 | end;
|
---|
1036 |
|
---|
1037 | { TTntMainMenu }
|
---|
1038 |
|
---|
1039 | {$IFDEF COMPILER_9_UP}
|
---|
1040 | function TTntMainMenu.CreateMenuItem: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
1041 | begin
|
---|
1042 | Result := TTntMenuItem.Create(Self);
|
---|
1043 | end;
|
---|
1044 | {$ENDIF}
|
---|
1045 |
|
---|
1046 | procedure TTntMainMenu.DoChange(Source: TMenuItem{TNT-ALLOW TMenuItem}; Rebuild: Boolean);
|
---|
1047 | begin
|
---|
1048 | inherited;
|
---|
1049 | UpdateMenuItems(Items, Self);
|
---|
1050 | if (THackMenuItem(Items).FMerged <> nil) then begin
|
---|
1051 | UpdateMenuItems(THackMenuItem(Items).FMerged, Self);
|
---|
1052 | end;
|
---|
1053 | end;
|
---|
1054 |
|
---|
1055 | { TTntPopupMenu }
|
---|
1056 |
|
---|
1057 | constructor TTntPopupMenu.Create(AOwner: TComponent);
|
---|
1058 | begin
|
---|
1059 | inherited;
|
---|
1060 | PopupList.Remove(Self);
|
---|
1061 | if TntPopupList <> nil then
|
---|
1062 | TntPopupList.Add(Self);
|
---|
1063 | end;
|
---|
1064 |
|
---|
1065 | {$IFDEF COMPILER_9_UP}
|
---|
1066 | function TTntPopupMenu.CreateMenuItem: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
1067 | begin
|
---|
1068 | Result := TTntMenuItem.Create(Self);
|
---|
1069 | end;
|
---|
1070 | {$ENDIF}
|
---|
1071 |
|
---|
1072 | destructor TTntPopupMenu.Destroy;
|
---|
1073 | begin
|
---|
1074 | if TntPopupList <> nil then
|
---|
1075 | TntPopupList.Remove(Self);
|
---|
1076 | PopupList.Add(Self);
|
---|
1077 | inherited;
|
---|
1078 | end;
|
---|
1079 |
|
---|
1080 | procedure TTntPopupMenu.DoChange(Source: TMenuItem{TNT-ALLOW TMenuItem}; Rebuild: Boolean);
|
---|
1081 | begin
|
---|
1082 | inherited;
|
---|
1083 | UpdateMenuItems(Items, Self);
|
---|
1084 | end;
|
---|
1085 |
|
---|
1086 | procedure TTntPopupMenu.Popup(X, Y: Integer);
|
---|
1087 | begin
|
---|
1088 | Menus.PopupList := TntPopupList;
|
---|
1089 | try
|
---|
1090 | inherited;
|
---|
1091 | finally
|
---|
1092 | Menus.PopupList := TntPopupList.SavedPopupList;
|
---|
1093 | end;
|
---|
1094 | end;
|
---|
1095 |
|
---|
1096 | { TTntPopupList }
|
---|
1097 |
|
---|
1098 | procedure TTntPopupList.WndProc(var Message: TMessage);
|
---|
1099 | var
|
---|
1100 | I, Item: Integer;
|
---|
1101 | MenuItem: TMenuItem{TNT-ALLOW TMenuItem};
|
---|
1102 | FindKind: TFindItemKind;
|
---|
1103 | begin
|
---|
1104 | case Message.Msg of
|
---|
1105 | WM_ENTERMENULOOP:
|
---|
1106 | begin
|
---|
1107 | Menus.PopupList := SavedPopupList;
|
---|
1108 | for i := 0 to Count - 1 do
|
---|
1109 | FixMenuBiDiProblem(Items[i]);
|
---|
1110 | end;
|
---|
1111 | WM_MENUSELECT:
|
---|
1112 | with TWMMenuSelect(Message) do
|
---|
1113 | begin
|
---|
1114 | FindKind := fkCommand;
|
---|
1115 | if MenuFlag and MF_POPUP <> 0 then FindKind := fkHandle;
|
---|
1116 | for I := 0 to Count - 1 do
|
---|
1117 | begin
|
---|
1118 | if FindKind = fkHandle then
|
---|
1119 | begin
|
---|
1120 | if Menu <> 0 then
|
---|
1121 | Item := Integer(GetSubMenu(Menu, IDItem)) else
|
---|
1122 | Item := -1;
|
---|
1123 | end
|
---|
1124 | else
|
---|
1125 | Item := IDItem;
|
---|
1126 | MenuItem := TPopupMenu{TNT-ALLOW TPopupMenu}(Items[I]).FindItem(Item, FindKind);
|
---|
1127 | if MenuItem <> nil then
|
---|
1128 | begin
|
---|
1129 | TntApplication.Hint := WideGetLongHint(WideGetMenuItemHint(MenuItem));
|
---|
1130 | Exit;
|
---|
1131 | end;
|
---|
1132 | end;
|
---|
1133 | TntApplication.Hint := '';
|
---|
1134 | end;
|
---|
1135 | end;
|
---|
1136 | inherited;
|
---|
1137 | end;
|
---|
1138 |
|
---|
1139 | initialization
|
---|
1140 | TntPopupList := TTntPopupList.Create;
|
---|
1141 | TntPopupList.SavedPopupList := Menus.PopupList;
|
---|
1142 |
|
---|
1143 | finalization
|
---|
1144 | FreeAndNil(TntPopupList);
|
---|
1145 |
|
---|
1146 | end.
|
---|