Mercurial > projects > dwt2
comparison org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/widgets/Menu.d @ 0:6dd524f61e62
add dwt win and basic java stuff
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 02 Mar 2009 14:44:16 +0100 |
parents | |
children | 2e09b0e6857a |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:6dd524f61e62 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.swt.widgets.Menu; | |
14 | |
15 import org.eclipse.swt.SWT; | |
16 import org.eclipse.swt.SWTException; | |
17 import org.eclipse.swt.events.HelpListener; | |
18 import org.eclipse.swt.events.MenuListener; | |
19 import org.eclipse.swt.graphics.Color; | |
20 import org.eclipse.swt.graphics.Image; | |
21 import org.eclipse.swt.graphics.Point; | |
22 import org.eclipse.swt.graphics.Rectangle; | |
23 import org.eclipse.swt.internal.ImageList; | |
24 import org.eclipse.swt.internal.win32.OS; | |
25 | |
26 import org.eclipse.swt.widgets.Widget; | |
27 import org.eclipse.swt.widgets.Decorations; | |
28 import org.eclipse.swt.widgets.MenuItem; | |
29 import org.eclipse.swt.widgets.Control; | |
30 import org.eclipse.swt.widgets.Shell; | |
31 import org.eclipse.swt.widgets.TypedListener; | |
32 | |
33 import java.lang.all; | |
34 | |
35 /** | |
36 * Instances of this class are user interface objects that contain | |
37 * menu items. | |
38 * <dl> | |
39 * <dt><b>Styles:</b></dt> | |
40 * <dd>BAR, DROP_DOWN, POP_UP, NO_RADIO_GROUP</dd> | |
41 * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd> | |
42 * <dt><b>Events:</b></dt> | |
43 * <dd>Help, Hide, Show </dd> | |
44 * </dl> | |
45 * <p> | |
46 * Note: Only one of BAR, DROP_DOWN and POP_UP may be specified. | |
47 * Only one of LEFT_TO_RIGHT or RIGHT_TO_LEFT may be specified. | |
48 * </p><p> | |
49 * IMPORTANT: This class is <em>not</em> intended to be subclassed. | |
50 * </p> | |
51 * | |
52 * @see <a href="http://www.eclipse.org/swt/snippets/#menu">Menu snippets</a> | |
53 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a> | |
54 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
55 */ | |
56 | |
57 public class Menu : Widget { | |
58 /** | |
59 * the handle to the OS resource | |
60 * (Warning: This field is platform dependent) | |
61 * <p> | |
62 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT | |
63 * public API. It is marked public only so that it can be shared | |
64 * within the packages provided by SWT. It is not available on all | |
65 * platforms and should never be accessed from application code. | |
66 * </p> | |
67 */ | |
68 public HMENU handle; | |
69 | |
70 int x, y; | |
71 HBRUSH hBrush; | |
72 HWND hwndCB; | |
73 int id0, id1; | |
74 int foreground = -1, background = -1; | |
75 Image backgroundImage; | |
76 bool hasLocation; | |
77 MenuItem cascade; | |
78 Decorations parent; | |
79 ImageList imageList; | |
80 | |
81 /* Resource ID for SHMENUBARINFO */ | |
82 static const int ID_PPC = 100; | |
83 | |
84 /* SmartPhone SoftKeyBar resource ids */ | |
85 static const int ID_SPMM = 102; | |
86 static const int ID_SPBM = 103; | |
87 static const int ID_SPMB = 104; | |
88 static const int ID_SPBB = 105; | |
89 static const int ID_SPSOFTKEY0 = 106; | |
90 static const int ID_SPSOFTKEY1 = 107; | |
91 | |
92 /** | |
93 * Constructs a new instance of this class given its parent, | |
94 * and sets the style for the instance so that the instance | |
95 * will be a popup menu on the given parent's shell. | |
96 * <p> | |
97 * After constructing a menu, it can be set into its parent | |
98 * using <code>parent.setMenu(menu)</code>. In this case, the parent may | |
99 * be any control in the same widget tree as the parent. | |
100 * </p> | |
101 * | |
102 * @param parent a control which will be the parent of the new instance (cannot be null) | |
103 * | |
104 * @exception IllegalArgumentException <ul> | |
105 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> | |
106 * </ul> | |
107 * @exception SWTException <ul> | |
108 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
109 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
110 * </ul> | |
111 * | |
112 * @see SWT#POP_UP | |
113 * @see Widget#checkSubclass | |
114 * @see Widget#getStyle | |
115 */ | |
116 public this (Control parent) { | |
117 this (checkNull (parent).menuShell (), SWT.POP_UP); | |
118 } | |
119 | |
120 /** | |
121 * Constructs a new instance of this class given its parent | |
122 * (which must be a <code>Decorations</code>) and a style value | |
123 * describing its behavior and appearance. | |
124 * <p> | |
125 * The style value is either one of the style constants defined in | |
126 * class <code>SWT</code> which is applicable to instances of this | |
127 * class, or must be built by <em>bitwise OR</em>'ing together | |
128 * (that is, using the <code>int</code> "|" operator) two or more | |
129 * of those <code>SWT</code> style constants. The class description | |
130 * lists the style constants that are applicable to the class. | |
131 * Style bits are also inherited from superclasses. | |
132 * </p><p> | |
133 * After constructing a menu or menuBar, it can be set into its parent | |
134 * using <code>parent.setMenu(menu)</code> or <code>parent.setMenuBar(menuBar)</code>. | |
135 * </p> | |
136 * | |
137 * @param parent a decorations control which will be the parent of the new instance (cannot be null) | |
138 * @param style the style of menu to construct | |
139 * | |
140 * @exception IllegalArgumentException <ul> | |
141 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> | |
142 * </ul> | |
143 * @exception SWTException <ul> | |
144 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
145 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
146 * </ul> | |
147 * | |
148 * @see SWT#BAR | |
149 * @see SWT#DROP_DOWN | |
150 * @see SWT#POP_UP | |
151 * @see Widget#checkSubclass | |
152 * @see Widget#getStyle | |
153 */ | |
154 public this (Decorations parent, int style) { | |
155 this (parent, checkStyle (style), null); | |
156 } | |
157 | |
158 /** | |
159 * Constructs a new instance of this class given its parent | |
160 * (which must be a <code>Menu</code>) and sets the style | |
161 * for the instance so that the instance will be a drop-down | |
162 * menu on the given parent's parent. | |
163 * <p> | |
164 * After constructing a drop-down menu, it can be set into its parentMenu | |
165 * using <code>parentMenu.setMenu(menu)</code>. | |
166 * </p> | |
167 * | |
168 * @param parentMenu a menu which will be the parent of the new instance (cannot be null) | |
169 * | |
170 * @exception IllegalArgumentException <ul> | |
171 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> | |
172 * </ul> | |
173 * @exception SWTException <ul> | |
174 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
175 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
176 * </ul> | |
177 * | |
178 * @see SWT#DROP_DOWN | |
179 * @see Widget#checkSubclass | |
180 * @see Widget#getStyle | |
181 */ | |
182 public this (Menu parentMenu) { | |
183 this (checkNull (parentMenu).parent, SWT.DROP_DOWN); | |
184 } | |
185 | |
186 /** | |
187 * Constructs a new instance of this class given its parent | |
188 * (which must be a <code>MenuItem</code>) and sets the style | |
189 * for the instance so that the instance will be a drop-down | |
190 * menu on the given parent's parent menu. | |
191 * <p> | |
192 * After constructing a drop-down menu, it can be set into its parentItem | |
193 * using <code>parentItem.setMenu(menu)</code>. | |
194 * </p> | |
195 * | |
196 * @param parentItem a menu item which will be the parent of the new instance (cannot be null) | |
197 * | |
198 * @exception IllegalArgumentException <ul> | |
199 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> | |
200 * </ul> | |
201 * @exception SWTException <ul> | |
202 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
203 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
204 * </ul> | |
205 * | |
206 * @see SWT#DROP_DOWN | |
207 * @see Widget#checkSubclass | |
208 * @see Widget#getStyle | |
209 */ | |
210 public this (MenuItem parentItem) { | |
211 this (checkNull (parentItem).parent); | |
212 } | |
213 | |
214 this (Decorations parent, int style, HWND handle) { | |
215 super (parent, checkStyle (style)); | |
216 this.parent = parent; | |
217 this.handle = handle; | |
218 /* | |
219 * Bug in IBM JVM 1.3.1. For some reason, when the checkOrientation() is | |
220 * called from createWidget(), the JVM issues this error: | |
221 * | |
222 * JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8) | |
223 * | |
224 * In addition, on Windows XP, a dialog appears with following error message, | |
225 * indicating that the problem may be in the JIT: | |
226 * | |
227 * AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll | |
228 * ModVer: 0.0.0.0 Offset: 000b6912 | |
229 * | |
230 * The fix is to call checkOrientation() from here. | |
231 */ | |
232 checkOrientation (parent); | |
233 createWidget (); | |
234 } | |
235 | |
236 void _setVisible (bool visible) { | |
237 if ((style & (SWT.BAR | SWT.DROP_DOWN)) !is 0) return; | |
238 auto hwndParent = parent.handle; | |
239 if (visible) { | |
240 int flags = OS.TPM_LEFTBUTTON; | |
241 if (OS.GetKeyState (OS.VK_LBUTTON) >= 0) flags |= OS.TPM_RIGHTBUTTON; | |
242 if ((style & SWT.RIGHT_TO_LEFT) !is 0) flags |= OS.TPM_RIGHTALIGN; | |
243 if ((parent.style & SWT.MIRRORED) !is 0) { | |
244 flags &= ~OS.TPM_RIGHTALIGN; | |
245 if ((style & SWT.LEFT_TO_RIGHT) !is 0) flags |= OS.TPM_RIGHTALIGN; | |
246 } | |
247 int nX = x, nY = y; | |
248 if (!hasLocation) { | |
249 int pos = OS.GetMessagePos (); | |
250 nX = OS.GET_X_LPARAM (pos); | |
251 nY = OS.GET_Y_LPARAM (pos); | |
252 } | |
253 /* | |
254 * Feature in Windows. It is legal use TrackPopupMenu() | |
255 * to display an empty menu as long as menu items are added | |
256 * inside of WM_INITPOPUPMENU. If no items are added, then | |
257 * TrackPopupMenu() fails and does not send an indication | |
258 * that the menu has been closed. This is not strictly a | |
259 * bug but leads to unwanted behavior when application code | |
260 * assumes that every WM_INITPOPUPMENU will eventually result | |
261 * in a WM_MENUSELECT, wParam=MAKEWPARAM (0, 0xFFFF), lParam=0 to | |
262 * indicate that the menu has been closed. The fix is to detect | |
263 * the case when TrackPopupMenu() fails and the number of items in | |
264 * the menu is zero and issue a fake WM_MENUSELECT. | |
265 */ | |
266 bool success = cast(bool) OS.TrackPopupMenu (handle, flags, nX, nY, 0, hwndParent, null); | |
267 if (!success && GetMenuItemCount (handle) is 0) { | |
268 OS.SendMessage (hwndParent, OS.WM_MENUSELECT, OS.MAKEWPARAM (0, 0xFFFF), 0); | |
269 } | |
270 } else { | |
271 OS.SendMessage (hwndParent, OS.WM_CANCELMODE, 0, 0); | |
272 } | |
273 } | |
274 | |
275 /** | |
276 * Adds the listener to the collection of listeners who will | |
277 * be notified when help events are generated for the control, | |
278 * by sending it one of the messages defined in the | |
279 * <code>HelpListener</code> interface. | |
280 * | |
281 * @param listener the listener which should be notified | |
282 * | |
283 * @exception IllegalArgumentException <ul> | |
284 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
285 * </ul> | |
286 * @exception SWTException <ul> | |
287 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
288 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
289 * </ul> | |
290 * | |
291 * @see HelpListener | |
292 * @see #removeHelpListener | |
293 */ | |
294 public void addHelpListener (HelpListener listener) { | |
295 checkWidget (); | |
296 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); | |
297 TypedListener typedListener = new TypedListener (listener); | |
298 addListener (SWT.Help, typedListener); | |
299 } | |
300 | |
301 /** | |
302 * Adds the listener to the collection of listeners who will | |
303 * be notified when menus are hidden or shown, by sending it | |
304 * one of the messages defined in the <code>MenuListener</code> | |
305 * interface. | |
306 * | |
307 * @param listener the listener which should be notified | |
308 * | |
309 * @exception IllegalArgumentException <ul> | |
310 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
311 * </ul> | |
312 * @exception SWTException <ul> | |
313 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
314 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
315 * </ul> | |
316 * | |
317 * @see MenuListener | |
318 * @see #removeMenuListener | |
319 */ | |
320 public void addMenuListener (MenuListener listener) { | |
321 checkWidget (); | |
322 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); | |
323 TypedListener typedListener = new TypedListener (listener); | |
324 addListener (SWT.Hide,typedListener); | |
325 addListener (SWT.Show,typedListener); | |
326 } | |
327 | |
328 static Control checkNull (Control control) { | |
329 if (control is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); | |
330 return control; | |
331 } | |
332 | |
333 static Menu checkNull (Menu menu) { | |
334 if (menu is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); | |
335 return menu; | |
336 } | |
337 | |
338 static MenuItem checkNull (MenuItem item) { | |
339 if (item is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); | |
340 return item; | |
341 } | |
342 | |
343 static int checkStyle (int style) { | |
344 return checkBits (style, SWT.POP_UP, SWT.BAR, SWT.DROP_DOWN, 0, 0, 0); | |
345 } | |
346 | |
347 void createHandle () { | |
348 if (handle !is null) return; | |
349 if ((style & SWT.BAR) !is 0) { | |
350 static if( OS.IsWinCE ) if (OS.IsPPC) { | |
351 auto hwndShell = parent.handle; | |
352 SHMENUBARINFO mbi; | |
353 mbi.cbSize = SHMENUBARINFO.sizeof; | |
354 mbi.hwndParent = hwndShell; | |
355 mbi.dwFlags = OS.SHCMBF_HIDDEN; | |
356 mbi.nToolBarId = ID_PPC; | |
357 mbi.hInstRes = OS.GetLibraryHandle (); | |
358 bool success = cast(bool) OS.SHCreateMenuBar (&mbi); | |
359 hwndCB = mbi.hwndMB; | |
360 if (!success) error (SWT.ERROR_NO_HANDLES); | |
361 /* Remove the item from the resource file */ | |
362 OS.SendMessage (hwndCB, OS.TB_DELETEBUTTON, 0, 0); | |
363 return; | |
364 } | |
365 /* | |
366 * Note in WinCE SmartPhone. The SoftBar contains only 2 items. | |
367 * An item can either be a menu or a button. | |
368 * SWT.BAR: creates a SoftBar with 2 menus | |
369 * SWT.BAR | SWT.BUTTON1: creates a SoftBar with 1 button | |
370 * for button1, and a menu for button2 | |
371 * SWT.BAR | SWT.BUTTON1 | SWT.BUTTON2: creates a SoftBar with | |
372 * 2 buttons | |
373 */ | |
374 static if (OS.IsSP) { | |
375 /* Determine type of menubar */ | |
376 int nToolBarId; | |
377 if ((style & SWT.BUTTON1) !is 0) { | |
378 nToolBarId = ((style & SWT.BUTTON2) !is 0) ? ID_SPBB : ID_SPBM; | |
379 } else { | |
380 nToolBarId = ((style & SWT.BUTTON2) !is 0) ? ID_SPMB : ID_SPMM; | |
381 } | |
382 | |
383 /* Create SHMENUBAR */ | |
384 SHMENUBARINFO mbi; | |
385 mbi.cbSize = SHMENUBARINFO.sizeof; | |
386 mbi.hwndParent = parent.handle; | |
387 mbi.dwFlags = OS.SHCMBF_HIDDEN; | |
388 mbi.nToolBarId = nToolBarId; /* as defined in .rc file */ | |
389 mbi.hInstRes = OS.GetLibraryHandle (); | |
390 if (!OS.SHCreateMenuBar (&mbi)) error (SWT.ERROR_NO_HANDLES); | |
391 hwndCB = mbi.hwndMB; | |
392 | |
393 /* | |
394 * Feature on WinCE SmartPhone. The SHCMBF_HIDDEN flag causes the | |
395 * SHMENUBAR to not be drawn. However the keyboard events still go | |
396 * through it. The workaround is to also hide the SHMENUBAR with | |
397 * ShowWindow (). | |
398 */ | |
399 OS.ShowWindow (hwndCB, OS.SW_HIDE); | |
400 | |
401 TBBUTTONINFO info = new TBBUTTONINFO (); | |
402 info.cbSize = TBBUTTONINFO.sizeof; | |
403 info.dwMask = OS.TBIF_COMMAND; | |
404 MenuItem item; | |
405 | |
406 /* Set first item */ | |
407 if (nToolBarId is ID_SPMM || nToolBarId is ID_SPMB) { | |
408 int /*long*/ hMenu = OS.SendMessage (hwndCB, OS.SHCMBM_GETSUBMENU, 0, ID_SPSOFTKEY0); | |
409 /* Remove the item from the resource file */ | |
410 OS.RemoveMenu (hMenu, 0, OS.MF_BYPOSITION); | |
411 Menu menu = new Menu (parent, SWT.DROP_DOWN, hMenu); | |
412 item = new MenuItem (this, menu, SWT.CASCADE, 0); | |
413 } else { | |
414 item = new MenuItem (this, null, SWT.PUSH, 0); | |
415 } | |
416 info.idCommand = id0 = item.id; | |
417 OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, ID_SPSOFTKEY0, info); | |
418 | |
419 /* Set second item */ | |
420 if (nToolBarId is ID_SPMM || nToolBarId is ID_SPBM) { | |
421 int /*long*/ hMenu = OS.SendMessage (hwndCB, OS.SHCMBM_GETSUBMENU, 0, ID_SPSOFTKEY1); | |
422 OS.RemoveMenu (hMenu, 0, OS.MF_BYPOSITION); | |
423 Menu menu = new Menu (parent, SWT.DROP_DOWN, hMenu); | |
424 item = new MenuItem (this, menu, SWT.CASCADE, 1); | |
425 } else { | |
426 item = new MenuItem (this, null, SWT.PUSH, 1); | |
427 } | |
428 info.idCommand = id1 = item.id; | |
429 OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, ID_SPSOFTKEY1, info); | |
430 | |
431 /* | |
432 * Override the Back key. For some reason, the owner of the menubar | |
433 * must be a Dialog or it won't receive the WM_HOTKEY message. As | |
434 * a result, Shell on WinCE SP must use the class Dialog. | |
435 */ | |
436 int dwMask = OS.SHMBOF_NODEFAULT | OS.SHMBOF_NOTIFY; | |
437 int /*long*/ lParam = OS.MAKELPARAM (dwMask, dwMask); | |
438 OS.SendMessage (hwndCB, OS.SHCMBM_OVERRIDEKEY, OS.VK_ESCAPE, lParam); | |
439 return; | |
440 } | |
441 handle = OS.CreateMenu (); | |
442 if (handle is null) error (SWT.ERROR_NO_HANDLES); | |
443 static if (OS.IsHPC) { | |
444 auto hwndShell = parent.handle; | |
445 hwndCB = OS.CommandBar_Create (OS.GetModuleHandle (null), hwndShell, 1); | |
446 if (hwndCB is null) error (SWT.ERROR_NO_HANDLES); | |
447 OS.CommandBar_Show (hwndCB, false); | |
448 OS.CommandBar_InsertMenubarEx (hwndCB, 0, handle, 0); | |
449 /* | |
450 * The command bar hosts the 'close' button when the window does not | |
451 * have a caption. | |
452 */ | |
453 if ((parent.style & SWT.CLOSE) !is 0 && (parent.style & SWT.TITLE) is 0) { | |
454 OS.CommandBar_AddAdornments (hwndCB, 0, 0); | |
455 } | |
456 } | |
457 } else { | |
458 handle = OS.CreatePopupMenu (); | |
459 if (handle is null) error (SWT.ERROR_NO_HANDLES); | |
460 } | |
461 } | |
462 | |
463 void createItem (MenuItem item, int index) { | |
464 int count = GetMenuItemCount (handle); | |
465 if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE); | |
466 display.addMenuItem (item); | |
467 bool success = false; | |
468 if ((OS.IsPPC || OS.IsSP) && hwndCB !is null) { | |
469 if (OS.IsSP) return; | |
470 TBBUTTON lpButton; | |
471 lpButton.idCommand = item.id; | |
472 lpButton.fsStyle = cast(byte) OS.TBSTYLE_AUTOSIZE; | |
473 if ((item.style & SWT.CASCADE) !is 0) lpButton.fsStyle |= OS.TBSTYLE_DROPDOWN | 0x80; | |
474 if ((item.style & SWT.SEPARATOR) !is 0) lpButton.fsStyle = cast(byte) OS.BTNS_SEP; | |
475 lpButton.fsState = cast(byte) OS.TBSTATE_ENABLED; | |
476 lpButton.iBitmap = OS.I_IMAGENONE; | |
477 success = OS.SendMessage (hwndCB, OS.TB_INSERTBUTTON, index, &lpButton) !is 0; | |
478 } else { | |
479 static if (OS.IsWinCE) { | |
480 int uFlags = OS.MF_BYPOSITION; | |
481 TCHAR lpNewItem = null; | |
482 if ((item.style & SWT.SEPARATOR) !is 0) { | |
483 uFlags |= OS.MF_SEPARATOR; | |
484 } else { | |
485 lpNewItem = new TCHAR (0, " ", true); | |
486 } | |
487 success = OS.InsertMenu (handle, index, uFlags, item.id, lpNewItem); | |
488 if (success) { | |
489 MENUITEMINFO info = new MENUITEMINFO (); | |
490 info.cbSize = OS.MENUITEMINFO_sizeof; | |
491 info.fMask = OS.MIIM_DATA; | |
492 info.dwItemData = item.id; | |
493 success = OS.SetMenuItemInfo (handle, index, true, info); | |
494 } | |
495 } else { | |
496 /* | |
497 * Bug in Windows. For some reason, when InsertMenuItem() | |
498 * is used to insert an item without text, it is not possible | |
499 * to use SetMenuItemInfo() to set the text at a later time. | |
500 * The fix is to insert the item with some text. | |
501 * | |
502 * Feature in Windows. When an empty string is used instead | |
503 * of a space and InsertMenuItem() is used to set a submenu | |
504 * before setting text to a non-empty string, the menu item | |
505 * becomes unexpectedly disabled. The fix is to insert a | |
506 * space. | |
507 */ | |
508 auto hHeap = OS.GetProcessHeap (); | |
509 TCHAR[] buffer = StrToTCHARs (0, " \0"); | |
510 int byteCount = (buffer.length-1) * TCHAR.sizeof; | |
511 auto pszText = cast(TCHAR*) OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); | |
512 OS.MoveMemory (pszText, buffer.ptr, byteCount); | |
513 MENUITEMINFO info; | |
514 info.cbSize = OS.MENUITEMINFO_sizeof; | |
515 info.fMask = OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_DATA; | |
516 info.wID = item.id; | |
517 info.dwItemData = item.id; | |
518 info.fType = item.widgetStyle (); | |
519 info.dwTypeData = pszText; | |
520 success = cast(bool) OS.InsertMenuItem (handle, index, true, &info); | |
521 if (pszText !is null) OS.HeapFree (hHeap, 0, pszText); | |
522 } | |
523 } | |
524 if (!success) { | |
525 display.removeMenuItem (item); | |
526 error (SWT.ERROR_ITEM_NOT_ADDED); | |
527 } | |
528 redraw (); | |
529 } | |
530 | |
531 void createWidget () { | |
532 /* | |
533 * Bug in IBM JVM 1.3.1. For some reason, when the following code is called | |
534 * from this method, the JVM issues this error: | |
535 * | |
536 * JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8) | |
537 * | |
538 * In addition, on Windows XP, a dialog appears with following error message, | |
539 * indicating that the problem may be in the JIT: | |
540 * | |
541 * AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll | |
542 * ModVer: 0.0.0.0 Offset: 000b6912 | |
543 * | |
544 * The fix is to move the code to the caller of this method. | |
545 */ | |
546 // checkOrientation (parent); | |
547 createHandle (); | |
548 parent.addMenu (this); | |
549 } | |
550 | |
551 int defaultBackground () { | |
552 return OS.GetSysColor (OS.COLOR_MENU); | |
553 } | |
554 | |
555 int defaultForeground () { | |
556 return OS.GetSysColor (OS.COLOR_MENUTEXT); | |
557 } | |
558 | |
559 void destroyAccelerators () { | |
560 parent.destroyAccelerators (); | |
561 } | |
562 | |
563 void destroyItem (MenuItem item) { | |
564 static if (OS.IsWinCE) { | |
565 if ((OS.IsPPC || OS.IsSP) && hwndCB !is null) { | |
566 if (OS.IsSP) { | |
567 redraw(); | |
568 return; | |
569 } | |
570 int index = OS.SendMessage (hwndCB, OS.TB_COMMANDTOINDEX, item.id, 0); | |
571 if (OS.SendMessage (hwndCB, OS.TB_DELETEBUTTON, index, 0) is 0) { | |
572 error (SWT.ERROR_ITEM_NOT_REMOVED); | |
573 } | |
574 int count = OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0); | |
575 if (count is 0) { | |
576 if (imageList !is null) { | |
577 OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0); | |
578 display.releaseImageList (imageList); | |
579 imageList = null; | |
580 } | |
581 } | |
582 } else { | |
583 int index = 0; | |
584 MENUITEMINFO info; | |
585 info.cbSize = OS.MENUITEMINFO_sizeof; | |
586 info.fMask = OS.MIIM_DATA; | |
587 while (OS.GetMenuItemInfo (handle, index, true, &info)) { | |
588 if (info.dwItemData is item.id) break; | |
589 index++; | |
590 } | |
591 if (info.dwItemData !is item.id) { | |
592 error (SWT.ERROR_ITEM_NOT_REMOVED); | |
593 } | |
594 if (!OS.DeleteMenu (handle, index, OS.MF_BYPOSITION)) { | |
595 error (SWT.ERROR_ITEM_NOT_REMOVED); | |
596 } | |
597 } | |
598 } else { | |
599 if (!OS.DeleteMenu (handle, item.id, OS.MF_BYCOMMAND)) { | |
600 error (SWT.ERROR_ITEM_NOT_REMOVED); | |
601 } | |
602 } | |
603 redraw (); | |
604 } | |
605 | |
606 override void destroyWidget () { | |
607 MenuItem cascade = this.cascade; | |
608 HMENU hMenu = handle; | |
609 HWND hCB = hwndCB; | |
610 releaseHandle (); | |
611 static if (OS.IsWinCE) { | |
612 if( hCB !is null ){ | |
613 OS.CommandBar_Destroy (hCB); | |
614 } | |
615 } else { | |
616 if (cascade !is null) { | |
617 if (!OS.IsSP) cascade.setMenu (null, true); | |
618 } else { | |
619 if (hMenu !is null) OS.DestroyMenu (hMenu); | |
620 } | |
621 } | |
622 } | |
623 | |
624 void fixMenus (Decorations newParent) { | |
625 MenuItem [] items = getItems (); | |
626 for (int i=0; i<items.length; i++) { | |
627 items [i].fixMenus (newParent); | |
628 } | |
629 parent.removeMenu (this); | |
630 newParent.addMenu (this); | |
631 this.parent = newParent; | |
632 } | |
633 | |
634 /** | |
635 * Returns the receiver's background color. | |
636 * | |
637 * @return the background color | |
638 * | |
639 * @exception SWTException <ul> | |
640 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
641 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
642 * </ul> | |
643 * | |
644 * @since 3.3 | |
645 */ | |
646 /*public*/ Color getBackground () { | |
647 checkWidget (); | |
648 return Color.win32_new (display, background !is -1 ? background : defaultBackground ()); | |
649 } | |
650 | |
651 /** | |
652 * Returns the receiver's background image. | |
653 * | |
654 * @return the background image | |
655 * | |
656 * @exception SWTException <ul> | |
657 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
658 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
659 * </ul> | |
660 * | |
661 * @since 3.3 | |
662 */ | |
663 /*public*/ Image getBackgroundImage () { | |
664 checkWidget (); | |
665 return backgroundImage; | |
666 } | |
667 | |
668 /** | |
669 * Returns a rectangle describing the receiver's size and location | |
670 * relative to its parent (or its display if its parent is null), | |
671 * unless the receiver is a menu or a shell. In this case, the | |
672 * location is relative to the display. | |
673 * <p> | |
674 * Note that the bounds of a menu or menu item are undefined when | |
675 * the menu is not visible. This is because most platforms compute | |
676 * the bounds of a menu dynamically just before it is displayed. | |
677 * </p> | |
678 * | |
679 * @return the receiver's bounding rectangle | |
680 * | |
681 * @exception SWTException <ul> | |
682 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
683 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
684 * </ul> | |
685 * | |
686 * @since 3.1 | |
687 */ | |
688 /*public*/ Rectangle getBounds () { | |
689 checkWidget (); | |
690 static if (OS.IsWinCE) return new Rectangle (0, 0, 0, 0); | |
691 if ((style & SWT.BAR) !is 0) { | |
692 if (parent.menuBar !is this) { | |
693 return new Rectangle (0, 0, 0, 0); | |
694 } | |
695 auto hwndShell = parent.handle; | |
696 MENUBARINFO info; | |
697 info.cbSize = MENUBARINFO.sizeof; | |
698 if (OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, 0, &info)) { | |
699 int width = info.rcBar.right - info.rcBar.left; | |
700 int height = info.rcBar.bottom - info.rcBar.top; | |
701 return new Rectangle (info.rcBar.left, info.rcBar.top, width, height); | |
702 } | |
703 } else { | |
704 int count = GetMenuItemCount (handle); | |
705 if (count !is 0) { | |
706 RECT rect1; | |
707 if (OS.GetMenuItemRect (null, handle, 0, &rect1)) { | |
708 RECT rect2; | |
709 if (OS.GetMenuItemRect (null, handle, count - 1, &rect2)) { | |
710 int x = rect1.left - 2, y = rect1.top - 2; | |
711 int width = (rect2.right - rect2.left) + 4; | |
712 int height = (rect2.bottom - rect1.top) + 4; | |
713 return new Rectangle (x, y, width, height); | |
714 } | |
715 } | |
716 } | |
717 } | |
718 return new Rectangle (0, 0, 0, 0); | |
719 } | |
720 | |
721 /** | |
722 * Returns the default menu item or null if none has | |
723 * been previously set. | |
724 * | |
725 * @return the default menu item. | |
726 * | |
727 * </ul> | |
728 * @exception SWTException <ul> | |
729 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
730 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
731 * </ul> | |
732 */ | |
733 public MenuItem getDefaultItem () { | |
734 checkWidget (); | |
735 static if (OS.IsWinCE) return null; | |
736 int id = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED); | |
737 if (id is -1) return null; | |
738 MENUITEMINFO info; | |
739 info.cbSize = OS.MENUITEMINFO_sizeof; | |
740 info.fMask = OS.MIIM_ID; | |
741 if (OS.GetMenuItemInfo (handle, id, false, &info)) { | |
742 return display.getMenuItem (info.wID); | |
743 } | |
744 return null; | |
745 } | |
746 | |
747 /** | |
748 * Returns <code>true</code> if the receiver is enabled, and | |
749 * <code>false</code> otherwise. A disabled menu is typically | |
750 * not selectable from the user interface and draws with an | |
751 * inactive or "grayed" look. | |
752 * | |
753 * @return the receiver's enabled state | |
754 * | |
755 * @exception SWTException <ul> | |
756 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
757 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
758 * </ul> | |
759 * | |
760 * @see #isEnabled | |
761 */ | |
762 public bool getEnabled () { | |
763 checkWidget (); | |
764 return (state & DISABLED) is 0; | |
765 } | |
766 | |
767 /** | |
768 * Returns the foreground color that the receiver will use to draw. | |
769 * | |
770 * @return the receiver's foreground color | |
771 * | |
772 * @exception SWTException <ul> | |
773 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
774 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
775 * </ul> | |
776 */ | |
777 /*public*/ Color getForeground () { | |
778 checkWidget (); | |
779 return Color.win32_new (display, foreground !is -1 ? foreground : defaultForeground ()); | |
780 } | |
781 | |
782 /** | |
783 * Returns the item at the given, zero-relative index in the | |
784 * receiver. Throws an exception if the index is out of range. | |
785 * | |
786 * @param index the index of the item to return | |
787 * @return the item at the given index | |
788 * | |
789 * @exception IllegalArgumentException <ul> | |
790 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> | |
791 * </ul> | |
792 * @exception SWTException <ul> | |
793 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
794 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
795 * </ul> | |
796 */ | |
797 public MenuItem getItem (int index) { | |
798 checkWidget (); | |
799 int id = 0; | |
800 if ((OS.IsPPC || OS.IsSP) && hwndCB !is null) { | |
801 static if (OS.IsPPC) { | |
802 TBBUTTON lpButton; | |
803 int result = OS.SendMessage (hwndCB, OS.TB_GETBUTTON, index, &lpButton); | |
804 if (result is 0) error (SWT.ERROR_CANNOT_GET_ITEM); | |
805 id = lpButton.idCommand; | |
806 } | |
807 if (OS.IsSP) { | |
808 if (!(0 <= index && index <= 1)) error (SWT.ERROR_CANNOT_GET_ITEM); | |
809 id = index is 0 ? id0 : id1; | |
810 } | |
811 } else { | |
812 MENUITEMINFO info; | |
813 info.cbSize = OS.MENUITEMINFO_sizeof; | |
814 info.fMask = OS.MIIM_DATA; | |
815 if (!OS.GetMenuItemInfo (handle, index, true, &info)) { | |
816 error (SWT.ERROR_INVALID_RANGE); | |
817 } | |
818 id = info.dwItemData; | |
819 } | |
820 return display.getMenuItem (id); | |
821 } | |
822 | |
823 /** | |
824 * Returns the number of items contained in the receiver. | |
825 * | |
826 * @return the number of items | |
827 * | |
828 * @exception SWTException <ul> | |
829 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
830 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
831 * </ul> | |
832 */ | |
833 public int getItemCount () { | |
834 checkWidget (); | |
835 return GetMenuItemCount (handle); | |
836 } | |
837 | |
838 /** | |
839 * Returns a (possibly empty) array of <code>MenuItem</code>s which | |
840 * are the items in the receiver. | |
841 * <p> | |
842 * Note: This is not the actual structure used by the receiver | |
843 * to maintain its list of items, so modifying the array will | |
844 * not affect the receiver. | |
845 * </p> | |
846 * | |
847 * @return the items in the receiver | |
848 * | |
849 * @exception SWTException <ul> | |
850 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
851 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
852 * </ul> | |
853 */ | |
854 public MenuItem [] getItems () { | |
855 checkWidget (); | |
856 if ((OS.IsPPC || OS.IsSP) && hwndCB !is null) { | |
857 if (OS.IsSP) { | |
858 MenuItem [] result = new MenuItem [2]; | |
859 result[0] = display.getMenuItem (id0); | |
860 result[1] = display.getMenuItem (id1); | |
861 return result; | |
862 } | |
863 int count = OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0); | |
864 TBBUTTON lpButton; | |
865 MenuItem [] result = new MenuItem [count]; | |
866 for (int i=0; i<count; i++) { | |
867 OS.SendMessage (hwndCB, OS.TB_GETBUTTON, i, &lpButton); | |
868 result [i] = display.getMenuItem (lpButton.idCommand); | |
869 } | |
870 return result; | |
871 } | |
872 int index = 0, count = 0; | |
873 int length = OS.IsWinCE ? 4 : OS.GetMenuItemCount (handle); | |
874 MenuItem [] items = new MenuItem [length]; | |
875 MENUITEMINFO info; | |
876 info.cbSize = OS.MENUITEMINFO_sizeof; | |
877 info.fMask = OS.MIIM_DATA; | |
878 while (OS.GetMenuItemInfo (handle, index, true, &info)) { | |
879 if (count is items.length) { | |
880 MenuItem [] newItems = new MenuItem [count + 4]; | |
881 System.arraycopy (items, 0, newItems, 0, count); | |
882 items = newItems; | |
883 } | |
884 MenuItem item = display.getMenuItem (info.dwItemData); | |
885 if (item !is null) items [count++] = item; | |
886 index++; | |
887 } | |
888 if (count is items.length) return items; | |
889 MenuItem [] result = new MenuItem [count]; | |
890 System.arraycopy (items, 0, result, 0, count); | |
891 return result; | |
892 } | |
893 | |
894 int GetMenuItemCount (HANDLE handle) { | |
895 static if (OS.IsWinCE) { | |
896 if ((OS.IsPPC || OS.IsSP) && hwndCB !is null) { | |
897 return OS.IsSP ? 2 : OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0); | |
898 } | |
899 int count = 0; | |
900 MENUITEMINFO info; | |
901 info.cbSize = OS.MENUITEMINFO_sizeof; | |
902 while (OS.GetMenuItemInfo (handle, count, true, &info)) count++; | |
903 return count; | |
904 } | |
905 return OS.GetMenuItemCount (handle); | |
906 } | |
907 | |
908 override String getNameText () { | |
909 String result = ""; | |
910 MenuItem [] items = getItems (); | |
911 int length_ = items.length; | |
912 if (length_ > 0) { | |
913 for (int i=0; i<length_-1; i++) { | |
914 result = result ~ items [i].getNameText() ~ ", "; | |
915 } | |
916 result = result ~ items [length_-1].getNameText (); | |
917 } | |
918 return result; | |
919 } | |
920 | |
921 /** | |
922 * Returns the receiver's parent, which must be a <code>Decorations</code>. | |
923 * | |
924 * @return the receiver's parent | |
925 * | |
926 * @exception SWTException <ul> | |
927 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
928 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
929 * </ul> | |
930 */ | |
931 public Decorations getParent () { | |
932 checkWidget (); | |
933 return parent; | |
934 } | |
935 | |
936 /** | |
937 * Returns the receiver's parent item, which must be a | |
938 * <code>MenuItem</code> or null when the receiver is a | |
939 * root. | |
940 * | |
941 * @return the receiver's parent item | |
942 * | |
943 * @exception SWTException <ul> | |
944 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
945 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
946 * </ul> | |
947 */ | |
948 public MenuItem getParentItem () { | |
949 checkWidget (); | |
950 return cascade; | |
951 } | |
952 | |
953 /** | |
954 * Returns the receiver's parent item, which must be a | |
955 * <code>Menu</code> or null when the receiver is a | |
956 * root. | |
957 * | |
958 * @return the receiver's parent item | |
959 * | |
960 * @exception SWTException <ul> | |
961 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
962 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
963 * </ul> | |
964 */ | |
965 public Menu getParentMenu () { | |
966 checkWidget (); | |
967 if (cascade !is null) return cascade.parent; | |
968 return null; | |
969 } | |
970 | |
971 /** | |
972 * Returns the receiver's shell. For all controls other than | |
973 * shells, this simply returns the control's nearest ancestor | |
974 * shell. Shells return themselves, even if they are children | |
975 * of other shells. | |
976 * | |
977 * @return the receiver's shell | |
978 * | |
979 * @exception SWTException <ul> | |
980 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
981 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
982 * </ul> | |
983 * | |
984 * @see #getParent | |
985 */ | |
986 public Shell getShell () { | |
987 checkWidget (); | |
988 return parent.getShell (); | |
989 } | |
990 | |
991 /** | |
992 * Returns <code>true</code> if the receiver is visible, and | |
993 * <code>false</code> otherwise. | |
994 * <p> | |
995 * If one of the receiver's ancestors is not visible or some | |
996 * other condition makes the receiver not visible, this method | |
997 * may still indicate that it is considered visible even though | |
998 * it may not actually be showing. | |
999 * </p> | |
1000 * | |
1001 * @return the receiver's visibility state | |
1002 * | |
1003 * @exception SWTException <ul> | |
1004 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1005 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1006 * </ul> | |
1007 */ | |
1008 public bool getVisible () { | |
1009 checkWidget (); | |
1010 if ((style & SWT.BAR) !is 0) { | |
1011 return this is parent.menuShell ().menuBar; | |
1012 } | |
1013 if ((style & SWT.POP_UP) !is 0) { | |
1014 Menu [] popups = display.popups; | |
1015 if (popups is null) return false; | |
1016 for (int i=0; i<popups.length; i++) { | |
1017 if (popups [i] is this) return true; | |
1018 } | |
1019 } | |
1020 Shell shell = getShell (); | |
1021 Menu menu = shell.activeMenu; | |
1022 while (menu !is null && menu !is this) { | |
1023 menu = menu.getParentMenu (); | |
1024 } | |
1025 return this is menu; | |
1026 } | |
1027 | |
1028 int imageIndex (Image image) { | |
1029 if (hwndCB is null || image is null) return OS.I_IMAGENONE; | |
1030 if (imageList is null) { | |
1031 Rectangle bounds = image.getBounds (); | |
1032 imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height); | |
1033 int index = imageList.add (image); | |
1034 HANDLE hImageList = imageList.getHandle (); | |
1035 OS.SendMessage (hwndCB, OS.TB_SETIMAGELIST, 0, hImageList); | |
1036 return index; | |
1037 } | |
1038 int index = imageList.indexOf (image); | |
1039 if (index is -1) { | |
1040 index = imageList.add (image); | |
1041 } else { | |
1042 imageList.put (index, image); | |
1043 } | |
1044 return index; | |
1045 } | |
1046 | |
1047 /** | |
1048 * Searches the receiver's list starting at the first item | |
1049 * (index 0) until an item is found that is equal to the | |
1050 * argument, and returns the index of that item. If no item | |
1051 * is found, returns -1. | |
1052 * | |
1053 * @param item the search item | |
1054 * @return the index of the item | |
1055 * | |
1056 * @exception IllegalArgumentException <ul> | |
1057 * <li>ERROR_NULL_ARGUMENT - if the item is null</li> | |
1058 * </ul> | |
1059 * @exception SWTException <ul> | |
1060 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1061 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1062 * </ul> | |
1063 */ | |
1064 public int indexOf (MenuItem item) { | |
1065 checkWidget (); | |
1066 if (item is null) error (SWT.ERROR_NULL_ARGUMENT); | |
1067 if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); | |
1068 if (item.parent !is this) return -1; | |
1069 if ((OS.IsPPC || OS.IsSP) && hwndCB !is null) { | |
1070 if (OS.IsPPC) { | |
1071 return OS.SendMessage (hwndCB, OS.TB_COMMANDTOINDEX, item.id, 0); | |
1072 } | |
1073 if (OS.IsSP) { | |
1074 if (item.id is id0) return 0; | |
1075 if (item.id is id1) return 1; | |
1076 return -1; | |
1077 } | |
1078 } | |
1079 int index = 0; | |
1080 MENUITEMINFO info; | |
1081 info.cbSize = OS.MENUITEMINFO_sizeof; | |
1082 info.fMask = OS.MIIM_DATA; | |
1083 while (OS.GetMenuItemInfo (handle, index, true, &info)) { | |
1084 if (info.dwItemData is item.id) return index; | |
1085 index++; | |
1086 } | |
1087 return -1; | |
1088 } | |
1089 | |
1090 /** | |
1091 * Returns <code>true</code> if the receiver is enabled and all | |
1092 * of the receiver's ancestors are enabled, and <code>false</code> | |
1093 * otherwise. A disabled menu is typically not selectable from the | |
1094 * user interface and draws with an inactive or "grayed" look. | |
1095 * | |
1096 * @return the receiver's enabled state | |
1097 * | |
1098 * @exception SWTException <ul> | |
1099 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1100 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1101 * </ul> | |
1102 * | |
1103 * @see #getEnabled | |
1104 */ | |
1105 public bool isEnabled () { | |
1106 checkWidget (); | |
1107 Menu parentMenu = getParentMenu (); | |
1108 if (parentMenu is null) { | |
1109 return getEnabled () && parent.isEnabled (); | |
1110 } | |
1111 return getEnabled () && parentMenu.isEnabled (); | |
1112 } | |
1113 | |
1114 /** | |
1115 * Returns <code>true</code> if the receiver is visible and all | |
1116 * of the receiver's ancestors are visible and <code>false</code> | |
1117 * otherwise. | |
1118 * | |
1119 * @return the receiver's visibility state | |
1120 * | |
1121 * @exception SWTException <ul> | |
1122 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1123 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1124 * </ul> | |
1125 * | |
1126 * @see #getVisible | |
1127 */ | |
1128 public bool isVisible () { | |
1129 checkWidget (); | |
1130 return getVisible (); | |
1131 } | |
1132 | |
1133 void redraw () { | |
1134 if (!isVisible ()) return; | |
1135 if ((style & SWT.BAR) !is 0) { | |
1136 display.addBar (this); | |
1137 } else { | |
1138 update (); | |
1139 } | |
1140 } | |
1141 | |
1142 override void releaseHandle () { | |
1143 super.releaseHandle (); | |
1144 handle = null; | |
1145 cascade = null; | |
1146 } | |
1147 | |
1148 override void releaseChildren (bool destroy) { | |
1149 MenuItem [] items = getItems (); | |
1150 for (int i=0; i<items.length; i++) { | |
1151 MenuItem item = items [i]; | |
1152 if (item !is null && !item.isDisposed ()) { | |
1153 if (OS.IsPPC && hwndCB !is null) { | |
1154 item.dispose (); | |
1155 } else { | |
1156 item.release (false); | |
1157 } | |
1158 } | |
1159 } | |
1160 super.releaseChildren (destroy); | |
1161 } | |
1162 | |
1163 override void releaseParent () { | |
1164 super.releaseParent (); | |
1165 if ((style & SWT.BAR) !is 0) { | |
1166 display.removeBar (this); | |
1167 if (this is parent.menuBar) { | |
1168 parent.setMenuBar (null); | |
1169 } | |
1170 } else { | |
1171 if ((style & SWT.POP_UP) !is 0) { | |
1172 display.removePopup (this); | |
1173 } | |
1174 } | |
1175 } | |
1176 | |
1177 override void releaseWidget () { | |
1178 super.releaseWidget (); | |
1179 backgroundImage = null; | |
1180 if (hBrush is null) OS.DeleteObject (hBrush); | |
1181 hBrush = null; | |
1182 if (OS.IsPPC && hwndCB !is null) { | |
1183 if (imageList !is null) { | |
1184 OS.SendMessage (hwndCB, OS.TB_SETIMAGELIST, 0, 0); | |
1185 display.releaseToolImageList (imageList); | |
1186 imageList = null; | |
1187 } | |
1188 } | |
1189 if (parent !is null) parent.removeMenu (this); | |
1190 parent = null; | |
1191 } | |
1192 | |
1193 /** | |
1194 * Removes the listener from the collection of listeners who will | |
1195 * be notified when the help events are generated for the control. | |
1196 * | |
1197 * @param listener the listener which should no longer be notified | |
1198 * | |
1199 * @exception IllegalArgumentException <ul> | |
1200 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
1201 * </ul> | |
1202 * @exception SWTException <ul> | |
1203 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1204 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1205 * </ul> | |
1206 * | |
1207 * @see HelpListener | |
1208 * @see #addHelpListener | |
1209 */ | |
1210 public void removeHelpListener (HelpListener listener) { | |
1211 checkWidget (); | |
1212 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); | |
1213 if (eventTable is null) return; | |
1214 eventTable.unhook (SWT.Help, listener); | |
1215 } | |
1216 | |
1217 /** | |
1218 * Removes the listener from the collection of listeners who will | |
1219 * be notified when the menu events are generated for the control. | |
1220 * | |
1221 * @param listener the listener which should no longer be notified | |
1222 * | |
1223 * @exception IllegalArgumentException <ul> | |
1224 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
1225 * </ul> | |
1226 * @exception SWTException <ul> | |
1227 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1228 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1229 * </ul> | |
1230 * | |
1231 * @see MenuListener | |
1232 * @see #addMenuListener | |
1233 */ | |
1234 public void removeMenuListener (MenuListener listener) { | |
1235 checkWidget (); | |
1236 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); | |
1237 if (eventTable is null) return; | |
1238 eventTable.unhook (SWT.Hide, listener); | |
1239 eventTable.unhook (SWT.Show, listener); | |
1240 } | |
1241 | |
1242 /** | |
1243 * Sets the receiver's background color to the color specified | |
1244 * by the argument, or to the default system color for the control | |
1245 * if the argument is null. | |
1246 * | |
1247 * @param color the new color (or null) | |
1248 * | |
1249 * @exception IllegalArgumentException <ul> | |
1250 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> | |
1251 * </ul> | |
1252 * @exception SWTException <ul> | |
1253 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1254 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1255 * </ul> | |
1256 * | |
1257 * @since 3.3 | |
1258 */ | |
1259 /*public*/ void setBackground (Color color) { | |
1260 checkWidget (); | |
1261 int pixel = -1; | |
1262 if (color !is null) { | |
1263 if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
1264 pixel = color.handle; | |
1265 } | |
1266 if (pixel is background) return; | |
1267 background = pixel; | |
1268 updateBackground (); | |
1269 } | |
1270 | |
1271 /** | |
1272 * Sets the receiver's background image to the image specified | |
1273 * by the argument, or to the default system color for the control | |
1274 * if the argument is null. The background image is tiled to fill | |
1275 * the available space. | |
1276 * | |
1277 * @param image the new image (or null) | |
1278 * | |
1279 * @exception IllegalArgumentException <ul> | |
1280 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> | |
1281 * <li>ERROR_INVALID_ARGUMENT - if the argument is not a bitmap</li> | |
1282 * </ul> | |
1283 * @exception SWTException <ul> | |
1284 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1285 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1286 * </ul> | |
1287 * | |
1288 * @since 3.3 | |
1289 */ | |
1290 /*public*/ void setBackgroundImage (Image image) { | |
1291 checkWidget (); | |
1292 if (image !is null) { | |
1293 if (image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); | |
1294 if (image.type !is SWT.BITMAP) error (SWT.ERROR_INVALID_ARGUMENT); | |
1295 } | |
1296 if (backgroundImage is image) return; | |
1297 backgroundImage = image; | |
1298 updateBackground (); | |
1299 } | |
1300 | |
1301 /** | |
1302 * Sets the receiver's foreground color to the color specified | |
1303 * by the argument, or to the default system color for the control | |
1304 * if the argument is null. | |
1305 * | |
1306 * @param color the new color (or null) | |
1307 * | |
1308 * @exception IllegalArgumentException <ul> | |
1309 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> | |
1310 * </ul> | |
1311 * @exception SWTException <ul> | |
1312 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1313 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1314 * </ul> | |
1315 * | |
1316 * @since 3.3 | |
1317 */ | |
1318 /*public*/ void setForeground (Color color) { | |
1319 checkWidget (); | |
1320 int pixel = -1; | |
1321 if (color !is null) { | |
1322 if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
1323 pixel = color.handle; | |
1324 } | |
1325 if (pixel is foreground) return; | |
1326 foreground = pixel; | |
1327 updateForeground (); | |
1328 } | |
1329 | |
1330 /** | |
1331 * Sets the default menu item to the argument or removes | |
1332 * the default emphasis when the argument is <code>null</code>. | |
1333 * | |
1334 * @param item the default menu item or null | |
1335 * | |
1336 * @exception IllegalArgumentException <ul> | |
1337 * <li>ERROR_INVALID_ARGUMENT - if the menu item has been disposed</li> | |
1338 * </ul> | |
1339 * @exception SWTException <ul> | |
1340 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1341 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1342 * </ul> | |
1343 */ | |
1344 public void setDefaultItem (MenuItem item) { | |
1345 checkWidget (); | |
1346 int newID = -1; | |
1347 if (item !is null) { | |
1348 if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); | |
1349 if (item.parent !is this) return; | |
1350 newID = item.id; | |
1351 } | |
1352 static if (OS.IsWinCE) return; | |
1353 int oldID = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED); | |
1354 if (newID is oldID) return; | |
1355 OS.SetMenuDefaultItem (handle, newID, OS.MF_BYCOMMAND); | |
1356 redraw (); | |
1357 } | |
1358 | |
1359 /** | |
1360 * Enables the receiver if the argument is <code>true</code>, | |
1361 * and disables it otherwise. A disabled menu is typically | |
1362 * not selectable from the user interface and draws with an | |
1363 * inactive or "grayed" look. | |
1364 * | |
1365 * @param enabled the new enabled state | |
1366 * | |
1367 * @exception SWTException <ul> | |
1368 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1369 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1370 * </ul> | |
1371 */ | |
1372 public void setEnabled (bool enabled) { | |
1373 checkWidget (); | |
1374 state &= ~DISABLED; | |
1375 if (!enabled) state |= DISABLED; | |
1376 } | |
1377 | |
1378 /** | |
1379 * Sets the location of the receiver, which must be a popup, | |
1380 * to the point specified by the arguments which are relative | |
1381 * to the display. | |
1382 * <p> | |
1383 * Note that this is different from most widgets where the | |
1384 * location of the widget is relative to the parent. | |
1385 * </p><p> | |
1386 * Note that the platform window manager ultimately has control | |
1387 * over the location of popup menus. | |
1388 * </p> | |
1389 * | |
1390 * @param x the new x coordinate for the receiver | |
1391 * @param y the new y coordinate for the receiver | |
1392 * | |
1393 * @exception SWTException <ul> | |
1394 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1395 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1396 * </ul> | |
1397 */ | |
1398 public void setLocation (int x, int y) { | |
1399 checkWidget (); | |
1400 if ((style & (SWT.BAR | SWT.DROP_DOWN)) !is 0) return; | |
1401 this.x = x; | |
1402 this.y = y; | |
1403 hasLocation = true; | |
1404 } | |
1405 | |
1406 /** | |
1407 * Sets the location of the receiver, which must be a popup, | |
1408 * to the point specified by the argument which is relative | |
1409 * to the display. | |
1410 * <p> | |
1411 * Note that this is different from most widgets where the | |
1412 * location of the widget is relative to the parent. | |
1413 * </p><p> | |
1414 * Note that the platform window manager ultimately has control | |
1415 * over the location of popup menus. | |
1416 * </p> | |
1417 * | |
1418 * @param location the new location for the receiver | |
1419 * | |
1420 * @exception IllegalArgumentException <ul> | |
1421 * <li>ERROR_NULL_ARGUMENT - if the point is null</li> | |
1422 * </ul> | |
1423 * @exception SWTException <ul> | |
1424 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1425 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1426 * </ul> | |
1427 * | |
1428 * @since 2.1 | |
1429 */ | |
1430 public void setLocation (Point location) { | |
1431 checkWidget (); | |
1432 if (location is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); | |
1433 setLocation (location.x, location.y); | |
1434 } | |
1435 | |
1436 /** | |
1437 * Marks the receiver as visible if the argument is <code>true</code>, | |
1438 * and marks it invisible otherwise. | |
1439 * <p> | |
1440 * If one of the receiver's ancestors is not visible or some | |
1441 * other condition makes the receiver not visible, marking | |
1442 * it visible may not actually cause it to be displayed. | |
1443 * </p> | |
1444 * | |
1445 * @param visible the new visibility state | |
1446 * | |
1447 * @exception SWTException <ul> | |
1448 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
1449 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
1450 * </ul> | |
1451 */ | |
1452 public void setVisible (bool visible) { | |
1453 checkWidget (); | |
1454 if ((style & (SWT.BAR | SWT.DROP_DOWN)) !is 0) return; | |
1455 if (visible) { | |
1456 display.addPopup (this); | |
1457 } else { | |
1458 display.removePopup (this); | |
1459 _setVisible (false); | |
1460 } | |
1461 } | |
1462 | |
1463 void update () { | |
1464 if (OS.IsPPC || OS.IsSP) return; | |
1465 static if (OS.IsHPC) { | |
1466 /* | |
1467 * Each time a menu has been modified, the command menu bar | |
1468 * must be redrawn or it won't update properly. For example, | |
1469 * a submenu will not drop down. | |
1470 */ | |
1471 Menu menuBar = parent.menuBar; | |
1472 if (menuBar !is null) { | |
1473 Menu menu = this; | |
1474 while (menu !is null && menu !is menuBar) { | |
1475 menu = menu.getParentMenu (); | |
1476 } | |
1477 if (menu is menuBar) { | |
1478 OS.CommandBar_DrawMenuBar (menuBar.hwndCB, 0); | |
1479 OS.CommandBar_Show (menuBar.hwndCB, true); | |
1480 } | |
1481 } | |
1482 return; | |
1483 } | |
1484 static if (OS.IsWinCE) return; | |
1485 if ((style & SWT.BAR) !is 0) { | |
1486 if (this is parent.menuBar) OS.DrawMenuBar (parent.handle); | |
1487 return; | |
1488 } | |
1489 if (OS.WIN32_VERSION < OS.VERSION (4, 10)) { | |
1490 return; | |
1491 } | |
1492 bool hasCheck = false, hasImage = false; | |
1493 MenuItem [] items = getItems (); | |
1494 for (int i=0; i<items.length; i++) { | |
1495 MenuItem item = items [i]; | |
1496 if (item.image !is null) { | |
1497 hasImage = true; | |
1498 if (hasCheck) break; | |
1499 } | |
1500 if ((item.style & (SWT.CHECK | SWT.RADIO)) !is 0) { | |
1501 hasCheck = true; | |
1502 if ( hasImage) break; | |
1503 } | |
1504 } | |
1505 | |
1506 /* | |
1507 * Bug in Windows. If a menu contains items that have | |
1508 * images and can be checked, Windows does not include | |
1509 * the width of the image and the width of the check when | |
1510 * computing the width of the menu. When the longest item | |
1511 * does not have an image, the label and the accelerator | |
1512 * text can overlap. The fix is to use SetMenuItemInfo() | |
1513 * to indicate that all items have a bitmap and then include | |
1514 * the width of the widest bitmap in WM_MEASURECHILD. | |
1515 * | |
1516 * NOTE: This work around causes problems on Windows 98. | |
1517 * Under certain circumstances that have yet to be isolated, | |
1518 * some menus can become huge and blank. For now, do not | |
1519 * run the code on Windows 98. | |
1520 * | |
1521 * NOTE: This work around doesn't run on Vista because | |
1522 * WM_MEASURECHILD and WM_DRAWITEM cause Vista to lose | |
1523 * the menu theme. | |
1524 */ | |
1525 if (!OS.IsWin95) { | |
1526 if (OS.WIN32_VERSION < OS.VERSION (6, 0)) { | |
1527 MENUITEMINFO info; | |
1528 info.cbSize = OS.MENUITEMINFO_sizeof; | |
1529 info.fMask = OS.MIIM_BITMAP; | |
1530 for (int i=0; i<items.length; i++) { | |
1531 MenuItem item = items [i]; | |
1532 if ((style & SWT.SEPARATOR) is 0) { | |
1533 if (item.image is null || foreground !is -1) { | |
1534 info.hbmpItem = hasImage || foreground !is -1 ? OS.HBMMENU_CALLBACK : null; | |
1535 OS.SetMenuItemInfo (handle, item.id, false, &info); | |
1536 } | |
1537 } | |
1538 } | |
1539 } | |
1540 } | |
1541 | |
1542 /* Update the menu to hide or show the space for bitmaps */ | |
1543 MENUINFO lpcmi; | |
1544 lpcmi.cbSize = MENUINFO.sizeof; | |
1545 lpcmi.fMask = OS.MIM_STYLE; | |
1546 OS.GetMenuInfo (handle, &lpcmi); | |
1547 if (hasImage && !hasCheck) { | |
1548 lpcmi.dwStyle |= OS.MNS_CHECKORBMP; | |
1549 } else { | |
1550 lpcmi.dwStyle &= ~OS.MNS_CHECKORBMP; | |
1551 } | |
1552 OS.SetMenuInfo (handle, &lpcmi); | |
1553 } | |
1554 | |
1555 void updateBackground () { | |
1556 if (hBrush is null) OS.DeleteObject (hBrush); | |
1557 hBrush = null; | |
1558 if (backgroundImage !is null) { | |
1559 hBrush = OS.CreatePatternBrush (backgroundImage.handle); | |
1560 } else { | |
1561 if (background !is -1) hBrush = OS.CreateSolidBrush (background); | |
1562 } | |
1563 MENUINFO lpcmi; | |
1564 lpcmi.cbSize = MENUINFO.sizeof; | |
1565 lpcmi.fMask = OS.MIM_BACKGROUND; | |
1566 lpcmi.hbrBack = hBrush; | |
1567 OS.SetMenuInfo (handle, &lpcmi); | |
1568 } | |
1569 | |
1570 void updateForeground () { | |
1571 if (OS.WIN32_VERSION < OS.VERSION (4, 10)) return; | |
1572 MENUITEMINFO info; | |
1573 info.cbSize = OS.MENUITEMINFO_sizeof; | |
1574 int index = 0; | |
1575 while (OS.GetMenuItemInfo (handle, index, true, &info)) { | |
1576 info.fMask = OS.MIIM_BITMAP; | |
1577 info.hbmpItem = OS.HBMMENU_CALLBACK; | |
1578 OS.SetMenuItemInfo (handle, index, true, &info); | |
1579 index++; | |
1580 } | |
1581 redraw (); | |
1582 } | |
1583 } | |
1584 |