public class XeoMenu extends Applet { // The background image. This had better not be null. Image image;
// These two fields are used to do double-buffering. // The dimensions of bbuf is exactly the dimensions of the applet. Image bbuf; Graphics bbufG;
// This field is set to true only when the background image has // completely loaded. boolean imageDone;
/* Menu data */ Rectangle[] hitArea; Rectangle[] srcRect; Point[] dstPt; boolean[] down; String[] url;
/* Submenu data */ String[][] itemUrl; String[][] item;
// If >= 0, this fields holds the index of the current menu. // If -1, no menu is current. int curMenu;
// If >= 0, this fields holds the index of the current menu item. // If -1, no menu item is current. int curMenuItem;
// This is an array of rectangles - one rectangle for each menu item. // Each rectangle specifies the // location (relative to the left-corner of the applet) of a menu item. // // menuItemRect is null when curMenu is -1. // It becomes non-null when curMenu >= 0. // // Note: it would have been better PRogramming to define classes for // the menu and menu items. However, I decided for this little applet // to keep the number of class files to a minimum to minimize the download // time. Rectangle[] menuItemRect;
// This is the color to paint "behind" the image. Color bgColor;
// [0] is the text color of a menu item; [1] is the text color of a highlig hted // menu item. Color fgMenUColor[] = new Color[2];
// This is the background of a menu item; [1] is the background color of a // highlighted menu item. Color bgMenuColor[] = new Color[2];
// marginH is the number of pixels on the left and right edges of the menu. // marginV is the number of pixels on the top and bottom edges of the menu. int marginH, marginV;
// This is the font used to display the menu item labels. Font f;
// This is the font metrics of 'f'. FontMetrics fm;
// Get color parameters. ints = parseInt(getParameter("bg-color"), " "); bgColor = new Color(ints[0], ints[1], ints[2]); ints = parseInt(getParameter("fg-menu-color"), " "); fgMenuColor[0] = new Color(ints[0], ints[1], ints[2]); ints = parseInt(getParameter("fg-hi-menu-color"), " "); fgMenuColor[1] = new Color(ints[0], ints[1], ints[2]); ints = parseInt(getParameter("bg-menu-color"), " "); bgMenuColor[0] = new Color(ints[0], ints[1], ints[2]); ints = parseInt(getParameter("bg-hi-menu-color"), " "); bgMenuColor[1] = new Color(ints[0], ints[1], ints[2]);
// Create back buffer for double-buffering. bbuf = createImage(size().width, size().height); bbufG = bbuf.getGraphics();
// Determine the font from the font-height. int fh = Integer.parseInt(getParameter("font-height")); int i = fh; while (i > 10) { f = new Font(getParameter("font"), Font.PLAIN, i); fm = getFontMetrics(f); if (fm.getHeight() <= fh) { break; } i--; }
// Get the menu parameters. for (i=0; ; i++) { if (getParameter("menu"+i) == null) { hitArea = new Rectangle[i]; srcRect = new Rectangle[i]; dstPt = new Point[i]; url = new String[i]; down = new boolean[i]; itemUrl = new String[i][]; item = new String[i][];
break; } }
for (i=0; i String[] fields = parse(getParameter("menu"+i), getParameter("separ ator")); // Get the hit area. ints = parseInt(fields[0], " "); hitArea[i] = new Rectangle(ints[0], ints[1], ints[2], ints[3]);
// Get the source image. ints = parseInt(fields[1], " "); srcRect[i] = new Rectangle(ints[0], ints[1], ints[2], ints[3]);
// Get the destination point. ints = parseInt(fields[2], " "); dstPt[i] = new Point(ints[0], ints[1]); down[i] = fields[3].equals("d"); url[i] = fields[4];
item[i] = new String[(fields.length-5)/2]; itemUrl[i] = new String[(fields.length-5)/2]; for (int j=0; j item[i][j] = fields[j*2+5]; itemUrl[i][j] = fields[j*2+6]; } } }
// s is a string containing 'sep' separators. This method // breaks up the string at the separators and returns the resulting // strings in an array. The result may have zero length but is never null. String[] parse(String s, String sep) { StringTokenizer st = new StringTokenizer(s, sep); String result[] = new String[st.countTokens()];
for (int i=0; i result[i] = st.nextToken(); } return result; }
// This method is similar to parse() except that the strings are // assumed to be decimal integers. This method coverts these integer // strings into integers and returns them in an array. // The result may have zero length but is never null. int[] parseInt(String s, String sep) { StringTokenizer st = new StringTokenizer(s, sep); int[] result = new int[st.countTokens()];
for (int i=0; i result[i] = Integer.parseInt(st.nextToken()); } return result; }
public void paint(Graphics g) { imageDone = false; update(g); }
g2 = bbuf.getGraphics(); for (int i=0; i drawMenuItem(g2, i); } g2.dispose(); } g.drawImage(bbuf, 0, 0, this); }
void drawMenuItem(Graphics g, int i) { int x, y, w, height; // break the menu item label into lines. String[] line = parse(item[curMenu][i], getParameter("newline"));
int hi = 0; if (i == curMenuItem) { hi = 1; getAppletContext().showStatus(itemUrl[curMenu][i]); } g.setColor(bgMenuColor[hi]); g.fillRect(menuItemRect[i].x, menuItemRect[i].y, menuItemRect[i].width, menuItemRect[i].height);
// set color for text and box g.setColor(fgMenuColor[hi]);
// draw box around menu item. g.drawRect(menuItemRect[i].x, menuItemRect[i].y, menuItemRect[i].width, menuItemRect[i].height);
// draw label g.setFont(f); y = menuItemRect[i].y + marginV; for (i=0; i g.drawString(line[i], menuItemRect[i].x+menuItemRect[i].width-fm.stringWidth(line[i]) -marginH, y + fm.getAscent()); y += fm.getHeight(); } }
public boolean mouseExit(Event evt, int x, int y) { curMenuItem = curMenu = -1; repaint(); return true; }
public boolean mouseEnter(Event evt, int x, int y) { return mouseMove(evt, x, y); }
public boolean mouseDown(Event evt, int x, int y) { try { String u = null;
if (curMenuItem >= 0 && itemUrl[curMenu].length > 0) { u = itemUrl[curMenu][curMenuItem]; } else if (curMenu >= 0) { u = url[curMenu]; } if (u != null) { URL url = new URL (getDocumentBase(), u);
// Add one extra pixel for the left edge. maxWidth += 2 * marginH + 1; if (down[m]) { y = Math.max(0, Math.min(size().height-maxHeight-1, dstPt[curMenu].y + srcRect[curMenu].height-1)); } else { y = Math.max(0, Math.min(size().height-maxHeight-1, dstPt[curMenu].y - maxHeight)); } x = dstPt[curMenu].x + srcRect[curMenu].width-maxWidth-1; for (int i=0; i menuItemRect[i].x = x; menuItemRect[i].y = y; menuItemRect[i].width = maxWidth; y += menuItemRect[i].height; } getAppletContext().showStatus(url[curMenu]); } } repaint(); } return true; }
// Returns the index of the rectangle in rs containing x and y. // Returns -1 if either rs is null or x and y is not in rs. int inMenu(Rectangle[] rs, int x, int y) { if (rs != null) { for (int i=0; i if (rs[i].inside(x, y)) { return i; } } } return -1; } }