KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > widgets > MenuItem


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  *******************************************************************************/

11 package org.eclipse.swt.widgets;
12
13  
14 import org.eclipse.swt.internal.win32.*;
15 import org.eclipse.swt.*;
16 import org.eclipse.swt.graphics.*;
17 import org.eclipse.swt.events.*;
18
19 /**
20  * Instances of this class represent a selectable user interface object
21  * that issues notification when pressed and released.
22  * <dl>
23  * <dt><b>Styles:</b></dt>
24  * <dd>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</dd>
25  * <dt><b>Events:</b></dt>
26  * <dd>Arm, Help, Selection</dd>
27  * </dl>
28  * <p>
29  * Note: Only one of the styles CHECK, CASCADE, PUSH, RADIO and SEPARATOR
30  * may be specified.
31  * </p><p>
32  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
33  * </p>
34  */

35
36 public class MenuItem extends Item {
37     Menu parent, menu;
38     int hBitmap, id, accelerator;
39     /*
40     * Feature in Windows. On Windows 98, it is necessary
41     * to add 4 pixels to the width of the image or the image
42     * and text are too close. On other Windows platforms,
43     * this causes the text of the longest item to touch the
44     * accelerator text. The fix is to use smaller margins
45     * everywhere but on Windows 98.
46     */

47     final static int MARGIN_WIDTH = OS.IsWin95 ? 2 : 1;
48     final static int MARGIN_HEIGHT = OS.IsWin95 ? 2 : 1;
49
50 /**
51  * Constructs a new instance of this class given its parent
52  * (which must be a <code>Menu</code>) and a style value
53  * describing its behavior and appearance. The item is added
54  * to the end of the items maintained by its parent.
55  * <p>
56  * The style value is either one of the style constants defined in
57  * class <code>SWT</code> which is applicable to instances of this
58  * class, or must be built by <em>bitwise OR</em>'ing together
59  * (that is, using the <code>int</code> "|" operator) two or more
60  * of those <code>SWT</code> style constants. The class description
61  * lists the style constants that are applicable to the class.
62  * Style bits are also inherited from superclasses.
63  * </p>
64  *
65  * @param parent a menu control which will be the parent of the new instance (cannot be null)
66  * @param style the style of control to construct
67  *
68  * @exception IllegalArgumentException <ul>
69  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
70  * </ul>
71  * @exception SWTException <ul>
72  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
73  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
74  * </ul>
75  *
76  * @see SWT#CHECK
77  * @see SWT#CASCADE
78  * @see SWT#PUSH
79  * @see SWT#RADIO
80  * @see SWT#SEPARATOR
81  * @see Widget#checkSubclass
82  * @see Widget#getStyle
83  */

84 public MenuItem (Menu parent, int style) {
85     super (parent, checkStyle (style));
86     this.parent = parent;
87     parent.createItem (this, parent.getItemCount ());
88 }
89
90 /**
91  * Constructs a new instance of this class given its parent
92  * (which must be a <code>Menu</code>), a style value
93  * describing its behavior and appearance, and the index
94  * at which to place it in the items maintained by its parent.
95  * <p>
96  * The style value is either one of the style constants defined in
97  * class <code>SWT</code> which is applicable to instances of this
98  * class, or must be built by <em>bitwise OR</em>'ing together
99  * (that is, using the <code>int</code> "|" operator) two or more
100  * of those <code>SWT</code> style constants. The class description
101  * lists the style constants that are applicable to the class.
102  * Style bits are also inherited from superclasses.
103  * </p>
104  *
105  * @param parent a menu control which will be the parent of the new instance (cannot be null)
106  * @param style the style of control to construct
107  * @param index the zero-relative index to store the receiver in its parent
108  *
109  * @exception IllegalArgumentException <ul>
110  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
111  * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
112  * </ul>
113  * @exception SWTException <ul>
114  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
115  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
116  * </ul>
117  *
118  * @see SWT#CHECK
119  * @see SWT#CASCADE
120  * @see SWT#PUSH
121  * @see SWT#RADIO
122  * @see SWT#SEPARATOR
123  * @see Widget#checkSubclass
124  * @see Widget#getStyle
125  */

126 public MenuItem (Menu parent, int style, int index) {
127     super (parent, checkStyle (style));
128     this.parent = parent;
129     parent.createItem (this, index);
130 }
131
132 MenuItem (Menu parent, Menu menu, int style, int index) {
133     super (parent, checkStyle (style));
134     this.parent = parent;
135     this.menu = menu;
136     if (menu != null) menu.cascade = this;
137     display.addMenuItem (this);
138 }
139
140 /**
141  * Adds the listener to the collection of listeners who will
142  * be notified when the arm events are generated for the control, by sending
143  * it one of the messages defined in the <code>ArmListener</code>
144  * interface.
145  *
146  * @param listener the listener which should be notified
147  *
148  * @exception IllegalArgumentException <ul>
149  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
150  * </ul>
151  * @exception SWTException <ul>
152  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
153  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
154  * </ul>
155  *
156  * @see ArmListener
157  * @see #removeArmListener
158  */

159 public void addArmListener (ArmListener listener) {
160     checkWidget ();
161     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
162     TypedListener typedListener = new TypedListener (listener);
163     addListener (SWT.Arm, typedListener);
164 }
165
166 /**
167  * Adds the listener to the collection of listeners who will
168  * be notified when the help events are generated for the control, by sending
169  * it one of the messages defined in the <code>HelpListener</code>
170  * interface.
171  *
172  * @param listener the listener which should be notified
173  *
174  * @exception IllegalArgumentException <ul>
175  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
176  * </ul>
177  * @exception SWTException <ul>
178  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
179  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
180  * </ul>
181  *
182  * @see HelpListener
183  * @see #removeHelpListener
184  */

185 public void addHelpListener (HelpListener listener) {
186     checkWidget ();
187     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
188     TypedListener typedListener = new TypedListener (listener);
189     addListener (SWT.Help, typedListener);
190 }
191
192 /**
193  * Adds the listener to the collection of listeners who will
194  * be notified when the menu item is selected by the user, by sending
195  * it one of the messages defined in the <code>SelectionListener</code>
196  * interface.
197  * <p>
198  * When <code>widgetSelected</code> is called, the stateMask field of the event object is valid.
199  * <code>widgetDefaultSelected</code> is not called.
200  * </p>
201  *
202  * @param listener the listener which should be notified when the menu item is selected by the user
203  *
204  * @exception IllegalArgumentException <ul>
205  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
206  * </ul>
207  * @exception SWTException <ul>
208  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
209  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
210  * </ul>
211  *
212  * @see SelectionListener
213  * @see #removeSelectionListener
214  * @see SelectionEvent
215  */

216 public void addSelectionListener (SelectionListener listener) {
217     checkWidget ();
218     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
219     TypedListener typedListener = new TypedListener(listener);
220     addListener (SWT.Selection,typedListener);
221     addListener (SWT.DefaultSelection,typedListener);
222 }
223
224 protected void checkSubclass () {
225     if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
226 }
227
228 static int checkStyle (int style) {
229     return checkBits (style, SWT.PUSH, SWT.CHECK, SWT.RADIO, SWT.SEPARATOR, SWT.CASCADE, 0);
230 }
231
232 void destroyWidget () {
233     parent.destroyItem (this);
234     releaseHandle ();
235 }
236
237 void fillAccel (ACCEL accel) {
238     accel.fVirt = 0;
239     accel.cmd = accel.key = 0;
240     if (accelerator == 0 || !getEnabled ()) return;
241     int fVirt = OS.FVIRTKEY;
242     int key = accelerator & SWT.KEY_MASK;
243     int vKey = Display.untranslateKey (key);
244     if (vKey != 0) {
245         key = vKey;
246     } else {
247         switch (key) {
248             /*
249             * Bug in Windows. For some reason, VkKeyScan
250             * fails to map ESC to VK_ESCAPE and DEL to
251             * VK_DELETE. The fix is to map these keys
252             * as a special case.
253             */

254             case 27: key = OS.VK_ESCAPE; break;
255             case 127: key = OS.VK_DELETE; break;
256             default: {
257                 key = Display.wcsToMbcs ((char) key);
258                 if (key == 0) return;
259                 if (OS.IsWinCE) {
260                     key = OS.CharUpper ((short) key);
261                 } else {
262                     vKey = OS.VkKeyScan ((short) key) & 0xFF;
263                     if (vKey == -1) {
264                         fVirt = 0;
265                     } else {
266                         key = vKey;
267                     }
268                 }
269             }
270         }
271     }
272     accel.key = (short) key;
273     accel.cmd = (short) id;
274     accel.fVirt = (byte) fVirt;
275     if ((accelerator & SWT.ALT) != 0) accel.fVirt |= OS.FALT;
276     if ((accelerator & SWT.SHIFT) != 0) accel.fVirt |= OS.FSHIFT;
277     if ((accelerator & SWT.CONTROL) != 0) accel.fVirt |= OS.FCONTROL;
278 }
279
280 void fixMenus (Decorations newParent) {
281     if (menu != null) menu.fixMenus (newParent);
282 }
283
284 /**
285  * Returns the widget accelerator. An accelerator is the bit-wise
286  * OR of zero or more modifier masks and a key. Examples:
287  * <code>SWT.CONTROL | SWT.SHIFT | 'T', SWT.ALT | SWT.F2</code>.
288  * The default value is zero, indicating that the menu item does
289  * not have an accelerator.
290  *
291  * @return the accelerator or 0
292  *
293  * </ul>
294  * @exception SWTException <ul>
295  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
296  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
297  * </ul>
298  */

299 public int getAccelerator () {
300     checkWidget ();
301     return accelerator;
302 }
303
304 /**
305  * Returns a rectangle describing the receiver's size and location
306  * relative to its parent (or its display if its parent is null).
307  *
308  * @return the receiver's bounding rectangle
309  *
310  * @exception SWTException <ul>
311  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
312  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
313  * </ul>
314  *
315  * @since 3.1
316  */

317 /*public*/ Rectangle getBounds () {
318     checkWidget ();
319     if (OS.IsWinCE) return new Rectangle (0, 0, 0, 0);
320     int index = parent.indexOf (this);
321     if (index == -1) return new Rectangle (0, 0, 0, 0);
322     if ((parent.style & SWT.BAR) != 0) {
323         Decorations shell = parent.parent;
324         if (shell.menuBar != parent) {
325             return new Rectangle (0, 0, 0, 0);
326         }
327         int hwndShell = shell.handle;
328         MENUBARINFO info1 = new MENUBARINFO ();
329         info1.cbSize = MENUBARINFO.sizeof;
330         if (!OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, 1, info1)) {
331             return new Rectangle (0, 0, 0, 0);
332         }
333         MENUBARINFO info2 = new MENUBARINFO ();
334         info2.cbSize = MENUBARINFO.sizeof;
335         if (!OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, index + 1, info2)) {
336             return new Rectangle (0, 0, 0, 0);
337         }
338         int x = info2.left - info1.left;
339         int y = info2.top - info1.top;
340         int width = info2.right - info2.left;
341         int height = info2.bottom - info2.top;
342         return new Rectangle (x, y, width, height);
343     } else {
344         int hMenu = parent.handle;
345         RECT rect1 = new RECT ();
346         if (!OS.GetMenuItemRect (0, hMenu, 0, rect1)) {
347             return new Rectangle (0, 0, 0, 0);
348         }
349         RECT rect2 = new RECT ();
350         if (!OS.GetMenuItemRect (0, hMenu, index, rect2)) {
351             return new Rectangle (0, 0, 0, 0);
352         }
353         int x = rect2.left - rect1.left + 2;
354         int y = rect2.top - rect1.top + 2;
355         int width = rect2.right - rect2.left;
356         int height = rect2.bottom - rect2.top;
357         return new Rectangle (x, y, width, height);
358     }
359 }
360
361 /**
362  * Returns <code>true</code> if the receiver is enabled, and
363  * <code>false</code> otherwise. A disabled menu item is typically
364  * not selectable from the user interface and draws with an
365  * inactive or "grayed" look.
366  *
367  * @return the receiver's enabled state
368  *
369  * @exception SWTException <ul>
370  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
371  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
372  * </ul>
373  *
374  * @see #isEnabled
375  */

