📄 firescreen.java
字号:
/* * Fire (Flexible Interface Rendering Engine) is a set of graphics widgets for creating GUIs for j2me applications. * Copyright (C) 2006-2008 Bluevibe (www.bluevibe.net) * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * *//* * Created on Feb 22, 2008 */package gr.fire.core;import gr.fire.ui.Alert;import gr.fire.ui.FlyAnimation;import gr.fire.ui.SoftKeyAnimation;import gr.fire.util.FireConnector;import gr.fire.util.Log;import gr.fire.util.Queue;import javax.microedition.lcdui.Canvas;import javax.microedition.lcdui.Command;import javax.microedition.lcdui.Display;import javax.microedition.lcdui.Displayable;import javax.microedition.lcdui.Font;import javax.microedition.lcdui.Graphics;import javax.microedition.lcdui.Image;import javax.microedition.lcdui.game.Sprite;/** * @author padeler * */public class FireScreen extends Canvas implements Runnable{ /** * FireScreen NORMAL Orientation * * @see #setOrientation(int) */ public static final byte NORMAL = 0x00; /** * FireScreen landscape (right handed) orientation * * @see #setOrientation(int) */ public static final byte LANDSCAPERIGHT = 0x01; /** * FireScreen landscape (left handed) orientation * * @see #setOrientation(int) */ public static final byte LANDSCAPELEFT = 0x02; public static final int NONE = 0x00000000; public static final int CENTER = 0x00000001; public static final int RIGHT = 0x00000002; public static final int LEFT = 0x00000004; public static final int TOP = 0x00000008; public static final int BOTTOM = 0x00000010; public static final int VCENTER = 0x00000020; /** * FireScreen determines the handset type on startup and assignes the left * Softkey key code to this variable */ public static int leftSoftKey = -6; /** * FireScreen determines the handset type on startup and assignes the right * Softkey key code to this variable */ public static int rightSoftKey = -7; private static final Object[][] keyMaps = { { "Nokia", new Integer(-6), new Integer(-7) }, { "ricsson", new Integer(-6), new Integer(-7) }, { "iemens", new Integer(-1), new Integer(-4) }, { "otorola", new Integer(-21), new Integer(-22) }, { "harp", new Integer(-21), new Integer(-22) }, { "j2me", new Integer(-6), new Integer(-7) }, { "intent JTE", new Integer(57345), new Integer(57346) } }; /** * ZINDEX is the location a component on the Z axis (depth) it controls in * which order the Component will be painted. <br/> The current component * set in the methods getCurrent and setCurrent is always considered the * component on zindex=0. <br/> The indexes should be used as follows (this * is a recomendation, it is not forced): <br/> -3, -2, -1 : Backgrounds and * background animations <br/> 0, 1, 2, 3 : Panels, Containers, popup menus * and user traversable components in general. <br/> 4, 5, 6, 7, ... : * Animations, effects, transition animations, mouse pointers, etc. <br/> * * @see #setCurrent(Component) * @see #getCurrent() * @see #addComponent(Component, int) * */ public static final int ZINDEX_MAX = 8; /** * @see #ZINDEX_MAX */ public static final int ZINDEX_MIN = -3; public static final int LEFT_SOFTKEY_ZINDEX=7; public static final int RIGHT_SOFTKEY_ZINDEX=8; private static FireScreen singleton = null; private static Theme theme; private static Font navbarFont; /* ***************** Support variables ***************************** */ private Display display = null; private Image offscreen; // offscreen image used when rendering in // landscape modes. private int softkeyController = -1; // holds the max zindex of a top level // component thas is focusable and has // softkeys // variables that control tha behaivior of the FireScreen canvas private boolean visible = true; // flag toggled by showNotify and hideNotify // to start or stop animations and repaint // screen when its displayed. private boolean generateRepeatEvents = false; // if the platform does not // support keyRepeated // events the FireScreen // will produce these // manually. private static final int NO_PRESSED_KEY=-1000; private int pressedKeyCode = NO_PRESSED_KEY; private long pressedKeyTime = 0; private long keyRepeatPeriod = 200; // if generateRepeatEvents==true, // keyRepeated events will be generated // every this amount of miliseconds private int orientation = NORMAL; private boolean animationsEnabled = true; private Queue animationQueue; /** Vector containing all the stacked components currently open on the scren. */ private Component selectedComponent = null; // holds the currently selected // component. private Component[] componentSlots = new Component[(ZINDEX_MAX - ZINDEX_MIN) + 1]; private Thread animationThread; private FireScreen(Display display) { /* **** Hack for Motorola phones ********** Thanks to Maxim Blagov */ /* * **** Some (if not all) Motorola phones, return "j2me" to * getProperty("microedition.platform") */ String platform = null; String prop = System.getProperty("com.mot.carrier.URL"); if (prop != null) { platform = "motorola"; } else { try { Class.forName("com.motorola.graphics.j3d.Graphics3D"); platform = "motorola"; } catch (Throwable e) { } } if (platform == null) // ok its propably not a motorola phone. { platform = System.getProperty("microedition.platform"); } /* ******************************************************** */ Log.logDebug("Running on platform: " + platform); for (int i = 0; i < keyMaps.length; ++i) { String manufacturer = (String) keyMaps[i][0]; if (platform.indexOf(manufacturer) != -1) { if (i == 1) // ta sony ericsson exoun enalaktika keys sta // p800/p900/p908/p802 { if (platform.indexOf("P900") != -1 || platform.indexOf("P908") != -1) { leftSoftKey = ((Integer) keyMaps[i][2]).intValue(); rightSoftKey = ((Integer) keyMaps[i][1]).intValue(); } else { leftSoftKey = ((Integer) keyMaps[i][1]).intValue(); rightSoftKey = ((Integer) keyMaps[i][2]).intValue(); } } else { leftSoftKey = ((Integer) keyMaps[i][1]).intValue(); rightSoftKey = ((Integer) keyMaps[i][2]).intValue(); } break; } } if (theme == null) setTheme(new Theme());// default theme this.display = display; // if platform does not have support ket repeat events, i must generate // them. generateRepeatEvents = !hasRepeatEvents(); animationQueue = new Queue(); animationThread = new Thread(this); animationThread.start(); } public void paint(Graphics g) { int width = getWidth(); int height = getHeight(); int clipX = g.getClipX(), clipY = g.getClipY(), clipW = g.getClipWidth(), clipH = g.getClipHeight(); int trX = g.getTranslateX(); int trY = g.getTranslateY(); try { Graphics dest; if (orientation != NORMAL) { if (offscreen == null || offscreen.getWidth() != width || offscreen.getHeight() != height) { offscreen = Image.createImage(width, height); } dest = offscreen.getGraphics(); // invert the clip information. // NOTE: No need to invert the translate information. int t; if (orientation == LANDSCAPELEFT) { t = clipY; clipY = clipX; clipX = width - t - clipH; } else { t = clipX; clipX = clipY; clipY = height - t - clipW; } t = clipW; clipW = clipH; clipH = t; dest.translate(-dest.getTranslateX() + trX, -dest.getTranslateY() + trY); dest.setClip(clipX, clipY, clipW, clipH); } else dest = g; /* ***** Clean the area that will be repainted. ***** */ // clean the bg to white... dest.setColor(0x00FFFFFF); dest.fillRect(clipX, clipY, clipW, clipH); // this will only // repaint the clipped // region. /* * ************ paint the fireScreen animations behind the * components. ***************** */ for (int i = 0; i < componentSlots.length; ++i) { Component paintable = componentSlots[i]; if (paintable != null && paintable.visible) { if (!paintable.valid) { paintable.validate(); } // ok, now paint or animate the component. if (paintable.animation != null) { if (paintable.animation.intersects(clipX, clipY, clipW, clipH)) { dest.clipRect(paintable.animation.x, paintable.animation.y, paintable.animation.width, paintable.animation.height); dest.translate(paintable.animation.x, paintable.animation.y); paintable.animation.paint(dest); dest.translate(-dest.getTranslateX() + trX, -dest.getTranslateY() + trY); dest.setClip(clipX, clipY, clipW, clipH); } } else { if (paintable.intersects(clipX, clipY, clipW, clipH)) { dest.clipRect(paintable.x, paintable.y, paintable.width, paintable.height); dest.translate(paintable.x, paintable.y); paintable.paint(dest); dest.translate(-dest.getTranslateX() + trX, -dest.getTranslateY() + trY); dest.setClip(clipX, clipY, clipW, clipH); } } dest.translate(-dest.getTranslateX() + trX, -dest.getTranslateY() + trY); dest.setClip(clipX, clipY, clipW, clipH); } } } catch (OutOfMemoryError e) { Runtime.getRuntime().gc(); animationQueue.removeAll(); animationsEnabled = false; // not much to do at this point but // disable animations anyway. Runtime.getRuntime().gc(); Log.logError("OutOfMemory inside FireScreen.paint().", e); } catch (Throwable e) { Log.logError("Exception inside FireScreen.paint().", e); } /* * **** Finally paint the offscreen. This step is only used when drawing * in landscape modes. **** */ switch (orientation) { case NORMAL: break; case LANDSCAPELEFT: g.drawRegion(offscreen, 0, 0, width, height, Sprite.TRANS_ROT270, 0, 0, Graphics.TOP | Graphics.LEFT); break; case LANDSCAPERIGHT: g.drawRegion(offscreen, 0, 0, width, height, Sprite.TRANS_ROT90, 0, 0, Graphics.TOP | Graphics.LEFT); break; } } /** * Registers an animation on the internal animation queue. The animatation * will remain in the queue until its completed or its removed using the * {@link #removeAnimation(Animation)} method. * * @see Animation * @param anim */ public void registerAnimation(Animation anim) { animationQueue.add(anim); if (anim.parent != null) anim.parent.animation = anim; } /** * Removes the animation from the internal animation queue. * * <b>Note:</b> If this animation is a top level component it should be * removed using the removeComponent instead. This method will remove the * animation from the Queue but will not remove it from the FireScreen top * level components list. * * @see #registerAnimation(Animation) * @param anim */ public void removeAnimation(Animation anim) { animationQueue.remove(anim); if (anim.parent != null) anim.parent.animation = null; } /* * This method is called by a component each time its right or left softkey commands are set. * If the component's softkeys are currently displayed, the updateSoftKeys() method is called * to change the displayed softkeys. */ void componentSoftKeyUpdate(Component cmp) { if(cmp==null) return; if(cmp==selectedComponent || (softkeyController>-1 && componentSlots[softkeyController]==cmp)) { // update the softkeys is needed. updateSoftKeys(); } } private void updateSoftKeys() { Command left=null,right=null; Component softKeyOwner = selectedComponent; if((softKeyOwner==null || (softKeyOwner.leftSoftKeyCommand==null && softKeyOwner.rightSoftKeyCommand==null)) && softkeyController>-1) { softKeyOwner = componentSlots[softkeyController]; } if(softKeyOwner!=null) { left = softKeyOwner.leftSoftKeyCommand; right = softKeyOwner.rightSoftKeyCommand; } int lidx = LEFT_SOFTKEY_ZINDEX - ZINDEX_MIN; int ridx = RIGHT_SOFTKEY_ZINDEX - ZINDEX_MIN; SoftKeyAnimation leftSoftKeyCmp=null,rightSoftKeyCmp=null; if (left != null || right != null) { int keyH = navbarFont.getHeight(); int lh=keyH,rh=keyH; int dw = getWidth(); int dh = getHeight(); int navbarBgColor = theme.getIntProperty("navbar.bg.color"); int navbarFgColor = theme.getIntProperty("navbar.fg.color"); int lx=0,ly=0,rx=0,ry=0; int lw = (left!=null?navbarFont.stringWidth(left.getLabel()):0); int rw = (right!=null?navbarFont.stringWidth(right.getLabel()):0); switch(orientation) { case NORMAL: if(theme.decorBottom>keyH) {lh = theme.decorBottom;rh= theme.decorBottom;} lx=0;ly=dh-lh; rx=dw-rw;ry=dh-rh; break; case LANDSCAPELEFT: if(theme.decorTop>keyH) lh = theme.decorTop; if(theme.decorBottom>keyH) rh= theme.decorBottom; lx=0;ly=0; rx=0;ry=dh-rh; break; case LANDSCAPERIGHT: if(theme.decorTop>keyH) rh = theme.decorTop; if(theme.decorBottom>keyH) lh= theme.decorBottom; lx=dw-lw;ly=dh-lh; rx=dw-rw;ry=0; break; } if (left != null) { leftSoftKeyCmp = new SoftKeyAnimation(left.getLabel()); leftSoftKeyCmp.setFont(navbarFont); leftSoftKeyCmp.setBackgroundColor(navbarBgColor); leftSoftKeyCmp.setForegroundColor(navbarFgColor); leftSoftKeyCmp.setPosition(lx,ly); leftSoftKeyCmp.setWidth(lw); leftSoftKeyCmp.setHeight(lh); leftSoftKeyCmp.validate(); } if (right != null) { rightSoftKeyCmp = new SoftKeyAnimation(right.getLabel()); rightSoftKeyCmp.setFont(navbarFont); rightSoftKeyCmp.setBackgroundColor(navbarBgColor); rightSoftKeyCmp.setForegroundColor(navbarFgColor); rightSoftKeyCmp.setPosition(rx,ry); rightSoftKeyCmp.setWidth(rw); rightSoftKeyCmp.setHeight(rh); rightSoftKeyCmp.validate(); } } if(componentSlots[lidx]!=null) repaintScreen(componentSlots[lidx].x,componentSlots[lidx].y,componentSlots[lidx].width,componentSlots[lidx].height); if(componentSlots[ridx]!=null) repaintScreen(componentSlots[ridx].x,componentSlots[ridx].y,componentSlots[ridx].width,componentSlots[ridx].height); componentSlots[lidx]=leftSoftKeyCmp; componentSlots[ridx]=rightSoftKeyCmp; if(leftSoftKeyCmp!=null) leftSoftKeyCmp.repaint(); if(rightSoftKeyCmp!=null) rightSoftKeyCmp.repaint(); } /** * Returns the current panel set on the FireScreen. * * @return */ public Component getCurrent() { return componentSlots[-ZINDEX_MIN]; } /** * Set a Displayable to the FireScreen. * * @param p */ public void setCurrent(Displayable d) { display.setCurrent(d); } /** * Utility method to easily display popups that should be located near the component that triggered them. * For example when opening a drop-down menu, it should be opened near the menu component that triggered it. * This method provides an easy way to open the popup, without the need to calculate its position (x,y). * It takes into acount the location of the trigger component and the orientation of the screen. * * * @param popup The popup component to display * @param cmp The component that is the logical trigger for this popup to apear * @param zindex The zindex on which the popup will be added using the {@link #addCommand(Command)} method. */ public void showPopupOnComponent(Component popup, Component cmp, int zindex) { int popupX=0,popupY=0,cmpX=0,cmpY=0,cmpW=0,cmpH=0; // first calculate the position of the trigger component if(cmp!=null) { Component t = cmp; while(t!=null) { cmpX+=t.x; cmpY+=t.y; t = t.parent; } cmpW = cmp.getWidth(); cmpH = cmp.getHeight(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -