FileDocCategorySizeDatePackage
SoftButtonLayer.javaAPI DocphoneME MR2 API (J2ME)27319Wed May 02 18:00:20 BST 2007com.sun.midp.chameleon.layers

SoftButtonLayer

public class SoftButtonLayer extends CLayer implements CommandListener
Soft button layer.

Fields Summary
protected String[]
labels
Labels for each of the softbuttons.
protected Command[]
scrCmds
A cached copy of the set of screen commands sent from the Display.
protected CommandListener
scrListener
The CommandListener to notify for any screen commands executed.
protected Command[]
itmCmds
A cached copy of the set of item commands sent from the Display.
protected ItemCommandListener
itemListener
The ItemCommandListener to notify for any item commands executed.
protected Command
soft1
The command associated with soft button #1. null if there is no command associated with button #1.
protected Command[]
soft2
The set of commands associated with soft button #2. null if there are no commands associated with button #2. If there is only one element in this array, there is no need for a menu and soft button #2 will behave similar to soft button #1 and invoke the listener directly upon button press.
protected SubMenuCommand
subMenu
When a sub menu is currently active, this reference is non-null.
private CLayer
cachedScrollable
keep scrollable and scrollListener to recover them after menu dismiss
private ScrollListener
cachedListener
protected static final int[]
cmdWeights
A set of weights assigned to each of the types of Commands. The array is set up to return the weight of the Command type for each index, ie. Command.BACK has a defined value of 2 from the MIDP specification, cmdWieghts[Command.BACK] == 4, that is, there are three other Command types which sort higher than BACK (ITEM, SCREEN, and OK). The weighting is specified in the MIDP Human Interface Specification (Sun Internal).
protected MenuLayer
menuLayer
A System menu to popup and display when a set of commands needs to be displayed.
protected boolean
menuUP
A flag indicating the system menu is up.
protected boolean
alertUP
A flag indicating the alert is up.
protected ChamDisplayTunnel
tunnel
A tunnel to utilize to notify of command invocation.
protected Command
swap
An internal variable defined once to avoid costly heap thrashing.
protected int
typeX
Internal variables defined once to avoid costly heap thrashing.
protected int
typeY
protected int
buttonx
Internal variables for the paint loop.
protected int
buttony
protected int
buttonw
protected int
buttonh
private boolean
isInteractive
True if user is interacting with the layer
Constructors Summary
public SoftButtonLayer(ChamDisplayTunnel tunnel)
Construct a SoftButtonLayer. The layer's background image and color information is obtained directly from the SoftButtonSkin class, such as background image, tile, and/or background color.

param
tunnel channel for command notifications

 // = false;

                                           
       
        super(SoftButtonSkin.IMAGE_BG, SoftButtonSkin.COLOR_BG);
        super.setSupportsInput(true);
        super.setVisible(true);
        this.tunnel = tunnel;

        labels = new String[SoftButtonSkin.NUM_BUTTONS];
    
Methods Summary
public booleanbelongToCmdLayers(int x, int y)
Returns true if the point lies in the bounds of commnad layers subset like buttons, menu, submenu

param
x the "x" coordinate of the point
param
y the "y" coordinate of the point
return
true if the point lies in the bounds of commnad layers subset

        return containsPoint(x,y) ||
            (menuLayer != null && 
             (menuLayer.containsPoint(x,y) ||
              (menuLayer.cascadeMenu != null &&
               menuLayer.cascadeMenu.containsPoint(x,y))
              )
             );
    
public voidcommandAction(Command c, Displayable d)
Commandlistener interface implementation. Handle softbuton commands.

param
c command
param
d displayable

        dismissMenu();
    
public voidcommandSelected(Command cmd)
Selects a command.

param
cmd the command selected

        if (cmd == null) {
            return;
        }
        dismissMenu();
        processCommand(cmd);
    
protected intcompare(Command a, Command b)
Compares two commands.

param
a first command for comparison
param
b second command for comparison
return
0 if commands are the same; negative if the first object is lower; positive is first command is higher.

        if (a == null || b == null) {
            return 0;
        }

        typeX = a.getCommandType();
        typeY = b.getCommandType();
        if (typeX != typeY) {
            return cmdWeights[typeX] - cmdWeights[typeY];
        } else {
            return a.getPriority() - b.getPriority();
        }
    