376 public boolean getEnabled () {
377     checkWidget ();
378     if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) {
379         int hwndCB = parent.hwndCB;
380         TBBUTTONINFO info = new TBBUTTONINFO ();
381         info.cbSize = TBBUTTONINFO.sizeof;
382         info.dwMask = OS.TBIF_STATE;
383         OS.SendMessage (hwndCB, OS.TB_GETBUTTONINFO, id, info);
384         return (info.fsState & OS.TBSTATE_ENABLED) != 0;
385     }
386     int hMenu = parent.handle;
387     MENUITEMINFO info = new MENUITEMINFO ();
388     info.cbSize = MENUITEMINFO.sizeof;
389     info.fMask = OS.MIIM_STATE;
390     boolean success;
391     if (OS.IsWinCE) {
392         int index = parent.indexOf (this);
393         if (index == -1) error (SWT.ERROR_CANNOT_GET_ENABLED);
394         success = OS.GetMenuItemInfo (hMenu, index, true, info);
395     } else {
396         success = OS.GetMenuItemInfo (hMenu, id, false, info);
397     }
398     if (!success) error (SWT.ERROR_CANNOT_GET_ENABLED);
399     return (info.fState & (OS.MFS_DISABLED | OS.MFS_GRAYED)) == 0;
400 }
401
402 /**
403  * Returns the receiver's cascade menu if it has one or null
404  * if it does not. Only <code>CASCADE</code> menu items can have
405  * a pull down menu. The sequence of key strokes, button presses
406  * and/or button releases that are used to request a pull down
407  * menu is platform specific.
408  *
409  * @return the receiver's menu
410  *
411  * @exception SWTException <ul>
412  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
413  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
414  * </ul>
415  */

