/** * The menu raster images. */ protected Image[][][] menuIcons;
/** * The index of the current frame for each icon */ protected int[][] currentFrame;
/** * The row/col index of the currently-focused icon. */ protected int focusRow;
/** * The row/col index of the currently-focused icon. */ protected int focusCol;
/** * The padding ratio. */ protected float padding;
/** * @param svgImage the SVGImage this canvas should paint. * @param numRows the number of rows of icons. * @param numCols the number of columns of icons. * @param padding the margin around each icons, as a percentage of the * icon's bounding box. * @param numFramesFocus the number of frames to sample in order to get * from the unselected frame to the focused state. * @param frameLength the amount of time between frames. */ protected MenuCanvas(final SVGImage svgImage, final int numRows, final int numCols, final float padding, final int numFramesFocus, final float frameLength) { if ((svgImage == null) || (numRows <= 0) || (numCols <= 0) || (padding < 0) || (numFramesFocus < 1) || (frameLength <= 0)) { throw new IllegalArgumentException(); }
// The input svgImage should have numRows * numCols icons under the // root svg element. final int numIcons = numRows * numCols; Document doc = svgImage.getDocument(); SVGSVGElement svg = (SVGSVGElement)doc.getDocumentElement();
// Load all the icons in a Vector for future manipulation Vector iconVector = new Vector();
for (int i = 0; i < numIcons; i++) { SVGElement iconElt = (SVGElement)doc.getElementById("icon_" + i);
if (iconElt == null) { throw new IllegalArgumentException("The SVG Image does not have " + numIcons + " icons under the root svg element" + " icon_" + i + " does not exist in the document"); }
if (!(iconElt instanceof SVGLocatableElement)) { throw new IllegalArgumentException("The " + (i + 1) + "th icon under the " + "root svg element is not a <g>"); }
// Hide all icons initially iconElt.setTrait("display", "none");
iconVector.addElement(iconElt); }
// Now, compute the size allocated to each icon. int width = getWidth(); int height = getHeight();
for (int i = 0; i < numIcons; ++i) { SVGLocatableElement icon = (SVGLocatableElement)iconVector.elementAt(i);
// Get the user space bounding box for the icon SVGRect bbox = icon.getBBox(); if (bbox == null) { // If someone tampered with the svg menu file, the bbox // could be null iconViewBox[i] = null; continue; }
for (int ri = 0; ri < numRows; ri++) { for (int ci = 0; ci < numCols; ci++, i++) { // Get the icon we want to draw SVGLocatableElement icon = (SVGLocatableElement)iconVector.elementAt(i);
// Now, set the icon's display to 'inline' before drawing // it to the offscreen. icon.setTrait("display", "inline");
// "zoom" the icon if (iconViewBox[i] != null) { svg.setRectTrait("viewBox", iconViewBox[i]); }
// Create a bitmap to draw into svg.setCurrentTime(0);
for (int fi = 0; fi < numFrames; fi++) { menuIcons[ri][ci][fi] = Image.createImage(iconWidth, iconHeight);
// Get a Graphics instance that we can draw into Graphics g = menuIcons[ri][ci][fi].getGraphics(); g.setColor(255, 0, 0); g.fillRect(0, 0, iconWidth, iconHeight); sg.bindTarget(g); sg.render(0, 0, svgImage); sg.releaseTarget();
svgImage.incrementTime(frameLength); }
icon.setTrait("display", "none"); } }
// The following thread handles animating the currently focused item. final long frameLengthMs = (long)(frameLength * 1000); Thread th = new Thread() { public void run() { long start = 0; long end = 0; long sleep = 0; boolean interrupted = false;
while (!interrupted) { start = System.currentTimeMillis();
int cr = focusRow; int cc = focusCol; boolean needUpdate = false;
for (int ri = 0; ri < numRows; ri++) { for (int ci = 0; ci < numCols; ci++) { // Process icon (ri, ci)
if ((cr == ri) && (cc == ci)) { // We are processing the focused icon. // If we are below the focused frame, just increase the frame index if (curFrame < numFramesFocus) { // Move towards focused state on the focusIn animation curFrame += 1; needUpdate = true; } else { // Do nothing, we are in the right frame already. } } else { // We are _not_ on the focused frame. if (curFrame > 0) { curFrame -= 1; needUpdate = true; } }
currentFrame[ri][ci] = curFrame; } }
if (needUpdate) { repaint(); serviceRepaints(); }
end = System.currentTimeMillis(); sleep = frameLengthMs - (end - start);
public void keyPressed(int keyCode) { int r = focusRow; int c = focusCol;
switch (getGameAction(keyCode)) { case LEFT: c--;
if (c < 0) { c = numCols - 1; }
break;
case RIGHT: c++;
if (c == numCols) { c = 0; }
break;
case UP: r--;
if (r < 0) { r = numRows - 1; }
break;
case DOWN: r++;
if (r == numRows) { r = 0; }
break;
default:
// do nothing break; }
focusRow = r; focusCol = c; }
public void paint(Graphics g) { int fi = 0;
for (int ri = 0; ri < numRows; ri++) { for (int ci = 0; ci < numCols; ci++) { fi = currentFrame[ri][ci]; g.drawImage(menuIcons[ri][ci][fi], ci * iconWidth, ri * iconHeight, Graphics.TOP | Graphics.LEFT); } } } }