View Javadoc

1   // Copyright 2003-2005, FreeHEP.
2   package hep.wired.interaction;
3   
4   import java.awt.*;
5   import java.awt.event.*;
6   import java.awt.geom.*;
7   import javax.swing.*;
8   
9   import org.freehep.application.Application;
10  
11  import hep.wired.edit.WiredCompoundEdit;
12  import hep.wired.edit.Translate;
13  import hep.wired.edit.Scale;
14  import hep.wired.feature.Translateable;
15  import hep.wired.services.RecordPlot;
16  import hep.wired.services.GraphicsPanel;
17  import hep.wired.image.WiredBaseImage;
18  
19  /***
20   * Drag/click to define a rectangle to scale and translate the plot.
21   *
22   * @author Mark Donszelmann
23   * @version $Id: DragRectangleToScale.java 1858 2005-06-08 00:11:23Z duns $
24   */
25  public class DragRectangleToScale extends DefaultInteractionHandler {
26  
27      private static final String name = "Combined Translate-Scale";
28      private static final int cursorSize = 32;
29      private static final double fixedScale = Math.sqrt(2);
30      
31      private boolean fixedRatio = true;
32      private int xp, yp;
33      private int xd, yd;
34      private Rectangle rectangle;
35      
36      /***
37       * Create a rectangle handler to generate scale edits.
38       */
39      public DragRectangleToScale() {
40          super("Drag Rectangle to Scale");
41      }
42  
43      public Icon getIcon(int size) {
44          return WiredBaseImage.getIcon("Rectangle%w", size);
45      }    
46  
47      public String getDescription() {
48          return "Click center-zoom-in, Alt-Click to zoom-out-displace, Drag rectangle to zoom.";
49      }
50      
51      public boolean isSupportedBy(GraphicsPanel panel) {
52          return new Translate().isSupportedBy(panel) &&
53                 new Scale().isSupportedBy(panel);
54      }
55  
56      public void changeCursor(RecordPlot plot, InputEvent event) {
57          if (event.getID() == MouseEvent.MOUSE_DRAGGED) {
58              plot.setCursor(WiredBaseImage.getBestCursor("RectangleScaleCursor%w", cursorSize, cursorSize));
59          } else if (event.isAltDown()) {
60              plot.setCursor(WiredBaseImage.getBestCursor("RectangleScaleMinusCursor%w", cursorSize, cursorSize));
61          } else {
62              plot.setCursor(WiredBaseImage.getBestCursor("RectangleScalePlusCursor%w", cursorSize, cursorSize));
63          }
64      }
65  
66      public void reset(RecordPlot plot, InputEvent event) {
67          rectangle = null;
68          plot.drawShape(null);
69          Application.getApplication().setStatusMessage(getDescription());
70      }
71  
72      public void mouseEntered(RecordPlot plot, MouseEvent event) {
73          plot.requestFocusInWindow();
74          changeCursor(plot, event);
75      }
76      
77      /***
78       * Store starting point of rectangle.
79       */
80      public void mouseButton1DragStarted(RecordPlot plot, MouseEvent event) {
81          xp = event.getX();
82          yp = event.getY();
83          changeCursor(plot, event);
84          Application.getApplication().setStatusMessage("Drag rectangle to zoom, Shift removes ratio constraint.");
85      }
86  
87      /***
88       * Update moving point of rectangle and draw.
89       */
90      public void mouseButton1Dragged(RecordPlot plot, MouseEvent event) {
91          xd = event.getX();
92          yd = event.getY();
93          defineRectangle(plot, event);
94      }
95  
96      /***
97       * Update end point of rectangle, translate and scale, and remove rectangle.
98       */
99      public void mouseButton1DragEnded(RecordPlot plot, MouseEvent event) {
100         translateAndScale(plot, rectangle, fixedRatio);
101         reset(plot, event);
102     }
103     
104     // FIXME, WIRED-377, separate this from the selection
105     public static void translateAndScale(RecordPlot plot, Rectangle2D rectangle, boolean fixedRatio) {
106         double du = rectangle.getX()+rectangle.getWidth()/2 -plot.getWidth()/2;
107         double dv = rectangle.getY()+rectangle.getHeight()/2-plot.getHeight()/2;
108 
109         WiredCompoundEdit edit = new WiredCompoundEdit(name);
110 
111         // center
112         Translateable translateable = (Translateable)plot.getGraphicsPanel().getFeature(Translateable.class);
113         double t[] = translateable.getModelTranslation(new double[] { -du, dv, 0 }, plot.getGraphicsPanel().getViewPort());        
114         Translate translate = new Translate(t[0], t[1], t[2], rectangle, 5);
115         Shape shape = translate.createTransformedShape((Component)plot, rectangle);
116         edit.addEdit(translate);
117 
118         // zoom
119         double sx = plot.getWidth() / (rectangle.getWidth()+1);
120         double sy = fixedRatio ? sx : plot.getHeight() / (rectangle.getHeight()+1);
121         double sz = fixedRatio ? sx : Math.min(sx, sy);
122         edit.addEdit(new Scale(sx, sy, sz, shape, 5));
123 
124         edit.end();
125         plot.postEdit(edit);
126     }    
127 
128     public void mouseButton1Released(RecordPlot plot, MouseEvent event) {
129         changeCursor(plot, event);
130     }
131 
132     public boolean shiftKeyPressed(RecordPlot plot, KeyEvent event) {
133         defineRectangle(plot, event);
134         return true;
135     }
136 
137     public boolean shiftKeyReleased(RecordPlot plot, KeyEvent event) {
138         defineRectangle(plot, event);
139         return true;
140     }
141 
142     public boolean altKeyPressed(RecordPlot plot, KeyEvent event) {
143         changeCursor(plot, event);
144         return true;
145     }
146 
147     public boolean altKeyReleased(RecordPlot plot, KeyEvent event) {
148         changeCursor(plot, event);
149         return true;
150     }
151 
152     private void defineRectangle(RecordPlot plot, InputEvent event) {
153         // no need to define if we pressed a key and rectangle was defined before
154         if ((event instanceof KeyEvent) && (rectangle == null)) return;
155 
156         int dx = xd - xp;
157         int dy = yd - yp;
158                 
159         // restrict rectangle for plot ratio when shift is not-pressed
160         if (!event.isShiftDown()) {
161             double ratio = (double)plot.getHeight() / (double)plot.getWidth();
162             if (Math.abs(dy) < Math.abs(dx) * ratio) {
163                 dy = (int)(Math.abs(dx)*((dy < 0) ? -1 : 1)*ratio);
164             } else {
165                 dx = (int)(Math.abs(dy)*((dx < 0) ? -1 : 1)/ratio);
166             }
167             fixedRatio = true;
168         } else {
169             fixedRatio = false;
170         }
171         rectangle = new Rectangle(Math.min(xp, xp + dx),
172                                   Math.min(yp, yp + dy),
173                                   Math.abs(dx),
174                                   Math.abs(dy));
175         plot.drawShape(rectangle);
176     }
177 
178     /***
179      * Translate point to center and zoom in (or out if alt key pressed).
180      */
181     public void mouseButton1Clicked(RecordPlot plot, MouseEvent event) {
182         
183         int w2 = plot.getWidth()/2;
184         int h2 = plot.getHeight()/2;
185         int du = event.getX()-w2;
186         int dv = event.getY()-h2;
187 
188         WiredCompoundEdit edit = new WiredCompoundEdit(name);
189 
190         if (event.isAltDown()) {
191             Shape shape = new Rectangle(0, 0, 2*w2, 2*h2);
192 
193             // zoom out
194             Scale scale = new Scale(1/fixedScale, 1/fixedScale, 1/fixedScale, shape, 5);
195             shape = scale.createTransformedShape((Component)plot, shape);
196             edit.addEdit(scale);
197 
198             // offset from center
199             Translateable translateable = (Translateable)plot.getGraphicsPanel().getFeature(Translateable.class);
200             double t[] = translateable.getModelTranslation(new double[] { du*fixedScale, -dv*fixedScale, 0 }, plot.getGraphicsPanel().getViewPort());        
201             edit.addEdit(new Translate(t[0], t[1], t[2], shape, 5));
202         } else {
203             int ws2 = (int)(w2/fixedScale);
204             int hs2 = (int)(h2/fixedScale);
205             Shape shape = new Rectangle(event.getX()-ws2, event.getY()-hs2, 2*ws2, 2*hs2);
206 
207             // center
208             Translateable translateable = (Translateable)plot.getGraphicsPanel().getFeature(Translateable.class);
209             double t[] = translateable.getModelTranslation(new double[] { -du, dv, 0 }, plot.getGraphicsPanel().getViewPort());        
210             Translate translate = new Translate(t[0], t[1], t[2], shape, 5);
211             shape = translate.createTransformedShape((Component)plot, shape);
212             edit.addEdit(translate);
213 
214             // zoom in
215             edit.addEdit(new Scale(fixedScale, fixedScale, fixedScale, shape, 5));
216         }
217         edit.end();
218         plot.postEdit(edit);
219     }
220 
221     public String toString() {
222         return "Drag rectangle to Scale";
223     }
224 }