/** * @file Draw3d.java * @author R Daniel Bergeron * @see DrawCanvas.java *

* This java program shows how to create a simple program that can be used * either as an applet or application and contains a Canvas for use in simple * graphics drawing. In this case, we put an applet into an ApplicFrame, then * put the canvas and a button panel into the applet. If the program is run * as an applet, we just put the canvas and buttonPanel into the applet. *

* modified by Robert S Laramee * modification date Thursday 12 Nov 98 * A new AutoRotate Menu was added * modification date Tuesday 17 Nov 98 * The Edit Mode Menu was modified to include 2 different * drawing modes: Normal (3D) and Solid Object (2D) * modification date Saturday 21 Nov 98 * A method addUserShape() was added to add user defined * solid object shapes to the shape menu * Also, a method was added to return a reference to this * application class (myApp) * modification date Wednesday 21 Nov 98 * A File menu was added. Every application needs a file * menu. * modification date Thursday 10 Dec 98 * All menus were changed to JMenus (Swing) * buidMenus() method modified to use JMenus (Swing) * Menu --> JMenu * MenuItem --> JMenuItem * Slider --> JSlider * Panel --> JPanel */ import java.applet.Applet; import java.awt.*; // needed for both Applet and Application import java.awt.event.*; import java.util.*; import javax.swing.*; /** * Swing3d class is the main class for the program */ public class Swing3d extends Applet { public static Swing3d myApp; private static boolean runAsApplet=true; // set if run as applet private static ApplicFrame appFrame; // frame if run as applic private static JMenuBar appMenuBar; private static JMenu appMenus[]; // array of applic menus private static JPopupMenu popup; private static JMenu shapeMenu; private JSlider zFrontSlider; // sliders for interaction private JSlider zBackSlider; private JSlider xRotSlider; private JSlider yRotSlider; private JSlider zRotSlider; private static DrawCanvas canvas; // used for drawing private JPanel buttonPanel; // collects color buttons public static void main(String args[]) { runAsApplet = false; myApp = new Swing3d(); appFrame = new ApplicFrame("Draw Application", myApp); myApp.buildMenus(); myApp.buildSliders(appFrame); appFrame.getContentPane().add (canvas, BorderLayout.CENTER ); appFrame.setJMenuBar( appMenuBar ); // setJMenuBar()! appFrame.setSize(500, 500); // define window size appFrame.show(); // Tell window mgr to display window } /** Applet methods * Normally init, start, stop, and destroy are overridden. * We'll also need to override showStatus. * --- init */ public void init() { setLayout (new BorderLayout()); } /** --- start * Note: when run as an application, this is executed as part of the * constructor for the ApplicFrame. Hence, the static variables set * in the main function have not been initialized yet, esp. appFrame. */ public void start() { canvas = new DrawCanvas (); canvas.setBackground( Color.blue ); canvas.setSize(500,500); } //--- stop ---------------------------------------------------- public void stop() { remove(canvas); } //--- destroy ------------------------------------------------- public void destroy() { } //--- showStatus ---------------------------------------------- // showStatus has to be overridden since the Status window is // created by the browser/appletviewer, so if run as an application // a call to showStatus would fail. Here we simply output a status // message to standard out. public void showStatus(String s) { if ( runAsApplet ) // we're an applet super.showStatus(s); else System.out.println("Status: " + s); } /** * buildSliders * Build the sliders (scrollbars) for zFront, zBack, and x,y,z * rotations. For now this is just going to be very ugly -- just build * them all in a row at the bottom. * * Slider --> JSlider */ void buildSliders(ApplicFrame frame ) { // define all 5 sliders zFrontSlider = new JSlider("zFront",JScrollBar.HORIZONTAL, 0, -1, 0 ); zBackSlider = new JSlider("zBack", JScrollBar.HORIZONTAL, 0, -1, -1 ); xRotSlider = new JSlider("X", JScrollBar.VERTICAL, -180, 180, 0 ); yRotSlider = new JSlider("Y", JScrollBar.HORIZONTAL, -180, 180, 0 ); zRotSlider = new JSlider("Z", JScrollBar.VERTICAL, -180, 180, 0 ); /** * These are some unnamed inner classes: */ FloatListener zFrontListener = new FloatListener () { public void valueChanged( float f ) { zFront(f); } }; zFrontSlider.addFloatListener( zFrontListener ); FloatListener zBackListener = new FloatListener () { public void valueChanged( float f ) { zBack(f); } }; zBackSlider.addFloatListener( zBackListener ); FloatListener xRotateListener = new FloatListener () { public void valueChanged( float f ) { xRotate(f); } public void reset() { xRotateReset(); } }; xRotSlider.addFloatListener( xRotateListener ); FloatListener yRotateListener = new FloatListener () { public void valueChanged( float f ) { yRotate(f); } public void reset() { yRotateReset(); } }; yRotSlider.addFloatListener( yRotateListener ); FloatListener zRotateListener = new FloatListener () { public void valueChanged( float f ) { zRotate(f); } public void reset() { zRotateReset(); } }; zRotSlider.addFloatListener( zRotateListener ); /** * Panel --> JPanel * We'll put 2 z-sliders into one panel that will go North. */ JPanel northPanel = new JPanel(); northPanel.setLayout( new GridLayout(1,2)); northPanel.add( zFrontSlider ); northPanel.add( zBackSlider ); frame.getContentPane().add(northPanel, BorderLayout.NORTH); // The Xrotation panel goes West, Yrotation South and Zrotation East JPanel southPanel = new JPanel(); southPanel.setLayout( new GridLayout(1,1)); southPanel.add( yRotSlider ); frame.getContentPane().add (southPanel, BorderLayout.SOUTH); JPanel eastPanel = new JPanel(); eastPanel.setLayout( new GridLayout(1,1)); eastPanel.add( zRotSlider ); frame.getContentPane().add (eastPanel, BorderLayout.EAST); JPanel westPanel = new JPanel(); westPanel.setLayout( new GridLayout(1,1)); westPanel.add( xRotSlider ); frame.getContentPane().add (westPanel, BorderLayout.WEST); } /** * buildMenus() was modified to use JMenus (Swing) instead * Menu --> JMenu * MenuItem --> JMenuItem * PopupMenu --> JPopupMenu * uses the setDefaultLightWeightPopupEnabled() method to ensure the * menu is never lightweight. */ void buildMenus( ) { JPopupMenu.setDefaultLightWeightPopupEnabled(false); int i; final int menuCount = 6; // file, edit, color, shape, fill, autorotate appMenus = new JMenu[ menuCount ]; appMenus[0] = buildFileMenu(); appMenus[1] = buildEditMenu(); appMenus[2] = buildColorMenu(); appMenus[3] = buildShapeMenu(); appMenus[4] = buildFillModeMenu(); appMenus[5] = buildAutoRotateMenu(); // added if ( runAsApplet ) // then we're an applet, make popup menu { popup = new JPopupMenu( "MenuBar" ); for ( i=0; i < appMenus.length; i++ ) popup.add( appMenus[i] ); canvas.addPopup( popup ); // tell my canvas that it has popup } else { // we're an application put menus into menu bar appMenuBar = new JMenuBar(); for ( i=0; i < appMenus.length; i++ ) appMenuBar.add( appMenus[i] ); } } /** * build the shape menu was modified. The HOUSE option was removed and * now solid object shapes are added dynamically * Menu --> JMenu * MenuItem --> JMenuItem * @return JMenu */ public JMenu buildShapeMenu( ) { int i,j; int numItems; // # menu items String shapeNames[] = { "Cube", "Tetrahedron" }; int shapes[] = { DrawCanvas.CUBE, DrawCanvas.TETRA, DrawCanvas.SOLID }; JMenuItem shapeItems[]; shapeMenu = new JMenu ( "Shapes" ); numItems = shapeNames.length; shapeItems = new JMenuItem[ numItems ]; for ( i=0; i < numItems; i++ ) { shapeItems[ i ] = new JMenuItem( shapeNames[ i ] ); shapeMenu.add( shapeItems[ i ]); shapeItems[ i ].addActionListener( new DrawCanvas.SetShapeAL (canvas, shapes[ i ], null )); } return shapeMenu; } /** * This was added so The Solid Object class could call the addUserShape() * method. We want the shape menu to add an item whenever a solid shape * definition is drawn. It is kind of a hack (not very graceful). */ public static Swing3d getApp() { return myApp; } /** * addUserShape adds a user defined shape to the shape menu * This is called from the Solid Object and InSerialize classes. * Menu --> JMenu * MenuItem --> JMenuItem * getLabel() --> getText() * @param name -the name of the new shape */ public void addUserShape(String name) { // don't add a name that's already there for (int i = 0; i < shapeMenu.getItemCount(); i++) { if (shapeMenu.getItem(i).getText().equals(name)) { System.out.println("** Warning: shape: " + name + " already in menu."); return; } } JMenuItem newItem = new JMenuItem(name); shapeMenu.add( newItem ); newItem.addActionListener( new DrawCanvas.SetShapeAL (canvas, DrawCanvas.SOLID, name)); } /** * build the file menu * Menu --> JMenu * MenuItem --> JMenuItem * @return JMenu */ private JMenu buildFileMenu( ) { int i; String fileNames[] = { "Open ", "Save ", "Quit "}; int fileModes[] = { DrawCanvas.OPEN, DrawCanvas.SAVE, DrawCanvas.QUIT }; JMenuItem fileItems[]; JMenu fileMenu = new JMenu ( "File" ); fileItems = new JMenuItem[ fileNames.length ]; for ( i=0; i < fileNames.length; i++ ) { fileItems[ i ] = new JMenuItem( fileNames[ i ] ); fileMenu.add( fileItems[ i ]); fileItems[ i ].addActionListener( new DrawCanvas.SetFileModeAL (canvas, fileModes[ i ] )); } return fileMenu; } /** * build the Edit menu * Menu --> JMenu * MenuItem --> JMenuItem * @return JMenu */ private JMenu buildEditMenu( ) { int i; String editNames[] = { "Normal Drawing Mode (3D)", "New Solid Object (2D)", "Delete One Object", "Erase All", "Reset View" }; int editModes[] = { DrawCanvas.DRAWNORMAL, DrawCanvas.DRAWSOLID, DrawCanvas.DELETE_ONE, DrawCanvas.ERASE, DrawCanvas.RESETVIEW }; JMenuItem editItems[]; JMenu editMenu = new JMenu ( "Edit" ); editItems = new JMenuItem[ editNames.length ]; for ( i=0; i < editNames.length; i++ ) { editItems[ i ] = new JMenuItem( editNames[ i ] ); editMenu.add( editItems[ i ]); editItems[ i ].addActionListener( new DrawCanvas.SetEditModeAL (canvas, editModes[ i ] )); } return editMenu; } /** * build the Color menu * Menu --> JMenu * MenuItem --> JMenuItem * @return JMenu */ private JMenu buildColorMenu( ) { int i; String colorNames[] = { "White", "Cyan", "Yellow", "Blue", "Red", "Green" }; Color colors[] = { Color.white, Color.cyan, Color.yellow, Color.blue, Color.red, Color.green }; JMenuItem colorItems[]; JMenu colorMenu = new JMenu ( "Color" ); colorItems = new JMenuItem[ colorNames.length ]; for ( i=0; i < colorNames.length; i++ ) { colorItems[ i ] = new JMenuItem( colorNames[ i ] ); colorMenu.add( colorItems[ i ]); colorItems[ i ].addActionListener( new DrawCanvas.SetColorAL (canvas, colors[ i ] )); } return colorMenu; } /** * build the Fill Mode menu * Menu --> JMenu * MenuItem --> JMenuItem * @return JMenu */ private JMenu buildFillModeMenu( ) { int i; String fillModeNames[] = { "Filled ", "Hollow "}; int fillModes[] = { DrawCanvas.FILLED, DrawCanvas.HOLLOW }; JMenuItem fillModeItems[]; JMenu fillModeMenu = new JMenu ( "FillModes" ); fillModeItems = new JMenuItem[ fillModeNames.length ]; for ( i=0; i < fillModeNames.length; i++ ) { fillModeItems[ i ] = new JMenuItem( fillModeNames[ i ] ); fillModeMenu.add( fillModeItems[ i ]); fillModeItems[ i ].addActionListener( new DrawCanvas.SetFillModeAL (canvas, fillModes[ i ] )); } return fillModeMenu; } /** * buildAutoRotateMenu *

