/************************************************************** * This is the main GUI JFrame for the Mandelbrot explorer. **************************************************************/ import java.awt.BorderLayout; import java.awt.GridLayout; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.event.ActionListener; import java.awt.event.ComponentListener; import java.awt.event.ComponentEvent; import java.awt.event.MouseEvent; import java.awt.event.ActionEvent; import java.net.URL; import java.text.DecimalFormat; import javax.swing.*; import javax.swing.border.*; import javax.swing.event.*; public class MandelFrame extends JFrame implements ActionListener, ComponentListener { // flag to determine when gui initialization is completed private boolean isInitialized = false; // pathname where applet was started private URL codeBase; // filename of color map private ColorMap colorMap = new ColorMap(); // timer for updating display (default = every 100ms) private javax.swing.Timer timer = new javax.swing.Timer(100, this); // Mandelbrot region private DoubleSquare square = new DoubleSquare(-1.5, -1.0, 2.0); private int dwell = 256; private MandelPanel displayPanel; // status field private JTextField statusTextField = new JTextField(""); // square selection private JLabel xLabel = new JLabel("x "); private JLabel yLabel = new JLabel("y "); private JLabel sizeLabel = new JLabel("size "); private JTextField xTextField = new JTextField(12); private JTextField yTextField = new JTextField(12); private JTextField sizeTextField = new JTextField(12); // constructor public MandelFrame(URL codeBase) { super("Mandelbrot Explorer"); this.codeBase = codeBase; colorMap = new ColorMap(getURL("default.map")); // init the size and layout of this frame setSize(805, 678); setLayout(new BorderLayout()); /****************************************** * South Panel ******************************************/ statusTextField.setEditable(false); statusTextField.setBorder(BorderFactory.createLoweredBevelBorder()); add(statusTextField, BorderLayout.SOUTH); /****************************************** * East Panel ******************************************/ Box eastBox = new Box(BoxLayout.Y_AXIS); // dwell slider final JSlider dwellSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 4096, 512); dwellSlider.setToolTipText("Adjust dwell"); TitledBorder tb = new TitledBorder(new EtchedBorder()); tb.setTitle("Dwell = " + dwellSlider.getValue()); dwellSlider.setBorder(tb); dwellSlider.setPreferredSize(new Dimension(80, 46)); dwellSlider.addChangeListener( new ChangeListener() { public void stateChanged(ChangeEvent e) { TitledBorder border = (TitledBorder) dwellSlider.getBorder(); border.setTitle("Dwell = " + dwellSlider.getValue()); dwell = dwellSlider.getValue(); dwellSlider.repaint(); displayPanel.setDwell(dwell); } } ); // square coordinate panel JPanel coordinatePanel = new JPanel(new BorderLayout()); JPanel coordinateLabels = new JPanel(new GridLayout(4, 0, 0, 5)); JPanel coordinateValues = new JPanel(new GridLayout(4, 0, 0, 5)); TextFieldListener textFieldListener = new TextFieldListener(); xTextField.addActionListener(textFieldListener); yTextField.addActionListener(textFieldListener); sizeTextField.addActionListener(textFieldListener); coordinateLabels.add(xLabel); coordinateLabels.add(yLabel); coordinateLabels.add(sizeLabel); coordinateValues.add(xTextField); coordinateValues.add(yTextField); coordinateValues.add(sizeTextField); setCoordinateText(); coordinatePanel.add(coordinateLabels, BorderLayout.WEST); coordinatePanel.add(coordinateValues, BorderLayout.EAST); // color map chooser String[] dataFiles = { "default.map", "altern.map", "blues.map", "bw.map", "chroma.map", "defaultw.map", "firestrm.map", "gamma1.map", "gamma2.map", "glasses1.map", "glasses2.map", "green.map", "grey.map", "headache.map", "injector.map", "landscap.map", "lyapunov.map", "neon.map", "paintjet.map", "topo.map", "volcano.map", }; final JComboBox fileList = new JComboBox(dataFiles); TitledBorder tbb = new TitledBorder(new EtchedBorder()); tbb.setTitle("Select a colormap"); fileList.setBorder(tbb); fileList.setPreferredSize(new Dimension(140, 50)); fileList.setEditable(true); fileList.setSelectedIndex(0); fileList.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String urlName = (String) fileList.getSelectedItem(); colorMap = new ColorMap(getURL(urlName)); stopAnimation(); startAnimation(); } }); // add all of the componets eastBox.add(fileList); eastBox.add(javax.swing.Box.createVerticalStrut(10)); eastBox.add(dwellSlider); eastBox.add(javax.swing.Box.createVerticalStrut(20)); eastBox.add(coordinatePanel); JPanel eastPanel = new JPanel(new BorderLayout()); eastPanel.add(eastBox, BorderLayout.NORTH); eastPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); add(eastPanel, BorderLayout.EAST); /****************************************** * Main Display Panel ******************************************/ JPanel centerPanel = new JPanel(new BorderLayout()); displayPanel = new MandelPanel(); displayPanel.addComponentListener(this); MouseSelectionListener selectionListener = new MouseSelectionListener(); displayPanel.addMouseListener(selectionListener); displayPanel.addMouseMotionListener(selectionListener); centerPanel.add(displayPanel, BorderLayout.CENTER); // buttonbar stuff JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout(1, 0)); ButtonListener buttonListener = new ButtonListener(); String[] buttonGif = new String[] { "Pause24.gif", "Stop24.gif", "Play24.gif", "ZoomIn24.gif", "ZoomOut24.gif", "Refresh24.gif", "Information24.gif"}; String[] buttonTip = new String[] { "Pause the computation", "Stop the computation", "Begin the computation", "Zoom in 2x", "Zoom out 2x", "Reset to default region", "Applet information"}; String[] buttonAct = new String[] { "pause", "stop", "play", "zoom in", "zoom out", "refresh", "information"}; for (int i = 0; i < buttonGif.length; i++) { JButton b = new JButton(new ImageIcon(getURL(buttonGif[i]))); b.setActionCommand(buttonAct[i]); b.setToolTipText(buttonTip[i]); b.addActionListener(buttonListener); buttonPanel.add(b); } centerPanel.add(buttonPanel, BorderLayout.SOUTH); add(centerPanel, BorderLayout.CENTER); // no more GUI code allowed below here setVisible(true); isInitialized = true; } // read in URL private URL getURL(String filename) { URL url = null; try { url = new URL(codeBase, filename); } catch (Exception e) { System.out.println("Error loading: codebase = " + codeBase + ", " + "filename = " + filename); } return url; } // update x, y, and size private void setCoordinateText() { DecimalFormat decimalFormat = new DecimalFormat("0.0000000000000"); xTextField.setText("" + decimalFormat.format(square.x)); yTextField.setText("" + decimalFormat.format(square.y)); sizeTextField.setText("" + decimalFormat.format(square.size)); } // start the animation thread public void startAnimation() { if (!timer.isRunning()) { displayPanel.setColorMap(colorMap); displayPanel.setDwell(dwell); displayPanel.setSquare(square); displayPanel.start(); timer.start(); setCoordinateText(); } } // stop the animation thread public void stopAnimation() { if (timer.isRunning()) { timer.stop(); } displayPanel.stop(); showStatus("# pixels = " + displayPanel.getCurrentStep()); } // pause the animation thread. public synchronized void pauseAnimation() { if (timer.isRunning()) { timer.stop(); displayPanel.pause(); } else { timer.start(); displayPanel.pause(); } } public void showStatus(String s) { statusTextField.setText(s); } // display Mandelbrot set via Timer public void actionPerformed(ActionEvent e) { if (displayPanel.getCurrentStep() == displayPanel.getTotalSteps()) stopAnimation(); displayPanel.repaint(); showStatus("# pixels = " + displayPanel.getCurrentStep()); } // window resized public void componentResized(ComponentEvent e) { if (isInitialized) { stopAnimation(); startAnimation(); } } public void componentHidden(ComponentEvent e) { } public void componentMoved(ComponentEvent e) { } public void componentShown(ComponentEvent e) { } /******************************************************* * Handle buttons pushed *******************************************************/ private class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { String ac = e.getActionCommand(); if (ac.equals("refresh")) { stopAnimation(); square = new DoubleSquare(-1.5, -1.0, 2.0); startAnimation(); } else if (ac.equals("stop")) { stopAnimation(); } else if (ac.equals("play")) { stopAnimation(); startAnimation(); } else if (ac.equals("pause")) { pauseAnimation(); } else if (ac.equals("zoom out")) { stopAnimation(); square = square.scale(2.0); startAnimation(); } else if (ac.equals("zoom in")) { stopAnimation(); square = square.scale(0.5); startAnimation(); } else if (ac.equals("information")) { JOptionPane.showMessageDialog(null, "Copyright 2001, Kevin Wayne", "About Mandelbrot Explorer", JOptionPane.INFORMATION_MESSAGE); } } } /******************************************************* * Handle text field entries in coordinate panel *******************************************************/ private class TextFieldListener implements ActionListener { public void actionPerformed(ActionEvent e) { try { double x = Double.parseDouble(xTextField.getText()); double y = Double.parseDouble(yTextField.getText()); double size = Double.parseDouble(sizeTextField.getText()); square = new DoubleSquare(x, y, size); stopAnimation(); startAnimation(); } catch (NumberFormatException ex) { showStatus("Illegal coordinate entry."); } } } /******************************************************* * Handle mouse selection of square region to zoom in *******************************************************/ private class MouseSelectionListener extends MouseInputAdapter { private IntPoint p; // initial point selected private IntPoint q; // point where mouse was dragged to private IntSquare currentSquare; public void mousePressed(MouseEvent e) { if (e.getClickCount() == 2) { showStatus("Point = " + displayPanel.toMathCoordinates(new IntPoint(e.getX(), e.getY()))); } else { p = new IntPoint(e.getX(), e.getY()); q = p; currentSquare = new IntSquare(p, p); } } public void mouseDragged(MouseEvent e) { q = new IntPoint(e.getX(), e.getY()); currentSquare = new IntSquare(p, q); displayPanel.setSelectionSquare(currentSquare); displayPanel.repaint(); showStatus("Square: " + displayPanel.toMathCoordinates(currentSquare)); } public void mouseReleased(MouseEvent e) { Rectangle r = displayPanel.getBounds(); if ((currentSquare.size > 0) && r.contains(new Rectangle(currentSquare.x, currentSquare.y, currentSquare.size, currentSquare.size))) { displayPanel.resetSelectionSquare(); square = displayPanel.toMathCoordinates(currentSquare); stopAnimation(); startAnimation(); } else if (e.getClickCount() == 2) { // do nothing } else { showStatus("Square not selected"); displayPanel.resetSelectionSquare(); displayPanel.repaint(); } } } }