create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / gui / components / compass / CompassSelectionButton.java
1 package net.sf.openrocket.gui.components.compass;
2
3 import java.awt.Dimension;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6
7 import javax.swing.BorderFactory;
8 import javax.swing.JButton;
9 import javax.swing.JLabel;
10 import javax.swing.JPanel;
11 import javax.swing.JPopupMenu;
12 import javax.swing.JSpinner;
13 import javax.swing.border.BevelBorder;
14 import javax.swing.event.ChangeEvent;
15 import javax.swing.event.ChangeListener;
16
17 import net.miginfocom.swing.MigLayout;
18 import net.sf.openrocket.gui.Resettable;
19 import net.sf.openrocket.gui.adaptors.DoubleModel;
20 import net.sf.openrocket.gui.components.FlatButton;
21 import net.sf.openrocket.l10n.Translator;
22 import net.sf.openrocket.startup.Application;
23 import net.sf.openrocket.util.Chars;
24 import net.sf.openrocket.util.MathUtil;
25
26
27 /**
28  * A button that displays a current compass direction and opens a popup to edit
29  * the value when clicked.
30  * 
31  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
32  */
33 public class CompassSelectionButton extends FlatButton implements Resettable {
34         
35         private static final Translator trans = Application.getTranslator();
36         
37         private static final int POPUP_COMPASS_SIZE = 200;
38         private static final double SECTOR = 45;
39         
40         private static int minWidth = -1;
41         
42
43         private final DoubleModel model;
44         private final ChangeListener listener;
45         
46         private JPopupMenu popup;
47         
48         
49         public CompassSelectionButton(final DoubleModel model) {
50                 this.model = model;
51                 
52                 JPanel panel = new JPanel(new MigLayout("fill, ins 0"));
53                 panel.setOpaque(false);
54                 
55                 CompassPointer pointer = new CompassPointer(model);
56                 pointer.setPreferredSize(new Dimension(24, 24));
57                 pointer.setMarkerFont(null);
58                 pointer.setPointerArrow(false);
59                 pointer.setPointerWidth(0.45f);
60                 pointer.setScaler(1.0f);
61                 panel.add(pointer, "gapright rel");
62                 
63
64                 final JLabel label = new JLabel();
65                 label.setText(getLabel(model.getValue()));
66                 panel.add(label);
67                 
68                 listener = new ChangeListener() {
69                         @Override
70                         public void stateChanged(ChangeEvent e) {
71                                 label.setText(getLabel(model.getValue()));
72                         }
73                 };
74                 model.addChangeListener(listener);
75                 
76
77                 if (minWidth < 0) {
78                         calculateMinWidth();
79                         label.setMinimumSize(new Dimension(minWidth, 0));
80                 }
81                 
82
83                 this.add(panel);
84                 
85                 this.addActionListener(new ActionListener() {
86                         @Override
87                         public void actionPerformed(ActionEvent e) {
88                                 openPopup();
89                         }
90                 });
91         }
92         
93         
94
95
96         private String getLabel(double value) {
97                 String str;
98                 
99                 value = MathUtil.reduce360(value);
100                 value = Math.toDegrees(value);
101                 str = "" + Math.round(value) + Chars.DEGREE + " (";
102                 
103                 if (value <= 0.5 * SECTOR || value >= 7.5 * SECTOR) {
104                         str += trans.get("lbl.N");
105                 } else if (value <= 1.5 * SECTOR) {
106                         str += trans.get("lbl.NE");
107                 } else if (value <= 2.5 * SECTOR) {
108                         str += trans.get("lbl.E");
109                 } else if (value <= 3.5 * SECTOR) {
110                         str += trans.get("lbl.SE");
111                 } else if (value <= 4.5 * SECTOR) {
112                         str += trans.get("lbl.S");
113                 } else if (value <= 5.5 * SECTOR) {
114                         str += trans.get("lbl.SW");
115                 } else if (value <= 6.5 * SECTOR) {
116                         str += trans.get("lbl.W");
117                 } else {
118                         str += trans.get("lbl.NW");
119                 }
120                 
121                 str += ")";
122                 return str;
123         }
124         
125         
126         private void openPopup() {
127                 if (popup == null) {
128                         popup = new JPopupMenu();
129                         
130
131                         final JPanel panel = new JPanel(new MigLayout("fill"));
132                         
133                         final CompassPointer rose = new CompassSelector(model);
134                         rose.setPreferredSize(new Dimension(POPUP_COMPASS_SIZE, POPUP_COMPASS_SIZE));
135                         panel.add(rose, "spany, gapright unrel");
136                         
137                         panel.add(new JPanel(), "growy, wrap");
138                         
139                         JSpinner spin = new JSpinner(model.getSpinnerModel());
140                         panel.add(spin, "wmin 50lp, growx, gapright 0, aligny bottom");
141                         
142                         panel.add(new JLabel("" + Chars.DEGREE), "wrap para");
143                         
144                         JButton close = new JButton("OK");
145                         close.addActionListener(new ActionListener() {
146                                 @Override
147                                 public void actionPerformed(ActionEvent e) {
148                                         popup.setVisible(false);
149                                 }
150                         });
151                         panel.add(close, "span 2, growx, wrap");
152                         
153                         panel.add(new JPanel(), "growy, wrap");
154                         
155                         popup.add(panel);
156                         popup.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
157                 }
158                 
159                 popup.pack();
160                 
161                 Dimension popupSize = popup.getPreferredSize();
162                 Dimension buttonSize = this.getSize();
163                 
164                 int posX = buttonSize.width / 2 - popupSize.width / 2;
165                 int posY = buttonSize.height / 2 - popupSize.height / 2;
166                 popup.show(this, posX, posY);
167         }
168         
169         private void calculateMinWidth() {
170                 JLabel label = new JLabel();
171                 int max = 0;
172                 for (double deg = 0; deg < 360; deg += 0.99999999999) {
173                         label.setText(getLabel(Math.toRadians(deg)));
174                         int w = label.getPreferredSize().width;
175                         if (w > max) {
176                                 max = w;
177                         }
178                 }
179                 minWidth = max + 1;
180         }
181         
182         
183
184
185         @Override
186         public void resetModel() {
187                 model.removeChangeListener(listener);
188         }
189         
190 }