public voiddismissMenu()
Dismiss menu layer.

        if (menuUP) {
            menuUP = false;
            menuLayer.dismiss();
            if (owner != null) {
                menuLayer.setScrollInd(null);
                owner.removeLayer(menuLayer);
            }
        }
        toggleMenu(menuUP);
    
public CommandgetSoftOne()
Returns the left soft button (one).

return
the command that's tied to the left soft button

        return soft1;
    
public Command[]getSoftTwo()
Returns the command array tied to the right soft button (two).

return
the command array that's tied to the right soft button

        return soft2;
    
protected voidinitMenu()
Initializes the menu from menu resources.

        MenuResources.load();
        menuLayer = new MenuLayer();
        Command menuClose = new Command(SoftButtonSkin.TEXT_BACKCMD,
                Command.BACK, 1);
        menuLayer.setCommands(new Command[]{menuClose});
        menuLayer.setCommandListener(this);
    
protected voidinitialize()
Initializes the soft button layer.

        super.initialize();
        setAnchor();
    
protected booleanisCommandActive(Command cmd)
Determines if it is possible to process the command.

param
cmd the command to check
return
true if command can be processed, false otherwise


        if (tunnel == null || cmd == null) {
            return false;
        }

        if ((isItemCommand(cmd) && (itemListener != null)) 
            || (scrListener != null)) {
            return true;
        }

        return false;
    
public booleanisInteractive()
Returnes true if user is interacting with the layer, false otherwise. used by MIDPWindow to check if the layer should become visible.

        return isInteractive;
    
protected booleanisItemCommand(Command cmd)
Checks if the item is a command.

param
cmd the item to be checked
return
true if the command is found in the list of item commands

        if (itmCmds.length == 0) {
            return false;
        }

        for (int i = 0; i < itmCmds.length; i++) {
            if (itmCmds[i] == cmd) {
                return true;
            }
        }
        return false;
    
protected booleanisSoft1Active()
Determines if soft button 1 will be processed by the layer. Called by keyInput to determine if the corresponding key event should be absorbed by SoftButtonLayer.

return
true if soft1 command can be processed, false otherwise

        // when MIDPWindow is not in full screen mode, we absorb
        // all key events reserved for the delivery of commands
        if (!((MIDPWindow)owner).isInFullScreenMode()) {
            return true;
        }

        // for full screen mode we should check if soft key is useful
        if (menuUP) {
            return true;
        } else {
            return isCommandActive(soft1);
        }

    
protected booleanisSoft2Active()
Determines if soft button 2 will be processed by the layer. Called by keyInput to determine if the corresponding key event should be absorbed by SoftButtonLayer.

return
true if soft2 command can be processed, false otherwise

        // when MIDPWindow is not in full screen mode, we absorb
        // all key events reserved for the delivery of commands
        if (!((MIDPWindow)owner).isInFullScreenMode()) {
            return true;
        }

        // for full screen mode we should check if soft key is useful
        if (menuUP) {
            return true;
        } else if (soft2 != null) {
            if (soft2.length == 1 &&
                soft2[0] instanceof SubMenuCommand) {
                return true;
            }
            // search for at least one active command
            for (int i = 0; i < soft2.length; i++) {
                if (isCommandActive(soft2[i])) {
                    return true;
                }
            }
        }
        return false;
    
public booleankeyInput(int type, int keyCode)
Handle key input from a keypad. Parameters describe the type of key event and the platform-specific code for the key. (Codes are translated using the lcdui.Canvas)

param
type the type of key event
param
keyCode the numeric code assigned to the key
return
true if this method processed the input, otherwise false.

        // SoftButtonLayer absorbs soft button 
        // event only if corresponding soft button is "active".
        // For further clarification please refer to
        // isSoft1Active() and isSoft2Active() methods.

        boolean ret = false;
        if (keyCode == EventConstants.SOFT_BUTTON1) {
            if (isSoft1Active()) {
                if (type == EventConstants.PRESSED) {
                    setInteractive(true);
                    ret = true;
                } else if (type == EventConstants.RELEASED) {
                    soft1();
                    ret = true;
                }
            }
        } else if (keyCode == EventConstants.SOFT_BUTTON2) {
            if (isSoft2Active()) {
                if (type == EventConstants.PRESSED) {
                    setInteractive(true);
                    ret = true;
                } else if (type == EventConstants.RELEASED) {
                    soft2();
                    ret = true;
                }
            }
        }
        return ret;
    
