/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores
* CA 94065 USA or visit www.oracle.com if you need additional information or
* have any questions.
*/
package com.sun.lwuit;
import com.sun.lwuit.animations.CommonTransitions;
import com.sun.lwuit.animations.Transition;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.events.ActionListener;
import com.sun.lwuit.geom.Dimension;
import com.sun.lwuit.layouts.BorderLayout;
import com.sun.lwuit.layouts.BoxLayout;
import com.sun.lwuit.layouts.FlowLayout;
import com.sun.lwuit.layouts.GridLayout;
import com.sun.lwuit.list.ListCellRenderer;
import com.sun.lwuit.plaf.LookAndFeel;
import com.sun.lwuit.plaf.Style;
import com.sun.lwuit.plaf.UIManager;
import java.util.Vector;
/**
* This class represents the Form MenuBar.
* This class is responsible to show the Form Commands and to handle device soft
* keys, back key, clear key, etc...
* This class can be overridden and replaced in the LookAndFeel
* @see LookAndFeel#setMenuBarClass(java.lang.Class)
* @author Chen Fishbein
*/
public class MenuBar extends Container implements ActionListener {
private Command selectCommand;
private Command defaultCommand;
/**
* Indicates the command that is defined as the back command out of this form.
* A back command can be used both to map to a hardware button (e.g. on the Sony Ericsson devices)
* and by elements such as transitions etc. to change the behavior based on
* direction (e.g. slide to the left to enter screen and slide to the right to exit with back).
*/
private Command backCommand;
/**
* Indicates the command that is defined as the clear command out of this form similar
* in spirit to the back command
*/
private Command clearCommand;
/**
* This member holds the left soft key value
*/
static int leftSK;
/**
* This member holds the right soft key value
*/
static int rightSK;
/**
* This member holds the 2nd right soft key value
* this is used for different BB devices
*/
static int rightSK2;
/**
* This member holds the back command key value
*/
static int backSK;
/**
* This member holds the clear command key value
*/
static int clearSK;
static int backspaceSK;
static {
// RIM and potentially other devices reinitialize the static initializer thus overriding
// the new static values set by the initialized display https://lwuit.dev.java.net/issues/show_bug.cgi?id=232
if (Display.getInstance() == null || Display.getInstance().getImplementation() == null) {
leftSK = -6;
rightSK = -7;
rightSK2 = -7;
backSK = -11;
clearSK = -8;
backspaceSK = -8;
}
}
private Command menuCommand;
private Vector commands = new Vector();
private Button[] soft;
private Command[] softCommand;
private Button left;
private Button right;
private Button main;
private ListCellRenderer menuCellRenderer;
private Transition transitionIn;
private Transition transitionOut;
private Component commandList;
private Style menuStyle;
private Command selectMenuItem;
private Command cancelMenuItem;
private Form parent;
private int softkeyCount;
private boolean thirdSoftButton;
/**
* Empty Constructor
*/
public MenuBar() {
}
/**
* Initialize the MenuBar
*
* @param parent the associated Form
*/
protected void initMenuBar(Form parent) {
this.parent = parent;
selectMenuItem = createMenuSelectCommand();
cancelMenuItem = createMenuCancelCommand();
LookAndFeel lf = UIManager.getInstance().getLookAndFeel();
menuStyle = UIManager.getInstance().getComponentStyle("Menu");
setUIID("SoftButton");
menuCommand = new Command(UIManager.getInstance().localize("menu", "Menu"), lf.getMenuIcons()[2]);
// use the slide transition by default
if (lf.getDefaultMenuTransitionIn() != null || lf.getDefaultMenuTransitionOut() != null) {
transitionIn = lf.getDefaultMenuTransitionIn();
transitionOut = lf.getDefaultMenuTransitionOut();
} else {
transitionIn = CommonTransitions.createSlide(CommonTransitions.SLIDE_VERTICAL, true, 300, true);
transitionOut = CommonTransitions.createSlide(CommonTransitions.SLIDE_VERTICAL, false, 300, true);
}
menuCellRenderer = lf.getMenuRenderer();
softkeyCount = Display.getInstance().getImplementation().getSoftkeyCount();
thirdSoftButton = Display.getInstance().isThirdSoftButton();
int commandBehavior = getCommandBehavior();
if (softkeyCount > 1 && commandBehavior < Display.COMMAND_BEHAVIOR_BUTTON_BAR) {
if (thirdSoftButton) {
setLayout(new GridLayout(1, 3));
soft = new Button[]{createSoftButton("SoftButtonCenter"), createSoftButton("SoftButtonLeft"), createSoftButton("SoftButtonRight")};
main = soft[0];
left = soft[1];
right = soft[2];
if (parent.isRTL()) {
right.setUIID("SoftButtonLeft");
left.setUIID("SoftButtonRight");
addComponent(right);
addComponent(main);
addComponent(left);
} else {
addComponent(left);
addComponent(main);
addComponent(right);
}
if (isReverseSoftButtons()) {
Button b = soft[1];
soft[1] = soft[2];
soft[2] = b;
}
} else {
setLayout(new GridLayout(1, 2));
soft = new Button[]{createSoftButton("SoftButtonLeft"), createSoftButton("SoftButtonRight")};
main = soft[0];
left = soft[0];
right = soft[1];
if (parent.isRTL()) {
right.setUIID("SoftButtonLeft");
left.setUIID("SoftButtonRight");
addComponent(right);
addComponent(left);
} else {
addComponent(left);
addComponent(right);
}
if (isReverseSoftButtons()) {
Button b = soft[0];
soft[0] = soft[1];
soft[1] = b;
}
}
// It doesn't make sense for softbuttons to have ... at the end
for (int iter = 0; iter < soft.length; iter++) {
soft[iter].setEndsWith3Points(false);
}
} else {
// special case for touch screens we still want the 3 softbutton areas...
if (thirdSoftButton) {
setLayout(new GridLayout(1, 3));
soft = new Button[]{createSoftButton("SoftButtonCenter"), createSoftButton("SoftButtonLeft"), createSoftButton("SoftButtonRight")};
main = soft[0];
left = soft[1];
right = soft[2];
addComponent(left);
addComponent(main);
addComponent(right);
if (isReverseSoftButtons()) {
Button b = soft[1];
soft[1] = soft[2];
soft[2] = b;
}
} else {
soft = new Button[]{createSoftButton("SoftButtonCenter")};
}
}
softCommand = new Command[soft.length];
}
private int getCommandBehavior() {
int i = Display.getInstance().getCommandBehavior();
if(Display.getInstance().getImplementation().getSoftkeyCount() == 0) {
if(i != Display.COMMAND_BEHAVIOR_BUTTON_BAR && i != Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK &&
i != Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_RIGHT) {
return Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK;
}
return i;
}
if(i == Display.COMMAND_BEHAVIOR_DEFAULT) {
if(Display.getInstance().isTouchScreenDevice()) {
return Display.COMMAND_BEHAVIOR_TOUCH_MENU;
}
return Display.COMMAND_BEHAVIOR_SOFTKEY;
}
return i;
}
/**
* Default command is invoked when a user presses fire, this functionality works
* well in some situations but might collide with elements such as navigation
* and combo boxes. Use with caution.
*
* @param defaultCommand the command to treat as default
*/
public void setDefaultCommand(Command defaultCommand) {
this.defaultCommand = defaultCommand;
}
/**
* Default command is invoked when a user presses fire, this functionality works
* well in some situations but might collide with elements such as navigation
* and combo boxes. Use with caution.
*
* @return the command to treat as default
*/
public Command getDefaultCommand() {
if (selectCommand != null) {
return selectCommand;
}
return defaultCommand;
}
/**
* Indicates the command that is defined as the clear command in this form.
* A clear command can be used both to map to a "clear" hardware button
* if such a button exists.
*
* @param clearCommand the command to treat as the clear Command
*/
public void setClearCommand(Command clearCommand) {
this.clearCommand = clearCommand;
}
/**
* Indicates the command that is defined as the clear command in this form.
* A clear command can be used both to map to a "clear" hardware button
* if such a button exists.
*
* @return the command to treat as the clear Command
*/
public Command getClearCommand() {
return clearCommand;
}
private Button findCommandComponent(Command c) {
Button b = findCommandComponent(c, this);
if(b == null) {
return findCommandComponent(c, parent.getTitleArea());
}
return b;
}
private Button findCommandComponent(Command c, Container cnt) {
int count = cnt.getComponentCount();
for(int iter = 0 ; iter < count ; iter++) {
Component current = cnt.getComponentAt(iter);
if(current instanceof Button) {
Button b = (Button)current;
if(b.getCommand() == c) {
return b;
}
} else {
if(current instanceof Container) {
findCommandComponent(c, (Container)current);
}
}
}
return null;
}
private void moveCommandToTitle(Container title, Command c) {
Button b = findCommandComponent(c);
if(b != null) {
b.getParent().removeComponent(b);
} else {
b = new Button(c);
}
b.setUIID("TitleCommand");
title.addComponent(b);
}
private void adaptTitleLayoutBackCommandStructure() {
Container t = parent.getTitleArea();
if(t.getComponentCount() == 3) {
return;
}
BorderLayout titleLayout = (BorderLayout)t.getLayout();
titleLayout.setCenterBehavior(BorderLayout.CENTER_BEHAVIOR_CENTER_ABSOLUTE);
t.removeAll();
t.addComponent(BorderLayout.CENTER, parent.getTitleComponent());
Container leftContainer = new Container(new BoxLayout(BoxLayout.X_AXIS));
Container rightContainer = new Container(new BoxLayout(BoxLayout.X_AXIS));
t.addComponent(BorderLayout.EAST, rightContainer);
t.addComponent(BorderLayout.WEST, leftContainer);
}
private Container findLeftTitleContainer() {
return (Container)((BorderLayout)parent.getTitleArea().getLayout()).getWest();
}
private Container findRightTitleContainer() {
return (Container)((BorderLayout)parent.getTitleArea().getLayout()).getEast();
}
private void updateTitleCommandPlacement() {
int commandBehavior = getCommandBehavior();
Container t = parent.getTitleArea();
BorderLayout titleLayout = (BorderLayout)t.getLayout();
if(getParent() == null) {
installMenuBar();
} else {
if(getParent() == parent.getTitleArea() && commandBehavior != Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_RIGHT) {
getParent().removeComponent(this);
installMenuBar();
}
}
if(!(parent instanceof Dialog)) {
if(commandBehavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK && parent.getTitle() != null && parent.getTitle().length() > 0) {
synchronizeCommandsWithButtonsInBackbutton();
/*adaptTitleLayoutBackCommandStructure();
Container leftContainer = findLeftTitleContainer();
Container rightContainer = findRightTitleContainer();
if(parent.getTitle() != null && parent.getTitle().length() > 0) {
if(backCommand != null) {
Button b = new Button(backCommand);
b.setUIID("BackCommand");
leftContainer.addComponent(b);
removeCommand(backCommand);
}
if(Display.getInstance().isTablet()) {
if(getCommandCount() > 0) {
moveCommandToTitle(rightContainer, getCommand(0));
}
if(getCommandCount() > 1) {
moveCommandToTitle(leftContainer, getCommand(1));
}
if(getCommandCount() > 2) {
moveCommandToTitle(rightContainer, getCommand(2));
}
if(getCommandCount() > 3 && backCommand == null) {
moveCommandToTitle(leftContainer, getCommand(3));
}
} else {
if(getCommandCount() > 0) {
moveCommandToTitle(rightContainer, getCommand(0));
}
if(getCommandCount() > 1 && backCommand == null) {
moveCommandToTitle(leftContainer, getCommand(1));
}
}
}*/
return;
} else {
if(commandBehavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_RIGHT ||
commandBehavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK) {
if(getParent() != null) {
if(getParent() == parent.getTitleArea()) {
return;
}
getParent().removeComponent(this);
}
parent.getTitleArea().addComponent(BorderLayout.EAST, this);
return;
}
}
}
if(t.getComponentCount() > 1) {
titleLayout.setCenterBehavior(BorderLayout.CENTER_BEHAVIOR_SCALE);
Label l = parent.getTitleComponent();
t.removeAll();
t.addComponent(BorderLayout.CENTER, l);
}
}
/**
* Indicates the command that is defined as the back command out of this form.
* A back command can be used both to map to a hardware button (e.g. on the Sony Ericsson devices)
* and by elements such as transitions etc. to change the behavior based on
* direction (e.g. slide to the left to enter screen and slide to the right to exit with back).
*
* @param backCommand the command to treat as the back Command
*/
public void setBackCommand(Command backCommand) {
this.backCommand = backCommand;
if(getCommandBehavior() == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK) {
int i = commands.indexOf(backCommand);
if(i > -1) {
commands.removeElementAt(i);
}
}
updateTitleCommandPlacement();
}
/**
* Indicates the command that is defined as the back command out of this form.
* A back command can be used both to map to a hardware button (e.g. on the Sony Ericsson devices)
* and by elements such as transitions etc. to change the behavior based on
* direction (e.g. slide to the left to enter screen and slide to the right to exit with back).
*
* @return the command to treat as the back Command
*/
public Command getBackCommand() {
return backCommand;
}
/**
* The selectCommand is the command to invoke when a Component has foucs in
* Third Soft Button state.
*
* @return the select command
*/
public Command getSelectCommand() {
return selectCommand;
}
/**
* Sets the select command
*
* @param selectCommand
*/
public void setSelectCommand(Command selectCommand) {
this.selectCommand = selectCommand;
}
/**
* Updates the command mapping to the softbuttons
*/
private void updateCommands() {
int commandBehavior = getCommandBehavior();
if(commandBehavior == Display.COMMAND_BEHAVIOR_NATIVE) {
Display.getInstance().getImplementation().setNativeCommands(commands);
return;
}
if(commandBehavior >= Display.COMMAND_BEHAVIOR_BUTTON_BAR) {
return;
}
if (soft.length > 1) {
soft[0].setText("");
soft[1].setText("");
soft[0].setIcon(null);
soft[1].setIcon(null);
int commandSize = getCommandCount();
if (soft.length > 2) {
soft[2].setText("");
if (commandSize > 2) {
if (commandSize > 3) {
softCommand[2] = menuCommand;
} else {
softCommand[2] = getCommand(getCommandCount() - 3);
}
soft[2].setText(softCommand[2].getCommandName());
soft[2].setIcon(softCommand[2].getIcon());
} else {
softCommand[2] = null;
}
}
if (commandSize > 0) {
softCommand[0] = getCommand(getCommandCount() - 1);
soft[0].setText(softCommand[0].getCommandName());
soft[0].setIcon(softCommand[0].getIcon());
if (commandSize > 1) {
if (soft.length == 2 && commandSize > 2) {
softCommand[1] = menuCommand;
} else {
softCommand[1] = getCommand(getCommandCount() - 2);
}
soft[1].setText(softCommand[1].getCommandName());
soft[1].setIcon(softCommand[1].getIcon());
} else {
softCommand[1] = null;
}
} else {
softCommand[0] = null;
softCommand[1] = null;
}
// we need to add the menu bar to an already visible form
if (commandSize == 1) {
if (parent.isVisible()) {
parent.revalidate();
}
}
repaint();
}
}
/**
* Invoked when a softbutton is pressed
*/
public void actionPerformed(ActionEvent evt) {
if (evt.isConsumed()) {
return;
}
Object src = evt.getSource();
if (commandList == null) {
Button source = (Button) src;
for (int iter = 0; iter < soft.length; iter++) {
if (source == soft[iter]) {
if (softCommand[iter] == menuCommand) {
showMenu();
return;
}
if (softCommand[iter] != null) {
ActionEvent e = new ActionEvent(softCommand[iter]);
softCommand[iter].actionPerformed(e);
if (!e.isConsumed()) {
parent.actionCommandImpl(softCommand[iter]);
}
}
return;
}
}
} else {
// the list for the menu sent the event
if (src instanceof Button) {
for (int iter = 0; iter < soft.length; iter++) {
if (src == soft[iter]) {
Container parent = commandList.getParent();
while (parent != null) {
if (parent instanceof Dialog) {
((Dialog) parent).actionCommand(softCommand[iter]);
return;
}
parent = parent.getParent();
}
}
}
}
Command c = getComponentSelectedCommand(commandList);
if(!c.isEnabled()) {
return;
}
Container p = commandList.getParent();
while (p != null) {
if (p instanceof Dialog) {
((Dialog) p).actionCommand(c);
return;
}
p = p.getParent();
}
}
}
/**
* Creates a soft button Component
* @return the softbutton component
*/
protected Button createSoftButton(String uiid) {
Button b = new Button();
b.setUIID(uiid);
b.addActionListener(this);
b.setFocusable(false);
b.setTactileTouch(true);
updateSoftButtonStyle(b);
return b;
}
private void updateSoftButtonStyle(Button b) {
if (softkeyCount < 2) {
b.getStyle().setMargin(0, 0, 0, 0);
b.getStyle().setPadding(0, 0, 0, 0);
}
}
/**
* @inheritDoc
*/
public void setUnselectedStyle(Style style) {
style.setMargin(Component.TOP, 0, true);
style.setMargin(Component.BOTTOM, 0, true);
super.setUnselectedStyle(style);
if (soft != null) {
for (int iter = 0; iter < soft.length; iter++) {
updateSoftButtonStyle(soft[iter]);
}
}
}
/**
* Prevents scaling down of the menu when there is no text on the menu bar
*/
protected Dimension calcPreferredSize() {
if (soft.length > 1) {
Dimension d = super.calcPreferredSize();
if ((soft[0].getText() == null || soft[0].getText().equals("")) &&
(soft[1].getText() == null || soft[1].getText().equals("")) &&
soft[0].getIcon() == null && soft[1].getIcon() == null &&
(soft.length < 3 ||
((soft[2].getText() == null || soft[2].getText().equals("")) && soft[2].getIcon() == null))) {
d.setHeight(0);
}
return d;
}
return super.calcPreferredSize();
}
/**
* Sets the menu transitions for showing/hiding the menu, can be null...
*/
public void setTransitions(Transition transitionIn, Transition transitionOut) {
this.transitionIn = transitionIn;
this.transitionOut = transitionOut;
}
/**
* This method shows the menu on the Form.
* The method creates a Dialog with the commands and calls showMenuDialog.
* The method blocks until the user dispose the dialog.
*/
public void showMenu() {
final Dialog d = new Dialog("Menu", "");
d.setDisposeWhenPointerOutOfBounds(true);
d.setMenu(true);
d.setTransitionInAnimator(transitionIn);
d.setTransitionOutAnimator(transitionOut);
d.setLayout(new BorderLayout());
d.setScrollable(false);
//calling parent.createCommandComponent is done only for backward
//compatability reasons, in the next version this call be replaced with
//calling directly to createCommandComponent
((Form) d).getMenuBar().commandList = createCommandComponent(commands);
if (menuCellRenderer != null && ((Form) d).getMenuBar().commandList instanceof List) {
((List) ((Form) d).getMenuBar().commandList).setListCellRenderer(menuCellRenderer);
}
d.getContentPane().getStyle().setMargin(0, 0, 0, 0);
d.addComponent(BorderLayout.CENTER, ((Form) d).getMenuBar().commandList);
if (thirdSoftButton) {
d.addCommand(selectMenuItem);
d.addCommand(cancelMenuItem);
} else {
d.addCommand(cancelMenuItem);
if (soft.length > 1) {
d.addCommand(selectMenuItem);
}
}
d.setClearCommand(cancelMenuItem);
d.setBackCommand(cancelMenuItem);
if (((Form) d).getMenuBar().commandList instanceof List) {
((List) ((Form) d).getMenuBar().commandList).addActionListener(((Form) d).getMenuBar());
}
Command result = showMenuDialog(d);
if (result != cancelMenuItem) {
Command c = null;
if (result == selectMenuItem) {
c = getComponentSelectedCommand(((Form) d).getMenuBar().commandList);
if (c != null) {
ActionEvent e = new ActionEvent(c);
c.actionPerformed(e);
}
} else {
c = result;
// a touch menu will always send its commands on its own...
if (!UIManager.getInstance().getLookAndFeel().isTouchMenus()) {
c = result;
if (c != null) {
ActionEvent e = new ActionEvent(c);
c.actionPerformed(e);
}
}
}
// menu item was handled internally in a touch interface that is not a touch menu
if (c != null) {
parent.actionCommandImpl(c);
}
}
if (((Form) d).getMenuBar().commandList instanceof List) {
((List) ((Form) d).getMenuBar().commandList).removeActionListener(((Form) d).getMenuBar());
}
Form upcoming = Display.getInstance().getCurrentUpcoming();
if (upcoming == parent) {
d.disposeImpl();
} else {
parent.tint = (upcoming instanceof Dialog);
}
}
Button[] getSoftButtons() {
return soft;
}
private void addTwoTitleButtons(Container leftContainer, Container rightContainer) {
ensureCommandsInContainer(getCommand(0), null, rightContainer, "TitleCommand", null);
if(parent.getBackCommand() != null) {
ensureCommandsInContainer(parent.getBackCommand(), null, leftContainer, "BackCommand", null);
updateGridCommands(1);
} else {
ensureCommandsInContainer(getCommand(1), null, leftContainer, "TitleCommand", null);
updateGridCommands(2);
}
}
private void updateGridCommands(int startOffset) {
int cmdCount = getCommandCount() - startOffset;
if(cmdCount <= 0) {
return;
}
setLayout(new GridLayout(1, cmdCount));
while(cmdCount < getComponentCount()) {
removeComponent(getComponentAt(getComponentCount() - 1));
}
int off = startOffset;
while(getComponentCount() < cmdCount) {
Button btn = new Button(getCommand(off));
btn.setUIID("TouchCommand");
off++;
addComponent(btn);
}
for(int iter = 0 ; iter < cmdCount ; iter++) {
Button btn = (Button)getComponentAt(iter);
if(btn.getCommand() != getCommand(iter + startOffset)) {
btn.setCommand(getCommand(iter + startOffset));
}
}
}
private void synchronizeCommandsWithButtonsInBackbutton() {
adaptTitleLayoutBackCommandStructure();
Container leftContainer = findLeftTitleContainer();
Container rightContainer = findRightTitleContainer();
int componentCount = getCommandCount();
if(parent.getBackCommand() != null) {
if(leftContainer.getComponentCount() == 0) {
Button back = new Button(parent.getBackCommand());
leftContainer.addComponent(back);
back.setUIID("BackCommand");
} else {
Button b = (Button)leftContainer.getComponentAt(0);
if(b.getCommand() != parent.getBackCommand()) {
b.setCommand(parent.getBackCommand());
b.setUIID("BackCommand");
}
}
componentCount++;
}
switch(componentCount) {
case 0:
leftContainer.removeAll();
rightContainer.removeAll();
removeAll();
break;
case 1:
if(parent.getBackCommand() != null) {
rightContainer.removeAll();
ensureCommandsInContainer(parent.getBackCommand(), null, leftContainer, "BackCommand", null);
} else {
leftContainer.removeAll();
ensureCommandsInContainer(getCommand(0), null, rightContainer, "TitleCommand", null);
}
removeAll();
break;
case 2:
addTwoTitleButtons(leftContainer, rightContainer);
break;
case 3:
if(Display.getInstance().isTablet()) {
ensureCommandsInContainer(getCommand(0), getCommand(2), rightContainer, "TitleCommand", "TitleCommand");
if(parent.getBackCommand() != null) {
ensureCommandsInContainer(parent.getBackCommand(), null, leftContainer, "BackCommand", null);
} else {
ensureCommandsInContainer(getCommand(1), null, leftContainer, "TitleCommand", null);
}
removeAll();
} else {
addTwoTitleButtons(leftContainer, rightContainer);
}
break;
default:
if(Display.getInstance().isTablet()) {
ensureCommandsInContainer(getCommand(0), getCommand(2), rightContainer, "TitleCommand", "TitleCommand");
if(parent.getBackCommand() != null) {
ensureCommandsInContainer(parent.getBackCommand(), getCommand(1), leftContainer, "BackCommand", "TitleCommand");
updateGridCommands(3);
} else {
ensureCommandsInContainer(getCommand(1), getCommand(3), leftContainer, "TitleCommand", "TitleCommand");
updateGridCommands(4);
}
} else {
addTwoTitleButtons(leftContainer, rightContainer);
}
break;
}
}
private void ensureCommandsInContainer(Command a, Command b, Container c, String styleA, String styleB) {
if(c.getComponentCount() == 0) {
Button btn = new Button(a);
btn.setUIID(styleA);
c.addComponent(btn);
if(b != null) {
btn = new Button(b);
btn.setUIID(styleB);
c.addComponent(btn);
}
return;
}
if(c.getComponentCount() == 1) {
Button btn = (Button)c.getComponentAt(0);
btn.setUIID(styleA);
if(btn.getCommand() != a) {
btn.setCommand(a);
}
if(b != null) {
btn = new Button(b);
btn.setUIID(styleB);
c.addComponent(btn);
}
return;
}
if(c.getComponentCount() == 2) {
Button btn = (Button)c.getComponentAt(0);
btn.setUIID(styleA);
if(btn.getCommand() != a) {
btn.setCommand(a);
}
if(b != null) {
btn = (Button)c.getComponentAt(1);
btn.setUIID(styleB);
if(btn.getCommand() != b) {
btn.setCommand(b);
}
} else {
c.removeComponent(c.getComponentAt(1));
}
return;
}
}
/**
* Adds a Command to the MenuBar
*
* @param cmd Command to add
*/
public void addCommand(Command cmd) {
// prevent duplicate commands which might happen in some edge cases
// with the select command
if (commands.contains(cmd)) {
return;
}
// special case for default commands which are placed at the end and aren't overriden later
if (soft.length > 2 && cmd == parent.getDefaultCommand()) {
commands.addElement(cmd);
} else {
commands.insertElementAt(cmd, 0);
}
if(!(parent instanceof Dialog)) {
int behavior = getCommandBehavior();
if(behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR || behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK ||
behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_RIGHT) {
if(behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK && (cmd == parent.getBackCommand() ||
findCommandComponent(cmd) != null)) {
return;
}
if(parent.getBackCommand() != cmd) {
if(behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK && parent.getTitle() != null && parent.getTitle().length() > 0) {
synchronizeCommandsWithButtonsInBackbutton();
return;
}
setLayout(new GridLayout(1, getCommandCount()));
addComponent(createTouchCommandButton(cmd));
} else {
commands.removeElement(cmd);
}
return;
}
}
updateCommands();
}
/**
* Returns the command occupying the given index
*
* @param index offset of the command
* @return the command at the given index
*/
public Command getCommand(int index) {
return (Command) commands.elementAt(index);
}
/**
* Returns number of commands
*
* @return number of commands
*/
public int getCommandCount() {
return commands.size();
}
/**
* Add a Command to the MenuBar
*
* @param cmd Command to Add
* @param index determines the order of the added commands
*/
protected void addCommand(Command cmd, int index) {
if (getCommandCount() == 0 && parent != null) {
installMenuBar();
}
// prevent duplicate commands which might happen in some edge cases
// with the select command
if (commands.contains(cmd)) {
return;
}
commands.insertElementAt(cmd, index);
if(!(parent instanceof Dialog)) {
int behavior = getCommandBehavior();
if(behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR ||
behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK ||
behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_RIGHT) {
if(behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK && cmd == parent.getBackCommand()) {
return;
}
if(behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK && parent.getTitle() != null && parent.getTitle().length() > 0) {
synchronizeCommandsWithButtonsInBackbutton();
return;
}
if(parent.getBackCommand() != cmd) {
setLayout(new GridLayout(1, getCommandCount()));
addComponent(index, createTouchCommandButton(cmd));
revalidate();
} else {
commands.removeElement(cmd);
}
return;
}
}
updateCommands();
}
/**
* Adds the MenuBar on the parent Form
*/
protected void installMenuBar() {
if (getParent() == null) {
int type = Display.getInstance().getCommandBehavior();
if(type == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_RIGHT) {
parent.getTitleArea().addComponent(BorderLayout.EAST, this);
return;
}
if(softkeyCount > 1 || type == Display.COMMAND_BEHAVIOR_BUTTON_BAR ||
type == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK) {
parent.addComponentToForm(BorderLayout.SOUTH, this);
}
}
}
/**
* Removes the MenuBar from the parent Form
*/
protected void unInstallMenuBar() {
parent.removeComponentFromForm(this);
Container t = parent.getTitleArea();
BorderLayout titleLayout = (BorderLayout)t.getLayout();
titleLayout.setCenterBehavior(BorderLayout.CENTER_BEHAVIOR_SCALE);
Label l = parent.getTitleComponent();
t.removeAll();
if(l.getParent() != null) {
l.getParent().removeComponent(l);
}
t.addComponent(BorderLayout.CENTER, l);
}
/**
* Remove all commands from the menuBar
*/
protected void removeAllCommands() {
commands.removeAllElements();
int behavior = getCommandBehavior();
if(behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR ||
behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK ||
behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_RIGHT) {
parent.getTitleArea().removeAll();
parent.getTitleArea().addComponent(BorderLayout.CENTER, parent.getTitleComponent());
removeAll();
return;
}
updateCommands();
}
/**
* Removes a Command from the MenuBar
*
* @param cmd Command to remove
*/
protected void removeCommand(Command cmd) {
int behavior = getCommandBehavior();
if(behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR ||
behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK ||
behavior == Display.COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_RIGHT) {
int i = commands.indexOf(cmd);
if(i > -1) {
commands.removeElementAt(i);
Button b = findCommandComponent(cmd);
if(b != null) {
removeComponent(b);
}
if(getCommandCount() > 0) {
setLayout(new GridLayout(1, getCommandCount()));
}
}
return;
}
commands.removeElement(cmd);
updateCommands();
}
void addSelectCommand(String selectText) {
if (thirdSoftButton) {
if (selectCommand == null) {
selectCommand = createSelectCommand();
}
selectCommand.setCommandName(selectText);
addCommand(selectCommand);
}
}
void removeSelectCommand() {
if (thirdSoftButton) {
removeCommand(selectCommand);
}
}
/**
* Factory method that returns the Form select Command.
* This Command is used when Display.getInstance().isThirdSoftButton()
* returns true.
* This method can be overridden to customize the Command on the Form.
*
* @return Command
*/
protected Command createSelectCommand() {
return new Command(UIManager.getInstance().localize("select", "Select"));
}
/**
* Factory method that returns the Form Menu select Command.
* This method can be overridden to customize the Command on the Form.
*
* @return Command
*/
protected Command createMenuSelectCommand() {
LookAndFeel lf = UIManager.getInstance().getLookAndFeel();
return new Command(UIManager.getInstance().localize("select", "Select"), lf.getMenuIcons()[0]);
}
/**
* Factory method that returns the Form Menu cancel Command.
* This method can be overridden to customize the Command on the Form.
*
* @return Command
*/
protected Command createMenuCancelCommand() {
LookAndFeel lf = UIManager.getInstance().getLookAndFeel();
return new Command(UIManager.getInstance().localize("cancel", "Cancel"), lf.getMenuIcons()[1]);
}
/**
* The MenuBar default implementation shows the menu commands in a List
* contained in a Dialog.
* This method replaces the menu ListCellRenderer of the Menu List.
*
* @param menuCellRenderer
*/
public void setMenuCellRenderer(ListCellRenderer menuCellRenderer) {
this.menuCellRenderer = menuCellRenderer;
}
/**
* Returns the Menu Dialog Style
*
* @return Menu Dialog Style
*/
public Style getMenuStyle() {
return menuStyle;
}
static boolean isLSK(int keyCode) {
return keyCode == leftSK;
}
static boolean isRSK(int keyCode) {
return keyCode == rightSK || keyCode == rightSK2;
}
/**
* This method returns true if the MenuBar should handle the given keycode.
*
* @param keyCode to determine if the MenuBar is responsible for.
* @return true if the keycode is a MenuBar related keycode such as softkey,
* back button, clear button, ...
*/
public boolean handlesKeycode(int keyCode) {
int game = Display.getInstance().getGameAction(keyCode);
if (keyCode == leftSK || (keyCode == rightSK || keyCode == rightSK2) || keyCode == backSK ||
(keyCode == clearSK && clearCommand != null) ||
(keyCode == backspaceSK && clearCommand != null) ||
(thirdSoftButton && game == Display.GAME_FIRE)) {
return true;
}
return false;
}
/**
* @inheritDoc
*/
public void keyPressed(int keyCode) {
int commandBehavior = getCommandBehavior();
if(commandBehavior >= Display.COMMAND_BEHAVIOR_BUTTON_BAR) {
return;
}
if (getCommandCount() > 0) {
if (keyCode == leftSK) {
if (left != null) {
left.pressed();
}
} else {
// it might be a back command or the fire...
if ((keyCode == rightSK || keyCode == rightSK2)) {
if (right != null) {
right.pressed();
}
} else {
if (Display.getInstance().getGameAction(keyCode) == Display.GAME_FIRE) {
main.pressed();
}
}
}
}
}
/**
* @inheritDoc
*/
public void keyReleased(int keyCode) {
int commandBehavior = getCommandBehavior();
if(commandBehavior >= Display.COMMAND_BEHAVIOR_BUTTON_BAR && keyCode != backSK && keyCode != clearSK && keyCode != backspaceSK) {
return;
}
if (getCommandCount() > 0) {
if (softkeyCount < 2 && keyCode == leftSK) {
if (commandList != null) {
Container parent = commandList.getParent();
while (parent != null) {
if (parent instanceof Dialog && ((Dialog) parent).isMenu()) {
return;
}
parent = parent.getParent();
}
}
showMenu();
return;
} else {
if (keyCode == leftSK) {
if (left != null) {
left.released();
}
return;
} else {
// it might be a back command...
if ((keyCode == rightSK || keyCode == rightSK2)) {
if (right != null) {
right.released();
}
return;
} else {
if (Display.getInstance().getGameAction(keyCode) == Display.GAME_FIRE) {
main.released();
return;
}
}
}
}
}
// allows a back/clear command to occur regardless of whether the
// command was added to the form
Command c = null;
if (keyCode == backSK) {
// the back command should be invoked
c = parent.getBackCommand();
} else {
if (keyCode == clearSK || keyCode == backspaceSK) {
c = getClearCommand();
}
}
if (c != null) {
ActionEvent ev = new ActionEvent(c, keyCode);
c.actionPerformed(ev);
if (!ev.isConsumed()) {
parent.actionCommandImpl(c);
}
}
}
/**
* @inheritDoc
*/
public void refreshTheme() {
super.refreshTheme();
if (menuStyle.isModified()) {
menuStyle.merge(UIManager.getInstance().getComponentStyle("Menu"));
} else {
menuStyle = UIManager.getInstance().getComponentStyle("Menu");
}
if (menuCellRenderer != null) {
List tmp = new List();
tmp.setListCellRenderer(menuCellRenderer);
tmp.refreshTheme();
}
for (int iter = 0; iter < soft.length; iter++) {
updateSoftButtonStyle(soft[iter]);
}
revalidate();
}
/*private void fixCommandAlignment() {
if (left != null) {
if (parent.isRTL()) {
left.setAlignment(Label.RIGHT);
right.setAlignment(Label.LEFT);
} else {
left.setAlignment(Label.LEFT);
right.setAlignment(Label.RIGHT);
}
if(main != null && main != left && main != right) {
main.setAlignment(CENTER);
}
}
}*/
/**
* A menu is implemented as a dialog, this method allows you to override dialog
* display in order to customize the dialog menu in various ways
*
* @param menu a dialog containing menu options that can be customized
* @return the command selected by the user in the dialog (not menu) Select
* or Cancel
*/
protected Command showMenuDialog(Dialog menu) {
boolean pref = UIManager.getInstance().isThemeConstant("menuPrefSizeBool", false);
int height;
int marginLeft;
int marginRight = 0;
if(pref) {
Container dialogContentPane = menu.getDialogComponent();
marginLeft = parent.getWidth() - (dialogContentPane.getPreferredW() +
menu.getStyle().getPadding(LEFT) +
menu.getStyle().getPadding(RIGHT));
marginLeft = Math.max(0, marginLeft);
if(parent.getSoftButtonCount() > 1) {
height = parent.getHeight() - parent.getSoftButton(0).getParent().getPreferredH() - dialogContentPane.getPreferredH();
} else {
height = parent.getHeight() - dialogContentPane.getPreferredH();
}
height = Math.max(0, height);
} else {
float menuWidthPercent = 1 - Float.parseFloat(UIManager.getInstance().getThemeConstant("menuWidthPercent", "75")) / 100;
float menuHeightPercent = 1 - Float.parseFloat(UIManager.getInstance().getThemeConstant("menuHeightPercent", "50")) / 100;
height = (int) (parent.getHeight() * menuHeightPercent);
marginLeft = (int) (parent.getWidth() * menuWidthPercent);
}
if (isReverseSoftButtons()) {
marginRight = marginLeft;
marginLeft = 0;
}
if (UIManager.getInstance().getLookAndFeel().isTouchMenus() && UIManager.getInstance().isThemeConstant("PackTouchMenuBool", true)) {
return menu.showPacked(BorderLayout.SOUTH, true);
} else {
return menu.show(height, 0, marginLeft, marginRight, true);
}
}
/**
* Allows an individual form to reverse the layout direction of the softbuttons, this method is RTL
* sensitive and might reverse the result based on RTL state
*
* @return The value of UIManager.getInstance().getLookAndFeel().isReverseSoftButtons()
*/
protected boolean isReverseSoftButtons() {
LookAndFeel lf = UIManager.getInstance().getLookAndFeel();
if (isRTL()) {
return !lf.isReverseSoftButtons();
}
return lf.isReverseSoftButtons();
}
/**
* Calculates the amount of columns to give to the touch commands within the
* grid
*
* @param grid container that will be arranged in the grid containing the
* components
* @return an integer representing the touch command grid size
*/
protected int calculateTouchCommandGridColumns(Container grid) {
int count = grid.getComponentCount();
int maxWidth = 0;
for (int iter = 0; iter < count; iter++) {
Component c = grid.getComponentAt(iter);
Style s = c.getUnselectedStyle();
// bidi doesn't matter since this is just a summary of width
maxWidth = Math.max(maxWidth,
c.getPreferredW() +
s.getMargin(false, LEFT) + s.getMargin(false, RIGHT));
}
return Math.max(2, Display.getInstance().getDisplayWidth() / maxWidth);
}
/**
* Creates a touch command for use as a touch menu item
*
* @param c command to map into the returned button
* @return a button that would fire the touch command appropriately
*/
protected Button createTouchCommandButton(Command c) {
Button b = new Button(c);
if(b.getIcon() == null) {
// some themes look awful without any icon
b.setIcon((Image)UIManager.getInstance().getThemeImageConstant("defaultCommandImage"));
}
b.setTactileTouch(true);
b.setTextPosition(Label.BOTTOM);
b.setEndsWith3Points(false);
b.setUIID("TouchCommand");
return b;
}
/**
* Creates the component containing the commands within the given vector
* used for showing the menu dialog, this method calls the createCommandList
* method by default however it allows more elaborate menu creation.
*
* @param commands list of command objects
* @return Component that will result in the parent menu dialog recieving a command event
*/
protected Component createCommandComponent(Vector commands) {
// Create a touch based menu interface
if (UIManager.getInstance().getLookAndFeel().isTouchMenus()) {
Container menu = new Container();
menu.setScrollableY(true);
for (int iter = 0; iter < commands.size(); iter++) {
Command c = (Command)commands.elementAt(iter);
menu.addComponent(createTouchCommandButton(c));
}
if(!UIManager.getInstance().isThemeConstant("touchCommandFlowBool", false)) {
int cols = calculateTouchCommandGridColumns(menu);
if(cols > getCommandCount()) {
cols = getCommandCount();
}
int rows = Math.max(1, getCommandCount() / cols + (getCommandCount() % cols != 0 ? 1 : 0) );
if(rows > 1) {
// try to prevent too many columns concentraiting within a single row
int remainingColumns = (rows * cols) % getCommandCount();
int newCols = cols;
int newRows = rows;
while(remainingColumns != 0 && remainingColumns > 1 && newCols >= 2) {
newCols--;
newRows = Math.max(1, getCommandCount() / newCols + (getCommandCount() % newCols != 0 ? 1 : 0) );
if(newRows != rows) {
break;
}
remainingColumns = (newRows * newCols) % getCommandCount();
}
if(newRows == rows) {
cols = newCols;
rows = newRows;
}
}
GridLayout g = new GridLayout(rows, cols);
g.setFillLastRow(UIManager.getInstance().isThemeConstant("touchCommandFillBool", true));
menu.setLayout(g);
} else {
((FlowLayout)menu.getLayout()).setFillRows(true);
}
menu.setPreferredW(Display.getInstance().getDisplayWidth());
return menu;
}
return createCommandList(commands);
}
/**
* This method returns a Vector of Command objects
*
* @return Vector of Command objects
*/
protected Vector getCommands() {
return commands;
}
/**
* Creates the list component containing the commands within the given vector
* used for showing the menu dialog
*
* @param commands list of command objects
* @return List object
*/
protected List createCommandList(Vector commands) {
List l = new List(commands);
l.setUIID("CommandList");
Component c = (Component) l.getRenderer();
c.setUIID("Command");
c = l.getRenderer().getListFocusComponent(l);
c.setUIID("CommandFocus");
l.setFixedSelection(List.FIXED_NONE_CYCLIC);
if(UIManager.getInstance().isThemeConstant("menuPrefSizeBool", false)) {
// an entry way down in the list might be noticeably wider
l.setListSizeCalculationSampleCount(50);
}
return l;
}
Command getComponentSelectedCommand(Component cmp) {
if (cmp instanceof List) {
List l = (List) cmp;
return (Command) l.getSelectedItem();
} else {
cmp = cmp.getComponentForm().getFocused();
if (cmp instanceof Button) {
return ((Button) cmp).getCommand();
}
}
// nothing to do for this case...
return null;
}
/**
* This method returns the select menu item, when a menu is opened
* @return select Command
*/
protected Command getSelectMenuItem() {
return selectMenuItem;
}
/**
* This method returns the cancel menu item, when a menu is opened
* @return cancel Command
*/
protected Command getCancelMenuItem() {
return cancelMenuItem;
}
}