package net.sf.openrocket.gui.components.compass; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSpinner; import javax.swing.border.BevelBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.gui.Resettable; import net.sf.openrocket.gui.SpinnerEditor; import net.sf.openrocket.gui.adaptors.DoubleModel; import net.sf.openrocket.gui.components.FlatButton; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.Chars; import net.sf.openrocket.util.MathUtil; /** * A button that displays a current compass direction and opens a popup to edit * the value when clicked. * * @author Sampo Niskanen <sampo.niskanen@iki.fi> */ public class CompassSelectionButton extends FlatButton implements Resettable { private static final Translator trans = Application.getTranslator(); private static final int POPUP_COMPASS_SIZE = 200; private static final double SECTOR = 45; private static int minWidth = -1; @SuppressWarnings("hiding") private final DoubleModel model; private final ChangeListener listener; private JPopupMenu popup; public CompassSelectionButton(final DoubleModel model) { this.model = model; JPanel panel = new JPanel(new MigLayout("fill, ins 0")); panel.setOpaque(false); CompassPointer pointer = new CompassPointer(model); pointer.setPreferredSize(new Dimension(24, 24)); pointer.setMarkerFont(null); pointer.setPointerArrow(false); pointer.setPointerWidth(0.45f); pointer.setScaler(1.0f); panel.add(pointer, "gapright rel"); final JLabel label = new JLabel(); label.setText(getLabel(model.getValue())); panel.add(label); listener = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { label.setText(getLabel(model.getValue())); } }; model.addChangeListener(listener); if (minWidth < 0) { calculateMinWidth(); label.setMinimumSize(new Dimension(minWidth, 0)); } this.add(panel); this.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { openPopup(); } }); } private String getLabel(double value) { String str; value = MathUtil.reduce360(value); value = Math.toDegrees(value); str = "" + Math.round(value) + Chars.DEGREE + " ("; if (value <= 0.5 * SECTOR || value >= 7.5 * SECTOR) { str += trans.get("lbl.N"); } else if (value <= 1.5 * SECTOR) { str += trans.get("lbl.NE"); } else if (value <= 2.5 * SECTOR) { str += trans.get("lbl.E"); } else if (value <= 3.5 * SECTOR) { str += trans.get("lbl.SE"); } else if (value <= 4.5 * SECTOR) { str += trans.get("lbl.S"); } else if (value <= 5.5 * SECTOR) { str += trans.get("lbl.SW"); } else if (value <= 6.5 * SECTOR) { str += trans.get("lbl.W"); } else { str += trans.get("lbl.NW"); } str += ")"; return str; } private void openPopup() { if (popup == null) { popup = new JPopupMenu(); final JPanel panel = new JPanel(new MigLayout("fill")); final CompassPointer rose = new CompassSelector(model); rose.setPreferredSize(new Dimension(POPUP_COMPASS_SIZE, POPUP_COMPASS_SIZE)); panel.add(rose, "spany, gapright unrel"); panel.add(new JPanel(), "growy, wrap"); JSpinner spin = new JSpinner(model.getSpinnerModel()); spin.setEditor( new SpinnerEditor( spin ) ); panel.add(spin, "wmin 50lp, growx, gapright 0, aligny bottom"); panel.add(new JLabel("" + Chars.DEGREE), "wrap para"); JButton close = new JButton("OK"); close.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { popup.setVisible(false); } }); panel.add(close, "span 2, growx, wrap"); panel.add(new JPanel(), "growy, wrap"); popup.add(panel); popup.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); } popup.pack(); Dimension popupSize = popup.getPreferredSize(); Dimension buttonSize = this.getSize(); int posX = buttonSize.width / 2 - popupSize.width / 2; int posY = buttonSize.height / 2 - popupSize.height / 2; popup.show(this, posX, posY); } private void calculateMinWidth() { JLabel label = new JLabel(); int max = 0; for (double deg = 0; deg < 360; deg += 0.99999999999) { label.setText(getLabel(Math.toRadians(deg))); int w = label.getPreferredSize().width; if (w > max) { max = w; } } minWidth = max + 1; } @Override public void resetModel() { model.removeChangeListener(listener); } }