protected voidpaintBody(Graphics g)
Renders the soft button layer.

param
g the graphics context to be updated


        g.setFont(SoftButtonSkin.FONT);


        for (int i = 0; i < SoftButtonSkin.NUM_BUTTONS; i++) {
            if (labels[i] == null) {
                continue;
            }

            buttonw = SoftButtonSkin.FONT.stringWidth(labels[i]);
            if (buttonw > SoftButtonSkin.BUTTON_MAX_WIDTH[i]) {
                buttonw = SoftButtonSkin.BUTTON_MAX_WIDTH[i];
            }

            switch (SoftButtonSkin.BUTTON_ALIGN_X[i]) {
                case Graphics.HCENTER:
                    buttonx =
                            SoftButtonSkin.BUTTON_ANCHOR_X[i] - (buttonw / 2);
                    break;
                case Graphics.RIGHT:
                    buttonx = SoftButtonSkin.BUTTON_ANCHOR_X[i] - buttonw;
                    break;
                case Graphics.LEFT:
                default:
                    buttonx = SoftButtonSkin.BUTTON_ANCHOR_X[i];
                    break;
            }
            buttony = SoftButtonSkin.BUTTON_ANCHOR_Y[i];
            //buttonh = SoftButtonSkin.FONT.getHeight();
            g.translate(buttonx, buttony);

            Text.drawTruncStringShadowed(g, labels[i], SoftButtonSkin.FONT,
                    SoftButtonSkin.COLOR_FG, SoftButtonSkin.COLOR_FG_SHD,
                    SoftButtonSkin.BUTTON_SHD_ALIGN, buttonw);
        }
    
public booleanpointerInput(int type, int x, int y)
Handles pointer input events.

param
type the event type for this input event
param
x the x coordinate of the input event
param
y the y coordinate of the input event
return
true always

        if (type != EventConstants.PRESSED) {
            return true;
        }

        for (int i = 0; i < SoftButtonSkin.NUM_BUTTONS; i++) {
            switch (SoftButtonSkin.BUTTON_ALIGN_X[i]) {
                case Graphics.LEFT:
                    if (x < SoftButtonSkin.BUTTON_ANCHOR_X[i] ||
                            (x > SoftButtonSkin.BUTTON_ANCHOR_X[i] +
                                    SoftButtonSkin.BUTTON_MAX_WIDTH[i])) {
                        continue;
                    }
                    break;
                case Graphics.RIGHT:
                    if (x > SoftButtonSkin.BUTTON_ANCHOR_X[i] ||
                            (x < SoftButtonSkin.BUTTON_ANCHOR_X[i] -
                                    SoftButtonSkin.BUTTON_MAX_WIDTH[i])) {
                        continue;
                    }
                    break;
                default:
                    continue;
            }
            if (y >= SoftButtonSkin.BUTTON_ANCHOR_Y[i]
                    && y <= bounds[H]) {
                softPress(i);
            }
        }

        // SoftButtonLayer always swallows any pointer input, as there is no
        // need to forward the press on to any other layer.
        return true;
    
protected voidprocessCommand(Command cmd)
Processes commands.

param
cmd the selected command


        setInteractive(false);

        if (tunnel == null || cmd == null) {
            return;
        }

        if (subMenu != null) {
            subMenu.notifyListener(cmd);
            subMenu = null;
        } else if (isItemCommand(cmd)) {
            tunnel.callItemListener(cmd, itemListener);
        } else {
            tunnel.callScreenListener(cmd, scrListener);
        }
    
public voidsetAnchor()
Sets the anchor constraints for rendering operation.

        bounds[X] = 0;
        bounds[Y] = ScreenSkin.HEIGHT - SoftButtonSkin.HEIGHT;
        bounds[W] = ScreenSkin.WIDTH;
        bounds[H] = SoftButtonSkin.HEIGHT;
    