416 public Menu getMenu () {
417     checkWidget ();
418     return menu;
419 }
420
421 String JavaDoc getNameText () {
422     if ((style & SWT.SEPARATOR) != 0) return "|";
423     return super.getNameText ();
424 }
425
426 /**
427  * Returns the receiver's parent, which must be a <code>Menu</code>.
428  *
429  * @return the receiver's parent
430  *
431  * @exception SWTException <ul>
432  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
433  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
434  * </ul>
435  */

436 public Menu getParent () {
437     checkWidget ();
438     return parent;
439 }
440
441 /**
442  * Returns <code>true</code> if the receiver is selected,
443  * and false otherwise.
444  * <p>
445  * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
446  * it is selected when it is checked.
447  *
448  * @return the selection state
449  *
450  * @exception SWTException <ul>
451  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
452  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
453  * </ul>
454  */

455 public boolean getSelection () {
456     checkWidget ();
457     if ((style & (SWT.CHECK | SWT.RADIO)) == 0) return false;
458     if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) return false;
459     int hMenu = parent.handle;
460     MENUITEMINFO info = new MENUITEMINFO ();
461     info.cbSize = MENUITEMINFO.sizeof;
462     info.fMask = OS.MIIM_STATE;
463     boolean success = OS.GetMenuItemInfo (hMenu, id, false, info);
464     if (!success) error (SWT.ERROR_CANNOT_GET_SELECTION);
465     return (info.fState & OS.MFS_CHECKED) !=0;
466 }
467
468 /**
469  * Returns <code>true</code> if the receiver is enabled and all
470  * of the receiver's ancestors are enabled, and <code>false</code>
471  * otherwise. A disabled menu item is typically not selectable from the
472  * user interface and draws with an inactive or "grayed" look.
473  *
474  * @return the receiver's enabled state
475  *
476  * @exception SWTException <ul>
477  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
478  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
479  * </ul>
480  *
481  * @see #getEnabled
482  */

483 public boolean isEnabled () {
484     return getEnabled () && parent.isEnabled ();
485 }
486
487 void releaseChildren (boolean destroy) {
488     if (menu != null) {
489         menu.release (false);
490         menu = null;
491     }
492     super.releaseChildren (destroy);
493 }
494
495 void releaseHandle () {
496     super.releaseHandle ();
497     parent = null;
498     id = -1;
499 }
500
501 void releaseMenu () {
502     if (!OS.IsSP) setMenu (null);
503     menu = null;
504 }
505
506 void releaseParent () {
507     super.releaseParent ();
508     if (menu != null) menu.dispose ();
509     menu = null;
510 }
511
512 void releaseWidget () {
513     super.releaseWidget ();
514     if (hBitmap != 0) OS.DeleteObject (hBitmap);
515     hBitmap = 0;
516     if (accelerator != 0) {
517         parent.destroyAccelerators ();
518     }
519     accelerator = 0;
520     display.removeMenuItem (this);
521 }
522
523 /**
524  * Removes the listener from the collection of listeners who will
525  * be notified when the arm events are generated for the control.
526  *
527  * @param listener the listener which should no longer be notified
528  *
529  * @exception IllegalArgumentException <ul>
530  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
531  * </ul>
532  * @exception SWTException <ul>
533  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
534  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
535  * </ul>
536  *
537  * @see ArmListener
538  * @see #addArmListener
539  */

540 public void removeArmListener (ArmListener listener) {
541     checkWidget ();
542     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
543     if (eventTable == null) return;
544     eventTable.unhook (SWT.Arm, listener);
545 }
546 /**
547  * Removes the listener from the collection of listeners who will
548  * be notified when the help events are generated for the control.
549  *
550  * @param listener the listener which should no longer be notified
551  *
552  * @exception IllegalArgumentException <ul>
553  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
554  * </ul>
555  * @exception SWTException <ul>
556  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
557  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
558  * </ul>
559  *
560  * @see HelpListener
561  * @see #addHelpListener
562  */

563 public void removeHelpListener (HelpListener listener) {
564     checkWidget ();
565     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
566     if (eventTable == null) return;
567     eventTable.unhook (SWT.Help, listener);
568 }
569 /**
570  * Removes the listener from the collection of listeners who will
571  * be notified when the control is selected by the user.
572  *
573  * @param listener the listener which should no longer be notified
574  *
575  * @exception IllegalArgumentException <ul>
576  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
577  * </ul>
578  * @exception SWTException <ul>
579  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
580  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
581  * </ul>
582  *
583  * @see SelectionListener
584  * @see #addSelectionListener
585  */

586 public void removeSelectionListener (SelectionListener listener) {
587     checkWidget ();
588     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
589     if (eventTable == null) return;
590     eventTable.unhook (SWT.Selection, listener);
591     eventTable.unhook (SWT.DefaultSelection,listener);
592 }
593
594 void selectRadio () {
595     int index = 0;
596     MenuItem [] items = parent.getItems ();
597     while (index < items.length && items [index] != this) index++;
598     int i = index - 1;
599     while (i >= 0 && items [i].setRadioSelection (false)) --i;
600     int j = index + 1;
601     while (j < items.length && items [j].setRadioSelection (false)) j++;
602     setSelection (true);
603 }
604
605 /**
606  * Sets the widget accelerator. An accelerator is the bit-wise
607  * OR of zero or more modifier masks and a key. Examples:
608  * <code>SWT.MOD1 | SWT.MOD2 | 'T', SWT.MOD3 | SWT.F2</code>.
609  * <code>SWT.CONTROL | SWT.SHIFT | 'T', SWT.ALT | SWT.F2</code>.
610  * The default value is zero, indicating that the menu item does
611  * not have an accelerator.
612  *
613  * @param accelerator an integer that is the bit-wise OR of masks and a key
614  *
615  * </ul>
616  * @exception SWTException <ul>
617  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
618  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
619  * </ul>
620  */

621 public void setAccelerator (int accelerator) {
622     checkWidget ();
623     if (this.accelerator == accelerator) return;
624     this.accelerator = accelerator;
625     parent.destroyAccelerators ();
626 }
627
628 /**
629  * Enables the receiver if the argument is <code>true</code>,
630  * and disables it otherwise. A disabled menu item is typically
631  * not selectable from the user interface and draws with an
632  * inactive or "grayed" look.
633  *
634  * @param enabled the new enabled state
635  *
636  * @exception SWTException <ul>
637  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
638  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
639  * </ul>
640  */

641 public void setEnabled (boolean enabled) {
642     checkWidget ();
643     if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) {
644         int hwndCB = parent.hwndCB;
645         TBBUTTONINFO info = new TBBUTTONINFO ();
646         info.cbSize = TBBUTTONINFO.sizeof;
647         info.dwMask = OS.TBIF_STATE;
648         OS.SendMessage (hwndCB, OS.TB_GETBUTTONINFO, id, info);
649         info.fsState &= ~OS.TBSTATE_ENABLED;
650         if (enabled) info.fsState |= OS.TBSTATE_ENABLED;
651         OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, id, info);
652     } else {
653         int hMenu = parent.handle;
654         if (OS.IsWinCE) {
655             int index = parent.indexOf (this);
656             if (index == -1) return;
657             int uEnable = OS.MF_BYPOSITION | (enabled ? OS.MF_ENABLED : OS.MF_GRAYED);
658             OS.EnableMenuItem (hMenu, index, uEnable);
659         } else {
660             MENUITEMINFO info = new MENUITEMINFO ();
661             info.cbSize = MENUITEMINFO.sizeof;
662             info.fMask = OS.MIIM_STATE;
663             boolean success = OS.GetMenuItemInfo (hMenu, id, false, info);
664             if (!success) error (SWT.ERROR_CANNOT_SET_ENABLED);
665             int bits = OS.MFS_DISABLED | OS.MFS_GRAYED;
666             if (enabled) {
667                 if ((info.fState & bits) == 0) return;
668                 info.fState &= ~bits;
669             } else {
670                 if ((info.fState & bits) == bits) return;
671                 info.fState |= bits;
672             }
673             success = OS.SetMenuItemInfo (hMenu, id, false, info);
674             if (!success) {
675                 /*
676                 * Bug in Windows. For some reason SetMenuItemInfo(),
677                 * returns a fail code when setting the enabled or
678                 * selected state of a default item, but sets the
679                 * state anyway. The fix is to ignore the error.
680                 *
681                 * NOTE: This only happens on Vista.
682                 */

683                 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
684                     success = id == OS.GetMenuDefaultItem (hMenu, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
685                 }
686                 if (!success) error (SWT.ERROR_CANNOT_SET_ENABLED);
687             }
688         }
689     }
690     parent.destroyAccelerators ();
691     parent.redraw ();
692 }
693
694 /**
695  * Sets the image the receiver will display to the argument.
696  * <p>
697  * Note: This operation is a hint and is not supported on
698  * platforms that do not have this concept (for example, Windows NT).
699  * </p>
700  *
701  * @param image the image to display
702  *
703  * @exception SWTException <ul>
704  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
705  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
706  * </ul>
707  */

708 public void setImage (Image image) {
709     checkWidget ();
710     if ((style & SWT.SEPARATOR) != 0) return;
711     super.setImage (image);
712     if (OS.IsWinCE) {
713         if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) {
714             int hwndCB = parent.hwndCB;
715             TBBUTTONINFO info = new TBBUTTONINFO ();
716             info.cbSize = TBBUTTONINFO.sizeof;
717             info.dwMask = OS.TBIF_IMAGE;
718             info.iImage = parent.imageIndex (image);
719             OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, id, info);
720         }
721         return;
722     }
723     if (OS.WIN32_VERSION < OS.VERSION (4, 10)) return;
724     MENUITEMINFO info = new MENUITEMINFO ();
725     info.cbSize = MENUITEMINFO.sizeof;
726     info.fMask = OS.MIIM_BITMAP;
727     if (parent.foreground != -1) {
728         info.hbmpItem = OS.HBMMENU_CALLBACK;
729     } else {
730         if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
731             if (hBitmap != 0) OS.DeleteObject (hBitmap);
732             info.hbmpItem = hBitmap = image != null ? Display.create32bitDIB (image) : 0;
733         } else {
734             info.hbmpItem = OS.HBMMENU_CALLBACK;
735         }
736     }
737     int hMenu = parent.handle;
738     OS.SetMenuItemInfo (hMenu, id, false, info);
739     parent.redraw ();
740 }
741
742 /**
743  * Sets the receiver's pull down menu to the argument.
744  * Only <code>CASCADE</code> menu items can have a
745  * pull down menu. The sequence of key strokes, button presses
746  * and/or button releases that are used to request a pull down
747  * menu is platform specific.
748  * <p>
749  * Note: Disposing of a menu item that has a pull down menu
750  * will dispose of the menu. To avoid this behavior, set the
751  * menu to null before the menu item is disposed.
752  * </p>
753  *
754  * @param menu the new pull down menu
755  *
756  * @exception IllegalArgumentException <ul>
757  * <li>ERROR_MENU_NOT_DROP_DOWN - if the menu is not a drop down menu</li>
758  * <li>ERROR_MENUITEM_NOT_CASCADE - if the menu item is not a <code>CASCADE</code></li>
759  * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed</li>
760  * <li>ERROR_INVALID_PARENT - if the menu is not in the same widget tree</li>
761  * </ul>
762  * @exception SWTException <ul>
763  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
764  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
765  * </ul>
766  */

