/* JitterbugViewer.java History: 08 Jul 08 Update to reflect changes to JitterbugController. 28 Feb 07 Replace deprecated show() with setVisible(). Use nested classes rather than implementing MouseListener and MouseMotionListener interfaces. 05 Aug 06 Add an "Animate" button. Don't bother with MIN_STAGE_INDEX or singleStep() function (it was only called in one place). 03 Aug 06 Convert GUI to Swing. Decrease initial size from 700x700 to 600x600. Handle selection of "Animate" option using ActionListener rather than ItemListener since Swing, which is right since it doesn't represent a change in the JComboBox state, doesn't report reselection of the Animate option to ItemListeners whereas AWT does for the Choice device. Rename ANIMATE_OPTION_LABEL, STEP_OPTION_LABEL and MIN_STAGE_OPTION to ANIMATE_LABEL, STEP_LABEL and MIN_STAGE_INDEX. Add new labels ANIMATE_INDEX and STEP_INDEX. Remove weird event handling logic necessary when programmatic device changes are reported as if they were user changes. 29 May 06 Substitute drag-driven rotation for clunky scrollbar-driven rotation. Eliminate help window. 31 Oct 05 Remove semi-useless magnify facility, move rotate bar south and make y axis default rotation axis. Make axis codes coincide with choice values. 17 Oct 05 Remove M_ prefix from all constants. Encapsulate more stage information in JitterbugController rather than have JitterbugViewer deal with it. 14 Oct 05 JitterbugPicture renamed to JitterbugController. 13 Oct 05 Rename m_X constant X_AXIS. Similarly for m_Y and m_Z. Replace deprecated resize() call with setSize(). Replace deprecated event handlers with listeners of various sorts. Step Button now indirectly steps by setting choice value to "Step" which is now the only place where singleStep() is called. For default case, singleStep() now checks that the selection isn't already "Step" when setting the choice value to "Step". These last two changes are to handle a situation where programmatically set choices now activate the appropriate listeners. This only happens with the Blackdown Linux Java implementation, so I think it's a bug, but I'll cover myself anyway. 16 Sep 05 Add simple help window and i18n (de, en, es, fr). 15 Sep 05 Add JitterbugViewer.main() so this file can supercede JitterbugViewerPgm.java as well as serve as an applet. Rename this file from JitterbugViewerApplet.java to JitterbugViewer.java. Don't declare m_X, m_Y and m_Z as public ("@see m_axis" was messing up javadoc). 24 Mar 99 Added javadoc comments. Changed name of m_dim to m_axis. Centered rotate Scrollbar on 0. 02 Mar 99 Allow acceleration of animation. 01 Mar 99 Allow animation to be stopped and different stages viewed. 23 Feb 99 Created. */ import java.util.*; import java.awt.*; import javax.swing.*; import javax.swing.event.*; import java.awt.event.*; /** GUI for viewing jitterbug animation. @author Bob Burkhardt */ public class JitterbugViewer extends JApplet implements ActionListener, ItemListener { JitterbugController m_controller; JComboBox m_select_stage; JButton m_single_step, m_animate; ResourceBundle m_vocabulary; /** Initial dimension of viewing square for stand-alone app. */ static final int INITIAL_DIM = 600; /** Indicate whether left-mouse-button drag is in progress. MOUSE_PRESSED indicates drag in progress; otherwise, MOUSE_RELEASED. */ int m_drag = MouseEvent.MOUSE_RELEASED; public void init() { m_vocabulary = ResourceBundle.getBundle("Vocabulary"); getContentPane().setLayout(new BorderLayout()); JPanel p = new JPanel(); p.setLayout(new FlowLayout()); m_animate = new JButton(m_vocabulary.getString(ANIMATE_LABEL)); m_animate.addActionListener(this); p.add(m_animate); m_select_stage = new JComboBox(); m_select_stage.addItem(m_vocabulary.getString(ANIMATE_LABEL)); m_select_stage.addItem(m_vocabulary.getString(STEP_LABEL)); for (int i = JitterbugModel.DEFAULT_STAGE + 1; i <= JitterbugModel.MAX_STAGE; i++) { String label = JitterbugModel.getStageLabel(i); m_select_stage.addItem(m_vocabulary.getString(label)); } m_select_stage.addItemListener(this); m_select_stage.addActionListener(this); p.add(m_select_stage); m_single_step = new JButton(m_vocabulary.getString(STEP_LABEL)); m_single_step.addActionListener(this); p.add(m_single_step); getContentPane().add("North", p); m_controller = new JitterbugController(); m_controller.addMouseListener(m_mouseListener); m_controller.addMouseMotionListener(m_mouseMotionListener); getContentPane().add("Center", m_controller); m_controller.resetRotation(); } public static void main(String[] args) { JFrame f = new JFrame("Jitterbug"); JitterbugViewer jitterbug = new JitterbugViewer(); jitterbug.init(); f.getContentPane().add(jitterbug); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setSize(INITIAL_DIM, INITIAL_DIM); f.setVisible(true); } /** Handle JComboBox stage selections (Animate and Step handled elsewhere). */ public void itemStateChanged(ItemEvent evt) { if (evt.getSource() == m_select_stage) { int choice = m_select_stage.getSelectedIndex(); if (choice > STEP_INDEX) { m_controller.suspend(); m_controller.setStage(JitterbugModel.DEFAULT_STAGE + (choice - STEP_INDEX)); } } } /** Handle JButton events and JComboBox Animate and Step selections. */ public void actionPerformed(ActionEvent evt) { if (evt.getSource() == m_select_stage) { // Step and Animate selections from JComboBox are handled here // so that repeated selections of the same item can be handled int choice = m_select_stage.getSelectedIndex(); if (choice == ANIMATE_INDEX) { if (m_controller.isSuspended()) m_controller.resume(); else m_controller.accelerate(); } else if (choice == STEP_INDEX) { m_controller.suspend(); m_controller.step(); m_select_stage.setSelectedIndex (STEP_INDEX + (m_controller.getStage() - JitterbugModel.DEFAULT_STAGE)); } } else if (evt.getSource() == m_single_step) { // refer button presses to handler for selections m_select_stage.setSelectedIndex(STEP_INDEX); } else if (evt.getSource() == m_animate) { // refer button presses to handler for selections m_select_stage.setSelectedIndex(ANIMATE_INDEX); } } /** Mouse listener code to start and stop user bug rotations via the mouse. */ MouseAdapter m_mouseListener = new MouseAdapter() { /** Watch for presses of the left mouse button, and update state accordingly (part of MouseListener interface). */ public void mousePressed(MouseEvent evt) { if (evt.getButton() == MouseEvent.BUTTON1) { m_drag = MouseEvent.MOUSE_PRESSED; m_controller.startRotation(evt.getX(), evt.getY()); } } /** Watch for presses of the left mouse button, and update state accordingly (part of MouseListener interface). */ public void mouseReleased(MouseEvent evt) { if (evt.getButton() == MouseEvent.BUTTON1) m_drag = MouseEvent.MOUSE_RELEASED; } }; /** Mouse motion listener code to carry out user bug rotations via the mouse. */ MouseMotionAdapter m_mouseMotionListener = new MouseMotionAdapter() { /** Watch for mouse movements and adjust rotation accordingly (part of MouseMotionListener interface). */ public void mouseDragged(MouseEvent evt) { if (m_drag == MouseEvent.MOUSE_PRESSED) m_controller.updateRotation(evt.getX(), evt.getY()); } }; /** Label for animate option. */ final static String ANIMATE_LABEL = "Animate"; /** JComboBox index for animate option. */ final static int ANIMATE_INDEX = 0; /** Label for step option. */ final static String STEP_LABEL = "Step"; /** JComboBox index for step option. */ final static int STEP_INDEX = 1; }