1 package net.sf.openrocket.gui.components.compass;
3 import java.awt.Dimension;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
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;
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;
28 * A button that displays a current compass direction and opens a popup to edit
29 * the value when clicked.
31 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
33 public class CompassSelectionButton extends FlatButton implements Resettable {
35 private static final Translator trans = Application.getTranslator();
37 private static final int POPUP_COMPASS_SIZE = 200;
38 private static final double SECTOR = 45;
40 private static int minWidth = -1;
43 private final DoubleModel model;
44 private final ChangeListener listener;
46 private JPopupMenu popup;
49 public CompassSelectionButton(final DoubleModel model) {
52 JPanel panel = new JPanel(new MigLayout("fill, ins 0"));
53 panel.setOpaque(false);
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");
64 final JLabel label = new JLabel();
65 label.setText(getLabel(model.getValue()));
68 listener = new ChangeListener() {
70 public void stateChanged(ChangeEvent e) {
71 label.setText(getLabel(model.getValue()));
74 model.addChangeListener(listener);
79 label.setMinimumSize(new Dimension(minWidth, 0));
85 this.addActionListener(new ActionListener() {
87 public void actionPerformed(ActionEvent e) {
96 private String getLabel(double value) {
99 value = MathUtil.reduce360(value);
100 value = Math.toDegrees(value);
101 str = "" + Math.round(value) + Chars.DEGREE + " (";
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");
118 str += trans.get("lbl.NW");
126 private void openPopup() {
128 popup = new JPopupMenu();
131 final JPanel panel = new JPanel(new MigLayout("fill"));
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");
137 panel.add(new JPanel(), "growy, wrap");
139 JSpinner spin = new JSpinner(model.getSpinnerModel());
140 panel.add(spin, "wmin 50lp, growx, gapright 0, aligny bottom");
142 panel.add(new JLabel("" + Chars.DEGREE), "wrap para");
144 JButton close = new JButton("OK");
145 close.addActionListener(new ActionListener() {
147 public void actionPerformed(ActionEvent e) {
148 popup.setVisible(false);
151 panel.add(close, "span 2, growx, wrap");
153 panel.add(new JPanel(), "growy, wrap");
156 popup.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
161 Dimension popupSize = popup.getPreferredSize();
162 Dimension buttonSize = this.getSize();
164 int posX = buttonSize.width / 2 - popupSize.width / 2;
165 int posY = buttonSize.height / 2 - popupSize.height / 2;
166 popup.show(this, posX, posY);
169 private void calculateMinWidth() {
170 JLabel label = new JLabel();
172 for (double deg = 0; deg < 360; deg += 0.99999999999) {
173 label.setText(getLabel(Math.toRadians(deg)));
174 int w = label.getPreferredSize().width;
186 public void resetModel() {
187 model.removeChangeListener(listener);