package tim.prune.gui.colour; import java.awt.Color; import java.awt.Component; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.EtchedBorder; import tim.prune.I18nManager; import tim.prune.gui.GuiGridLayout; import tim.prune.gui.colour.ColourerFactory.ColourerId; /** * Class to provide a gui panel for selecting a colourer * including which colourer, the start/end colours and * optionally the max number of colours */ public class ColourerSelectorPanel extends JPanel { /** Combo box for selecting the type of colourer */ private JComboBox _typeCombo = null; /** Array of type ids as stored in combo box */ private ColourerId[] _typeIds = null; /** Panel object holding the colour patches */ private JPanel _patchPanel = null; /** Array of colour patches for start and end */ private ColourPatch[] _startEndPatches = null; /** Panel holding the max colours selection */ JPanel _maxColoursPanel = null; private JComboBox _maxColoursCombo = null; /** Array of label keys for the 2 patches */ private static final String[] LABEL_KEYS = {"start", "end"}; /** * Constructor * @param inColourChooser colour chooser to use (needs reference to parent dialog) */ public ColourerSelectorPanel(ColourChooser inColourChooser) { _typeIds = new ColourerId[] {ColourerId.NONE, ColourerId.BY_FILE, ColourerId.BY_SEGMENT, ColourerId.BY_DATE, ColourerId.BY_ALTITUDE, ColourerId.BY_SPEED, ColourerId.BY_VSPEED, ColourerId.BY_GRADIENT}; makeGuiComponents(inColourChooser); } /** * Create all the gui components and lay them out in the panel * @param inColourChooser colour chooser to use */ private void makeGuiComponents(ColourChooser inColourChooser) { // Etched border and vertical layout setBorder(BorderFactory.createCompoundBorder( BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(4, 4, 4, 4)) ); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); // Label at the top JLabel introLabel = new JLabel(I18nManager.getText("dialog.colourer.intro")); introLabel.setAlignmentX(Component.LEFT_ALIGNMENT); add(introLabel); // Combo box for selecting which colourer to use JPanel typePanel = new JPanel(); GuiGridLayout grid = new GuiGridLayout(typePanel); final String keyPrefix = "dialog.colourer.type."; String[] colourerTypes = new String[_typeIds.length]; for (int i=0; i(colourerTypes); _typeCombo.setAlignmentX(Component.LEFT_ALIGNMENT); _typeCombo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { onColourerTypeChanged(); } }); // Add to the panel grid.add(new JLabel(I18nManager.getText("dialog.colourer.type"))); grid.add(_typeCombo); typePanel.setAlignmentX(Component.LEFT_ALIGNMENT); add(typePanel); // Make panel for colour patches _patchPanel = new JPanel(); _patchPanel.setLayout(new GridLayout()); _startEndPatches = new ColourPatch[2]; // Blank column JPanel blankColumn = new JPanel(); ColourPatch blankPatch = new ColourPatch(Color.BLACK); blankPatch.setVisible(false); blankColumn.add(blankPatch); _patchPanel.add(blankColumn); // Loop over two columns of patches for (int i=0; i<2; i++) { JPanel colPanel = new JPanel(); colPanel.setLayout(new BoxLayout(colPanel, BoxLayout.Y_AXIS)); // Top label and patch colPanel.add(new JLabel(I18nManager.getText("dialog.colourer." + LABEL_KEYS[i]))); ColourPatch patch = new ColourPatch(Color.BLUE); // will be set by init() method shortly patch.addMouseListener(new PatchListener(patch, inColourChooser)); colPanel.add(patch); _startEndPatches[i] = patch; // Add column to panel colPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); _patchPanel.add(colPanel); } // Blank column blankColumn = new JPanel(); blankPatch = new ColourPatch(Color.BLACK); blankPatch.setVisible(false); blankColumn.add(blankPatch); _patchPanel.add(blankColumn); _patchPanel.setAlignmentX(Component.LEFT_ALIGNMENT); add(_patchPanel); // Combo box for selecting max colours _maxColoursPanel = new JPanel(); grid = new GuiGridLayout(_maxColoursPanel); grid.add(new JLabel(I18nManager.getText("dialog.colourer.maxcolours"))); String[] colourOptions = new String[] {"2", "3", "5", "10", "15"}; _maxColoursCombo = new JComboBox(colourOptions); grid.add(_maxColoursCombo); _maxColoursPanel.setAlignmentX(Component.LEFT_ALIGNMENT); add(_maxColoursPanel); } /** * Init the colours from the colourer (if possible) or the default colour * @param inColourer current colourer object, or null * @param inDefaultColour current colour for points */ public void init(PointColourer inColourer, Color inDefaultColour) { Color startColour = null, endColour = null; if (inColourer != null) { selectColourerType(ColourerFactory.getId(inColourer)); startColour = inColourer.getStartColour(); endColour = inColourer.getEndColour(); _maxColoursCombo.setSelectedItem("" + inColourer.getMaxColours()); } else { // no colourer, so default to 5 colours maximum _maxColoursCombo.setSelectedIndex(2); } if (startColour == null) {startColour = inDefaultColour;} if (endColour == null) {endColour = makeDefaultEndColour(inDefaultColour);} if (startColour != null) {_startEndPatches[0].setBackground(startColour);} if (endColour != null) {_startEndPatches[1].setBackground(endColour);} onColourerTypeChanged(); // make sure gui is updated } /** * Make a default end colour if there isn't one already defined * @param inStartColour start colour * @return end colour, with the hue shifted by a third from the start */ private static Color makeDefaultEndColour(Color inStartColour) { float[] defaultHSB = Color.RGBtoHSB(inStartColour.getRed(), inStartColour.getGreen(), inStartColour.getBlue(), null); // add 120 degrees to the hue defaultHSB[0] += (1.0f/3f); return Color.getHSBColor(defaultHSB[0], defaultHSB[1], defaultHSB[2]); } /** * React to the colourer type being changed * by showing / hiding gui elements */ private void onColourerTypeChanged() { final ColourerId id = _typeIds[_typeCombo.getSelectedIndex()]; // Set visibility of controls according to whether they're needed for the selected type _patchPanel.setVisible(ColourerFactory.areColoursRequired(id)); _maxColoursPanel.setVisible(ColourerFactory.isMaxColoursRequired(id)); } /** * @return the selected colourer object, or null */ public PointColourer getSelectedColourer() { final ColourerId id = _typeIds[_typeCombo.getSelectedIndex()]; return ColourerFactory.createColourer(id, _startEndPatches[0].getBackground(), _startEndPatches[1].getBackground(), _maxColoursCombo.getSelectedItem().toString()); } /** * Select the appropriate item in the dropdown * @param inId id of colourer to choose */ private void selectColourerType(ColourerId inId) { int selIndex = -1; for (int i=0; i<_typeIds.length; i++) { if (_typeIds[i] == inId) { selIndex = i; break; } } if (selIndex < 0) { System.err.println("Id " + inId + " not found in _typeIds!"); } else { _typeCombo.setSelectedIndex(selIndex); } } }