private voidsetBackground()
Sets the background based on current menu and alert settings.

        if (menuUP) {
            setBackground(SoftButtonSkin.IMAGE_MU_BG,
                    SoftButtonSkin.COLOR_MU_BG);
        } else if (alertUP) {
            setBackground(SoftButtonSkin.IMAGE_AU_BG,
                    SoftButtonSkin.COLOR_AU_BG);
        } else {
            setBackground(SoftButtonSkin.IMAGE_BG,
                    SoftButtonSkin.COLOR_BG);
        }
    
protected voidsetButtonLabels()
Sets the button labels.

        // reset all the labels
        for (int i = 0; i < SoftButtonSkin.NUM_BUTTONS; i++) {
            labels[i] = null;
        }

        // Port me : If a port had more than 2 soft buttons, adjust
        // the behavior here for extra buttons
        labels[0] = (soft1 == null) ? null : soft1.getLabel();
        if (soft2 == null) {
            labels[1] = null;
        } else if (soft2.length == 1) {
            labels[1] = soft2[0].getLabel();
        } else {
            labels[1] = SoftButtonSkin.TEXT_MENUCMD;
        }
        addDirtyRegion();
        requestRepaint();
    
private booleansetCommands(int cmdNum, int start, Command[] cmds)
Assigns the commands to soft1 and soft2 buttons .

param
cmdNum Number of commands
param
start Start index for soft2 commands array
param
cmds Source commands array
return
if any commnad has been assign to soft1 returns true, false otherwise

        int setSoft1 = 0;
        if (cmdNum > 0) {
            sortCommands(cmds, cmdNum);
            for (int i = 0; i < cmdNum; i++) {
                if (soft1 == null && !(cmds[i] instanceof SubMenuCommand)) {
                    soft1 = cmds[i];
                    setSoft1++;
                } else {
                    soft2[start + i - setSoft1] = cmds[i];
                }
            }
            if (setSoft1 > 0) {
                // decrement the soft2 array length
                Command[] soft2temp = new Command[soft2.length - 1];
                System.arraycopy(soft2, 0, soft2temp, 0, soft2temp.length);
                soft2 = soft2temp;
            }
        }
        return setSoft1 > 0;
    
private voidsetInteractive(boolean interactive)
Assigns new value to isInteractive and signals MIDPWindow.

        if (isInteractive != interactive) {
            isInteractive = interactive;
            if (owner instanceof MIDPWindow) {
                ((MIDPWindow)owner).updateLayout();
            }
        }
    
protected voidsoft1()
Soft button 1 handler.

        if (menuUP) {
            dismissMenu();
            subMenu = null;
            requestRepaint();
            setButtonLabels();
            setInteractive(false);
        } else {
            processCommand(soft1);
        }
    
protected voidsoft2()
Soft button 2 handler.

        if (soft2 != null) {
            if (soft2.length == 1 &&
                soft2[0] instanceof SubMenuCommand) {
                subMenu = (SubMenuCommand) soft2[0];
            }
            
            if (soft2.length > 1 ||
                subMenu != null) {
                if (menuLayer == null) {
                    initMenu();
                }
                menuLayer.setMenuCommands(soft2, this, 0);
                
                menuUP = true;
                toggleMenu(menuUP);
                
                // Show the menu
                if (owner != null) {
                    owner.addLayer(menuLayer);
                    menuLayer.setScrollInd(ScrollIndLayer.getInstance(ScrollIndSkin.MODE));
                }
                
                requestRepaint();

            } else if (soft2.length == 1) {
                // command action
                processCommand(soft2[0]);
            }
        } else {
            setInteractive(false);
        }
    
protected voidsoftPress(int buttonID)
Switch based on soft button pressed.

param
buttonID the button pushed

        switch (buttonID) {
            case 0:
                soft1();
                break;
            case 1:
                soft2();
                break;
        }
    
protected voidsortCommands(Command[] cmds, int num)
Rearranges the commands based on weights and priority.