767 public void setMenu (Menu menu) {
768     checkWidget ();
769
770     /* Check to make sure the new menu is valid */
771     if ((style & SWT.CASCADE) == 0) {
772         error (SWT.ERROR_MENUITEM_NOT_CASCADE);
773     }
774     if (menu != null) {
775         if (menu.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
776         if ((menu.style & SWT.DROP_DOWN) == 0) {
777             error (SWT.ERROR_MENU_NOT_DROP_DOWN);
778         }
779         if (menu.parent != parent.parent) {
780             error (SWT.ERROR_INVALID_PARENT);
781         }
782     }
783
784     /* Assign the new menu */
785     Menu oldMenu = this.menu;
786     if (oldMenu == menu) return;
787     if (oldMenu != null) oldMenu.cascade = null;
788     this.menu = menu;
789
790     /* Assign the new menu in the OS */
791     if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) {
792         if (OS.IsPPC) {
793             int hwndCB = parent.hwndCB;
794             int hMenu = menu == null ? 0 : menu.handle;
795             OS.SendMessage (hwndCB, OS.SHCMBM_SETSUBMENU, id, hMenu);
796         }
797         if (OS.IsSP) error (SWT.ERROR_CANNOT_SET_MENU);
798     } else {
799         /*
800         * Feature in Windows. When SetMenuItemInfo () is used to
801         * set a submenu and the menu item already has a submenu,
802         * Windows destroys the previous menu. This is undocumented
803         * and unexpected but not necessarily wrong. The fix is to
804         * remove the item with RemoveMenu () which does not destroy
805         * the submenu and then insert the item with InsertMenuItem ().
806         */

807         int hMenu = parent.handle;
808         MENUITEMINFO info = new MENUITEMINFO ();
809         info.cbSize = MENUITEMINFO.sizeof;
810         info.fMask = OS.MIIM_DATA;
811         int index = 0;
812         while (OS.GetMenuItemInfo (hMenu, index, true, info)) {
813             if (info.dwItemData == id) break;
814             index++;
815         }
816         if (info.dwItemData != id) return;
817         boolean restoreBitmap = false, success = false;
818         
819         /*
820         * Bug in Windows. When GetMenuItemInfo() is used to get the text,
821         * for an item that has a bitmap set using MIIM_BITMAP, the text is
822         * not returned. This means that when SetMenuItemInfo() is used to
823         * set the submenu and the current menu state, the text is lost.
824         * The fix is to temporarily remove the bitmap and restore it after
825         * the text and submenu have been set.
826         */

827         if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
828             info.fMask = OS.MIIM_BITMAP;
829             OS.GetMenuItemInfo (hMenu, index, true, info);
830             restoreBitmap = info.hbmpItem != 0 || parent.foreground != -1;
831             if (restoreBitmap) {
832                 info.hbmpItem = 0;
833                 success = OS.SetMenuItemInfo (hMenu, id, false, info);
834             }
835         }
836         
837         int cch = 128;
838         int hHeap = OS.GetProcessHeap ();
839         int byteCount = cch * TCHAR.sizeof;
840         int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
841         info.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_DATA;
842         info.dwTypeData = pszText;
843         info.cch = cch;
844         success = OS.GetMenuItemInfo (hMenu, index, true, info);
845         if (menu != null) {
846             menu.cascade = this;
847             info.fMask |= OS.MIIM_SUBMENU;
848             info.hSubMenu = menu.handle;
849         }
850         OS.RemoveMenu (hMenu, index, OS.MF_BYPOSITION);
851         if (OS.IsWinCE) {
852             /*
853             * On WinCE, InsertMenuItem() is not available. The fix is to
854             * use SetMenuItemInfo() but this call does not set the menu item
855             * state and submenu. The fix is to use InsertMenu() to insert
856             * the item, SetMenuItemInfo() to set the string and EnableMenuItem()
857             * and CheckMenuItem() to set the state.
858             */

859             int uIDNewItem = id;
860             int uFlags = OS.MF_BYPOSITION;
861             if (menu != null) {
862                 uFlags |= OS.MF_POPUP;
863                 uIDNewItem = menu.handle;
864             }
865             TCHAR lpNewItem = new TCHAR (0, " ", true);
866             success = OS.InsertMenu (hMenu, index, uFlags, uIDNewItem, lpNewItem);
867             if (success) {
868                 info.fMask = OS.MIIM_DATA | OS.MIIM_TYPE;
869                 success = OS.SetMenuItemInfo (hMenu, index, true, info);
870                 if ((info.fState & (OS.MFS_DISABLED | OS.MFS_GRAYED)) != 0) {
871                     OS.EnableMenuItem (hMenu, index, OS.MF_BYPOSITION | OS.MF_GRAYED);
872                 }
873                 if ((info.fState & OS.MFS_CHECKED) != 0) {
874                     OS.CheckMenuItem (hMenu, index, OS.MF_BYPOSITION | OS.MF_CHECKED);
875                 }
876             }
877         } else {
878             success = OS.InsertMenuItem (hMenu, index, true, info);
879             /*
880             * Restore the bitmap that was removed to work around a problem
881             * in GetMenuItemInfo() and menu items that have bitmaps set with
882             * MIIM_BITMAP.
883             */

884             if (OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
885                 if (restoreBitmap) {
886                     info.fMask = OS.MIIM_BITMAP;
887                     if (parent.foreground != -1) {
888                         info.hbmpItem = OS.HBMMENU_CALLBACK;
889                     } else {
890                         if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
891                             info.hbmpItem = hBitmap;
892                         } else {
893                             info.hbmpItem = OS.HBMMENU_CALLBACK;
894                         }
895                     }
896                     success = OS.SetMenuItemInfo (hMenu, id, false, info);
897                 }
898             }
899         }
900         if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
901         if (!success) error (SWT.ERROR_CANNOT_SET_MENU);
902     }
903     parent.destroyAccelerators ();
904 }
905
906 boolean setRadioSelection (boolean value) {
907     if ((style & SWT.RADIO) == 0) return false;
908     if (getSelection () != value) {
909         setSelection (value);
910         postEvent (SWT.Selection);
911     }
912     return true;
913 }
914
915 /**
916  * Sets the selection state of the receiver.
917  * <p>
918  * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
919  * it is selected when it is checked.
920  *
921  * @param selected the new selection state
922  *
923  * @exception SWTException <ul>
924  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
925  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
926  * </ul>
927  */

