www.pudn.com > Bluegammon蓝牙的应用编程.rar > Menu.java
// Copyright (c) 2005 Sony Ericsson Mobile Communications AB // // This software is provided "AS IS," without a warranty of any kind. // ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, // INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. // // THIS SOFTWARE IS COMPLEMENTARY OF JAYWAY AB (www.jayway.se) package bluegammon.gui.menu; import java.util.Stack; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Graphics; import bluegammon.Device; /** ** The
Menuclass takes care of coordination between *MenuPages,PageItems and user interaction. * It contains a navigation stack to handle breadcrumb behaviour. * It handles the painting of the menu via aMenuPainter. ** The navigation tree can either be implemented in the
PageItems * constructor, or via an implementation ofItemActionthat uses * the methodgotoPagein this class. ** A common example for using a
Menu: *
public class MenuCanvas extends Canvas implements ItemAction { static final int PRINT_1 = 1; static final int PRINT_2 = 2; Menu m_menu; public MenuCanvas() { // Create pages MenuPage mainPage = new MenuPage("STARTPAGE".toCharArray(), null); MenuPage nextPage = new MenuPage("NEXTPAGE".toCharArray(), null); // Create menu items PageItem anItem = new PageItem("Goto next page".toCharArray(), null, null, nextPage); PageItem anotherItem = new PageItem("Print 1".toCharArray(), null, this, null, PRINT_1); PageItem yetAnotherItem = new PageItem("Print 2".toCharArray(), null, this, null, PRINT_2); // Assign items to pages mainPage.addItem(anItem); mainPage.addItem(anotherItem); nextPage.addItem(yetAnotherItem); // Create and setup menu m_menu = new Menu(mainPage, this, new DefaultMenuPainter()); int menuPadding = 16; m_menu.setLocation(0, menuPadding); m_menu.setDimensions(getWidth(), getHeight() - menuPadding * 2); m_menu.setFrameData(10, 20); // 10 frames per transition, 20 ms between each frame m_menu.start(); } protected void paint(Graphics g) { g.setColor(0x000000); g.fillRect(0, 0, getWidth(), getHeight()); m_menu.paint(g); } protected void keyPressed(int keyCode) { m_menu.keyPressed(keyCode); } public void itemAction(MenuPage page, PageItem item) { int id = item.getId(); switch(id) { case PRINT_1: System.out.println("Item 1 is invoked"); break; case PRINT_2: System.out.println("Item 2 is invoked"); break; } } }* @author Peter Andersson */ public class Menu implements Runnable { /** The menu painter */ protected MenuPainter m_painter; /** The start page of this menu */ protected MenuPage m_startPage; /** Current page */ protected MenuPage m_curPage; /** Current selected item index in current page */ protected int m_curItemIndex; /** Transition flag */ protected boolean m_inTransition; /** Back transition flag */ protected boolean m_transitionBack; /** Transition destination page */ protected MenuPage m_transPage; /** Current transition frame */ protected int m_frame; /** Maximum transition frames */ protected int m_frames; /** Transition frame delay in milliseconds, 500 as default */ protected long m_frameDelay = 500; /** * The menu listener. For a compact framework, * we allow only one listener. */ protected MenuListener m_listener; /** Animation lock */ protected final Object ANIM_LOCK = new Object(); /** Thread running flag */ protected volatile boolean m_running = true; /** The canvas that renders this menu */ protected Canvas m_canvas; /** The navigation trail stack */ protected Stack m_history = new Stack(); /** Menu width */ protected int m_width = 0; /** Menu height */ protected int m_height = 0; /** Menu x offset */ protected int m_x = 0; /** Menu y offset */ protected int m_y = 0; /** * Creates a new menu. * * @param startPage The first page in this menu. * @param canvas The canvas that this menu is drawn upon. * @param painter The painter used to draw this menu. */ public Menu(MenuPage startPage, Canvas canvas, MenuPainter painter) { m_startPage = startPage; setCanvas(canvas); setPainter(painter); } /** * Activates this menu and jumps to the starting page. */ public void start() { new Thread(this, "Menu thread").start(); gotoPage(m_startPage); } /** * Call this from your displayable's paint method to paint the menu. * @param g The graphics context. */ public void paint(Graphics g) { if (m_width == 0 && m_height == 0 && m_canvas != null) { m_width = m_canvas.getWidth() - m_x; m_height = m_canvas.getHeight() - m_y; } if (m_inTransition && m_frames > 0) { m_painter.paintTransition(g, m_curPage, m_transPage, m_x, m_y, m_width, m_height, m_frame, m_frames, m_transitionBack); } else { m_painter.paintMenu(g, m_curPage, m_x, m_y, m_width, m_height); } } /** * Call this from your displayable's keyPressed or keyRepeated method * invoke user interaction on the menu. * @param keyCode The keyCode. */ public void keyPressed(int keyCode) { MenuPage curPage = getCurrentPage(); if (curPage != null && m_canvas != null) { if (keyCode == Device.KEYCODE_BACK) { goBack(); return; } int gameCode = m_canvas.getGameAction(keyCode); switch (gameCode) { case Canvas.LEFT: goBack(); break; case Canvas.FIRE: case Canvas.RIGHT: PageItem item = getSelectedItem(); if (gameCode == Canvas.FIRE && item != null && item.getAction() != null) { doAction(item.getAction(), curPage, item); } if (item != null && item.getSubPage() != null) { gotoPage(item.getSubPage()); } break; case Canvas.UP: setSelectedItemIndex(getSelectedItemIndex()-1); break; case Canvas.DOWN: setSelectedItemIndex(getSelectedItemIndex()+1); break; } } } /** * Steps forward to a new page. * @param newPage The new page. */ public void gotoPage(MenuPage newPage) { MenuPage curPage = null; synchronized(ANIM_LOCK) { curPage = getCurrentPage(); if (curPage != null) { m_history.push(curPage); } } if (m_listener != null) { m_listener.newPage(curPage, newPage, false); m_listener.itemSelected(newPage, null, newPage == null ? null : (newPage.itemAt(newPage.getSelectedIndex())) ); } startTransition(curPage, newPage, false); } /** * Steps back to previous page. Does nothing if there are no previous pages. */ public void goBack() { MenuPage curPage = null; MenuPage backPage = null; synchronized(ANIM_LOCK) { curPage = getCurrentPage(); if (m_history.size() > 0) { backPage = (MenuPage)m_history.pop(); } } if (backPage != null) { if (m_listener != null) { m_listener.newPage(curPage, backPage, true); m_listener.itemSelected(backPage, null, backPage == null ? null : (backPage.itemAt(backPage.getSelectedIndex())) ); } startTransition(curPage, backPage, true); } } /** * Executes specified action. * @param action The action to execute. * @param page The page from which the action was executed. * @param item The item the action is called from. */ protected void doAction(final ItemAction action, final MenuPage page, final PageItem item) { new Thread(new Runnable() { public void run() { try { action.itemAction(page, item); if (m_listener != null) { m_listener.actionCalled(page, item, action); } if (m_canvas != null) { m_canvas.repaint(); } } catch (Throwable t) { System.out.println("Exception in ItemAction"); t.printStackTrace(); } } },"ItemAction runner").start(); } /** * Returns current page. If a transition between pages are ongoing, * the destination page of the transition is returned. * @return Current page. */ public MenuPage getCurrentPage() { MenuPage curPage = null; synchronized(ANIM_LOCK) { if (m_inTransition) { curPage = m_transPage; } else { curPage = m_curPage; } } return curPage; } /** * Returns selected item or null if no item is currently selected. * @return Selected item or null. */ public PageItem getSelectedItem() { MenuPage curPage = getCurrentPage(); if (curPage != null) { return curPage.itemAt(curPage.getSelectedIndex()); } else { return null; } } /** * Returns index of selected item or -1 if no item is currently selected. * @return Index of selected item or -1. */ public int getSelectedItemIndex() { MenuPage curPage = getCurrentPage(); if (curPage != null) { return curPage.getSelectedIndex(); } else { return -1; } } /** * Sets index of selected item. * @param itemIndex The index of the item to select. */ public void setSelectedItemIndex(int itemIndex) { MenuPage curPage = getCurrentPage(); if (curPage != null) { PageItem oldItem = curPage.itemAt(curPage.getSelectedIndex()); curPage.setSelectedIndex(itemIndex); PageItem newItem = curPage.itemAt(curPage.getSelectedIndex()); if (m_listener != null) { m_listener.itemSelected(curPage, oldItem, newItem); } if (m_canvas != null) { m_canvas.repaint(); } } } /** * Returns the canvas this menu is drawn upon. * @return The canvas drawing this menu. */ public Canvas getCanvas() { return m_canvas; } /** * Sets the canvas this menu is drawn upon. * @param canvas The canvas drawing this menu. */ public void setCanvas(Canvas canvas) { m_canvas = canvas; } /** * Returns the listener. * @return The menu listener. */ public MenuListener getListener() { return m_listener; } /** * Sets the listener which is reported on menu events. * @param listener A menu listener. */ public void setListener(MenuListener listener) { m_listener = listener; } /** * Returns the painter used to paint the menu. * @return The painter. */ public MenuPainter getPainter() { return m_painter; } /** * Sets the painter used to paint the menu. * @param painter The painter. */ public void setPainter(MenuPainter painter) { m_painter = painter; } /** * Returns the frame delay in milliseconds. * @return The delay between each frame update. */ public long getFrameDelay() { return m_frameDelay; } /** * Returns number of frames in a page switch. * @return Number of frames in a page switch. */ public int getFrames() { return m_frames; } /** * Returns height of this menu. * @return The height. */ public int getHeight() { return m_height; } /** * Returns start page of this menu. * @return The start page. */ public MenuPage getStartPage() { return m_startPage; } /** * Returns width of this menu. * @return The width. */ public int getWidth() { return m_width; } /** * Returns x offset of this menu. * @return The x offset. */ public int getX() { return m_x; } /** * Returns y offset of this menu. * @return The y offset. */ public int getY() { return m_y; } /** * Sets the location of this menu. * @param x The x offset. * @param y The y offset. */ public void setLocation(int x, int y) { m_x = x; m_y = y; } /** * Sets the size of this menu. If width and height are zero, * these values will be collected from the canvas that this * menu is painted upon. * @param width The width. * @param height The height. */ public void setDimensions(int width, int height) { m_width = width; m_height = height; } /** * Sets the values used in a transition between to pages. * A transition consists of a number of frames with a delay * between each frame. A full transition will take * nbrOfFrames * (frameDelay + * time to paint frame) milliseconds. * * @param nbrOfFrames Number of frames in a transition. * @param frameDelay Delay in milliseconds in each transition. */ public void setFrameData(int nbrOfFrames, long frameDelay) { m_frames = nbrOfFrames; m_frameDelay = frameDelay; } /** * Starts a new transition between pages. If there is an ongoing transition, * this is immediately pushed to its end and the new one is started. * @param fromPage Transition source page. * @param toPage Transition destination page. * @param back True if it is a transition back to destination page, false otherwise. */ protected void startTransition(MenuPage fromPage, MenuPage toPage, boolean back) { synchronized(ANIM_LOCK) { m_curPage = fromPage; m_transPage = toPage; // Wait for ongoing transition to end if (m_inTransition) { ANIM_LOCK.notifyAll(); } while (m_inTransition) { try { ANIM_LOCK.wait(); } catch (InterruptedException e) {} } m_transitionBack = back; // Start new transition m_inTransition = true; ANIM_LOCK.notifyAll(); } } /** *Runnableimplementation, invokes * theMenuPainteron transitions. */ public void run() { while(m_running) { synchronized(ANIM_LOCK) { // Wait for a transition to be requested while (!m_inTransition) { try { ANIM_LOCK.wait(); } catch (InterruptedException e) {} } // Transition initiated m_inTransition = true; int frames = m_frames; long delay = m_frameDelay; MenuPage fromPage = m_curPage; MenuPage toPage = m_transPage; boolean backFlag = m_transitionBack; if (m_listener != null) { m_listener.transitionStarted(fromPage, toPage, delay, frames, backFlag); } // Do each frame in transition for (; m_frame < frames; m_frame++) { try { ANIM_LOCK.wait(delay); } catch (InterruptedException e1) {} if (m_canvas != null) { m_canvas.repaint(); } // Check if someone changed parameters for transition, // in that case interrupt current transition if (m_curPage != fromPage || m_transPage != toPage) { break; } } m_frame = 0; m_curPage = toPage; if (m_canvas != null) m_canvas.repaint(); m_inTransition = false; if (m_listener != null) { m_listener.transitionStopped(fromPage, toPage); } if (m_canvas != null) { m_canvas.repaint(); } // Notify that this transition has ended ANIM_LOCK.notifyAll(); } } } }