/*
* Created on March 9, 2007
*
* Copyright (c) 2007 Jens Gulden
*
* http://www.frinika.com
*
* This file is part of Frinika.
*
* Frinika is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* Frinika 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 Frinika; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.frinika.sequencer.gui;
import java.awt.GridBagConstraints;
import java.util.Collection;
import javax.swing.BoundedRangeModel;
import javax.swing.DefaultBoundedRangeModel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* GUI component which is a JSlider with a number-field (JSpinner)
* attached to it. This way, numerical values can be edited either
* "visually" (using the slider) or "precise" entering the number textually.
* Slider and umber-field are always in sync.
*
* @author Jens Gulden
*/
public class SliderNumberEditable extends JPanel {
protected String prefix;
protected String suffix;
protected float value;
protected float minimum = -100f;
protected float maximum = 100f;
protected float stepSize = 0;
protected int orientation = SwingConstants.HORIZONTAL;
protected ListenerSupport<ChangeListener, ChangeEvent> changeListeners = new ListenerSupport<ChangeListener, ChangeEvent>() {
public void notify(ChangeListener l, ChangeEvent e) {
l.stateChanged(e);
}
};
private javax.swing.JLabel prefixLabel;
private javax.swing.JSlider slider;
private javax.swing.JSpinner spinner;
private javax.swing.JLabel suffixLabel;
/** Creates new form BeanForm */
public SliderNumberEditable() {
initComponents();
layoutComponents();
}
public SliderNumberEditable(float value, float minimum, float maximum, float stepSize, String prefix, String suffix, int orientation) { // float sliderFactor) {
initComponents();
setValue(value);
setMinimum(minimum);
setMaximum(maximum);
setStepSize(stepSize);
setPrefix(prefix);
setSuffix(suffix);
setOrientation(orientation);
layoutComponents();
validate();
}
@Override
public void validate() {
SpinnerNumberModel model = new SpinnerNumberModel((Float)value, (Float)minimum, (Float)maximum, (Float)stepSize);
setModel(model);
super.validate();
}
public void setModel(SpinnerNumberModel model) {
slider.setModel(toBoundedRangeModel(model));
spinner.setModel(model);
if (((Float)model.getMaximum()).floatValue() == 100f) { // special: if maximum value is 100, force fix column size (independent from minimu, so 0 or -100 are possible as minimum for this)
JTextField tf = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField();
tf.setColumns(3); // will result in actually more than 3 characters, so negative values are fine
}
}
public boolean isEnabled() {
return slider.isEnabled();
}
public void setEnabled(boolean enabled) {
slider.setEnabled(enabled);
spinner.setEnabled(enabled);
}
public boolean getInverted() {
return slider.getInverted();
}
public int getMajorTickSpacing() {
return slider.getMajorTickSpacing();
}
public int getMinorTickSpacing() {
return slider.getMinorTickSpacing();
}
public int getOrientation() {
return slider.getOrientation();
}
public boolean getPaintLabels() {
return slider.getPaintLabels();
}
public boolean getPaintTicks() {
return slider.getPaintTicks();
}
public boolean getPaintTrack() {
return slider.getPaintTrack();
}
public boolean getSnapToTicks() {
return slider.getSnapToTicks();
}
public void setInverted(boolean b) {
slider.setInverted(b);
}
public void setMajorTickSpacing(int n) {
slider.setMajorTickSpacing(n);
}
public void setMinorTickSpacing(int n) {
slider.setMinorTickSpacing(n);
}
public void setOrientation(int orientation) {
if (this.orientation != orientation) {
this.orientation = orientation;
slider.setOrientation(orientation);
layoutComponents();
super.validate();
}
}
public void setPaintLabels(boolean b) {
slider.setPaintLabels(b);
}
public void setPaintTicks(boolean b) {
slider.setPaintTicks(b);
}
public void setPaintTrack(boolean b) {
slider.setPaintTrack(b);
}
public void setSnapToTicks(boolean b) {
slider.setSnapToTicks(b);
}
public static BoundedRangeModel toBoundedRangeModel(SpinnerNumberModel m) {
return new DefaultBoundedRangeModel((int)((Float)(m.getValue())).floatValue(), 0, (int)((Float)(m.getMinimum())).floatValue(), (int)((Float)(m.getMaximum())).floatValue());
}
public void addChangeListener(ChangeListener l) {
changeListeners.addListener(l);
}
public void removeChangeListener(ChangeListener l) {
changeListeners.removeListener(l);
}
public Collection<ChangeListener> getChangeListeners() {
return changeListeners.getListeners();
}
private void spinnerStateChanged(javax.swing.event.ChangeEvent evt) {
setValue( (Float)spinner.getModel().getValue() );
}
private void sliderStateChanged(javax.swing.event.ChangeEvent evt) {
setValue( slider.getModel().getValue() );
}
/**
* Getter for property prefix.
* @return Value of property prefix.
*/
public String getPrefix() {
return this.prefix;
}
/**
* Setter for property prefix.
* @param prefix New value of property prefix.
*/
public void setPrefix(String prefix) {
this.prefix = prefix;
if (prefix != null) {
prefixLabel.setText(prefix);
} else {
remove(prefixLabel);
}
}
/**
* Getter for property suffix.
* @return Value of property suffix.
*/
public String getSuffix() {
return this.suffix;
}
/**
* Setter for property suffix.
* @param suffix New value of property suffix.
*/
public void setSuffix(String suffix) {
this.suffix = suffix;
if (suffix != null) {
suffixLabel.setText(suffix);
} else {
remove(suffixLabel);
}
}
/**
* Getter for property value.
* @return Value of property value.
*/
public float getValue() {
return this.value;
}
/**
* Setter for property value.
* @param value New value of property value.
*/
public void setValue(float value) {
if (value < minimum) value = minimum; else if (value > maximum) value = maximum;
if (value != this.value) {
this.value = value;
slider.setValue(Math.round(value));
spinner.setValue(value);
changeListeners.notifyListeners(new ChangeEvent(this));
}
}
/**
* Getter for property minimum.
* @return Value of property minimum.
*/
public float getMinimum() {
return this.minimum;
}
/**
* Setter for property minimum.
* @param minimum New value of property minimum.
*/
public void setMinimum(float minimum) {
this.minimum = minimum;
}
/**
* Getter for property maximum.
* @return Value of property maximum.
*/
public float getMaximum() {
return this.maximum;
}
/**
* Setter for property maximum.
* @param maximum New value of property maximum.
*/
public void setMaximum(float maximum) {
this.maximum = maximum;
}
/**
* Getter for property stepSize.
* @return Value of property stepSize.
*/
public float getStepSize() {
return this.stepSize;
}
/**
* Setter for property stepSize.
* @param stepSize New value of property stepSize.
*/
public void setStepSize(float stepSize) {
this.stepSize = stepSize;
}
private void initComponents() {
slider = new javax.swing.JSlider();
prefixLabel = new javax.swing.JLabel();
spinner = new javax.swing.JSpinner();
suffixLabel = new javax.swing.JLabel();
this.setLayout(new java.awt.GridBagLayout());
slider.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
sliderStateChanged(evt);
}
});
spinner.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
spinnerStateChanged(evt);
}
});
}
private void layoutComponents() {
this.removeAll();
GridBagConstraints gridBagConstraints = new GridBagConstraints();
if (orientation == SwingConstants.HORIZONTAL) {
gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
} else { // vertical
gridBagConstraints.fill = GridBagConstraints.VERTICAL;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.gridx = GridBagConstraints.REMAINDER;
}
add(slider, gridBagConstraints);
gridBagConstraints = new GridBagConstraints();
if (orientation == SwingConstants.HORIZONTAL) {
gridBagConstraints.anchor = GridBagConstraints.NORTH;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
}
add(prefixLabel,gridBagConstraints);
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 5);
if (orientation == SwingConstants.HORIZONTAL) {
gridBagConstraints.anchor = GridBagConstraints.NORTH;
}
add(spinner, gridBagConstraints);
gridBagConstraints = new GridBagConstraints();
if (orientation == SwingConstants.HORIZONTAL) {
gridBagConstraints.anchor = GridBagConstraints.NORTH;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
}
add(suffixLabel, gridBagConstraints);
}
}