928 public void setSelection (boolean selected) {
929     checkWidget ();
930     if ((style & (SWT.CHECK | SWT.RADIO)) == 0) return;
931     if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) return;
932     int hMenu = parent.handle;
933     if (OS.IsWinCE) {
934         int index = parent.indexOf (this);
935         if (index == -1) return;
936         int uCheck = OS.MF_BYPOSITION | (selected ? OS.MF_CHECKED : OS.MF_UNCHECKED);
937         OS.CheckMenuItem (hMenu, index, uCheck);
938     } else {
939         MENUITEMINFO info = new MENUITEMINFO ();
940         info.cbSize = MENUITEMINFO.sizeof;
941         info.fMask = OS.MIIM_STATE;
942         boolean success = OS.GetMenuItemInfo (hMenu, id, false, info);
943         if (!success) error (SWT.ERROR_CANNOT_SET_SELECTION);
944         info.fState &= ~OS.MFS_CHECKED;
945         if (selected) info.fState |= OS.MFS_CHECKED;
946         success = OS.SetMenuItemInfo (hMenu, id, false, info);
947         if (!success) {
948             /*
949             * Bug in Windows. For some reason SetMenuItemInfo(),
950             * returns a fail code when setting the enabled or
951             * selected state of a default item, but sets the
952             * state anyway. The fix is to ignore the error.
953             *
954             * NOTE: This only happens on Vista.
955             */

956             if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
957                 success = id == OS.GetMenuDefaultItem (hMenu, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
958             }
959             if (!success) error (SWT.ERROR_CANNOT_SET_SELECTION);
960         }
961     }
962     parent.redraw ();
963 }
964 /**
965  * Sets the receiver's text. The string may include
966  * the mnemonic character and accelerator text.
967  * <p>
968  * Mnemonics are indicated by an '&amp;' that causes the next
969  * character to be the mnemonic. When the user presses a
970  * key sequence that matches the mnemonic, a selection
971  * event occurs. On most platforms, the mnemonic appears
972  * underlined but may be emphasised in a platform specific
973  * manner. The mnemonic indicator character '&amp;' can be
974  * escaped by doubling it in the string, causing a single
975  * '&amp;' to be displayed.
976  * </p>
977  * <p>
978  * Accelerator text is indicated by the '\t' character.
979  * On platforms that support accelerator text, the text
980  * that follows the '\t' character is displayed to the user,
981  * typically indicating the key stroke that will cause
982  * the item to become selected. On most platforms, the
983  * accelerator text appears right aligned in the menu.
984  * Setting the accelerator text does not install the
985  * accelerator key sequence. The accelerator key sequence
986  * is installed using #setAccelerator.
987  * </p>
988  *
989  * @param string the new text
990  *
991  * @exception IllegalArgumentException <ul>
992  * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
993  * </ul>
994  * @exception SWTException <ul>
995  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
996  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
997  * </ul>
998  *
999  * @see #setAccelerator
1000 */

1001public void setText (String JavaDoc string) {
1002    checkWidget ();
1003    if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1004    if ((style & SWT.SEPARATOR) != 0) return;
1005    if (text.equals (string)) return;
1006    super.setText (string);
1007    int hHeap = OS.GetProcessHeap ();
1008    int pszText = 0;
1009    boolean success = false;
1010    if ((OS.IsPPC || OS.IsSP) && parent.hwndCB != 0) {
1011        /*
1012        * Bug in WinCE PPC. Tool items on the menubar don't resize
1013        * correctly when the character '&' is used (even when it
1014        * is a sequence '&&'). The fix is to remove all '&' from
1015        * the string.
1016        */

1017        if (string.indexOf ('&') != -1) {
1018            int length = string.length ();
1019            char[] text = new char [length];
1020            string.getChars( 0, length, text, 0);
1021            int i = 0, j = 0;
1022            for (i=0; i<length; i++) {
1023                if (text[i] != '&') text [j++] = text [i];
1024            }
1025            if (j < i) string = new String JavaDoc (text, 0, j);
1026        }
1027        /* Use the character encoding for the default locale */
1028        TCHAR buffer = new TCHAR (0, string, true);
1029        int byteCount = buffer.length () * TCHAR.sizeof;
1030        pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
1031        OS.MoveMemory (pszText, buffer, byteCount);
1032        int hwndCB = parent.hwndCB;
1033        TBBUTTONINFO info2 = new TBBUTTONINFO ();
1034        info2.cbSize = TBBUTTONINFO.sizeof;
1035        info2.dwMask = OS.TBIF_TEXT;
1036        info2.pszText = pszText;
1037        success = OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, id, info2) != 0;
1038    } else {
1039        MENUITEMINFO info = new MENUITEMINFO ();
1040        info.cbSize = MENUITEMINFO.sizeof;
1041        int hMenu = parent.handle;
1042        
1043        /*
1044        * Bug in Windows 2000. For some reason, when MIIM_TYPE is set
1045        * on a menu item that also has MIIM_BITMAP, the MIIM_TYPE clears
1046        * the MIIM_BITMAP style. The fix is to reset both MIIM_BITMAP.
1047        * Note, this does not happen on Windows 98.
1048        */

1049        boolean restoreBitmap = false;
1050        if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
1051            info.fMask = OS.MIIM_BITMAP;
1052            OS.GetMenuItemInfo (hMenu, id, false, info);
1053            restoreBitmap = info.hbmpItem != 0 || parent.foreground != -1;
1054        }
1055        
1056        /* Use the character encoding for the default locale */
1057        TCHAR buffer = new TCHAR (0, string, true);
1058        int byteCount = buffer.length () * TCHAR.sizeof;
1059        pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
1060        OS.MoveMemory (pszText, buffer, byteCount);
1061        info.fMask = OS.MIIM_TYPE;
1062        info.fType = widgetStyle ();
1063        info.dwTypeData = pszText;
1064        success = OS.SetMenuItemInfo (hMenu, id, false, info);
1065
1066        /*
1067        * Restore the bitmap that was removed to work around a problem
1068        * in GetMenuItemInfo() and menu items that have bitmaps set with
1069        * MIIM_BITMAP.
1070        */

