/*******************************************************************************
*
*******************************************************************************/
package org.eclipse.swt.widgets;
import java.util.Date;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.HelpListener;
import org.eclipse.swt.events.MenuListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.RunnableCompatibility;
import org.eclipse.swt.internal.browser.OS;
import org.eclipse.swt.internal.xhtml.CSSStyle;
import org.eclipse.swt.internal.xhtml.Clazz;
import org.eclipse.swt.internal.xhtml.Element;
import org.eclipse.swt.internal.xhtml.HTMLEvent;
import org.eclipse.swt.internal.xhtml.document;
import org.eclipse.swt.internal.xhtml.window;
/**
* Instances of this class are user interface objects that contain
* menu items.
* <dl>
* <dt><b>Styles:</b></dt>
* <dd>BAR, DROP_DOWN, POP_UP, NO_RADIO_GROUP</dd>
* <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd>
* <dt><b>Events:</b></dt>
* <dd>Help, Hide, Show </dd>
* </dl>
* <p>
* Note: Only one of BAR, DROP_DOWN and POP_UP may be specified.
* Only one of LEFT_TO_RIGHT or RIGHT_TO_LEFT may be specified.
* </p><p>
* IMPORTANT: This class is <em>not</em> intended to be subclassed.
* </p>
*
* @j2sPrefix
* $WTC$$.registerCSS ("$wt.widgets.Menu");
*/
public class Menu extends Widget {
/**
* the handle to the OS resource
* (Warning: This field is platform dependent)
* <p>
* <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
* public API. It is marked public only so that it can be shared
* within the packages provided by SWT. It is not available on all
* platforms and should never be accessed from application code.
* </p>
*/
//public Element handle;
int x, y, hwndCB, id0, id1;
boolean hasLocation;
MenuItem cascade;
Decorations parent;
ImageList imageList;
MenuItem[] items;
MenuItem defaultItem;
Element btnFocus;
int currentIndex;
long lastFocusdTime;
Object[] acceleratorTable;
/* Resource ID for SHMENUBARINFO */
static final int ID_PPC = 100;
/* SmartPhone SoftKeyBar resource ids */
static final int ID_SPMM = 102;
static final int ID_SPBM = 103;
static final int ID_SPMB = 104;
static final int ID_SPBB = 105;
static final int ID_SPSOFTKEY0 = 106;
static final int ID_SPSOFTKEY1 = 107;
static final int GROWTH_RATE = 5;
private Object hMenuKeyDown;
Object hMenuBlur;
private Object hMenuFocus;
private Object hMenuMouseDown;
/**
* Constructs a new instance of this class given its parent,
* and sets the style for the instance so that the instance
* will be a popup menu on the given parent's shell.
*
* @param parent a control which will be the parent of the new instance (cannot be null)
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
* <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
* </ul>
*
* @see SWT#POP_UP
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public Menu (Control parent) {
this (checkNull (parent).menuShell (), SWT.POP_UP);
}
/**
* Constructs a new instance of this class given its parent
* (which must be a <code>Decorations</code>) and a style value
* describing its behavior and appearance.
* <p>
* The style value is either one of the style constants defined in
* class <code>SWT</code> which is applicable to instances of this
* class, or must be built by <em>bitwise OR</em>'ing together
* (that is, using the <code>int</code> "|" operator) two or more
* of those <code>SWT</code> style constants. The class description
* lists the style constants that are applicable to the class.
* Style bits are also inherited from superclasses.
* </p>
*
* @param parent a decorations control which will be the parent of the new instance (cannot be null)
* @param style the style of menu to construct
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
* <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
* </ul>
*
* @see SWT#BAR
* @see SWT#DROP_DOWN
* @see SWT#POP_UP
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public Menu (Decorations parent, int style) {
this (parent, checkStyle (style), null);
}
/**
* Constructs a new instance of this class given its parent
* (which must be a <code>Menu</code>) and sets the style
* for the instance so that the instance will be a drop-down
* menu on the given parent's parent.
*
* @param parentMenu a menu which will be the parent of the new instance (cannot be null)
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
* <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
* </ul>
*
* @see SWT#DROP_DOWN
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public Menu (Menu parentMenu) {
this (checkNull (parentMenu).parent, SWT.DROP_DOWN);
}
/**
* Constructs a new instance of this class given its parent
* (which must be a <code>MenuItem</code>) and sets the style
* for the instance so that the instance will be a drop-down
* menu on the given parent's parent menu.
*
* @param parentItem a menu item which will be the parent of the new instance (cannot be null)
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
* <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
* </ul>
*
* @see SWT#DROP_DOWN
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public Menu (MenuItem parentItem) {
this (checkNull (parentItem).parent);
}
Menu (Decorations parent, int style, Element handle) {
super (parent, checkStyle (style));
this .parent = parent;
this .handle = handle;
/*
* Bug in IBM JVM 1.3.1. For some reason, when the checkOrientation() is
* called from createWidget(), the JVM issues this error:
*
* JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8)
*
* In addition, on Windows XP, a dialog appears with following error message,
* indicating that the problem may be in the JIT:
*
* AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll
* ModVer: 0.0.0.0 Offset: 000b6912
*
* The fix is to call checkOrientation() from here.
*/
checkOrientation (parent);
createWidget ();
}
void _setVisible (boolean visible) {
if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
CSSStyle style = handle.style;
if (visible) {
//style.width = "200px";
Rectangle clientArea = getDisplay().getPrimaryMonitor().getClientArea();
style.zIndex = window.currentTopZIndex + 1000;
style.display = "block";
handle.style.height = "";
int height = OS.getContainerHeight(handle);
if (OS.isIE || OS.isOpera) {
int maxWidth = 0;
boolean hasImage = false;
boolean hasSelection = false;
MenuItem[] children = getItems();
for (int i = 0; i < children.length; i++) {
MenuItem item = children[i];
int width = OS.getStringStyledWidth(item.getText(), "menu-item-text", null);
if (item.getImage() != null) {
hasImage = true;
}
if ((item.getStyle() & (SWT.CHECK | SWT.RADIO)) != 0) {
hasImage = true;
}
maxWidth = Math.max(maxWidth, width);
}
handle.style.width = (maxWidth + (hasImage ? 18 : 0) + (hasSelection ? 18 : 0) + 32) + "px";
} else {
handle.style.width = "";
int width = OS.getContainerWidth(handle);
handle.style.width = (width + 32) + "px";
}
handle.style.height = height + "px";
int width = OS.getContainerWidth(handle);
int left = x, top = y;
if (y + height > clientArea.y + clientArea.height) {
if (y + height - clientArea.y - clientArea.height > height - y) {
top = y - height;
}
}
if (x + width > clientArea.x + clientArea.width) {
if (x + width - clientArea.x - clientArea.width > width - x) {
left = x - width;
}
}
style.left = left + "px";
style.top = top + "px";
OS.SetFocus(btnFocus); //btnFocus.focus();
if (hooks(SWT.Show)) sendEvent(SWT.Show);
} else {
style.display = "none";
style.width = "";
if (hooks(SWT.Hide)) sendEvent(SWT.Hide);
}
/*
int hwndParent = parent.handle;
if (visible) {
int flags = OS.TPM_LEFTBUTTON;
if (OS.GetKeyState (OS.VK_LBUTTON) >= 0) flags |= OS.TPM_RIGHTBUTTON;
if ((style & SWT.RIGHT_TO_LEFT) != 0) flags |= OS.TPM_RIGHTALIGN;
if ((parent.style & SWT.MIRRORED) != 0) {
flags &= ~OS.TPM_RIGHTALIGN;
if ((style & SWT.LEFT_TO_RIGHT) != 0) flags |= OS.TPM_RIGHTALIGN;
}
int nX = x, nY = y;
if (!hasLocation) {
int pos = OS.GetMessagePos ();
nX = (short) (pos & 0xFFFF);
nY = (short) (pos >> 16);
}
/*
* Feature in Windows. It is legal use TrackPopupMenu()
* to display an empty menu as long as menu items are added
* inside of WM_INITPOPUPMENU. If no items are added, then
* TrackPopupMenu() fails and does not send an indication
* that the menu has been closed. This is not strictly a
* bug but leads to unwanted behavior when application code
* assumes that every WM_INITPOPUPMENU will eventually result
* in a WM_MENUSELECT, wParam=0xFFFF0000, lParam=0 to indicate
* that the menu has been closed. The fix is to detect the
* case when TrackPopupMenu() fails and the number of items in
* the menu is zero and issue a fake WM_MENUSELECT.
*-/
boolean success = OS.TrackPopupMenu (handle, flags, nX, nY, 0, hwndParent, null);
if (!success && GetMenuItemCount (handle) == 0) {
OS.SendMessage (hwndParent, OS.WM_MENUSELECT, 0xFFFF0000, 0);
}
} else {
OS.SendMessage (hwndParent, OS.WM_CANCELMODE, 0, 0);
}
*/
}
/**
* Adds the listener to the collection of listeners who will
* be notified when help events are generated for the control,
* by sending it one of the messages defined in the
* <code>HelpListener</code> interface.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see HelpListener
* @see #removeHelpListener
*/
public void addHelpListener (HelpListener listener) {
checkWidget ();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener (listener);
addListener (SWT.Help, typedListener);
}
/**
* Adds the listener to the collection of listeners who will
* be notified when menus are hidden or shown, by sending it
* one of the messages defined in the <code>MenuListener</code>
* interface.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see MenuListener
* @see #removeMenuListener
*/
public void addMenuListener (MenuListener listener) {
checkWidget ();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener (listener);
addListener (SWT.Hide,typedListener);
addListener (SWT.Show,typedListener);
}
static Control checkNull (Control control) {
if (control == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
return control;
}
static Menu checkNull (Menu menu) {
if (menu == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
return menu;
}
static MenuItem checkNull (MenuItem item) {
if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
return item;
}
static int checkStyle (int style) {
return checkBits (style, SWT.POP_UP, SWT.BAR, SWT.DROP_DOWN, 0, 0, 0);
}
int nextMenuItemIndex (int dir) {
int index = currentIndex;
MenuItem[] menuItems = items;
int tested = 0;
int length = menuItems.length;
if (index == -1) {
index = dir < 0 ? length - 1 : 0;
while (tested < length &&
(menuItems[index].style & SWT.SEPARATOR) != 0) {
tested++;
index += dir;
}
return index;
} else {
index += dir;
if (index == -1 || index == length) {
index = dir < 0 ? length - 1 : 0;
}
while (tested < length &&
(menuItems[index].style & SWT.SEPARATOR) != 0) {
tested++;
index += dir;
}
}
if (index == length) {
index = -1;
}
return index;
}
void createHandle () {
items = new MenuItem[0];
currentIndex = -1;
lastFocusdTime = -1;
if (handle != null) return;
handle = document.createElement("DIV");
if ((style & SWT.BAR) != 0) {
handle.className = "menu-bar";
OS.addCSSClass(parent.handle, "shell-menu-bar");
int top = 3;
if (parent.titleBar != null) {
top = 3 + OS.getContainerHeight(parent.titleBar);
}
handle.style.top = top + "px";
parent.handle.appendChild(handle);
parent.shellMenuBar = handle;
} else {
document.body.appendChild(handle);
handle.className = "menu-default";
boolean supportShadow = false;
/**
* @j2sNative
* supportShadow = window["swt.disable.shadow"] != true;
*/ {}
if (supportShadow) {
Decorations.createNarrowShadowHandles(handle);
}
}
btnFocus = document.createElement("BUTTON");
//btnFocus.type = "BUTTON";
btnFocus.className = "menu-focus";
handle.appendChild(btnFocus);
hMenuKeyDown = new RunnableCompatibility() {
public void run() {
HTMLEvent evt = (HTMLEvent) getEvent();
MenuItem[] menuItems = items;
int index = currentIndex;
if (evt.keyCode == 13 || evt.keyCode == 10) {
if (index != -1) {
MenuItem i = menuItems[index];
Element target = menuItems[index].handle;
if (i.isEnabled())
/**
* @j2sNative
* try {
* target.click ();
* } catch (e) {
* try {
* var clickEvent = document.createEvent("MouseEvents");
* clickEvent.initEvent("click", true, true);
* target.dispatchEvent(clickEvent);
* } catch (e) {
* }
* }
*/ { target.toString(); }
}
} else if (evt.keyCode == 38 || evt.keyCode == 104) { // up
if (index == -1) {
index = nextMenuItemIndex(-1);
MenuItem i = menuItems[index];
/**
* @j2sNative
* i.hItemMouseEnter ();
*/ { i.toString(); }
} else {
MenuItem i = menuItems[index];
index = nextMenuItemIndex(-1);
MenuItem i1 = menuItems[index];
/**
* @j2sNative
* i.hItemMouseExit ();
* i1.hItemMouseEnter ();
*/ { i.toString(); i1.toString(); }
}
} else if (evt.keyCode == 40 || evt.keyCode == 98) { // down
if (index == -1) {
index = nextMenuItemIndex(1);
MenuItem i = menuItems[index];
/**
* @j2sNative
* i.hItemMouseEnter ();
*/ { i.toString(); }
} else {
MenuItem i = menuItems[index];
index = nextMenuItemIndex(1);
MenuItem i1 = menuItems[index];
/**
* @j2sNative
* i.hItemMouseExit ();
* i1.hItemMouseEnter ();
*/ { i.toString(); i1.toString(); }
}
} else if (evt.keyCode == 37 || evt.keyCode == 100) { // left
if ((style & SWT.BAR) != 0) {
if (index == -1) {
index = nextMenuItemIndex(-1);
MenuItem i = menuItems[index];
/**
* @j2sNative
* i.hItemMouseEnter ();
*/ { i.toString(); }
} else {
MenuItem i = menuItems[index];
index = nextMenuItemIndex(-1);
MenuItem i1 = menuItems[index];
/**
* @j2sNative
* i.hItemMouseExit ();
* i1.hItemMouseEnter ();
*/ { i.toString(); i1.toString(); }
}
}
} else if (evt.keyCode == 39 || evt.keyCode == 102) { // up
if ((style & SWT.BAR) != 0) {
if (index == -1) {
index = nextMenuItemIndex(1);
MenuItem i = menuItems[index];
/**
* @j2sNative
* i.hItemMouseEnter ();
*/ { i.toString(); }
} else {
MenuItem i = menuItems[index];
index = nextMenuItemIndex(1);
MenuItem i1 = menuItems[index];
/**
* @j2sNative
* i.hItemMouseExit ();
* i1.hItemMouseEnter ();
*/ { i.toString(); i1.toString(); }
}
}
} else {
for (int i = 0; i < menuItems.length; i++) {
if (menuItems[i] != null && menuItems[i].mnemonicChar == evt.keyCode) {
Element target = (Element) menuItems[i].handle;
if (menuItems[i].isEnabled())
/**
* @j2sNative
* try {
* target.click ();
* } catch (e) {
* try {
* var clickEvent = document.createEvent("MouseEvents");
* clickEvent.initEvent("click", true, true);
* target.dispatchEvent(clickEvent);
* } catch (e) {
* }
* }
*/ { target.toString(); }
break;
}
}
}
currentIndex = index;
}
};
Clazz.addEvent(btnFocus, "keydown", hMenuKeyDown);
hMenuBlur = new RunnableCompatibility() {
public void run() {
long time = new Date().getTime();
if (time - lastFocusdTime > 20) {
if ((style & SWT.BAR) == 0) {
handle.style.display = "none";
sendEvent(SWT.Hide);
} else {
//OS.removeCSSClass(handle, "menu-bar-selected");
}
}
}
};
Clazz.addEvent(btnFocus, "blur", hMenuBlur);
hMenuFocus = new RunnableCompatibility() {
public void run() {
lastFocusdTime = new Date().getTime();
}
};
Clazz.addEvent(btnFocus, "focus", hMenuFocus);
hMenuMouseDown = new RunnableCompatibility() {
public void run() {
lastFocusdTime = new Date().getTime();
}
};
Clazz.addEvent(handle, "mousedown", hMenuMouseDown);
if ((style & SWT.BAR) != 0) {
/*
if (OS.IsPPC) {
int hwndShell = parent.handle;
SHMENUBARINFO mbi = new SHMENUBARINFO ();
mbi.cbSize = SHMENUBARINFO.sizeof;
mbi.hwndParent = hwndShell;
mbi.dwFlags = OS.SHCMBF_HIDDEN;
mbi.nToolBarId = ID_PPC;
mbi.hInstRes = OS.GetLibraryHandle ();
boolean success = OS.SHCreateMenuBar (mbi);
hwndCB = mbi.hwndMB;
if (!success) error (SWT.ERROR_NO_HANDLES);
/* Remove the item from the resource file *-/
OS.SendMessage (hwndCB, OS.TB_DELETEBUTTON, 0, 0);
return;
}
/*
* Note in WinCE SmartPhone. The SoftBar contains only 2 items.
* An item can either be a menu or a button.
* SWT.BAR: creates a SoftBar with 2 menus
* SWT.BAR | SWT.BUTTON1: creates a SoftBar with 1 button
* for button1, and a menu for button2
* SWT.BAR | SWT.BUTTON1 | SWT.BUTTON2: creates a SoftBar with
* 2 buttons
*-/
if (OS.IsSP) {
/* Determine type of menubar *-/
int nToolBarId;
if ((style & SWT.BUTTON1) != 0) {
nToolBarId = ((style & SWT.BUTTON2) != 0) ? ID_SPBB : ID_SPBM;
} else {
nToolBarId = ((style & SWT.BUTTON2) != 0) ? ID_SPMB : ID_SPMM;
}
/* Create SHMENUBAR *-/
SHMENUBARINFO mbi = new SHMENUBARINFO ();
mbi.cbSize = SHMENUBARINFO.sizeof;
mbi.hwndParent = parent.handle;
mbi.dwFlags = OS.SHCMBF_HIDDEN;
mbi.nToolBarId = nToolBarId; /* as defined in .rc file *-/
mbi.hInstRes = OS.GetLibraryHandle ();
if (!OS.SHCreateMenuBar (mbi)) error (SWT.ERROR_NO_HANDLES);
hwndCB = mbi.hwndMB;
/*
* Feature on WinCE SmartPhone. The SHCMBF_HIDDEN flag causes the
* SHMENUBAR to not be drawn. However the keyboard events still go
* through it. The workaround is to also hide the SHMENUBAR with
* ShowWindow ().
*-/
OS.ShowWindow (hwndCB, OS.SW_HIDE);
TBBUTTONINFO info = new TBBUTTONINFO ();
info.cbSize = TBBUTTONINFO.sizeof;
info.dwMask = OS.TBIF_COMMAND;
MenuItem item;
/* Set first item *-/
if (nToolBarId == ID_SPMM || nToolBarId == ID_SPMB) {
int hMenu = OS.SendMessage (hwndCB, OS.SHCMBM_GETSUBMENU, 0, ID_SPSOFTKEY0);
/* Remove the item from the resource file *-/
OS.RemoveMenu (hMenu, 0, OS.MF_BYPOSITION);
Menu menu = new Menu (parent, SWT.DROP_DOWN, hMenu);
item = new MenuItem (this, menu, SWT.CASCADE, 0);
} else {
item = new MenuItem (this, null, SWT.PUSH, 0);
}
info.idCommand = id0 = item.id;
OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, ID_SPSOFTKEY0, info);
/* Set second item *-/
if (nToolBarId == ID_SPMM || nToolBarId == ID_SPBM) {
int hMenu = OS.SendMessage (hwndCB, OS.SHCMBM_GETSUBMENU, 0, ID_SPSOFTKEY1);
OS.RemoveMenu (hMenu, 0, OS.MF_BYPOSITION);
Menu menu = new Menu (parent, SWT.DROP_DOWN, hMenu);
item = new MenuItem (this, menu, SWT.CASCADE, 1);
} else {
item = new MenuItem (this, null, SWT.PUSH, 1);
}
info.idCommand = id1 = item.id;
OS.SendMessage (hwndCB, OS.TB_SETBUTTONINFO, ID_SPSOFTKEY1, info);
/*
* Override the Back key. For some reason, the owner of the menubar
* must be a Dialog or it won't receive the WM_HOTKEY message. As
* a result, Shell on WinCE SP must use the class Dialog.
*-/
int dwMask = OS.SHMBOF_NODEFAULT | OS.SHMBOF_NOTIFY;
int lParam = dwMask << 16 | dwMask;
OS.SendMessage (hwndCB, OS.SHCMBM_OVERRIDEKEY, OS.VK_ESCAPE, lParam);
return;
}
handle = OS.CreateMenu ();
if (handle == 0) error (SWT.ERROR_NO_HANDLES);
if (OS.IsHPC) {
int hwndShell = parent.handle;
hwndCB = OS.CommandBar_Create (OS.GetModuleHandle (null), hwndShell, 1);
if (hwndCB == 0) error (SWT.ERROR_NO_HANDLES);
OS.CommandBar_Show (hwndCB, false);
OS.CommandBar_InsertMenubarEx (hwndCB, 0, handle, 0);
/*
* The command bar hosts the 'close' button when the window does not
* have a caption.
*-/
if ((parent.style & SWT.CLOSE) != 0 && (parent.style & SWT.TITLE) == 0) {
OS.CommandBar_AddAdornments (hwndCB, 0, 0);
}
}
*/
} else {
//handle = OS.CreatePopupMenu ();
if (handle == null) error (SWT.ERROR_NO_HANDLES);
}
}
void createItem (MenuItem item, int index) {
int count = items.length; //GetMenuItemCount (handle);
if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
for (int i = 0; i < items.length; i++) {
if (items[i] == item) {
return;
}
}
items[items.length] = item;
display.addMenuItem (item);
item.handle = document.createElement("DIV");
item.handle.className = ((style & SWT.BAR) != 0) ? "menu-bar-item" : "menu-item";
handle.appendChild(item.handle);
if ((item.style & SWT.SEPARATOR) == 0) {
if ((item.style & (SWT.CHECK | SWT.RADIO)) != 0) {
OS.addCSSClass(handle, "menu-enable-status");
}
if ((style & SWT.BAR) == 0) {
Element el = document.createElement("DIV");
el.className = "menu-item-status";
item.handle.appendChild(el);
item.statusEl = el;
el = document.createElement("DIV");
el.className = "menu-item-image";
item.handle.appendChild(el);
item.imageEl = el;
el = document.createElement("DIV");
el.className = "menu-item-text";
item.handle.appendChild(el);
item.textEl = el;
el = document.createElement("DIV");
el.className = "menu-item-arrow";
item.handle.appendChild(el);
item.arrowEl = el;
if ((item.style & SWT.CASCADE) != 0) {
el = document.createElement("DIV");
el.className = "menu-item-arrow-right";
item.arrowEl.appendChild(el);
}
}
} else {
item.handle.className += " menu-item-seperator";
}
/*
boolean success = false;
if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
if (OS.IsSP) return;
TBBUTTON lpButton = new TBBUTTON ();
lpButton.idCommand = item.id;
lpButton.fsStyle = (byte) OS.TBSTYLE_AUTOSIZE;
if ((item.style & SWT.CASCADE) != 0) lpButton.fsStyle |= OS.TBSTYLE_DROPDOWN | 0x80;
if ((item.style & SWT.SEPARATOR) != 0) lpButton.fsStyle = (byte) OS.BTNS_SEP;
lpButton.fsState = (byte) OS.TBSTATE_ENABLED;
lpButton.iBitmap = OS.I_IMAGENONE;
success = OS.SendMessage (hwndCB, OS.TB_INSERTBUTTON, index, lpButton) != 0;
} else {
if (OS.IsWinCE) {
int uFlags = OS.MF_BYPOSITION;
TCHAR lpNewItem = null;
if ((item.style & SWT.SEPARATOR) != 0) {
uFlags |= OS.MF_SEPARATOR;
} else {
lpNewItem = new TCHAR (0, " ", true);
}
success = OS.InsertMenu (handle, index, uFlags, item.id, lpNewItem);
if (success) {
MENUITEMINFO info = new MENUITEMINFO ();
info.cbSize = MENUITEMINFO.sizeof;
info.fMask = OS.MIIM_DATA;
info.dwItemData = item.id;
success = OS.SetMenuItemInfo (handle, index, true, info);
}
} else {
/*
* Bug in Windows. For some reason, when InsertMenuItem()
* is used to insert an item without text, it is not possible
* to use SetMenuItemInfo() to set the text at a later time.
* The fix is to insert the item with some text.
*
* Feature in Windows. When an empty string is used instead
* of a space and InsertMenuItem() is used to set a submenu
* before setting text to a non-empty string, the menu item
* becomes unexpectedly disabled. The fix is to insert a
* space.
*-/
int hHeap = OS.GetProcessHeap ();
TCHAR buffer = new TCHAR (0, " ", true);
int byteCount = buffer.length () * TCHAR.sizeof;
int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
OS.MoveMemory (pszText, buffer, byteCount);
MENUITEMINFO info = new MENUITEMINFO ();
info.cbSize = MENUITEMINFO.sizeof;
info.fMask = OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_DATA;
info.wID = info.dwItemData = item.id;
info.fType = item.widgetStyle ();
info.dwTypeData = pszText;
success = OS.InsertMenuItem (handle, index, true, info);
if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
}
}
if (!success) {
display.removeMenuItem (item);
error (SWT.ERROR_ITEM_NOT_ADDED);
}
*/
redraw ();
}
void createWidget () {
/*
* Bug in IBM JVM 1.3.1. For some reason, when the following code is called
* from this method, the JVM issues this error:
*
* JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8)
*
* In addition, on Windows XP, a dialog appears with following error message,
* indicating that the problem may be in the JIT:
*
* AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll
* ModVer: 0.0.0.0 Offset: 000b6912
*
* The fix is to move the code to the caller of this method.
*/
// checkOrientation (parent);
createHandle ();
parent.addMenu (this );
}
/*
* Currently not used.
*-/
int defaultBackground () {
return OS.GetSysColor (OS.COLOR_MENU);
}
/*
* Currently not used.
*-/
int defaultForeground () {
return OS.GetSysColor (OS.COLOR_MENUTEXT);
}
*/
void destroyAccelerators () {
parent.destroyAccelerators ();
}
void registerAccelerator(int accelerator, MenuItem item){
if(acceleratorTable == null){
acceleratorTable = new Object[0];
}
int size = acceleratorTable.length;
acceleratorTable[size] = new Integer(accelerator);
acceleratorTable[size+1] = item;
}
boolean isAccelerated(HTMLEvent keyEvent){
int size = acceleratorTable.length;
for(int i = 0; i < size; i+=2){
int acclCode = ((Integer) acceleratorTable[i]).intValue();
if(
(((acclCode & SWT.CONTROL) != 0 && keyEvent.ctrlKey) || ((acclCode & SWT.CONTROL) == 0 )) &&
(((acclCode & SWT.ALT) != 0 && keyEvent.altKey) || ((acclCode & SWT.ALT) == 0)) &&
((acclCode & SWT.SHIFT) != 0 && keyEvent.shiftKey) || ((acclCode & SWT.SHIFT) == 0)
) {
acclCode &= ~(SWT.ALT | SWT.SHIFT | SWT.CONTROL);
if(acclCode == keyEvent.keyCode){
MenuItem item = (MenuItem) acceleratorTable[i+1];
/**
* @j2sNative
* try {
* item.handle.click ();
* } catch (e) {
* try {
* var clickEvent = document.createEvent("MouseEvents");
* clickEvent.initEvent("click", true, true);
* item.handle.dispatchEvent(clickEvent);
* } catch (e) {
* }
* }
*/ { item.toString(); }
}
}
}
return false;
}
void destroyItem (MenuItem item) {
/*
if (OS.IsWinCE) {
if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
if (OS.IsSP) {
redraw();
return;
}
int index = OS.SendMessage (hwndCB, OS.TB_COMMANDTOINDEX, item.id, 0);
if (OS.SendMessage (hwndCB, OS.TB_DELETEBUTTON, index, 0) == 0) {
error (SWT.ERROR_ITEM_NOT_REMOVED);
}
int count = OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0);
if (count == 0) {
if (imageList != null) {
OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0);
display.releaseImageList (imageList);
imageList = null;
}
}
} else {
int index = 0;
MENUITEMINFO info = new MENUITEMINFO ();
info.cbSize = MENUITEMINFO.sizeof;
info.fMask = OS.MIIM_DATA;
while (OS.GetMenuItemInfo (handle, index, true, info)) {
if (info.dwItemData == item.id) break;
index++;
}
if (info.dwItemData != item.id) {
error (SWT.ERROR_ITEM_NOT_REMOVED);
}
if (!OS.RemoveMenu (handle, index, OS.MF_BYPOSITION)) {
error (SWT.ERROR_ITEM_NOT_REMOVED);
}
}
} else {
if (!OS.RemoveMenu (handle, item.id, OS.MF_BYCOMMAND)) {
error (SWT.ERROR_ITEM_NOT_REMOVED);
}
}
*/
redraw ();
}
void destroyWidget () {
// int hMenu = handle, hCB = hwndCB;
releaseHandle ();
/*
if (OS.IsWinCE && hCB != 0) {
OS.CommandBar_Destroy (hCB);
} else {
if (hMenu != 0) OS.DestroyMenu (hMenu);
}
*/
if (handle != null) {
OS.destroyHandle(handle);
handle = null;
}
}
void fixMenus (Decorations newParent) {
MenuItem [] items = getItems ();
for (int i=0; i<items.length; i++) {
items [i].fixMenus (newParent);
}
parent.removeMenu (this );
newParent.addMenu (this );
this .parent = newParent;
}
/**
* Returns a rectangle describing the receiver's size and location
* relative to its parent (or its display if its parent is null),
* unless the receiver is a menu or a shell. In this case, the
* location is relative to the display.
* <p>
* Note that the bounds of a menu or menu item are undefined when
* the menu is not visible. This is because most platforms compute
* the bounds of a menu dynamically just before it is displayed.
* </p>
*
* @return the receiver's bounding rectangle
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @since 3.1
*/
/*public*/ Rectangle getBounds () {
checkWidget ();
//if (OS.IsWinCE) return new Rectangle (0, 0, 0, 0);
if ((style & SWT.BAR) != 0) {
if (parent.menuBar != this ) {
return new Rectangle (0, 0, 0, 0);
}
/*
int hwndShell = parent.handle;
MENUBARINFO info = new MENUBARINFO ();
info.cbSize = MENUBARINFO.sizeof;
if (OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, 0, info)) {
int width = info.right - info.left;
int height = info.bottom - info.top;
return new Rectangle (info.left, info.top, width, height);
}
*/
// TODO: SWT.BAR
} else {
int count = items.length; //GetMenuItemCount (handle);
if (count != 0) {
/*
RECT rect1 = new RECT ();
if (OS.GetMenuItemRect (0, handle, 0, rect1)) {
RECT rect2 = new RECT ();
if (OS.GetMenuItemRect (0, handle, count - 1, rect2)) {
int x = rect1.left - 2, y = rect1.top - 2;
int width = (rect2.right - rect2.left) + 4;
int height = (rect2.bottom - rect1.top) + 4;
return new Rectangle (x, y, width, height);
}
}
*/
int x, y, w, h;
Element hdl1 = items[0].handle;
Point pt1 = OS.calcuateRelativePosition(hdl1, document.body);
x = pt1.x;
y = pt1.y;
int textWidth = 0;
int accelWidth = 0;
for (int i = 0; i < count; i++) {
String text = items[i].text;
if (text == null) {
continue;
}
int idx = text.indexOf('\t');
String normalText = text;
String accelText = null;
if (idx != -1) {
normalText = text.substring(0, idx);
accelText = text.substring(idx + 1);
}
if (accelText != null && accelText.length() != 0) {
int width = OS.getStringStyledWidth(accelText, "menu-item-text", null);
if (width > accelWidth) {
accelWidth = width;
}
}
int width = OS.getStringStyledWidth(normalText, "menu-item-text", null);
if (width > textWidth) {
textWidth = width;
}
}
w = 16 + textWidth + 16 + accelWidth + 16 + 8; // 8 for extra safe width
if (handle.className.indexOf("menu-enable-status") != -1 &&
handle.className.indexOf("menu-enable-image") != -1) {
w += 16;
}
if (count == 1) {
//w = OS.getContainerWidth(hdl1);
h = OS.getContainerHeight(hdl1);
} else {
Element hdl2 = items[count - 1].handle;
Point pt2 = OS.calcuateRelativePosition(hdl2, document.body);
//w = OS.getContainerWidth(hdl2);
h = pt2.y - pt1.y + OS.getContainerHeight(hdl2);
}
return new Rectangle(x - 2, y - 2, w + 4, h + 4);
}
}
return new Rectangle (0, 0, 0, 0);
}
/**
* Returns the default menu item or null if none has
* been previously set.
*
* @return the default menu item.
*
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public MenuItem getDefaultItem () {
checkWidget ();
/*
if (OS.IsWinCE) return null;
int id = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
if (id == -1) return null;
MENUITEMINFO info = new MENUITEMINFO ();
info.cbSize = MENUITEMINFO.sizeof;
info.fMask = OS.MIIM_ID;
if (OS.GetMenuItemInfo (handle, id, false, info)) {
return display.getMenuItem (info.wID);
}
*/
return defaultItem;
}
/**
* Returns <code>true</code> if the receiver is enabled, and
* <code>false</code> otherwise. A disabled menu is typically
* not selectable from the user interface and draws with an
* inactive or "grayed" look.
*
* @return the receiver's enabled state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see #isEnabled
*/
public boolean getEnabled () {
checkWidget ();
return (state & DISABLED) == 0;
}
/**
* Returns the item at the given, zero-relative index in the
* receiver. Throws an exception if the index is out of range.
*
* @param index the index of the item to return
* @return the item at the given index
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public MenuItem getItem (int index) {
checkWidget ();
/*
int id = 0;
if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
if (OS.IsPPC) {
TBBUTTON lpButton = new TBBUTTON ();
int result = OS.SendMessage (hwndCB, OS.TB_GETBUTTON, index, lpButton);
if (result == 0) error (SWT.ERROR_CANNOT_GET_ITEM);
id = lpButton.idCommand;
}
if (OS.IsSP) {
if (!(0 <= index && index <= 1)) error (SWT.ERROR_CANNOT_GET_ITEM);
id = index == 0 ? id0 : id1;
}
} else {
MENUITEMINFO info = new MENUITEMINFO ();
info.cbSize = MENUITEMINFO.sizeof;
info.fMask = OS.MIIM_DATA;
if (!OS.GetMenuItemInfo (handle, index, true, info)) {
error (SWT.ERROR_INVALID_RANGE);
}
id = info.dwItemData;
}
return display.getMenuItem (id);
*/
if (!(0 <= index && index <= items.length - 1)) error (SWT.ERROR_CANNOT_GET_ITEM);
return items[index];
}
/**
* Returns the number of items contained in the receiver.
*
* @return the number of items
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getItemCount () {
checkWidget ();
//return GetMenuItemCount (handle);
return items.length;
}
/**
* Returns a (possibly empty) array of <code>MenuItem</code>s which
* are the items in the receiver.
* <p>
* Note: This is not the actual structure used by the receiver
* to maintain its list of items, so modifying the array will
* not affect the receiver.
* </p>
*
* @return the items in the receiver
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public MenuItem [] getItems () {
checkWidget ();
/*
if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
if (OS.IsSP) {
MenuItem [] result = new MenuItem [2];
result[0] = display.getMenuItem (id0);
result[1] = display.getMenuItem (id1);
return result;
}
int count = OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0);
TBBUTTON lpButton = new TBBUTTON ();
MenuItem [] result = new MenuItem [count];
for (int i=0; i<count; i++) {
OS.SendMessage (hwndCB, OS.TB_GETBUTTON, i, lpButton);
result [i] = display.getMenuItem (lpButton.idCommand);
}
return result;
}
int count = 0;
int length = OS.IsWinCE ? 4 : OS.GetMenuItemCount (handle);
MenuItem [] items = new MenuItem [length];
MENUITEMINFO info = new MENUITEMINFO ();
info.cbSize = MENUITEMINFO.sizeof;
info.fMask = OS.MIIM_DATA;
while (OS.GetMenuItemInfo (handle, count, true, info)) {
if (count == items.length) {
MenuItem [] newItems = new MenuItem [count + 4];
System.arraycopy (items, 0, newItems, 0, count);
items = newItems;
}
items [count++] = display.getMenuItem (info.dwItemData);
}
if (count == items.length) return items;
*/
int count = items.length;
MenuItem [] result = new MenuItem [count];
System.arraycopy (items, 0, result, 0, count);
return result;
}
/*
int GetMenuItemCount (Element handle) {
if (OS.IsWinCE) {
if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
return OS.IsSP ? 2 : OS.SendMessage (hwndCB, OS.TB_BUTTONCOUNT, 0, 0);
}
int count = 0;
MENUITEMINFO info = new MENUITEMINFO ();
info.cbSize = MENUITEMINFO.sizeof;
while (OS.GetMenuItemInfo (handle, count, true, info)) count++;
return count;
}
return OS.GetMenuItemCount (handle);
}
*/
String getNameText () {
String result = "";
MenuItem [] items = getItems ();
int length = items.length;
if (length > 0) {
for (int i=0; i<length-1; i++) {
result = result + items [i].getNameText() + ", ";
}
result = result + items [length-1].getNameText ();
}
return result;
}
/**
* Returns the receiver's parent, which must be a <code>Decorations</code>.
*
* @return the receiver's parent
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public Decorations getParent () {
checkWidget ();
return parent;
}
/**
* Returns the receiver's parent item, which must be a
* <code>MenuItem</code> or null when the receiver is a
* root.
*
* @return the receiver's parent item
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public MenuItem getParentItem () {
checkWidget ();
return cascade;
}
/**
* Returns the receiver's parent item, which must be a
* <code>Menu</code> or null when the receiver is a
* root.
*
* @return the receiver's parent item
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public Menu getParentMenu () {
checkWidget ();
if (cascade != null) return cascade.parent;
return null;
}
/**
* Returns the receiver's shell. For all controls other than
* shells, this simply returns the control's nearest ancestor
* shell. Shells return themselves, even if they are children
* of other shells.
*
* @return the receiver's shell
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see #getParent
*/
public Shell getShell () {
checkWidget ();
return parent.getShell ();
}
/**
* Returns <code>true</code> if the receiver is visible, and
* <code>false</code> otherwise.
* <p>
* If one of the receiver's ancestors is not visible or some
* other condition makes the receiver not visible, this method
* may still indicate that it is considered visible even though
* it may not actually be showing.
* </p>
*
* @return the receiver's visibility state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public boolean getVisible () {
checkWidget ();
if ((style & SWT.BAR) != 0) {
return this == parent.menuShell ().menuBar;
}
if ((style & SWT.POP_UP) != 0) {
Menu [] popups = display.popups;
if (popups == null) return false;
for (int i=0; i<popups.length; i++) {
if (popups [i] == this ) return true;
}
}
Shell shell = getShell ();
Menu menu = shell.activeMenu;
while (menu != null && menu != this ) {
menu = menu.getParentMenu ();
}
return this == menu;
}
int imageIndex (Image image) {
/*
if (hwndCB == 0 || image == null) return OS.I_IMAGENONE;
if (imageList == null) {
int hOldList = OS.SendMessage (hwndCB, OS.TB_GETIMAGELIST, 0, 0);
if (hOldList != 0) OS.ImageList_Destroy (hOldList);
Rectangle bounds = image.getBounds ();
imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
int hImageList = imageList.getHandle ();
OS.SendMessage (hwndCB, OS.TB_SETIMAGELIST, 0, hImageList);
}
*/
int index = imageList.indexOf (image);
if (index == -1) {
index = imageList.add (image);
} else {
imageList.put (index, image);
}
return index;
}
/**
* Searches the receiver's list starting at the first item
* (index 0) until an item is found that is equal to the
* argument, and returns the index of that item. If no item
* is found, returns -1.
*
* @param item the search item
* @return the index of the item
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the string is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int indexOf (MenuItem item) {
checkWidget ();
if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
if (item.parent != this ) return -1;
/*
if ((OS.IsPPC || OS.IsSP) && hwndCB != 0) {
if (OS.IsPPC) {
return OS.SendMessage (hwndCB, OS.TB_COMMANDTOINDEX, item.id, 0);
}
if (OS.IsSP) {
if (item.id == id0) return 0;
if (item.id == id1) return 1;
return -1;
}
}
int index = 0;
MENUITEMINFO info = new MENUITEMINFO ();
info.cbSize = MENUITEMINFO.sizeof;
info.fMask = OS.MIIM_DATA;
while (OS.GetMenuItemInfo (handle, index, true, info)) {
if (info.dwItemData == item.id) return index;
index++;
}
*/
for (int i = 0; i < items.length; i++) {
if (items[i] == item) {
return i;
}
}
return -1;
}
/**
* Returns <code>true</code> if the receiver is enabled and all
* of the receiver's ancestors are enabled, and <code>false</code>
* otherwise. A disabled menu is typically not selectable from the
* user interface and draws with an inactive or "grayed" look.
*
* @return the receiver's enabled state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see #getEnabled
*/
public boolean isEnabled () {
checkWidget ();
Menu parentMenu = getParentMenu ();
if (parentMenu == null) return getEnabled ();
return getEnabled () && parentMenu.isEnabled ();
}
/**
* Returns <code>true</code> if the receiver is visible and all
* of the receiver's ancestors are visible and <code>false</code>
* otherwise.
*
* @return the receiver's visibility state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see #getVisible
*/
public boolean isVisible () {
checkWidget ();
return getVisible ();
}
void redraw () {
if (!isVisible ()) return;
if ((style & SWT.BAR) != 0) {
display.addBar (this );
} else {
update ();
}
}
protected void releaseChild () {
super .releaseChild ();
if (cascade != null) cascade.releaseMenu ();
if ((style & SWT.BAR) != 0) {
display.removeBar (this );
if (this == parent.menuBar) {
parent.setMenuBar (null);
}
} else {
if ((style & SWT.POP_UP) != 0) {
display.removePopup (this );
}
}
}
protected void releaseHandle () {
if (btnFocus != null) {
if (hMenuKeyDown != null) {
Clazz.removeEvent(btnFocus, "keydown", hMenuKeyDown);
hMenuKeyDown = null;
}
if (hMenuBlur != null) {
Clazz.removeEvent(btnFocus, "blur", hMenuBlur);
hMenuBlur = null;
}
if (hMenuFocus != null) {
Clazz.removeEvent(btnFocus, "focus", hMenuFocus);
hMenuFocus = null;
}
OS.destroyHandle(btnFocus);
btnFocus = null;
}
if (handle != null) {
if (hMenuMouseDown != null) {
Clazz.removeEvent(handle, "mousedown", hMenuMouseDown);
hMenuMouseDown = null;
}
OS.destroyHandle(handle);
handle = null;
}
super .releaseHandle ();
// handle = hwndCB = 0;
}
void releaseWidget () {
//MenuItem [] items = getItems ();
for (int i=0; i<items.length; i++) {
MenuItem item = items [i];
if (!item.isDisposed ()) {
/*
if (OS.IsPPC && hwndCB != 0) {
item.dispose ();
} else {
item.releaseResources ();
}
*/
item.releaseResources ();
}
items[i] = null;
}
items = new MenuItem[0];
/*
if (OS.IsPPC && hwndCB != 0) {
if (imageList != null) {
OS.SendMessage (hwndCB, OS.TB_SETIMAGELIST, 0, 0);
display.releaseToolImageList (imageList);
imageList = null;
}
}
*/
super .releaseWidget ();
if (parent != null) parent.removeMenu (this );
parent = null;
cascade = null;
}
/**
* Removes the listener from the collection of listeners who will
* be notified when the help events are generated for the control.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see HelpListener
* @see #addHelpListener
*/
public void removeHelpListener (HelpListener listener) {
checkWidget ();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
if (eventTable == null) return;
eventTable.unhook (SWT.Help, listener);
}
/**
* Removes the listener from the collection of listeners who will
* be notified when the menu events are generated for the control.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see MenuListener
* @see #addMenuListener
*/
public void removeMenuListener (MenuListener listener) {
checkWidget ();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
if (eventTable == null) return;
eventTable.unhook (SWT.Hide, listener);
eventTable.unhook (SWT.Show, listener);
}
/**
* Sets the default menu item to the argument or removes
* the default emphasis when the argument is <code>null</code>.
*
* @param item the default menu item or null
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_INVALID_ARGUMENT - if the menu item has been disposed</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setDefaultItem (MenuItem item) {
checkWidget ();
defaultItem = item;
/*
int newID = -1;
if (item != null) {
if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
if (item.parent != this) return;
newID = item.id;
}
if (OS.IsWinCE) return;
int oldID = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
if (newID == oldID) return;
OS.SetMenuDefaultItem (handle, newID, OS.MF_BYCOMMAND);
*/
redraw ();
}
/**
* Enables the receiver if the argument is <code>true</code>,
* and disables it otherwise. A disabled menu is typically
* not selectable from the user interface and draws with an
* inactive or "grayed" look.
*
* @param enabled the new enabled state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setEnabled (boolean enabled) {
checkWidget ();
state &= ~DISABLED;
if (!enabled) state |= DISABLED;
}
/**
* Sets the location of the receiver, which must be a popup,
* to the point specified by the arguments which are relative
* to the display.
* <p>
* Note that this is different from most widgets where the
* location of the widget is relative to the parent.
* </p><p>
* Note that the platform window manager ultimately has control
* over the location of popup menus.
* </p>
*
* @param x the new x coordinate for the receiver
* @param y the new y coordinate for the receiver
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setLocation (int x, int y) {
checkWidget ();
if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
this .x = x;
this .y = y;
hasLocation = true;
}
/**
* Sets the location of the receiver, which must be a popup,
* to the point specified by the argument which is relative
* to the display.
* <p>
* Note that this is different from most widgets where the
* location of the widget is relative to the parent.
* </p><p>
* Note that the platform window manager ultimately has control
* over the location of popup menus.
* </p>
*
* @param location the new location for the receiver
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the point is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @since 2.1
*/
public void setLocation (Point location) {
checkWidget ();
if (location == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
setLocation (location.x, location.y);
}
/**
* Marks the receiver as visible if the argument is <code>true</code>,
* and marks it invisible otherwise.
* <p>
* If one of the receiver's ancestors is not visible or some
* other condition makes the receiver not visible, marking
* it visible may not actually cause it to be displayed.
* </p>
*
* @param visible the new visibility state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setVisible (boolean visible) {
checkWidget ();
if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
if (visible) {
display.addPopup (this );
} else {
display.removePopup (this );
_setVisible (false);
}
}
void update () {
/*
if (OS.IsPPC || OS.IsSP) return;
if (OS.IsHPC) {
/*
* Each time a menu has been modified, the command menu bar
* must be redrawn or it won't update properly. For example,
* a submenu will not drop down.
*-/
Menu menuBar = parent.menuBar;
if (menuBar != null) {
Menu menu = this;
while (menu != null && menu != menuBar) {
menu = menu.getParentMenu ();
}
if (menu == menuBar) {
OS.CommandBar_DrawMenuBar (menuBar.hwndCB, 0);
OS.CommandBar_Show (menuBar.hwndCB, true);
}
}
return;
}
if (OS.IsWinCE) return;
if ((style & SWT.BAR) != 0) {
if (this == parent.menuBar) OS.DrawMenuBar (parent.handle);
return;
}
if (OS.WIN32_VERSION < OS.VERSION (4, 10)) {
return;
}
*/
boolean hasCheck = false, hasImage = false;
MenuItem [] items = getItems ();
for (int i=0; i<items.length; i++) {
MenuItem item = items [i];
if (item.image != null) {
if ((hasImage = true) && hasCheck) break;
}
if ((item.style & (SWT.CHECK | SWT.RADIO)) != 0) {
if ((hasCheck = true) && hasImage) break;
}
}
/*
* Bug in Windows. If a menu contains items that have
* images and can be checked, Windows does not include
* the width of the image and the width of the check when
* computing the width of the menu. When the longest item
* does not have an image, the label and the accelerator
* text can overlap. The fix is to use SetMenuItemInfo()
* to indicate that all items have a bitmap and then include
* the width of the widest bitmap in WM_MEASURECHILD.
*
* NOTE: This work around causes problems on Windows 98.
* Under certain circumstances that have yet to be isolated,
* some menus can become huge and blank. For now, do not
* run the code on Windows 98.
*-/
if (!OS.IsWin95) {
MENUITEMINFO info = new MENUITEMINFO ();
info.cbSize = MENUITEMINFO.sizeof;
info.fMask = OS.MIIM_BITMAP;
for (int i=0; i<items.length; i++) {
MenuItem item = items [i];
if ((style & SWT.SEPARATOR) == 0) {
if (item.image == null) {
info.hbmpItem = hasImage ? OS.HBMMENU_CALLBACK : 0;
OS.SetMenuItemInfo (handle, item.id, false, info);
}
}
}
}
/* Update the menu to hide or show the space for bitmaps *-/
MENUINFO lpcmi = new MENUINFO ();
lpcmi.cbSize = MENUINFO.sizeof;
lpcmi.fMask = OS.MIM_STYLE;
OS.GetMenuInfo (handle, lpcmi);
if (hasImage && !hasCheck) {
lpcmi.dwStyle |= OS.MNS_CHECKORBMP;
} else {
lpcmi.dwStyle &= ~OS.MNS_CHECKORBMP;
}
OS.SetMenuInfo (handle, lpcmi);
*/
}
}
|