/* * Copyright 2017 Laszlo Balazs-Csiki * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU * General Public License, version 3 as published by the Free * Software Foundation. * * Pixelitor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Pixelitor. If not, see <http://www.gnu.org/licenses/>. */ package pixelitor.gui.utils; import pixelitor.filters.gui.DefaultButton; import pixelitor.filters.gui.ParamGUI; import pixelitor.filters.gui.RangeParam; import pixelitor.filters.gui.Resettable; import javax.swing.*; import javax.swing.border.Border; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.util.Dictionary; import java.util.Enumeration; import static java.awt.Color.GRAY; /** * A GUI Component consisting of a JSlider, a JSpinner and optionally a default button. * The slider and the spinner are synchronized */ public class SliderSpinner extends JPanel implements ChangeListener, ParamGUI { private final JLabel label; private Resettable resettableParam; // if set to non-null, its reset is called instead of the reset this object public enum TextPosition { BORDER, WEST, NORTH, NONE } private final JSlider slider; private final JSpinner spinner; private DefaultButton defaultButton; private final RangeParam model; private Color leftColor; private Color rightColor; private final boolean colorsUsed; private boolean sliderMoved = false; private boolean spinnerMoved = false; public SliderSpinner(RangeParam model, TextPosition position, boolean addDefaultButton) { this(model, null, null, position, addDefaultButton); } public SliderSpinner(RangeParam model, Color leftColor, Color rightColor) { this(model, leftColor, rightColor, TextPosition.BORDER, true); } private SliderSpinner(RangeParam model, Color leftColor, Color rightColor, TextPosition textPosition, boolean addDefaultButton) { setLayout(new BorderLayout()); this.model = model; this.leftColor = leftColor; this.rightColor = rightColor; colorsUsed = leftColor != null; if (textPosition == TextPosition.BORDER) { if ((leftColor != null) && (rightColor != null)) { Border gradientBorder = new GradientBorder(leftColor, rightColor); this.setBorder(BorderFactory.createTitledBorder(gradientBorder, model.getName())); } else { this.setBorder(BorderFactory.createTitledBorder(model.getName())); this.leftColor = GRAY; this.rightColor = GRAY; } } slider = new JSlider(model); if (textPosition == TextPosition.BORDER) { setupTicks(); } slider.addChangeListener(this); spinner = new JSpinner(new SpinnerNumberModel( model.getValue(), //initial value model.getMinimum(), //min model.getMaximum(), //max 1)); spinner.addChangeListener(this); label = new JLabel(model.getName() + ": "); if (textPosition == TextPosition.WEST) { add(label, BorderLayout.WEST); } else if (textPosition == TextPosition.NORTH) { add(label, BorderLayout.NORTH); } JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT)); add(slider, BorderLayout.CENTER); p.add(spinner); if (addDefaultButton) { defaultButton = new DefaultButton(resettableParam == null ? model : resettableParam); // int spinnerHeight = (int) spinner.getPreferredSize().getHeight(); // defaultButton.setPreferredSize(new Dimension(spinnerHeight, spinnerHeight)); if (colorsUsed) { defaultButton.setBackground(GRAY); } p.add(defaultButton); } add(p, BorderLayout.EAST); // showTicksAsFloat(); } public void setupTicks() { int range = model.getMaximum() - model.getMinimum(); int minorSpacing; int majorSpacing; if (range == 100) { minorSpacing = 0; majorSpacing = 25; // } else if(range == 499) { // minorSpacing = 25; // majorSpacing = 100; } else if (range >= 7) { minorSpacing = (range + 1) / 8; majorSpacing = 2 * minorSpacing; } else { // dry brush has for example a range of only 5 minorSpacing = 0; majorSpacing = 1; } setupTicks(majorSpacing, minorSpacing); } public void setupTicks(int majorSpacing, int minorSpacing) { if (majorSpacing > 0) { slider.setMajorTickSpacing(majorSpacing); } if (minorSpacing > 0) { slider.setMinorTickSpacing(minorSpacing); } slider.setPaintTicks(true); slider.setPaintLabels(true); } public void showTicksAsFloat() { // TODO throws NullPointerException slider.createStandardLabels(10); @SuppressWarnings("unchecked") Dictionary<Integer, JLabel> labelsDict = slider.getLabelTable(); Enumeration<Integer> keys = labelsDict.keys(); while (keys.hasMoreElements()) { Integer i = keys.nextElement(); labelsDict.get(i).setText(String.valueOf(i / 100.0f)); } } public int getCurrentValue() { return model.getValue(); } @Override public void stateChanged(ChangeEvent e) { Object o = e.getSource(); if (o == slider) { if (spinnerMoved) { return; } int currentValue = slider.getValue(); sliderMoved = true; spinner.setValue(currentValue); sliderMoved = false; } else if (o == spinner) { if (sliderMoved) { return; } // this gets called even if the slider is modified by the user int currentValue = (Integer) spinner.getValue(); spinnerMoved = true; model.setValue(currentValue); spinnerMoved = false; } if (defaultButton != null) { defaultButton.updateState(); } if (colorsUsed) { if (model.isSetToDefault()) { defaultButton.setBackground(GRAY); } else { if (model.getValue() > model.getDefaultValue()) { defaultButton.setBackground(rightColor); } else { defaultButton.setBackground(leftColor); } } } } public void resetToDefaultSettings() { model.reset(false); } @Override public Dimension getMaximumSize() { return getPreferredSize(); } public RangeParam getModel() { return model; } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); slider.setEnabled(enabled); spinner.setEnabled(enabled); if (label != null) { label.setEnabled(enabled); } if (defaultButton != null) { defaultButton.setEnabled(enabled); } } public void setResettable(Resettable param) { resettableParam = param; } @Override public void updateGUI() { // nothing to do } public void setSliderName(String name) { slider.setName(name); } @Override public void setToolTip(String tip) { slider.setToolTipText(tip); spinner.setToolTipText(tip); } public void addChangeListener(ChangeListener listener) { slider.addChangeListener(listener); } }