/* * @(#)MiniPaint.java 1.0 14 July 2001 * * Copyright 2001 * College of Computer Science * Northeastern University * Boston, MA 02115 * * This software may be used for educational purposes as long as * this copyright notice is retained intact at the top of all files. * * Should this software be modified, the words "Modified from * Original" must be included as a comment below this notice. * * All publication rights are retained. This software or its * documentation may not be published in any media either in whole * or in part without explicit permission. * * Contact information: * Richard Rasala rasala@ccs.neu.edu * Viera Proulx vkp@ccs.neu.edu * Jeff Raab jmr@ccs.neu.edu * * Telephone: 617-373-2462 * * This software was created with support from Northeastern * University and from NSF grant DUE-9950829. */ import edu.neu.ccs.*; import edu.neu.ccs.gui.*; import edu.neu.ccs.util.*; import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.text.NumberFormat; import java.text.DecimalFormat; import java.io.*; import javax.swing.*; /** A simple minipaint program * User selcts one of four options: line, rectangle, oval, or circle * User selects color for the drawing * Coordinates of two key points are selected via mouse click * in the graphics area * The History of the painting is recorded in a TextAreaView * @author Viera K. Proulx * @author Richard Rasala * @version 14 July 2001 */ public class MiniPaint extends DisplayPanel implements JPTConstants { ///////////////// // Static Data // ///////////////// // constant: buffer size private static final int bufferSize = 400; // constants: names for the four options public static final int LINE = 0; public static final int RECTANGLE = 1; public static final int OVAL = 2; public static final int CIRCLE = 3; // constants: labels for the four options buttons private static final String[] drawSelection = {"LINE", "RECTANGLE", "OVAL", "CIRCLE"}; // default selection private static final int defaultSelection = LINE; // constants: settings for the default two points private static final String X1 = "100"; private static final String Y1 = "200"; private static final String X2 = "200"; private static final String Y2 = "100"; private static final String Mx = "0"; private static final String My = "0"; // constant: boolean value for selecting the first point private static final boolean FIRSTPOINT = true; private static final boolean SECONDPOINT = false; ///////////////// // Member Data // ///////////////// // Decimal format for output into text field views private DecimalFormat format = new DecimalFormat(); //////////////////////////////////////////// // Point2D views to track selected points // //////////////////////////////////////////// // view that records the selected first point private Point2DView firstPointView = new Point2DView(X1, Y1, // default view state "X1:", // label for the x coordinate view "Y1:", // label for the y coordinate view "First Point", // title for the display null, // no annotation used VERTICAL); // layout orientation // view that records the selected second point private Point2DView secondPointView = new Point2DView(X2, Y2, // default view state "X2:", // label for the x coordinate view "Y2:", // label for the y coordinate view "Second Point", // title for the display null, // no annotation used VERTICAL); // layout orientation // view that records the current mouse position private Point2DView mousePointView = new Point2DView(Mx, My, // default view state "Xmouse:", // label for the x coordinate view "Ymouse:", // label for the y coordinate view "Mouse Point", // title for the display null, // no annotation used VERTICAL); // layout orientation ///////////////////////////////////////////////////////////////// // Output text area, color view, options view to select shape, // // boolean view to indicate which poin is being selected // ///////////////////////////////////////////////////////////////// // panel to display past graphed colors, and shapes private TextAreaView history = new TextAreaView(); // color view where user can select the color for the drawing private ColorView color = new ColorView(Color.red); // options view where user selects the shape to draw private OptionsView drawSelectionView = new OptionsView (drawSelection, defaultSelection, new GridLayout(4, 0)); // boolean view to specify which point is being selected private BooleanView nextPointChoice = new BooleanView ("First Point", FIRSTPOINT); ///////////// // Actions // ///////////// // the actions for the actions panel /* * the clear action is constructed using * the String "Clear" to name its button * and specifying the clear method to be performed when pressed */ private SimpleAction clear = new SimpleAction("Clear") { public void perform(){ clear(); } }; /* * the new action is constructed using * the String "New First Point" to name its button * and specifying the start method to be performed when pressed */ private SimpleAction saveToFile = new SimpleAction("Save History") { public void perform(){ saveToFile(); } }; // list of actions to be included in the actions panel /* * array of actions is constructed */ private Action[] actionList = {clear, saveToFile}; // actions panel /* * actions panel is constructed * with the actions it will contain supplied as parameter */ private ActionsPanel actions = new ActionsPanel(actionList); ///////////////// // GUI Section // ///////////////// // overall control panel for the GUI private DisplayCollection controls = new DisplayCollection(); // square window for painting private BufferedPanel window = new BufferedPanel(bufferSize, bufferSize); // control panel to combine point data displays private DisplayCollection pointData = new DisplayCollection(HORIZONTAL); // control panel to combine color view and next point choice displays private DisplayCollection choicesView = new DisplayCollection(HORIZONTAL); ////////////////// // Main Program // ////////////////// /* * create a window * titled "Mini Paint" * whose contents are defined by the MiniPaint constructor */ public static void main(String[] args) { JPTFrame.createQuickJPTFrame("Mini Paint", new MiniPaint()); } ///////////////// // Constructor // ///////////////// public MiniPaint() { // layout for panel as a whole setLayout(new BorderLayout()); ////////////////// // View section // ////////////////// // assure that all point data information is shown as integers format.setMinimumFractionDigits(0); format.setMaximumFractionDigits(0); // set preferred size for the history text area history.setColumns(15); history.setRows(15); ///////////////// // GUI Section // ///////////////// // activate color chooser using single click color.setChooserClickCount(1); // add the point data views to the point data display pointData.add(mousePointView); pointData.add(firstPointView); pointData.add(secondPointView); // build choices view choicesView.add( new DisplayWrapper( new Display(color, "Color", null))); choicesView.add(nextPointChoice); // add four components to the controls controls.add(actions); controls.add(choicesView); controls.add( new DisplayWrapper( new Display(drawSelectionView, null, null))); // install history panel in a scrollable display and // add to controls wrapped with a title controls.add( new DisplayWrapper( new Display( new ScrollableDisplay(history), null, "Shapes drawn"))); ///////////////////////////////////////////////// // wrap the controls window into a titled display Display controlsDisplay = new Display(controls, null, "Controls"); ///////////////////////////////////////////////// // wrap the graphics window into a titled display Display windowDisplay = new Display(window, null, "Graphics"); //////////////////////////////////////////////////////////////// // add controls, the point data display, and the graphics window // to the main panel add(controlsDisplay, BorderLayout.WEST); add(windowDisplay, BorderLayout.CENTER); add(pointData, BorderLayout.SOUTH); /////////////////// // Mouse Section // /////////////////// // get the mouse action adapter from the graphics window panel MouseActionAdapter adapter = window.getMouseActionAdapter(); // record the point and draw (if second point) when mouse clicked adapter.addMouseClickedAction(new MouseAction() { public void mouseActionPerformed(MouseEvent mevt) { draw(mevt); } }); // track mouse motions adapter.addMouseMovedAction(new MouseAction() { public void mouseActionPerformed(MouseEvent mevt) { track(mevt); } }); // clear window reset(); } //////////////////////// // Action Definitions // //////////////////////// /* * clear action * * reset the text fields to the default initial default values * reset the color choice to red * clear the history text area * erase the graphics window */ public void clear() { // reset all GUI components reset(); // clear the graphics window window.clearPanel(); repaint(); } /* * saveToFile action * * save the history panel content to a file */ public void saveToFile() { // disable all actions and choices during the file choice controls.setEnabled(false); window.setEnabled(false); // build a file chooser and have the user choose a file, // quitting this operation if the user cancelled the choice JFileChooser chooser = new JFileChooser("."); // set the file extension to be .paint chooser.setFileFilter(new FileView.ExtensionFileFilter("paint")); // see if file was selected - quit if user canceled if (chooser.showSaveDialog(null) != JFileChooser.APPROVE_OPTION) { controls.setEnabled(true); window.setEnabled(true); return; } // write to the selected file try{ FileUtilities.writeFile( chooser.getSelectedFile(), // get the selected file history.getViewState(), // extract the text to save true); // OK to overwrite existing file } catch(Exception e) { System.out.println("Exception: " + e); } // enable the buttons for the next file controls.setEnabled(true); window.setEnabled(true); } ////////////////////////////// // Mouse Action Definitions // ////////////////////////////// /** * Mouse moved action for tracking the position of mouse * in the graph window */ public void track(MouseEvent mevt) { // record the mouse position in its text field view mousePointView.setViewState( mevt.getX(), mevt.getY(), format); } /** * Mouse clicked action for finding position of mouse in the graph window * and drawing the line to this position (if not a new polygon) */ public void draw(MouseEvent mevt) { // get the graphics context to draw the line Graphics2D G = window.getBufferGraphics(); boolean firstPoint = nextPointChoice.getBooleanValue(); if (firstPoint){ firstPointView.setViewState( mevt.getX(), mevt.getY(), format); nextPointChoice.setBooleanValue(SECONDPOINT); } else{ // get the start point from text field view Point2D.Double P1 = new XPoint2D(firstPointView.demandPoint2D()); // get the end point from mouse location Point2D.Double P2 = new Point2D.Double(mevt.getX(), mevt.getY()); // set the end point text field to current end point secondPointView.setViewState(P2, format); // draw the object specified by the two given points drawObject(P1, P2); nextPointChoice.setBooleanValue(FIRSTPOINT); } } // helper method that draws an object specified by two points private void drawObject(Point2D.Double P1, Point2D.Double P2){ int selection; Graphics2D G = window.getBufferGraphics(); // set paint color to user color choice G.setPaint(color.getColor()); switch (selection = drawSelectionView.getSelectedIndex()){ case LINE: // draw the line from P1 to P2 Line2D.Double L = new Line2D.Double(P1, P2); G.draw(L); break; case RECTANGLE: // assures that any two opposing points select a rectangle Rectangle2D.Double R = new Rectangle2D.Double(); R.setRect(buildRect(P1, P2)); G.fill(R); break; case OVAL: // assures that any two opposing points select an oval Ellipse2D.Double O = new Ellipse2D.Double(); O.setFrame(buildRect(P1, P2)); G.fill(O); break; case CIRCLE: // P1 is center, P2 is on the perimeter double radius = P2.distance(P1); Ellipse2D.Double C = new Ellipse2D.Double(P1.x - radius, P1.y - radius, 2 * radius, 2 * radius); G.fill(C); } // show the color and the line coordinates for history history.append(drawSelection[selection] + " "); history.append("(" + color.getViewState() + ")\n"); history.append("(" + (int)P1.x + ", " + (int)P1.y + ") : "); history.append("(" + (int)P2.x + ", " + (int)P2.y + ")\n"); repaint(); } // assures that any two opposing points of rectangle can be used private Rectangle2D.Double buildRect( Point2D.Double P1, Point2D.Double P2){ return new Rectangle2D.Double( min (P1.x, P2.x), // left position min (P1.y, P2.y), // top position max (P1.x, P2.x) - min (P1.x, P2.x), // width max (P1.y, P2.y) - min (P1.y, P2.y)); // height } // used to assure that any two opposing points of rectangle can be used private double min(double a, double b){ if (a < b) return a; return b; } // used to assure that any two opposing points of rectangle can be used private double max(double a, double b){ if (a >= b) return a; return b; } }