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