* This calls a new inner action listener class of DrawCanvas, * SetAutoRotateAL * Menu --> JMenu * MenuItem --> JMenuItem * @return JMenu */ private JMenu buildAutoRotateMenu( ) { int i; String rotateModeNames[] = { "AutoRotate about X axis", "AutoRotate about Y axis", "AutoRotate about Z axis", "Please Stop Rotating" }; int rotateModes[] = { DrawCanvas.ROTATEX, DrawCanvas.ROTATEY, DrawCanvas.ROTATEZ, DrawCanvas.STOP }; JMenuItem rotateModeItems[]; JMenu rotateModeMenu = new JMenu ( "AutoRotate" ); rotateModeItems = new JMenuItem[ rotateModeNames.length ]; for ( i=0; i < rotateModeNames.length; i++ ) { rotateModeItems[ i ] = new JMenuItem( rotateModeNames[ i ] ); rotateModeMenu.add( rotateModeItems[ i ]); rotateModeItems[ i ].addActionListener( new DrawCanvas.SetAutoRotateAL (canvas, rotateModes[ i ] )); } return rotateModeMenu; } //-------------- zFront -------------------------------- public void zFront ( float newval ) { DrawCanvas.setzFront( newval ); // Note: setting zFront, might change zBack zBackSlider.setValue( DrawCanvas.getzBack() ); } //-------------- zBack -------------------------------- public void zBack ( float newval ) { DrawCanvas.setzBack( newval ); // Note that zBack cannot be set in front of zFront zBackSlider.setValue( DrawCanvas.getzBack() ); } //-------------- xRotate -------------------------------- public void xRotate ( float newval ) { View.rotate( "x", newval ); canvas.repaint(); } //-------------- xRotateReset -------------------------------- public void xRotateReset ( ) { View.updateScene(); xRotSlider.setValue( 0 ); } //-------------- yRotate -------------------------------- public void yRotate ( float newval ) { View.rotate( "y", newval ); canvas.repaint(); } //-------------- yRotateReset -------------------------------- public void yRotateReset ( ) { View.updateScene(); yRotSlider.setValue( 0 ); } //-------------- zRotate -------------------------------- public void zRotate ( float newval ) { View.rotate( "z", newval ); canvas.repaint(); //System.err.println("New zRotate: " + newval ); } //-------------- zRotateReset -------------------------------- public void zRotateReset ( ) { View.updateScene(); zRotSlider.setValue( 0 ); } } // end Draw3d class