001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: /*
043: * SvgMenuAnotherStyle.java
044: *
045: * Created on April 10, 2006, 12:01 PM
046: *
047: * To change this template, choose Tools | Template Manager
048: * and open the template in the editor.
049: */
050:
051: package org.netbeans.microedition.svg;
052:
053: import java.util.Vector;
054: import javax.microedition.lcdui.Canvas;
055: import javax.microedition.lcdui.Command;
056: import javax.microedition.lcdui.CommandListener;
057: import javax.microedition.lcdui.Display;
058: import javax.microedition.m2g.SVGEventListener;
059: import javax.microedition.m2g.SVGImage;
060: import org.w3c.dom.Document;
061: import org.w3c.dom.Element;
062: import org.w3c.dom.svg.SVGAnimationElement;
063: import org.w3c.dom.svg.SVGElement;
064:
065: /**
066: * Screen representing a menu component. SVG animation can contain named elements,
067: * which are being focused while the users moves up/down. In the case SVG image
068: * contains animation on the focus event, the user can see the animated transition
069: * between the named elements.
070: *
071: * <p/> By default this component starts the animation automatically and runs in
072: * full screen mode.
073: *
074: * @author breh
075: */
076: public class SVGMenu extends SVGAnimatorWrapper {
077:
078: private static final String FOCUSINANIM_PREFFIX = "focusInAnim_";
079: private static final String FOCUSOUTANIM_PREFIX = "focusOutAnim_";
080:
081: /**
082: * Command fired when the user chooses a menu element.
083: */
084: public static final Command SELECT_COMMAND = new Command(
085: "SELECT_COMMAND", Command.ITEM, 0); // NOI18N
086:
087: /**
088: * value of selected index when no menu item is selected
089: */
090: public static final int SELECTED_INDEX_NONE = -1;
091:
092: private static final int NO_FOCUS = -1;
093:
094: private Vector menuElements;
095: private Document svgDocument;
096: private int currentFocus = NO_FOCUS;
097: private Display display;
098:
099: // menu element structure
100: private static class MenuElement {
101: SVGElement focusableElement;
102: int gameActionId;
103: SVGAnimationElement focusInAnimation;
104: SVGAnimationElement focusOutAnimation;
105: }
106:
107: /**
108: * Creates a new instance of SVGMenu. It requires SVGImage to be displayed as
109: * menu and display.
110: *
111: * <p/> Please note, supplied SVGImage shouldn't be reused in other SVGAnimator.
112: */
113: public SVGMenu(SVGImage svgImage, Display display) {
114: super (svgImage, display);
115: this .svgDocument = svgImage.getDocument();
116: this .menuElements = new Vector();
117: this .display = display;
118: setResetAnimationWhenStopped(false); // animation cannot be reset automatically
119: setSVGEventListener(new SvgMenuEventListener()); // set menu listener
120: setFullScreenMode(true); // menu is usually full screen
121: }
122:
123: /**
124: * Adds a menu element to the menu component. The menu element is identified
125: * by SVG element ID, so when the menu element is being selected, the
126: * element with given ID is being focused.
127: */
128: public void addMenuElement(String svgElementId) {
129: this .addMenuElement(svgElementId, Canvas.FIRE);
130: }
131:
132: /**
133: * Gets menu element id for given index.
134: * @return string element ID
135: * @throws IndexOutOfBoundException when a wrong index is used
136: */
137: public String getMenuElementID(int index)
138: throws IndexOutOfBoundsException {
139: if ((index < 0) || (index >= menuElements.size()))
140: throw new IndexOutOfBoundsException(
141: "Wrong index for menu element: " + index);
142: return ((MenuElement) menuElements.elementAt(index)).focusableElement
143: .getId();
144: }
145:
146: /**
147: * Implementation of addding the menu element
148: */
149: private void addMenuElement(String svgElementId, int gameActionId) {
150: MenuElement element = new MenuElement();
151: element.focusableElement = (SVGElement) svgDocument
152: .getElementById(svgElementId);
153: element.gameActionId = gameActionId;
154: // now try to find animation elements in by our patterns (Nokia S40 workaround)
155: // focus.in animation replacement
156: Element animElement = svgDocument
157: .getElementById(FOCUSINANIM_PREFFIX + svgElementId);
158: if (animElement instanceof SVGAnimationElement) {
159: element.focusInAnimation = (SVGAnimationElement) animElement;
160: }
161: // focus.out animation replacement
162: animElement = svgDocument.getElementById(FOCUSOUTANIM_PREFIX
163: + svgElementId);
164: if (animElement instanceof SVGAnimationElement) {
165: element.focusOutAnimation = (SVGAnimationElement) animElement;
166: }
167: menuElements.addElement(element);
168: resetFocus();
169: }
170:
171: /**
172: * Gets index of selected menu element
173: */
174: public int getSelectedIndex() {
175: return currentFocus;
176: }
177:
178: // we should also think about removeMenuElement, but this is not necessary for Visual Designer
179:
180: private void focusOn(int currentFocus, int nextFocus) {
181: //System.out.println("current="+currentFocus+", next="+nextFocus);
182: MenuElement currentElement = getMenuElementAt(currentFocus);
183: MenuElement nextElement = getMenuElementAt(nextFocus);
184: if (currentElement != null) {
185: // if it has focus out animation replacement
186: if (currentElement.focusInAnimation != null) {
187: stopAnimation(currentElement.focusInAnimation);
188: //System.out.println("Stopping focusIn replacement for current");
189: }
190: if (currentElement.focusOutAnimation != null) {
191: startAnimation(currentElement.focusOutAnimation);
192: //System.out.println("Dispatching focusOut replacement for current");
193: }
194: }
195: if (nextElement != null) {
196: if (nextElement.focusOutAnimation != null) {
197: stopAnimation(nextElement.focusOutAnimation);
198: //System.out.println("Stopping focusOut replacement for cunextrrent");
199: }
200: if (nextElement.focusInAnimation != null) {
201: // if it has focus in animation replacement
202: // remove current focus
203: getSVGImage().focusOn(null);
204: // start focus animation replacement
205: startAnimation(nextElement.focusInAnimation);
206: //System.out.println("Dispatching focusIn replacement for next");
207: } else {
208: // else use delvering focus on element
209: getSVGImage().focusOn(nextElement.focusableElement);
210: //System.out.println("Dispatching regular focusIn");
211: }
212: } else {
213: // we have a problem houston -- remove focus
214: getSVGImage().focusOn(null);
215: //System.out.println("Dispatching regular focusIn on null");
216: }
217: }
218:
219: private MenuElement getMenuElementAt(int index) {
220: if ((index >= 0) && (index < menuElements.size())) {
221: return (MenuElement) menuElements.elementAt(index);
222: } else {
223: return null;
224: }
225: }
226:
227: private void startAnimation(
228: final SVGAnimationElement svgAnimationElement) {
229: Runnable runnable = new Runnable() {
230: public void run() {
231: svgAnimationElement.beginElementAt(0f);
232: }
233: };
234: invokeLaterSafely(runnable);
235: }
236:
237: private void stopAnimation(
238: final SVGAnimationElement svgAnimationElement) {
239: Runnable runnable = new Runnable() {
240: public void run() {
241: svgAnimationElement.endElementAt(0f);
242: }
243: };
244: invokeLaterSafely(runnable);
245: }
246:
247: /**
248: * focus on the first element if applicable;
249: */
250: public void resetFocus() {
251: focusOn(currentFocus, 0);
252: currentFocus = 0;
253: }
254:
255: /**
256: * By default, focusNext simply moves the focus on the
257: * next focusable element in the focus ring.
258: */
259: public void focusNext() {
260: int nextFocus = currentFocus;
261: if (nextFocus + 1 != menuElements.size()) {
262: nextFocus++;
263: } else {
264: nextFocus = 0;
265: }
266: focusOn(currentFocus, nextFocus);
267: currentFocus = nextFocus;
268: }
269:
270: /**
271: * By default, focusNext simply moves the focus on the
272: * previous focusable element in the focus ring.
273: */
274: public void focusPrev() {
275: int nextFocus = currentFocus;
276: if (nextFocus == 0) {
277: nextFocus = menuElements.size();
278: }
279: nextFocus--;
280: focusOn(currentFocus, nextFocus);
281: currentFocus = nextFocus;
282: }
283:
284: // Listen to MIDP key events
285: // - UP/LEFT -> Focus on previous item.
286: // - DOWN/RIGHT -> Focus on next item.
287: private class SvgMenuEventListener implements SVGEventListener {
288: public void keyPressed(int keyCode) {
289: int gameAction = getSvgCanvas().getGameAction(keyCode);
290: if (gameAction == Canvas.UP || gameAction == Canvas.LEFT) {
291: getAnimator().invokeLater(new Runnable() {
292: public void run() {
293: focusPrev();
294: }
295: });
296: } else if (gameAction == Canvas.DOWN
297: || gameAction == Canvas.RIGHT) {
298: getAnimator().invokeLater(new Runnable() {
299: public void run() {
300: focusNext();
301: }
302: });
303: }
304:
305: MenuElement currentMenuElement = getMenuElementAt(currentFocus);
306: if (currentMenuElement != null) {
307: if (gameAction == currentMenuElement.gameActionId) {
308: // fire the action
309: fireSelectCommandAction();
310: }
311: // else do nothing !!!
312: } else {
313: //System.out.println("SvgMenuEventListener.keyPressed: Houston we have a problem : currentMenuElement == null !!!");
314: }
315: }
316:
317: private void fireSelectCommandAction() {
318: final CommandListener commandListener = SVGMenu.this
319: .getCommandListener();
320: if (commandListener != null) {
321: commandListener.commandAction(SVGMenu.SELECT_COMMAND,
322: SVGMenu.this );
323: }
324: }
325:
326: public void keyReleased(int keyCode) {
327: }
328:
329: public void pointerPressed(int x, int y) {
330: }
331:
332: public void pointerReleased(int x, int y) {
333: }
334:
335: public void hideNotify() {
336: }
337:
338: public void showNotify() {
339: }
340:
341: public void sizeChanged(int width, int height) {
342: }
343: }
344:
345: }
|