import java.awt.*; import java.applet.*; /** * The ControlPanel contains the buttons etc that allow the user to * change the group, current color, etc. */ class ControlPanel extends Panel implements Constants { Kali kali; String[] colorNames = { "black", "red", "yellow", "green", "lightBlue", "Blue" }; Color[] colors = { Color.black, Color.red, Color.yellow, Color.green, new Color(173, 216, 230), // light blue Color.blue }; int currentColor; int currentGroup; String wallpaperString = "Wallpaper Groups"; String friezeString = "Frieze Groups"; String rosetteString = "Rosette Groups"; DrawPanel drawPanel; Panorama panorama; ImageButton[] groupButton = new ImageButton[SymmetryGroups.getCount()]; ImageButton[] colorButton = new ImageButton[6]; Panel groupPanel; Panel wallpaperPanel; Panel friezePanel; Panel rosettePanel; GridBagLayout gridbag = new GridBagLayout(); public void setGroupType(int i) { groupPanel.removeAll(); GridBagConstraints c = new GridBagConstraints(); c.gridwidth = GridBagConstraints.REMAINDER; switch (i) { case GROUPTYPE_WALLPAPER: gridbag.setConstraints(wallpaperPanel, c); groupPanel.add(wallpaperPanel); break; case GROUPTYPE_FRIEZE: gridbag.setConstraints(friezePanel, c); groupPanel.add(friezePanel); break; case GROUPTYPE_ROSETTE: gridbag.setConstraints(rosettePanel, c); groupPanel.add(rosettePanel); break; } groupPanel.validate(); this.validate(); } /** * Create a new control panel object. * @param kali The Kali object for this applet * @param drawPanel The DrawPanel object for this applet * @param panorama The Panorama object for this applet */ public ControlPanel(Kali kali, DrawPanel drawPanel, Panorama panorama) { this.kali = kali; this.drawPanel = drawPanel; this.panorama = panorama; setBackground(Color.lightGray); int buttonRowCount = 7; int buttonsPerRow = 6; // NOTE: the button bitmaps are stored in a rectangular image // with 2*buttonRowCount rows and buttonsPerRow columns. The // first buttonRowCount rows contain the "up" state images, // and the second buttonRowCount rows contain the "down" state // images, in the same order. We load this image from the // server here, and chop it up into the individual buttons // below. Image bigimage = kali.getImageNow("buttons.gif"); Image upImage, downImage; int w = 32, h = 32; Graphics g; int row = 0; int col = 0; Label label; GridBagConstraints c; setLayout(gridbag); Font groupLabelFont = new Font("TimesRoman",Font.BOLD,18); Font buttonLabelFont = new Font("TimesRoman",Font.PLAIN,12); // // First create all the widgets and subpanels // // // Create the group buttons; each button gets put into // its own little panel (the bPanel array) together with // its label. It's in this loop where we chop up the big // image into individual ones for the buttons. // ImageButtonGroup groupButtons = new ImageButtonGroup(); Panel[] bPanel = new Panel[groupButton.length]; c = new GridBagConstraints(); c.gridwidth = GridBagConstraints.REMAINDER; for (int i=0; i<36; ++i) { upImage = kali.createImage(w, h); g = upImage.getGraphics(); g.drawImage(bigimage, -col*w, -row*h, kali); downImage = kali.createImage(w, h); g = downImage.getGraphics(); g.drawImage(bigimage, -col*w, -(row+buttonRowCount)*h, kali); groupButton[i] = new ImageButton(upImage, downImage, groupButtons); bPanel[i] = new Panel(); bPanel[i].setLayout(gridbag); gridbag.setConstraints(groupButton[i], c); bPanel[i].add(groupButton[i]); label = new Label(SymmetryGroups.group[i].name); label.setAlignment(Label.CENTER); label.setFont(buttonLabelFont); gridbag.setConstraints(label, c); bPanel[i].add(label); ++col; if (col >= buttonsPerRow) { col = 0; ++row; } } currentGroup = 0; groupButtons.setCurrent(groupButton[currentGroup]); // // Create the color buttons // ImageButtonGroup colorButtons = new ImageButtonGroup(); for (int i=0; i<6; ++i) { upImage = kali.createImage(w, h); g = upImage.getGraphics(); g.drawImage(bigimage, -col*w, -row*h, kali); downImage = kali.createImage(w, h); g = downImage.getGraphics(); g.drawImage(bigimage, -col*w, -(row+buttonRowCount)*h, kali); colorButton[i] = new ImageButton(upImage, downImage, colorButtons); ++col; if (col >= buttonsPerRow) { col = 0; ++row; } } currentColor = 0; colorButtons.setCurrent(colorButton[currentColor]); drawPanel.setForeground(colors[currentColor]); // // Create the color panel and layout the color // buttons in it. // Panel colorPanel = new Panel(); { colorPanel.setLayout(new GridLayout(1,6)); for (int i=0; i<6; ++i) { colorPanel.add(colorButton[i]); } } Label colorLabel = new Label("Colors"); colorLabel.setFont(groupLabelFont); // // Create the group type chooser widget // Choice groupChooser = new Choice(); groupChooser.setFont(groupLabelFont); groupChooser.addItem(wallpaperString); groupChooser.addItem(friezeString); groupChooser.addItem(rosetteString); // // Create the wallpaper button panel and layout // its buttons. // c = new GridBagConstraints(); wallpaperPanel = new Panel(); { Panel first16 = new Panel(); first16.setLayout(new GridLayout(4, 4)); for (int i=0; i<16; ++i) { first16.add(bPanel[i]); } c.gridwidth = GridBagConstraints.REMAINDER; wallpaperPanel.setLayout(gridbag); gridbag.setConstraints(first16, c); wallpaperPanel.add(first16); gridbag.setConstraints(bPanel[16], c); wallpaperPanel.add(bPanel[16]); // 17th button on last row by itself } // // Create the frieze button panel and layout // its buttons. // c = new GridBagConstraints(); friezePanel = new Panel(); { Panel first6 = new Panel(); first6.setLayout(new GridLayout(2, 3)); for (int i=17; i<23; ++i) { first6.add(bPanel[i]); } c.gridwidth = GridBagConstraints.REMAINDER; friezePanel.setLayout(gridbag); gridbag.setConstraints(first6, c); friezePanel.add(first6); gridbag.setConstraints(bPanel[23], c); friezePanel.add(bPanel[23]); // 7th button on last row by itself } friezePanel.invalidate(); friezePanel.validate(); // // Create the rosette button panel and layout // its buttons. // rosettePanel = new Panel(); { rosettePanel.setLayout(new GridLayout(2, 6)); for (int i=24; i<36; ++i) { rosettePanel.add(bPanel[i]); } } // // Create the general group button panel; this is a // placeholder panel into which we insert one of the actual // group panels (wallpaper, frieze, or rosette) later. // groupPanel = new GrowPanel(); // // Now layout the above items in the control panel // // color label: c = new GridBagConstraints(); c.gridwidth = GridBagConstraints.REMAINDER; c.insets = new Insets(0,5,0,5); // top,left,bottom,right gridbag.setConstraints(colorLabel, c); add(colorLabel); // color panel gridbag.setConstraints(colorPanel, c); add(colorPanel); // group chooser widget Insets oldInsets = c.insets; c.insets = new Insets(40,5,15,5); // top,left,bottom,right gridbag.setConstraints(groupChooser, c); add(groupChooser); c.insets = oldInsets; // group panel gridbag.setConstraints(groupPanel, c); add(groupPanel); // padding panel --- a panel with nothing in it, whose sole // purpose is to take up the extra space at the bottom Panel padPanel = new Panel(); c.gridheight = GridBagConstraints.REMAINDER; c.weighty = 1.0; c.weightx = 1.0; c.fill = GridBagConstraints.BOTH; gridbag.setConstraints(padPanel, c); add(padPanel); // // And finally, set the initial group type // setGroupType(GROUPTYPE_WALLPAPER); } // public void paint(Graphics g) { // Rectangle r = bounds(); // g.setColor(Color.lightGray); // g.draw3DRect(0, 0, r.width, r.height, true); // } /** * Given a ImageButton id, return the group index for the * corresponding group. (This makes use of the fact that the * group indices are consecutive integers starting with 0, in the * same order as the buttons.) */ private int findGroup(ImageButton button) { for (int i=0; i=0) { currentGroup = i; panorama.setGroup(i); drawPanel.clear(); drawPanel.repaint(); } else { i = findColor(button); if (i>=0) { currentColor = i; drawPanel.setForeground(colors[currentColor]); } else { System.out.println("unknown image button pressed"); } } } return true; } } /** * The GrowPanel object is somewhat of a kludge (OK, it's totally a * kludge). The idea is that I want to force the groupPanel, which is * the subpanel of the ControlPanel which contains the group buttons, * to have a fixed size, so that it doesn't change size (and hence * cause the entire ControlPanel's layout to change) when the * particular group button panel (wallpaper/frieze/rosette) that it * contains changes. So, in theory, I'd like a way of telling the * layout manager to force the groupPanel to have a certain size, and * that size should be computed at run-time to be the max size of the * 3 group button panels. In practice, however, I cannot figure out * how to compute the actual sizes of these (or any) panels until they * are actually painted to the screen. SO, the kludge is to use a * Panel whose size (as returned by its preferredSize() and * minimumSize() methods) is always the max of its previous size and * its current size. Then, as long as we start out with the largest * of the 3 possibilities (wallpaper), things should be OK. * *

* If you know of a better way to do this * * let me know! */ class GrowPanel extends Panel { /** * This holds the previous size. */ Dimension size = new Dimension(0,0); public Dimension preferredSize() { // We call the superclass preferredSize() method to compute the // "current" size. Dimension s = super.preferredSize(); size.width = Math.max(size.width,s.width); size.height = Math.max(size.height,s.height); return size; } public Dimension minimumSize() { return preferredSize(); } }