Back to Applets page
Click in the boxes below, select all and copy to grab the applet
HTML listing:
<HTML> <HEAD> <TITLE>XEO MENU</TITLE> </HEAD> <BODY BGCOLOR=WHITE> <APPLET CODEBASE="." CODE="XeoMenu" WIDTH=160 HEIGHT=364> <PARAM NAME=bg-color value="255 255 255"> <PARAM NAME=image VALUE="menu.gif"> <PARAM NAME=separator VALUE="|"> <PARAM NAMe=newline VALUE="^"> <PARAM NAME=font VALUE="Helvetica"> <PARAM NAME=font-height VALUE="14"> <PARAM NAME=marginh VALUE=2> <PARAM NAME=marginv VALUE=2> <param name=fg-menu-color value="0 0 0"> <param name=bg-menu-color value="255 255 255"> <param name=fg-hi-menu-color value="0 0 0"> <param name=bg-hi-menu-color value="150 150 150"> <PARAM NAME=menu0 VALUE="0 0 150 24|150 0 150 24|0 0|d|chap01.html|Cans & Can'ts|chap011.html|Secure Sandbox|chap012.html"> <PARAM NAME=menu1 VALUE="0 24 150 24|150 24 150 24|0 24|d|chap02.html|OO|chap021.html|Applet|chap022.html|Glossary|chap023.html"> <PARAM NAME=menu2 VALUE="0 53 150 34|150 53 150 34|0 53|d|chap03.html|Calling Java|chap031.html|Displaying HTML|chap023.html|Placing Applets|chap033.html|Passing Params|chap034.html"> <PARAM NAME=menu3 VALUE="0 86 150 24|150 86 150 24|0 86|d|chap04.html|Hello World!|chap041.html|Changing^Font Face|chap042.html|Setting back-^ground color|chap043.html|HTML to Java|chap044.html|Adding comments|chap045.html|Font styles|chap046.html|Font colors|chap047.html"> <PARAM NAME=menu4 VALUE="0 111 150 24|150 111 150 24|0 111|d|chap05.html|Declaring^variables|chap051.html|Strings|chap052.html|Variable scope|chap053.html|String methods|chap054.html|Numbers|chap055.html|String^conversions|chap056.html|Numeric^conversions|chap057.html|Conversion^by casting|chap058.html|Arrays|chap059.html"> <PARAM NAME=menu5 VALUE="0 139 150 30|150 139 150 30|0 139|d|chap06.html|If/then|chap061.html|If/then/else|chap062.html|For loops|chap063.html|While loops|chap064.html|Do/while loops|chap065.html|Break &^Continue|chap066.html|Switch/Case|chap067.html"> <PARAM NAME=menu6 VALUE="0 175 150 30|150 175 150 30|0 175|u|chap07.html|Drawing lines|chap071.html|2 Dimensions|chap072.html|Freehand drawing|chap073.html|Capturing keys|chap074.html|Arrow keys|chap075.html|Varying speed|chap076.html"> <PARAM NAME=menu7 VALUE="0 209 150 24|150 209 150 24|0 209|d|chap08.html|Password^protection|chap081.html|Text fields|chap082.html|Checkboxes|chap083.html|Radio buttons|chap084.html|Pulldown menus|chap085.html|On-the-fly menus|chap086.html|Text areas|chap087.html|Lists|chap088.html"> <PARAM NAME=menu8 VALUE="0 236 150 24|150 236 150 24|0 236|d|chap09.html|No Layout|chap091.html|FlowLayout|chap092.html|More FlowLayout|chap093.html|Border Layout|chap094.html|Grid Layout|chap095.html|Insets|chap096.html|Panels|chap097.html|CardLayout|chap098.html|GridBagLayout|chap099.html"> <PARAM NAME=menu9 VALUE="0 264 150 30|150 264 150 30|0 264|d|chap10.html|Java animation|chap101.html|Threading|chap102.html|Double-buffering|chap103.html"> <PARAM NAME=menu10 VALUE="0 296 150 30|150 296 150 30|0 296|d|chap11.html|Checking on Java|chap111.html|Public Java methods|chap112.html|JavaScript to Java|chap113.html|Using Java methods|chap114.html"> <PARAM NAME=menu11 VALUE="0 325 150 30|150 325 150 30|0 325|d|chap12.html|Tic-Tac-Toe|chap12.html|Calculator|chap13.html|Hierarchical^Menu|chap14.html"> </APPLET> </BODY> </HTML>
Applet listing:
/* Copyright: Sun Microsystems 1997. All rights reserved. Author: Patrick Chan (www.xeo.com) 7/19/96 Version: 1.1 */ import java.applet.*; import java.awt.*; import java.util.*; import java.net.*; 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 highlighted // 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; public void init() { int[] ints; // Grab applet parameters. image = getImage(getCodeBase(), getParameter("image")); marginH = Integer.parseInt(getParameter("marginh")); marginV = Integer.parseInt(getParameter("marginv")); // 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<hitArea.length; i++) { String[] fields = parse(getParameter("menu"+i), getParameter("separator")); // 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].length; 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.length; 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.length; i++) { result[i] = Integer.parseInt(st.nextToken()); } return result; } public void paint(Graphics g) { imageDone = false; update(g); } public void update(Graphics g) { Graphics g2; if (!imageDone) { imageDone = g.drawImage(image, 0, 0, this); return; } bbufG.setColor(bgColor); bbufG.fillRect(0, 0, size().width, size().height); bbufG.drawImage(image, 0, 0, this); if (curMenu >= 0) { g2 = bbuf.getGraphics(); // Paint the overlay image g2.clipRect(dstPt[curMenu].x, dstPt[curMenu].y, srcRect[curMenu].width, srcRect[curMenu].height); g2.drawImage(image, dstPt[curMenu].x-srcRect[curMenu].x, dstPt[curMenu].y-srcRect[curMenu].y, this); g2.dispose(); g2 = bbuf.getGraphics(); for (int i=0; i<menuItemRect.length; 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<line.length; 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); if (getParameter("target") != null) { getAppletContext().showDocument(url, getParameter("target")); } else { getAppletContext().showDocument(url); } } } catch (Exception e) { e.printStackTrace(); } return true; } public boolean mouseMove(Event evt, int x, int y) { if (curMenu >= 0) { int sm = inMenu(menuItemRect, x, y); if (curMenuItem != sm) { curMenuItem = sm; repaint(); } if (sm >= 0) { return true; } curMenu = -1; } int m = inMenu(hitArea, x, y); if (m != curMenu) { curMenu = m; // A new menu is now active so compute menuItemRect. if (m >= 0) { // Minimum width int maxWidth = 50; int maxHeight = 0; menuItemRect = new Rectangle[item[curMenu].length]; for (int i=0; i<menuItemRect.length; i++) { String[] line = parse(item[curMenu][i], getParameter("newline")); for (int j=0; j<line.length; j++) { int w = fm.stringWidth(line[j]); if (w > maxWidth) { maxWidth = w; } } menuItemRect[i] = new Rectangle(); menuItemRect[i].height = parse(item[curMenu][i], getParameter("newline")).length * fm.getHeight() + 2 * marginV; maxHeight += menuItemRect[i].height; } // 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<item[curMenu].length; 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<rs.length; i++) { if (rs[i].inside(x, y)) { return i; } } } return -1; } }