1    /*
2    Copyright 2000 by Ralph Hartley
3    This software is licenced under the terms of the
4    Gnu Public Licence
5    */
6    import javax.swing.*;
7    import java.awt.geom.*;
8    import java.awt.event.*;
9    import java.awt.*;
10   
11   public class Rose extends JComponent {
12   
13     public double theta = 0;
14   
15     double grabtheta = 0;
16     double oldtheta = 0;
17   
18     Scaleable target;
19   
20     public static int size = 80;
21   
22     int xoff=size/2;
23     int yoff=size/2;
24     int r=size/2;
25   
26     public Rose(Scaleable target) {
27       super();
28       this.target = target;
29       enableEvents(AWTEvent.MOUSE_EVENT_MASK|AWTEvent.MOUSE_MOTION_EVENT_MASK|
30           	 AWTEvent.COMPONENT_EVENT_MASK);
31       setSize(size,size);
32       setPreferredSize(new Dimension(xoff+r,yoff+r));
33       setMinimumSize(new Dimension(xoff+r,yoff+r));
34       setMaximumSize(new Dimension(xoff+r,yoff+r));
35     }
36   
37     double getTheta(Point p) {
38       return(-Math.atan2(p.getX()-xoff,p.getY()-yoff));
39     }
40   
41     protected void processComponentEvent(ComponentEvent e) {
42       super.processComponentEvent(e);
43       if (e.getID()==ComponentEvent.COMPONENT_RESIZED) {
44         Dimension s = getSize();
45         if (s.width<s.height) r = s.width/2-1;
46         else r = s.height/2-1;
47         xoff = s.width/2;
48         yoff = s.height/2;
49         repaint();
50       }
51     }
52   
53     protected void processMouseEvent(MouseEvent e) {
54       super.processMouseEvent(e);
55       if ((e.getModifiers()&InputEvent.BUTTON3_MASK) !=0) {
56         if (e.getID()==MouseEvent.MOUSE_PRESSED) {
57           javax.swing.Box box = new javax.swing.Box(BoxLayout.X_AXIS);
58           box.add(new JLabel("rotation angle:"));
59           JTextField text = new JTextField(""+(theta*180/Math.PI));
60           oldtheta = theta;
61           text.setColumns(30);
62           box.add(text);
63           int res = JOptionPane.showConfirmDialog(null,box,"Angle setting",
64           						JOptionPane.YES_NO_OPTION);
65           if (res == JOptionPane.YES_OPTION) {
66             double newtheta = Math.PI*Double.parseDouble(text.getText())/180;
67             change(newtheta);
68           }
69         }
70       } else {
71         if (e.getID()==MouseEvent.MOUSE_PRESSED) {
72           grabtheta = getTheta(e.getPoint());
73           oldtheta = theta;
74         }
75         if (e.getID()==MouseEvent.MOUSE_RELEASED) {
76           if (theta!=oldtheta) {
77             target.setRotation(theta);
78           }
79         }
80       }
81     }
82   
83     public void change(double newtheta) {
84       if (newtheta!=theta) {
85         theta=oldtheta=newtheta;
86         target.setRotation(theta);
87         repaint();
88       }
89     }
90   
91     protected void processMouseMotionEvent(MouseEvent e) {
92       super.processMouseMotionEvent(e);
93       if (e.getID()==MouseEvent.MOUSE_DRAGGED) {
94         double newtheta = getTheta(e.getPoint());
95         theta = (theta+newtheta-grabtheta+4*Math.PI)%(Math.PI*2);
96         grabtheta = newtheta;
97         repaint();
98       }
99     }
100  
101    static double tick = 0.2;
102  
103    public void paint(Graphics g) {
104      Graphics2D gr = (Graphics2D)g;
105      Dimension s = getSize();
106   
107      AffineTransform temp =gr.getTransform();
108      temp.concatenate(AffineTransform.getRotateInstance(theta,xoff,yoff));
109      gr.setTransform(temp);
110  
111      gr.drawOval(xoff-r,yoff-r,2*r,2*r); 
112      gr.drawLine(xoff,yoff-r,xoff,yoff+r-(int)(tick*r));
113  
114      gr.drawLine(xoff,yoff-r,xoff-(int)(tick*r),yoff-r+(int)(tick*r));
115      gr.drawLine(xoff,yoff-r,xoff+(int)(tick*r),yoff-r+(int)(tick*r));
116  
117      gr.drawLine(xoff,yoff+r-(int)(tick*r),xoff-(int)(tick*r),yoff+r);
118      gr.drawLine(xoff,yoff+r-(int)(tick*r),xoff+(int)(tick*r),yoff+r);
119    }
120  }
121