/* * Copyright 2005-2007 * Wolfgang S. Kechel, data2c GmbH (www.data2c.com) * * Author: Wolfgang S. Kechel - wolfgang.kechel@data2c.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.hecl.midp20.lcdui; import java.util.Enumeration; import java.util.Vector; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.List; import javax.microedition.lcdui.game.GameCanvas; import org.awt.Color; import org.awt.Rectangle; import org.graphics.Drawable; import org.hecl.midp20.MidletCmd; public class HeclCanvas extends GameCanvas implements CommandListener { // We treat the left/right softkey on our own and provide two additional // gamekeys to simplify the programming. public static final int GAME_LEFT_SK = -1; public static final int GAME_RIGHT_SK = -2; // Fallback keycodes, valid for: // Nokia, Samsung (SGH-D500) and SonyEricsson (K608i, K700i and V800) // and probably many more public static int KEYCODE_LEFT_SK = -6; public static int KEYCODE_RIGHT_SK = -7; public HeclCanvas(boolean suppressKeyEvents) { super(suppressKeyEvents); this.nokeyevents = !suppressKeyEvents; //de.enough.polish.ui.game.GameCanvas has no getGraphics method //#ifdef polish.blackberry this.mygraphics = super.getPolishGraphics(); //#else this.mygraphics = super.getGraphics(); //#endif calcScreenWidth(); this.drawable = new Drawable(this.mygraphics,this.drawwidth,this.drawheight); // Force initial draw showCommands(mygraphics); flushGraphics(); } public void addCommand(Command cmd) { for (int i=0; i<this.cmds.size(); i++) { if (cmd == (Command)this.cmds.elementAt(i)) { // Its the same just return return; } } if(!isfullscreen || SettingsCmd.cvkeepcmdsinfullscreen) super.addCommand(cmd); // Now insert it in order (according to priority) boolean inserted = false; for (int i=0; i<this.cmds.size(); i++) { if (cmd.getPriority() < ((Command)this.cmds.elementAt(i)).getPriority()) { this.cmds.insertElementAt(cmd,i); inserted = true; break; } } if (inserted == false) { // Not inserted just place it at the end this.cmds.addElement(cmd); } updateCommands(); } public void commandAction(Command c,Displayable d) { // command handler for the menu if(c == CMD_BACK) { MidletCmd.getDisplay().setCurrent(this); return; } if(c == List.SELECT_COMMAND) { int n = menulist.getSelectedIndex(); if(n == -1) return; ++n; if(n >= 1 && n < cmds.size()) { Command mycmd = (Command)cmds.elementAt(n); MidletCmd.getDisplay().setCurrent(this); handleCommand(mycmd); } } } public void handleCommand(Command c) { if(savecmdlistener != null) savecmdlistener.commandAction(c,this); } public void flushGraphics() { //#ifdef DEBUG Rectangle r = new Rectangle(mygraphics.getClipX(), mygraphics.getClipY(), mygraphics.getClipWidth(), mygraphics.getClipHeight()); System.err.println("HeclCanvas.flushgraphics()"); System.err.println("clip is: "+r.x +", "+r.y +", "+r.width +", "+r.height); mygraphics.setClip(0,0,240,309); //#endif super.flushGraphics(); //#ifdef DEBUG mygraphics.setClip(r.x,r.y,r.width,r.height); //#endif } public Color getCmdBgColor() {return cmdbgcolor;} public Color getCmdFgColor() {return cmdfgcolor;} public Vector getCommands() {return cmds;} public int getFullWidth() {return fullwidth;} public int getFullHeight() {return fullheight;} public int getDrawWidth() {return drawwidth;} public int getDrawHeight() {return drawheight;} public int getGameAction(int keyCode) { if(keyCode == KEYCODE_LEFT_SK) return GAME_LEFT_SK; if(keyCode == KEYCODE_RIGHT_SK) return GAME_RIGHT_SK; return super.getGameAction(keyCode); } public boolean getFullScreenMode() {return isfullscreen;} public Graphics getGraphics() {return mygraphics;} public int getKeyCode(int gameAction) { if(gameAction == GAME_LEFT_SK) return KEYCODE_LEFT_SK; if(gameAction == GAME_RIGHT_SK) return KEYCODE_RIGHT_SK; return super.getKeyCode(gameAction); } public String getKeyName(int keyCode) { if(keyCode == KEYCODE_LEFT_SK) return "LEFT_SK"; if(keyCode == KEYCODE_RIGHT_SK) return "RIGHT_SK"; return super.getKeyName(keyCode); } public void hideNotify() { callEventHandler(CanvasEvent.E_HIDE,0,0,drawwidth,drawheight,0); } public void setCmdBgColor(Color c) { cmdbgcolor = c; showCommands(mygraphics); } public void setCmdFgColor(Color c) { cmdfgcolor = c; showCommands(mygraphics); } public void setCommandListener(CommandListener l) { // we need to take care of the listener here since we override the // default behavior in fullscreen mode! cmdlistener = l; if(!isfullscreen) { // Just do it for non-fullscreen super.setCommandListener(cmdlistener); } else { // do not set, this will be done when fullscreen mode is turned off savecmdlistener = cmdlistener; } } public void setEventHandler(EventHandler eventHandler) { evh = eventHandler; } public void setFullScreenMode(boolean b) { // Commented out due to problem with WTK2.5.2 that forces us to // resitore fullscreen mode of canvas after performing setcurrent to a // non-canvas displayable. // //if(b == isfullscreen) // return; // ignore request for fullscreen canvas when disabled if(b && !SettingsCmd.cvallowfullscreen) return; isfullscreen = b; super.setFullScreenMode(isfullscreen); if(SettingsCmd.cvkeepcmdsinfullscreen) return; int n = cmds.size(); if(isfullscreen) { // disable commands savecmdlistener = cmdlistener; super.setCommandListener(null); for(int i=0; i<n; ++i) { super.removeCommand((Command)cmds.elementAt(i)); } showCommands(mygraphics); } else { // enable commands for(int i=0; i<n; ++i) { super.addCommand((Command)cmds.elementAt(i)); } cmdlistener = savecmdlistener; super.setCommandListener(cmdlistener); } } protected void showCommands(Graphics g) { //#ifdef DEBUG System.err.println("showCommands, fullscreen="+isfullscreen+", isshown="+isShown()); //#endif // Unfortunately, isShown does not work on some emulators, therefor we // simply draw the commands in any case here. if(SettingsCmd.cvdocmds && isfullscreen && cmds.size() > 0 && isShown()) { int oldcol = g.getColor(); Font oldfont = g.getFont(); int oldcx = g.getClipX(); int oldcy = g.getClipY(); int oldcw = g.getClipWidth(); int oldch = g.getClipHeight(); // Nokia 6630 fullscreen bug calcScreenWidth(); //#ifdef DEBUG System.err.println("drawing rect: y="+drawheight+", h="+CMDBARHEIGHT); System.err.println("size - w="+getWidth()+" h="+getHeight()); System.err.println("draw - w"+getDrawWidth()+" h="+getDrawHeight()); System.err.println("oldclip("+oldcx+","+oldcy+","+oldcw+","+oldch+")"); System.err.println("setclip(0,"+drawheight+","+drawwidth+","+CMDBARHEIGHT+")"); g.setColor(0xff0000); g.drawLine(0,0,getWidth(),getHeight()); //#endif // set clipping region to area where commands are shown g.setClip(0,drawheight,drawwidth,CMDBARHEIGHT); // clear rect in bg color g.setColor(cmdbgcolor.getRGB()); g.fillRect(0,drawheight,drawwidth,CMDBARHEIGHT); //g.drawLine(0,drawheight,drawwidth-1,drawheight+3); // Draw the labels g.setColor(cmdfgcolor.getRGB()); g.setFont(CMDFONT); int ypos = drawheight+1; Command c = buttons[0].getCommand(); if(c != null) { String l = c.getLabel(); g.drawString(l != null ? l : "Left", 1,ypos,Graphics.TOP|Graphics.LEFT); } c = buttons[1].getCommand(); if(c != null) { String l = c.getLabel(); g.drawString(l != null ? l : "Right", drawwidth-1,ypos,Graphics.TOP|Graphics.RIGHT); } c = buttons[2].getCommand(); if(c != null) { String l = c.getLabel(); g.drawString(l != null ? l : "Center", drawwidth/2,ypos,Graphics.TOP|Graphics.HCENTER); } g.setColor(oldcol); g.setFont(oldfont); //#ifdef DEBUG System.err.println("flushing: 0, "+drawheight +", "+drawwidth+", "+CMDBARHEIGHT); //#endif flushGraphics(0,drawheight,drawwidth,CMDBARHEIGHT); g.setClip(oldcx,oldcy,oldcw,oldch); } else { //System.err.println("no commands"); } } public void paint(Graphics g) { //#ifdef notdef System.err.println("HeclCanvas.paint called"); if(this.drawable != null) System.err.println("NEEDSFLUSH="+this.drawable.needsFlush()); //#endif callEventHandler(CanvasEvent.E_PAINT,0,0,drawwidth,drawheight,0); if(this.drawable != null && this.drawable.needsFlush()) { showCommands(mygraphics); flushGraphics(); } super.paint(g); } public void pointerPressed(int x,int y) { callEventHandler(CanvasEvent.E_PPRESS,x,y,drawwidth,drawheight,0); } public void pointerReleased(int x,int y) { callEventHandler(CanvasEvent.E_PRELEASE,x,y,drawwidth,drawheight,0); } public void pointerDragged(int x,int y) { callEventHandler(CanvasEvent.E_PDRAG,x,y,drawwidth,drawheight,0); } protected boolean isCommandKey(int keycode) { if(isfullscreen && cmds.size() > 0) { switch(getGameAction(keycode)) { case GAME_LEFT_SK: case GAME_RIGHT_SK: return true; case FIRE: return cmds.size() == 3; default: break; } } return false; } public void keyPressed(int keycode) { if(isfullscreen && cmds.size() > 0) { Command c = findCommand(keycode); if(c != null) { if(c == CMD_MENU) { menulist.setCommandListener(this); menulist.addCommand(CMD_BACK); MidletCmd.getDisplay().setCurrent(menulist); return; } handleCommand(c); return; } } callEventHandler(CanvasEvent.E_KPRESS,0,0,drawwidth,drawheight,keycode); } public void keyReleased(int keycode) { if(isfullscreen && cmds.size() > 0) { // ignore when command is selected if(findCommand(keycode) != null) return; } callEventHandler(CanvasEvent.E_KRELEASE,0,0,drawwidth,drawheight,keycode); } public void keyRepeated(int keycode) { if(isfullscreen && cmds.size() > 0) { // ignore when command is selected if(findCommand(keycode) != null) return; } callEventHandler(CanvasEvent.E_KREPEAT,0,0,drawwidth,drawheight,keycode); } public void removeCommand(Command cmd) { super.removeCommand(cmd); cmds.removeElement(cmd); cmds.trimToSize(); // update display updateCommands(); } public void showNotify() { callEventHandler(CanvasEvent.E_SHOW,0,0,drawwidth,drawheight,0); } //#ifdef polish.blackberry //#ifdef polish.usePolishGui //de.enough.polish.ui.AccessibleCanvas sizeChanged is public public //#else protected //#endif //#else protected //#endif void sizeChanged(int w,int h) { //#ifdef DEBUG System.err.println("size changed, w="+w+", h="+h); System.err.println("size changed, w="+super.getWidth()+", h="+super.getHeight()); //#endif // go calculate. remind: some nokia devices have a bug that cause // wrong values to be passed as arguments to this function. calcScreenWidth(); if(this.drawable != null) { this.drawable.resize(drawwidth,drawheight); } try { callEventHandler(CanvasEvent.E_RESIZE,0,0,drawwidth,drawheight,0); } catch(Exception e) { e.printStackTrace(); } showCommands(mygraphics); } protected void callEventHandler(int reason,int x,int y, int width,int height,int keycode) { if(evh != null) { try { //System.err.println("*** calling evh, reason="+reason); CanvasEvent ce = new CanvasEvent(this,reason,x,y,width,height,keycode); //System.err.println(ce.toString()); evh.handleEvent(ce); //System.err.println("*** evh done"); } catch(Exception e) { //System.err.println("**** CANVASEVENT PROBLEM"); e.printStackTrace(); } } } public Drawable getDrawable() {return this.drawable;} protected boolean isSoftKey(int keycode) { return (keycode == KEYCODE_LEFT_SK || keycode == KEYCODE_RIGHT_SK); } private Command findCommand(int keyCode) { for(int i=0; i < buttons.length; ++i) { Command c = buttons[i].getCommand(); if(c == null) continue; try { if(buttons[i].gamecode == getGameAction(keyCode)) { return c; } } catch(IllegalArgumentException illgl) { } } return null; } private void updateCommands() { if(!SettingsCmd.cvdocmds) return; for(int i=0; i<buttons.length; ++i) buttons[i].setCommand(null); Vector commandsTable = new Vector(); for (int i = 0; i < cmds.size(); i++) { commandsTable.addElement(null); } // Sort commands using priority Enumeration en = cmds.elements(); while (en.hasMoreElements()) { Command commandToSort = (Command)en.nextElement(); for (int i = 0; i < commandsTable.size(); i++) { if (commandsTable.elementAt(i) == null) { commandsTable.setElementAt(commandToSort, i); break; } if (commandToSort.getPriority() < ((Command)commandsTable.elementAt(i)).getPriority()) { for (int j = commandsTable.size() - 1; j > i; j--) { if (commandsTable.elementAt(j - 1) != null) { commandsTable.setElementAt(commandsTable.elementAt(j - 1), j); } } } } } if(commandsTable.size() > buttons.length) { // Menu is needed commandsTable.insertElementAt(CMD_MENU, 0); } assignCommands(commandsTable); showCommands(mygraphics); } private void assignCommands(Vector commandsTable) { if(commandsTable.size() <= buttons.length) { // we have one button for each command for (int i = 0; i < commandsTable.size(); i++) { for(int j=0; j<buttons.length; ++j) { Command c = (Command)commandsTable.elementAt(i); if (buttons[j].getCommand() == null && buttons[j].isPreferred(c)) { buttons[j].setCommand(c); commandsTable.removeElementAt(i); i--; break; } } } for (int i = 0; i < commandsTable.size(); i++) { for(int j=0; j<buttons.length; ++j) { if (buttons[j].getCommand() == null) { buttons[j].setCommand((Command)commandsTable.elementAt(i)); commandsTable.removeElementAt(i); i--; break; } } } } else { // more cmds than buttons if(buttons.length > 0) { buttons[0].setCommand((Command)commandsTable.firstElement()); commandsTable.removeElementAt(0); } if(buttons.length > 1) { for(int i=0; i<commandsTable.size(); ++i) { Command c = (Command)commandsTable.elementAt(i); if(null == buttons[1].getCommand() && buttons[1].isPreferred(c)) { buttons[1].setCommand(c); commandsTable.removeElementAt(i); } } } for(int i=2; i<buttons.length; ++i) buttons[i].setCommand(null); menulist.deleteAll(); menucommands = new Vector(); for (int i = 0; i < commandsTable.size(); i++) { Command c = (Command)commandsTable.elementAt(i); menucommands.addElement(c); menulist.append(WidgetInfo.commandLabel(c,false), null); } } } private void calcScreenWidth() { this.fullwidth = super.getWidth(); this.fullheight = super.getHeight(); this.drawwidth = fullwidth; this.drawheight = getFullScreenMode() && !SettingsCmd.cvkeepcmdsinfullscreen ? this.fullheight-CMDBARHEIGHT : this.fullheight; } public boolean getAutoFlushMode() { return this.autoflush; } public void setAutoFlushMode(boolean b) { this.autoflush = b; } protected boolean nokeyevents; protected EventHandler evh = null; protected Vector cmds = new Vector(); protected CommandListener cmdlistener = null; protected CommandListener savecmdlistener = null; private Graphics mygraphics = null; private boolean isfullscreen = false; private Drawable drawable; private SoftButton buttons[] = SoftButton.makeSoftButtons(); private Vector menucommands = null; private List menulist = new List("Menu", List.IMPLICIT); private int fullwidth = 1; private int fullheight = 1; private int drawwidth = 1; private int drawheight = 1; private Color cmdbgcolor = SettingsCmd.cvcmdbgcolor; private Color cmdfgcolor = SettingsCmd.cvcmdfgcolor; private boolean autoflush = true; static class SoftButton { private static SoftButton[] makeSoftButtons() { SoftButton[] v = new SoftButton[3]; v[0] = new SoftButton(KEYCODE_LEFT_SK,GAME_LEFT_SK, new int[]{Command.OK,Command.ITEM,Command.SCREEN}); v[1] = new SoftButton(KEYCODE_RIGHT_SK,GAME_RIGHT_SK, new int[]{Command.CANCEL,Command.EXIT, Command.BACK,Command.STOP}); v[2] = new SoftButton(0,Canvas.FIRE,new int[]{Command.SCREEN}); return v; } public SoftButton(int keyCode,int gameCode,int [] ptypes) { keycode = keyCode; gamecode = gameCode; preferredtype = ptypes; } public Command getCommand() { return cmd; } public void setCommand(Command c) { cmd = c; } public boolean isPreferred(Command c) { int cmdtype = c.getCommandType(); if(preferredtype != null) { for(int i=0; i<preferredtype.length; ++i) { if(cmdtype == preferredtype[i]) return true; } } return false; } public int keycode = 0; public int gamecode = 0; protected Command cmd = null; public int[] preferredtype = null; } private static final Command CMD_MENU = new Command("Optionen", Command.SCREEN, 0); private static final Command CMD_BACK = new Command("Zurück", Command.BACK, 0); private static final Command CMD_SELECT = new Command("Auswahl", Command.OK, 0); private static Font CMDFONT = Font.getFont(Font.FONT_STATIC_TEXT); //private static int CMDFONTHEIGHT = CMDFONT.getHeight(); private static int CMDBARHEIGHT = CMDFONT.getHeight()+2; static { //Globals.set("isblackberry", new Boolean(false)); try { // Siemens (S65) Class.forName("com.siemens.mp.lcdui.Image"); KEYCODE_LEFT_SK = -1; KEYCODE_RIGHT_SK = -4; } catch (ClassNotFoundException e1) { } try { // Blackberry Class.forName("net.rim.device.api.system.Application"); KEYCODE_LEFT_SK = 0x80000; KEYCODE_RIGHT_SK = 0x1b0000; //Globals.set("isblackberry", new Boolean(true)); } catch (ClassNotFoundException e2) { } } } // Variables: // mode:java // coding:utf-8 // End: