comparison dwt/widgets/Menu.d @ 45:d8635bb48c7c

Merge with SWT 3.5
author Jacob Carlborg <doob@me.com>
date Mon, 01 Dec 2008 17:07:00 +0100
parents 642f460a0908
children a470e49a1890
comparison
equal deleted inserted replaced
44:ca5e494f2bbf 45:d8635bb48c7c
1 /******************************************************************************* 1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others. 2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials 3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0 4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at 5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html 6 * http://www.eclipse.org/legal/epl-v10.html
7 * 7 *
8 * Contributors: 8 * Contributors:
9 * IBM Corporation - initial API and implementation 9 * IBM Corporation - initial API and implementation
10 * 10 *
11 * Port to the D programming language: 11 * Port to the D programming language:
12 * Jacob Carlborg <jacob.carlborg@gmail.com> 12 * Jacob Carlborg <doob@me.com>
13 *******************************************************************************/ 13 *******************************************************************************/
14 module dwt.widgets.Menu; 14 module dwt.widgets.Menu;
15 15
16 16
17 import dwt.DWT; 17 import dwt.DWT;
55 * Note: Only one of BAR, DROP_DOWN and POP_UP may be specified. 55 * Note: Only one of BAR, DROP_DOWN and POP_UP may be specified.
56 * Only one of LEFT_TO_RIGHT or RIGHT_TO_LEFT may be specified. 56 * Only one of LEFT_TO_RIGHT or RIGHT_TO_LEFT may be specified.
57 * </p><p> 57 * </p><p>
58 * IMPORTANT: This class is <em>not</em> intended to be subclassed. 58 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
59 * </p> 59 * </p>
60 *
61 * @see <a href="http://www.eclipse.org/swt/snippets/#menu">Menu snippets</a>
62 * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: ControlExample</a>
63 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
60 */ 64 */
61 public class Menu : Widget { 65 public class Menu : Widget {
62 /** 66 /**
63 * the handle to the OS resource 67 * the handle to the OS resource
64 * (Warning: This field is platform dependent) 68 * (Warning: This field is platform dependent)
68 * within the packages provided by DWT. It is not available on all 72 * within the packages provided by DWT. It is not available on all
69 * platforms and should never be accessed from application code. 73 * platforms and should never be accessed from application code.
70 * </p> 74 * </p>
71 */ 75 */
72 NSMenu nsMenu; 76 NSMenu nsMenu;
73 short id;
74 int x, y, itemCount; 77 int x, y, itemCount;
75 // int width, height; 78 bool hasLocation, visible;
76 bool hasLocation, modified, closed;
77 MenuItem [] items; 79 MenuItem [] items;
78 MenuItem cascade, defaultItem, lastTarget; 80 MenuItem cascade, defaultItem;
79 Decorations parent; 81 Decorations parent;
80 82
81 /** 83 /**
82 * Constructs a new instance of this class given its parent, 84 * Constructs a new instance of this class given its parent,
83 * and sets the style for the instance so that the instance 85 * and sets the style for the instance so that the instance
84 * will be a popup menu on the given parent's shell. 86 * will be a popup menu on the given parent's shell.
87 * <p>
88 * After constructing a menu, it can be set into its parent
89 * using <code>parent.setMenu(menu)</code>. In this case, the parent may
90 * be any control in the same widget tree as the parent.
91 * </p>
85 * 92 *
86 * @param parent a control which will be the parent of the new instance (cannot be null) 93 * @param parent a control which will be the parent of the new instance (cannot be null)
87 * 94 *
88 * @exception IllegalArgumentException <ul> 95 * @exception IllegalArgumentException <ul>
89 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> 96 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
111 * class, or must be built by <em>bitwise OR</em>'ing together 118 * class, or must be built by <em>bitwise OR</em>'ing together
112 * (that is, using the <code>int</code> "|" operator) two or more 119 * (that is, using the <code>int</code> "|" operator) two or more
113 * of those <code>DWT</code> style constants. The class description 120 * of those <code>DWT</code> style constants. The class description
114 * lists the style constants that are applicable to the class. 121 * lists the style constants that are applicable to the class.
115 * Style bits are also inherited from superclasses. 122 * Style bits are also inherited from superclasses.
123 * </p><p>
124 * After constructing a menu or menuBar, it can be set into its parent
125 * using <code>parent.setMenu(menu)</code> or <code>parent.setMenuBar(menuBar)</code>.
116 * </p> 126 * </p>
117 * 127 *
118 * @param parent a decorations control which will be the parent of the new instance (cannot be null) 128 * @param parent a decorations control which will be the parent of the new instance (cannot be null)
119 * @param style the style of menu to construct 129 * @param style the style of menu to construct
120 * 130 *
141 /** 151 /**
142 * Constructs a new instance of this class given its parent 152 * Constructs a new instance of this class given its parent
143 * (which must be a <code>Menu</code>) and sets the style 153 * (which must be a <code>Menu</code>) and sets the style
144 * for the instance so that the instance will be a drop-down 154 * for the instance so that the instance will be a drop-down
145 * menu on the given parent's parent. 155 * menu on the given parent's parent.
156 * <p>
157 * After constructing a drop-down menu, it can be set into its parentMenu
158 * using <code>parentMenu.setMenu(menu)</code>.
159 * </p>
146 * 160 *
147 * @param parentMenu a menu which will be the parent of the new instance (cannot be null) 161 * @param parentMenu a menu which will be the parent of the new instance (cannot be null)
148 * 162 *
149 * @exception IllegalArgumentException <ul> 163 * @exception IllegalArgumentException <ul>
150 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> 164 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
165 /** 179 /**
166 * Constructs a new instance of this class given its parent 180 * Constructs a new instance of this class given its parent
167 * (which must be a <code>MenuItem</code>) and sets the style 181 * (which must be a <code>MenuItem</code>) and sets the style
168 * for the instance so that the instance will be a drop-down 182 * for the instance so that the instance will be a drop-down
169 * menu on the given parent's parent menu. 183 * menu on the given parent's parent menu.
184 * <p>
185 * After constructing a drop-down menu, it can be set into its parentItem
186 * using <code>parentItem.setMenu(menu)</code>.
187 * </p>
170 * 188 *
171 * @param parentItem a menu item which will be the parent of the new instance (cannot be null) 189 * @param parentItem a menu item which will be the parent of the new instance (cannot be null)
172 * 190 *
173 * @exception IllegalArgumentException <ul> 191 * @exception IllegalArgumentException <ul>
174 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> 192 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
219 location.y = topView.frame().height - shellCoord.y; 237 location.y = topView.frame().height - shellCoord.y;
220 } else { 238 } else {
221 location = window.mouseLocationOutsideOfEventStream(); 239 location = window.mouseLocationOutsideOfEventStream();
222 } 240 }
223 NSEvent nsEvent = NSEvent.otherEventWithType(NSApplicationDefined, location, 0, 0.0, window.windowNumber(), window.graphicsContext(), cast(short)0, 0, 0); 241 NSEvent nsEvent = NSEvent.otherEventWithType(NSApplicationDefined, location, 0, 0.0, window.windowNumber(), window.graphicsContext(), cast(short)0, 0, 0);
224 NSMenu.static_popUpContextMenu_withEvent_forView_ (nsMenu, nsEvent, shell.view); 242 NSMenu.popUpContextMenu(nsMenu, nsEvent, shell.view);
225 } else { 243 } else {
226 nsMenu.cancelTracking (); 244 nsMenu.cancelTracking ();
227 } 245 }
228 } 246 }
229 247
279 addListener (DWT.Hide,typedListener); 297 addListener (DWT.Hide,typedListener);
280 addListener (DWT.Show,typedListener); 298 addListener (DWT.Show,typedListener);
281 } 299 }
282 300
283 void createHandle () { 301 void createHandle () {
284 // display.addMenu (this); 302 display.addMenu (this);
285 SWTMenu widget = cast(SWTMenu)(new SWTMenu()).alloc(); 303 NSMenu widget = cast(NSMenu)(new SWTMenu()).alloc();
286 widget.initWithTitle(NSString.stringWith("")); 304 widget.initWithTitle(NSString.stringWith(""));
287 widget.setAutoenablesItems(false); 305 widget.setAutoenablesItems(false);
288 widget.setTag(jniRef);
289 widget.setDelegate(widget); 306 widget.setDelegate(widget);
290 nsMenu = widget; 307 nsMenu = widget;
291 } 308 }
292 309
293 void createItem (MenuItem item, int index) { 310 void createItem (MenuItem item, int index) {
294 checkWidget ();
295 if (!(0 <= index && index <= itemCount)) error (DWT.ERROR_INVALID_RANGE); 311 if (!(0 <= index && index <= itemCount)) error (DWT.ERROR_INVALID_RANGE);
296 NSMenuItem nsItem = null; 312 NSMenuItem nsItem = null;
297 if ((item.style & DWT.SEPARATOR) !is 0) { 313 if ((item.style & DWT.SEPARATOR) !is 0) {
298 nsItem = NSMenuItem.separatorItem(); 314 nsItem = NSMenuItem.separatorItem();
299 nsItem.retain(); 315 nsItem.retain();
300 } else { 316 } else {
301 nsItem = cast(NSMenuItem)(new SWTMenuItem()).alloc(); 317 nsItem = cast(NSMenuItem)(new SWTMenuItem()).alloc();
302 nsItem.initWithTitle(NSString.stringWith(""), null, NSString.stringWith("")); 318 nsItem.initWithTitle(NSString.stringWith(""), null, NSString.stringWith(""));
303 nsItem.setTarget(nsItem); 319 nsItem.setTarget(nsItem);
304 nsItem.setAction(OS.sel_sendSelection); 320 nsItem.setAction(OS.sel_sendSelection);
305 //item.createJNIRef();
306 nsItem.setTag(item.jniRef);
307 } 321 }
308 item.nsItem = nsItem; 322 item.nsItem = nsItem;
323 item.createJNIRef();
324 item.register();
309 nsMenu.insertItem(nsItem, index); 325 nsMenu.insertItem(nsItem, index);
310 if (itemCount is items.length) { 326 if (itemCount is items.length) {
311 MenuItem [] newItems = new MenuItem [items.length + 4]; 327 MenuItem [] newItems = new MenuItem [items.length + 4];
312 System.arraycopy (items, 0, newItems, 0, items.length); 328 System.arraycopy (items, 0, newItems, 0, items.length);
313 items = newItems; 329 items = newItems;
314 } 330 }
315 System.arraycopy (items, index, items, index + 1, itemCount++ - index); 331 System.arraycopy (items, index, items, index + 1, itemCount++ - index);
316 items [index] = item; 332 items [index] = item;
317
318 NSMenu emptyMenu = item.createEmptyMenu (); 333 NSMenu emptyMenu = item.createEmptyMenu ();
319 if (emptyMenu !is null) { 334 if (emptyMenu !is null) {
320 item.nsItem.setSubmenu (emptyMenu); 335 nsItem.setSubmenu (emptyMenu);
321 } 336 }
337 //TODO - find a way to disable the menu instead of each item
338 if (!getEnabled ()) nsItem.setEnabled (false);
322 } 339 }
323 340
324 void createWidget () { 341 void createWidget () {
325 checkOrientation (parent); 342 checkOrientation (parent);
326 super.createWidget (); 343 super.createWidget ();
327 items = new MenuItem [4]; 344 items = new MenuItem [4];
345 }
346
347 void deregister () {
348 super.deregister ();
349 display.removeWidget (nsMenu);
328 } 350 }
329 351
330 void destroyItem (MenuItem item) { 352 void destroyItem (MenuItem item) {
331 int index = 0; 353 int index = 0;
332 while (index < itemCount) { 354 while (index < itemCount) {
565 checkWidget (); 587 checkWidget ();
566 if ((style & DWT.BAR) !is 0) { 588 if ((style & DWT.BAR) !is 0) {
567 return this is parent.menuShell ().menuBar; 589 return this is parent.menuShell ().menuBar;
568 } 590 }
569 if ((style & DWT.POP_UP) !is 0) { 591 if ((style & DWT.POP_UP) !is 0) {
570 // Menu [] popups = display.popups; 592 Menu [] popups = display.popups;
571 // if (popups is null) return false; 593 if (popups is null) return false;
572 // for (int i=0; i<popups.length; i++) { 594 for (int i=0; i<popups.length; i++) {
573 // if (popups [i] is this) return true; 595 if (popups [i] is this) return true;
574 // } 596 }
575 } 597 }
576 // MenuTrackingData outData = new MenuTrackingData (); 598 return visible;
577 // return OS.GetMenuTrackingData (handle, outData) is OS.noErr; 599 }
578 return false;
579 }
580
581 600
582 /** 601 /**
583 * Searches the receiver's list starting at the first item 602 * Searches the receiver's list starting at the first item
584 * (index 0) until an item is found that is equal to the 603 * (index 0) until an item is found that is equal to the
585 * argument, and returns the index of that item. If no item 604 * argument, and returns the index of that item. If no item
646 public bool isVisible () { 665 public bool isVisible () {
647 checkWidget (); 666 checkWidget ();
648 return getVisible (); 667 return getVisible ();
649 } 668 }
650 669
651 void menu_willHighlightItem(int menu, objc.id itemID) { 670 void menu_willHighlightItem(objc.id id, objc.SEL sel, objc.id menu, objc.id itemID) {
652 NSInteger jniRef = cast(NSInteger) OS.objc_msgSend(itemID, OS.sel_tag); 671 Widget widget = display.getWidget(itemID);
653 if (jniRef !is -1 && jniRef !is 0) { 672 if (widget instanceof MenuItem) {
654 Object object = OS.JNIGetObject(jniRef); 673 MenuItem item = (MenuItem)widget;
655 if ( null !is cast(MenuItem)object ) { 674 item.sendEvent (DWT.Arm);
656 MenuItem item = cast(MenuItem)object; 675 }
657 item.sendEvent (DWT.Arm); 676 }
677
678 void menuNeedsUpdate(int /*long*/ id, int /*long*/ sel, int /*long*/ menu) {
679 //This code is intentionally commented
680 //sendEvent (DWT.Show);
681 }
682
683 void menuWillOpen(int /*long*/ id, int /*long*/ sel, int /*long*/ menu) {
684 visible = true;
685 sendEvent (DWT.Show);
686 for (int i=0; i<items.length; i++) {
687 MenuItem item = items [i];
688 if (item !is null) {
689 if (item.accelerator is 0) {
690 if (item.nsItem.keyEquivalent ().length () !is 0 || item.nsItem.keyEquivalentModifierMask () !is 0) {
691 item.nsItem.setHidden (false);
692 }
693 }
658 } 694 }
659 } 695 }
660 } 696 }
661 697
662 void menuNeedsUpdate(int menu) { 698 void menuDidClose(int /*long*/ id, int /*long*/ sel, int /*long*/ menu) {
663 sendEvent (DWT.Show);
664 }
665
666 void menuWillClose(int menu) {
667 sendEvent (DWT.Hide); 699 sendEvent (DWT.Hide);
668 } 700 visible = false;
669 701 for (int i=0; i<items.length; i++) {
670 void menuWillOpen(int menu) { 702 MenuItem item = items [i];
671 } 703 if (item !is null) {
672 704 if (item.accelerator is 0) {
673 int modifierIndex (String accelText) { 705 if (item.nsItem.keyEquivalent().length () !is 0 || item.nsItem.keyEquivalentModifierMask () !is 0) {
674 int start = accelText.length () - 1; 706 item.nsItem.setHidden (true);
675 int index = start; 707 }
676 while (index >= 0) { 708 }
677 char c = accelText.charAt (index);
678 switch (c) {
679 case ' ':
680 if (index !is start) return index;
681 break;
682 case '\u2303':
683 case '\u2325':
684 case '\u21E7':
685 case '\u2318':
686 return index;
687 } 709 }
688 index--; 710 }
689 } 711 }
690 return -1; 712
691 } 713 void register () {
692 714 super.register ();
693 int numberOfItemsInMenu(int menu) { 715 display.addWidget (nsMenu, this);
694 System.Out.println("numver");
695 return 4;
696 } 716 }
697 717
698 void releaseChildren (bool destroy) { 718 void releaseChildren (bool destroy) {
699 if (items !is null) { 719 if (items !is null) {
700 for (int i=0; i<items.length; i++) { 720 for (int i=0; i<items.length; i++) {
721 } 741 }
722 } 742 }
723 743
724 void releaseWidget () { 744 void releaseWidget () {
725 super.releaseWidget (); 745 super.releaseWidget ();
726 // display.removeMenu (this); 746 display.removeMenu (this);
727 parent = null; 747 parent = null;
728 cascade = defaultItem = lastTarget = null; 748 cascade = defaultItem = null;
729 } 749 }
730 750
731 /** 751 /**
732 * Removes the listener from the collection of listeners who will 752 * Removes the listener from the collection of listeners who will
733 * be notified when the help events are generated for the control. 753 * be notified when the help events are generated for the control.
812 */ 832 */
813 public void setEnabled (bool enabled) { 833 public void setEnabled (bool enabled) {
814 checkWidget(); 834 checkWidget();
815 if (enabled) { 835 if (enabled) {
816 state &= ~DISABLED; 836 state &= ~DISABLED;
817 //OS.EnableMenuItem (handle, cast(short)0);
818 } else { 837 } else {
819 state |= DISABLED; 838 state |= DISABLED;
820 //OS.DisableMenuItem (handle, cast(short)0); 839 }
840 //TODO - find a way to disable the menu instead of each item
841 for (int i=0; i<items.length; i++) {
842 MenuItem item = items [i];
843 if (item !is null) {
844 /*
845 * Feature in the Macintosh. When a cascade menu
846 * item is disabled, rather than disabling the item,
847 * the submenu is disabled.
848 *
849 * There is no fix for this at this time.
850 */
851 item.nsItem.setEnabled (enabled && item.getEnabled ());
852 }
821 } 853 }
822 } 854 }
823 855
824 /** 856 /**
825 * Sets the location of the receiver, which must be a popup, 857 * Sets the location of the receiver, which must be a popup,
896 */ 928 */
897 public void setVisible (bool visible) { 929 public void setVisible (bool visible) {
898 checkWidget (); 930 checkWidget ();
899 if ((style & (DWT.BAR | DWT.DROP_DOWN)) !is 0) return; 931 if ((style & (DWT.BAR | DWT.DROP_DOWN)) !is 0) return;
900 if (visible) { 932 if (visible) {
901 // display.addPopup (this); 933 display.addPopup (this);
902 //TODO -WRONG
903 _setVisible (true);
904 } else { 934 } else {
905 // display.removePopup (this); 935 display.removePopup (this);
906 _setVisible (false);
907 } 936 }
908 } 937 }
909 938
910 } 939 }