001    /*
002     *  DotFrame.java
003     *      Part of the Spirograph problem set.
004     *
005     * Developed for "Rethinking CS101", a project of Lynn Andrea Stein's AP Group.
006     * For more information, see <a href="http://www.ai.mit.edu/projects/cs101/">the
007     * CS101 homepage</a> or email <las@ai.mit.edu>.
008     *
009     * Copyright (C) 1998 Massachusetts Institute of Technology.
010     * Please do not redistribute without obtaining permission.
011     */
012    
013    package spirograph;
014    
015    import java.awt.*;
016    import java.awt.event.*;
017    import java.util.*;
018    
019    import java.lang.reflect.Method;
020    import java.lang.reflect.InvocationTargetException;
021    
022    /** This class pops up the window for the Spirograph, creates all of
023     * the buttons and the DotPanel, and adds them. It also creates an
024     * instance of AdvEnv and passes it a listener that will set the
025     * velocity of the dot. It also starts and suspends the three
026     *  Threads (one for each of the AccelHandlers and one for the
027     *  DotPanel).</p>
028     *
029     * <p>Copyright © 1998 Massachusetts Institute of Technology.<br />
030     * Copyright © 2002-2003 Franklin W. Olin College of Engineering.</p>
031     *
032     * @author Luis Sarmenta, lfgs@cag.lcs.mit.edu
033     * @author Henry Wong, henryw@mit.edu
034     * @author Patrick G. Heck, gus.heck@olin.edu
035     * @version $Id: DotFrame.java,v 1.7 2004/02/09 20:55:03 gus Exp $
036     * @see Coord
037     * @see DotPanel
038     * @see AccelHandler
039     * @see AdvEnv
040     * @see SetVListener
041     * @see Spirograph
042     */
043    public class DotFrame extends Frame {
044    
045      // Must be fields for anonymouse classes
046      private Thread xSpirit, ySpirit, painter;
047      private boolean xStarted = false, yStarted = false, pStarted = false;
048      private DotPanel myPanel;
049      private ResetMenu myRM;
050      private Coord x, y;
051    
052      // These fields are used to calculate the difference in size
053      // between the Panel and the Frame. They are used in order to resize
054      // the Panel after the Frame has been resized.
055        
056      private int xDif;
057      private int yDif;
058    
059      private AdvEnv myAdvEnv;
060        
061      /** Creates a new Dot Frame with the Default font.
062       *
063       * @param xHandler The {@link AccelHandler} for the x direction
064       * @param yHandler The {@link AccelHandler} for the y direction
065       * @param xCoord The {@link Coord} object that defines our movement vectors on the x axis
066       * @param yCoord The {@link Coord} object that defines our movement vectors on the y axis
067       */
068      public DotFrame(AccelHandler xHandler, AccelHandler yHandler, Coord xCoord, Coord yCoord) {
069        this(xHandler, yHandler, xCoord, yCoord,
070             Spirograph.DEFAULTFONT);
071      }
072      
073      /** Creates a new dot frame with the default font and <code>null</code> handlers.
074       *
075       * @param xCoord The {@link Coord} object that defines our movement vectors on the x axis
076       * @param yCoord The {@link Coord} object that defines our movement vectors on the y axis
077       */  
078      public DotFrame(Coord xCoord, Coord yCoord) {
079          this((AccelHandler)null, (AccelHandler)null, xCoord, yCoord, Spirograph.DEFAULTFONT);
080      }
081            
082      /** Same as other constructor, except it sets the font rather than
083       * using a default.
084       *
085       * @param xHandler The {@link AccelHandler} for the x direction
086       * @param yHandler The {@link AccelHandler} for the y direction
087       * @param xCoord The {@link Coord} object that defines our movement vectors on the x axis
088       * @param yCoord The {@link Coord} object that defines our movement vectors on the y axis
089       * @param f The desired font for this component
090       */
091      public DotFrame(AccelHandler xHandler, AccelHandler yHandler, Coord xCoord, Coord yCoord, Font f) {
092            
093        this.setFont(f);
094        myPanel = new DotPanel(xCoord, yCoord);
095            
096        x = xCoord;
097        y = yCoord;
098                    
099        this.setLayout( new BorderLayout(10, 10)); 
100        
101        // Create the textfields and listeners for AdvEnv and pass them in.
102        TextField xVel = new TextField(3);
103        TextField yVel = new TextField(3);
104        SetPosGravListener panelListener = new SetPosGravListener(x,y,myPanel);
105        myPanel.addMouseListener(panelListener);
106        
107        myAdvEnv = new AdvEnv(xVel, yVel, myPanel);
108        
109        myRM = new ResetMenu();
110        myRM.addListeners(new ActionListener() {
111            public void actionPerformed(ActionEvent ae) {
112                myPanel.flushLines();
113                myPanel.paintBuf();
114            }
115        },
116        new ActionListener() {
117            public void actionPerformed(ActionEvent ae) {
118                myPanel.flushGrav();
119                myPanel.paintBuf();
120            }
121        },
122        new ActionListener() {
123            public void actionPerformed(ActionEvent ae) {
124                suspendSpirits();
125                suspendPainting();
126                x.setPos(0);
127                x.setVel(0);
128                y.setPos(0);
129                y.setVel(0);
130                myPanel.paintBuf();
131            }
132        },
133        new ActionListener() {
134            public void actionPerformed(ActionEvent ae) {
135                suspendSpirits();
136                suspendPainting();
137                x.setPos(0);
138                x.setVel(0);
139                y.setPos(0);
140                y.setVel(0);
141                myPanel.flushLines();
142                myPanel.flushGrav();
143                myPanel.paintBuf();
144            }
145        });
146        
147        if (xHandler == null) {
148            this.setTitle("Etch-a-Sketch Drawing");
149        }
150        
151        if (xHandler != null && yHandler != null) {
152            
153            this.setTitle("Spirograph");
154            
155            // Create the buttons and add some functionality.
156            Button start=new Button("Start");
157            start.addActionListener(new ActionListener() {
158                public void actionPerformed(ActionEvent e) {
159                    if(xStarted) {
160                        xSpirit.resume();
161                    } else {
162                        xSpirit.start();
163                        xStarted = true;
164                    }
165                    if(yStarted) {
166                        ySpirit.resume();
167                    } else {
168                        ySpirit.start();
169                        yStarted = true;
170                    }
171                    beginPainting();
172                }
173            });
174            
175            Button stop = new Button("Stop");
176            stop.addActionListener(new ActionListener() {
177                public void actionPerformed(ActionEvent ae) {
178                    xSpirit.suspend();
179                    ySpirit.suspend();
180                    painter.suspend();
181                }
182            });
183            
184            // Create the ResetMenu and some listeners for its various
185            // buttons
186            
187            Button reset=new Button("Reset");
188            reset.addActionListener(new ActionListener() {
189                public void actionPerformed(ActionEvent e) {
190                    myRM.setVisible(true);
191                }
192            });
193            
194            
195            
196            
197            // Add Listeners
198            SetVListener myVelSetter = new SetVListener(xVel, yVel, x, y);
199            myAdvEnv.addListener(myVelSetter);
200            
201            Button advEnv = new Button("Advanced Environment Options");
202            advEnv.addActionListener(new ActionListener() {
203                
204                public void actionPerformed(ActionEvent ae) {
205                    myAdvEnv.setVisible(true);
206                }
207            });
208            
209            // Create the Quit Button
210            Button quit=new Button("Quit");
211            quit.addActionListener (new ActionListener() {
212                public void actionPerformed(ActionEvent e) {
213                    xSpirit.stop();
214                    ySpirit.stop();
215                    setVisible(false);
216                    dispose();
217                    System.exit(0);
218                }
219            });
220            
221            System.out.println ("Buttons created.");
222            
223            // Create the Button panel
224            Panel p = new Panel();
225            p.setLayout(new FlowLayout(FlowLayout.CENTER));
226            
227            p.add(start); 
228            p.add(stop);
229            p.add(reset);
230            p.add(advEnv);
231            p.add(quit);
232            this.add("South",p);
233            
234            System.out.println ("Button panel created");
235            
236            xSpirit = new Thread (xHandler);
237            ySpirit = new Thread (yHandler);
238            
239        }
240        
241        painter = new Thread (myPanel);
242    
243        this.add("Center", myPanel);
244            
245        // The Spirograph handles Resizing the window by changing the
246        // size of the Panel. The variables xDif and yDif represents
247        // the difference in size between the Frame and the Panel.
248                
249        this.addComponentListener(new ComponentListener() {
250          // if the window is resized, notify the appropriate
251          // Objects.
252                    
253          public void componentResized(ComponentEvent e) {
254            int width = getSize().width-xDif;
255            int height = getSize().height-yDif;
256                        
257            System.out.println ("Resized to " + width
258                                + " wide and " +
259                                height + " high.");
260                    
261            myPanel.setSize(width,height);
262          }
263    
264          // I need to implement these methods for the
265          // ComponentListener interface.
266          public void componentHidden(ComponentEvent e){}
267          public void componentShown(ComponentEvent e){}
268          public void componentMoved(ComponentEvent e){}
269                
270        });
271                
272        System.out.println ("Stuff added.");
273                
274        this.pack();        
275        this.setVisible(true);
276    
277        // xDif and yDif have to be set after Frame is made Visible,
278        // otherwise the calls to getSize will return 0
279            
280        xDif = this.getSize().width - myPanel.getSize().width;
281        System.out.println ("Frame width: " + xDif);
282        yDif = this.getSize().height - myPanel.getSize().height;
283        System.out.println ("Frame height: " + yDif);
284            
285        System.out.println ("Done.");
286      }
287      
288      /** Show the advanced environment options. This method will be removed when
289       * my AdvEtchControls is fully implemented. It is only used by the new
290       * interface.
291       *
292       * @deprecated Since 1/14/03 - will be removed when AdvEtchControl is complete.
293       */  
294      public void showAdvEnv() {
295          myAdvEnv.setVisible(true);
296      }
297      
298      /** Show the advanced environment options. This method will be removed when
299       * my AdvEtchControls is fully implemented. It is only used by the new
300       * interface.
301       *
302       * @deprecated Since 1/14/03 - will be removed when AdvEtchControl is complete.
303       */  
304      public void showResetMenu() {
305          myRM.setVisible(true);
306      }
307      
308      /**
309       * Suspend the the painting thread. This uses the dangerous and deprecated
310       * <a href ="http://java.sun.com/j2se/1.4.1/docs/guide/misc/threadPrimitiveDeprecation.html">
311       * Thread.resume()</a> method.The thread it can be restarted
312       * with {@link DotFrame#beginPainting}
313       *
314       */  
315      public void suspendPainting() {
316          painter.suspend();
317      }
318      
319      /**
320       * Start or Resume painting actions. This uses the dangerous and deprecated
321       * <a href ="http://java.sun.com/j2se/1.4.1/docs/guide/misc/threadPrimitiveDeprecation.html">
322       * Thread.resume()</a> method. Painting Action can be
323       * suspended with {@link DotFrame#suspendPainting()}
324       *
325       */  
326      public void beginPainting() {
327          if(pStarted) {
328              painter.resume();
329          } else {
330              painter.start();
331              pStarted = true;
332          }
333      }
334      
335      /** Suspend the the spirit threads. This uses the dangerous and deprecated
336       * <a href ="http://java.sun.com/j2se/1.4.1/docs/guide/misc/threadPrimitiveDeprecation.html">
337       * Thread.resume()</a> method.
338       */  
339      public void suspendSpirits() {
340          if (xSpirit != null) {
341              xSpirit.suspend();
342          }
343          if (ySpirit != null) {
344              ySpirit.suspend();
345          }
346      }
347      
348      /** Stop the painting thread and call super.dispose()
349       */  
350      public void dispose() {
351          painter.stop();
352          super.dispose();
353      }
354    }
355    
356    /*
357     * $Log: DotFrame.java,v $
358     * Revision 1.7  2004/02/09 20:55:03  gus
359     * javadoc fixes
360     *
361     * Revision 1.6  2003/01/15 17:36:10  gus
362     * adding log keywords to files that don't have them
363     *
364     */