1071        if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
1072            if (restoreBitmap) {
1073                info.fMask = OS.MIIM_BITMAP;
1074                if (parent.foreground != -1) {
1075                    info.hbmpItem = OS.HBMMENU_CALLBACK;
1076                } else {
1077                    if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1078                        info.hbmpItem = hBitmap;
1079                    } else {
1080                        info.hbmpItem = OS.HBMMENU_CALLBACK;
1081                    }
1082                }
1083                success = OS.SetMenuItemInfo (hMenu, id, false, info);
1084            }
1085        }
1086    }
1087    if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
1088    if (!success) error (SWT.ERROR_CANNOT_SET_TEXT);
1089    parent.redraw ();
1090}
1091
1092int widgetStyle () {
1093    int bits = 0;
1094    Decorations shell = parent.parent;
1095    if ((shell.style & SWT.MIRRORED) != 0) {
1096        if ((parent.style & SWT.LEFT_TO_RIGHT) != 0) {
1097            bits |= OS.MFT_RIGHTJUSTIFY | OS.MFT_RIGHTORDER;
1098        }
1099    } else {
1100        if ((parent.style & SWT.RIGHT_TO_LEFT) != 0) {
1101            bits |= OS.MFT_RIGHTJUSTIFY | OS.MFT_RIGHTORDER;
1102        }
1103    }
1104    if ((style & SWT.SEPARATOR) != 0) return bits | OS.MFT_SEPARATOR;
1105    if ((style & SWT.RADIO) != 0) return bits | OS.MFT_RADIOCHECK;
1106    return bits | OS.MFT_STRING;
1107}
1108
1109LRESULT wmCommandChild (int wParam, int lParam) {
1110    if ((style & SWT.CHECK) != 0) {
1111        setSelection (!getSelection ());
1112    } else {
1113        if ((style & SWT.RADIO) != 0) {
1114            if ((parent.getStyle () & SWT.NO_RADIO_GROUP) != 0) {
1115                setSelection (!getSelection ());
1116            } else {
1117                selectRadio ();
1118            }
1119        }
1120    }
1121    Event event = new Event ();
1122    setInputState (event, SWT.Selection);
1123    postEvent (SWT.Selection, event);
1124    return null;
1125}
1126
1127LRESULT wmDrawChild (int wParam, int lParam) {
1128    DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
1129    OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
1130    if (image != null) {
1131        GCData data = new GCData();
1132        data.device = display;
1133        GC gc = GC.win32_new (struct.hDC, data);
1134        /*
1135        * Bug in Windows. When a bitmap is included in the
1136        * menu bar, the HDC seems to already include the left
1137        * coordinate. The fix is to ignore this value when
1138        * the item is in a menu bar.
1139        */

1140        int x = (parent.style & SWT.BAR) != 0 ? MARGIN_WIDTH * 2 : struct.left;
1141        Image image = getEnabled () ? this.image : new Image (display, this.image, SWT.IMAGE_DISABLE);
1142        gc.drawImage (image, x, struct.top + MARGIN_HEIGHT);
1143        if (this.image != image) image.dispose ();
1144        gc.dispose ();
1145    }
1146    if (parent.foreground != -1) OS.SetTextColor (struct.hDC, parent.foreground);
1147    return null;
1148}
1149
1150LRESULT wmMeasureChild (int wParam, int lParam) {
1151    MEASUREITEMSTRUCT struct = new MEASUREITEMSTRUCT ();
1152    OS.MoveMemory (struct, lParam, MEASUREITEMSTRUCT.sizeof);
1153    int width = 0, height = 0;
1154    if (image != null) {
1155        Rectangle rect = image.getBounds ();
1156        width = rect.width;
1157        height = rect.height;
1158    } else {
1159        /*
1160        * Bug in Windows. If a menu contains items that have
1161        * images and can be checked, Windows does not include
1162        * the width of the image and the width of the check when
1163        * computing the width of the menu. When the longest item
1164        * does not have an image, the label and the accelerator
1165        * text can overlap. The fix is to use SetMenuItemInfo()
1166        * to indicate that all items have a bitmap and then include
1167        * the width of the widest bitmap in WM_MEASURECHILD.
1168        */

1169        MENUINFO lpcmi = new MENUINFO ();
1170        lpcmi.cbSize = MENUINFO.sizeof;
1171        lpcmi.fMask = OS.MIM_STYLE;
1172        int hMenu = parent.handle;
1173        OS.GetMenuInfo (hMenu, lpcmi);
1174        if ((lpcmi.dwStyle & OS.MNS_CHECKORBMP) == 0) {
1175            MenuItem [] items = parent.getItems ();
1176            for (int i=0; i<items.length; i++) {
1177                MenuItem item = items [i];
1178                if (item.image != null) {
1179                    Rectangle rect = item.image.getBounds ();
1180                    width = Math.max (width, rect.width);
1181                }
1182            }
1183        }
1184    }
1185    if (width != 0 || height != 0) {
1186        struct.itemWidth = width + MARGIN_WIDTH * 2;
1187        struct.itemHeight = height + MARGIN_HEIGHT * 2;
1188        OS.MoveMemory (lParam, struct, MEASUREITEMSTRUCT.sizeof);
1189    }
1190    return null;
1191}
1192
1193}
1194
Popular Tags