param
cmds the commands to be sorted
param
num the number of commands to check

        // The number of commands is small, so we use a simple
        // Insertion sort that requires little heap        
        for (int i = 1; i < num; i++) {
            for (int j = i; j > 0; j--) {
                if (compare(cmds[j], cmds[j - 1]) < 0) {
                    swap = cmds[j];
                    cmds[j] = cmds[j - 1];
                    cmds[j - 1] = swap;
                } else break;
            }
        }
    
public booleansystemMenuUp()
Returns true if system menu is currently up, false otherwise.

return
true if system menu is up, false otherwise

        return menuUP;
    
public voidtoggleAlert(boolean alertUp)
Toggles the alert. Grabs the background and requests a repaint.

param
alertUp flag indicating the alaert has expired

        alertUP = alertUp;
        setBackground();
        requestRepaint();
    
public voidtoggleMenu(boolean menuUp)
Toggles the current menu selection. Grabs the background and requests a repaint.

param
menuUp the flag indicating the menu selection

        if (owner instanceof MIDPWindow) {
            ((MIDPWindow) owner).paintWash(menuUp);
        }
        setBackground();
        requestRepaint();
    
public voidupdate(CLayer[] layers)
Update bounds of layer

param
layers - current layer can be dependant on this parameter

        super.update(layers);
        setAnchor();
        if (null != menuLayer) {
            menuLayer.update(layers);
        }
    
public voidupdateCommandSet(Command[] itemCmds, int numI, ItemCommandListener itemListener, Command[] screenCmds, int numS, CommandListener scrListener)
Called by the system to update the set of commands associated with this button bar and its subsequent system menu.

param
itemCmds an array of item specific commands
param
numI the number of item specific commands
param
itemListener the ItemCommandListener to notify if any item commands are selected
param
screenCmds an array of screen specific commands
param
numS the number of screen specific commands
param
scrListener the CommandListener to notify if any screen commands are selected

        // Cache the values for later
        this.itmCmds = new Command[numI];
        if (numI > 0) {
            System.arraycopy(itemCmds, 0, this.itmCmds, 0, numI);
        }
        this.itemListener = itemListener;

        this.scrCmds = new Command[numS];
        if (numS > 0) {
            System.arraycopy(screenCmds, 0, this.scrCmds, 0, numS);
        }
        this.scrListener = scrListener;

        // reset the commands
        soft1 = null;

        if (numS > 0) {
            int index = -1;
            int type = -1;

            for (int i = 0; i < numS; i++) {
                if (!(this.scrCmds[i] instanceof SubMenuCommand)) {
                    switch (this.scrCmds[i].getCommandType()) {
                        case Command.BACK:
                            index = i;
                            type = Command.BACK;
                            break;
                        case Command.EXIT:
                            if (type != Command.BACK) {
                                index = i;
                                type = Command.EXIT;
                            }
                            break;
                        case Command.CANCEL:
                            if (type != Command.BACK && type != Command.EXIT) {
                                index = i;
                                type = Command.CANCEL;
                            }
                            break;
                        case Command.STOP:
                            if (type != Command.BACK && type != Command.EXIT &&
                                    type != Command.CANCEL) {
                                index = i;
                                type = Command.STOP;
                            }
                            break;
                        default:
                            break;
                    }
                } // if

                // We can short circuit the search if we find
                // a BACK command, because that is the highest weighted
                // Command for the left soft button
                if (type == Command.BACK) {
                    break;
                }
            } // for

            // If we have a command for the left button, we pop it out
            // of the array and decrement the number in the array - because
            // we'll sort them all together to form the right button (or menu)
            if (type > -1) {
                numS--;
                soft1 = this.scrCmds[index];
                System.arraycopy(screenCmds, index + 1,
                        scrCmds, index, numS - index);
            }
        }

        // Now fill in the 'right' soft button, possibly with a menu
        // of Commands
        switch (numI + numS) {
            case 0:
                soft2 = null;
                break;
            case 1:
                soft2 = new Command[1];
                soft2[0] = (numI > 0) ? this.itmCmds[0] : this.scrCmds[0];
                break;
            default:
                soft2 = new Command[numI + numS];

                if (setCommands(numI, 0, this.itmCmds)) {
                    numI--;
                }

                setCommands(numS, numI, this.scrCmds);

                break;
        }
        setButtonLabels();