//
// StepWidget.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.util;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.basic.BasicArrowButton;
/**
* StepWidget is a slider GUI component with
* directional step arrows at either end.
*/
public class StepWidget extends JPanel
implements ActionListener, ChangeListener
{
protected static final boolean DEBUG = false;
private static final int BUTTON_WIDTH = 25;
private static final int BUTTON_HEIGHT = 25;
private static final int GAP = 5;
private static final Dimension buttonSize =
new Dimension(BUTTON_WIDTH, BUTTON_HEIGHT);
protected JSlider step;
private boolean horiz;
protected JButton forward;
protected JButton back;
protected int min = 1;
protected int max = 1;
protected int cur = 1;
/** Constructs a StepWidget. */
public StepWidget(boolean horizontal) {
// determine orientation
horiz = horizontal;
int mainLayout, subLayout;
int backDir, stepDir, forwardDir;
Dimension gap;
Component glue1, glue2, glue3, glue4;
if (horizontal) {
mainLayout = BoxLayout.X_AXIS;
subLayout = BoxLayout.Y_AXIS;
backDir = BasicArrowButton.WEST;
stepDir = JSlider.HORIZONTAL;
forwardDir = BasicArrowButton.EAST;
gap = new Dimension(GAP, 0);
glue1 = Box.createVerticalGlue();
glue2 = Box.createVerticalGlue();
glue3 = Box.createVerticalGlue();
glue4 = Box.createVerticalGlue();
}
else {
mainLayout = BoxLayout.Y_AXIS;
subLayout = BoxLayout.X_AXIS;
backDir = BasicArrowButton.NORTH;
stepDir = JSlider.VERTICAL;
forwardDir = BasicArrowButton.SOUTH;
gap = new Dimension(0, GAP);
glue1 = Box.createHorizontalGlue();
glue2 = Box.createHorizontalGlue();
glue3 = Box.createHorizontalGlue();
glue4 = Box.createHorizontalGlue();
}
// create panels
JPanel before = new JPanel();
JPanel after = new JPanel();
setLayout(new BoxLayout(this, mainLayout));
before.setLayout(new BoxLayout(before, subLayout));
after.setLayout(new BoxLayout(after, subLayout));
// create components
back = new BasicArrowButton(backDir) {
public Dimension getPreferredSize() { return buttonSize; }
public Dimension getMaximumSize() { return buttonSize; }
};
step = new JSlider(stepDir, min, max, cur);
forward = new BasicArrowButton(forwardDir) {
public Dimension getPreferredSize() { return buttonSize; }
public Dimension getMaximumSize() { return buttonSize; }
};
step.setPaintTicks(true);
step.setAlignmentX(JButton.LEFT_ALIGNMENT);
// lay out components
add(before);
add(Box.createRigidArea(gap));
add(step);
add(Box.createRigidArea(gap));
add(after);
before.add(glue1);
before.add(back);
before.add(glue2);
after.add(glue3);
after.add(forward);
after.add(glue4);
// listen for GUI events
back.addActionListener(this);
forward.addActionListener(this);
step.addChangeListener(this);
// disable controls
setEnabled(false);
}
/** Returns the minimum size of the widget. */
public Dimension getMinimumSize() {
Dimension min = getPreferredSize();
return horiz ? new Dimension(0, min.height + 4 * GAP) :
new Dimension(min.width, 0);
}
/** Returns the maximum size of the widget. */
public Dimension getMaximumSize() {
Dimension max = getPreferredSize();
return horiz ? new Dimension(Integer.MAX_VALUE, max.height + 4 * GAP) :
new Dimension(max.width, Integer.MAX_VALUE);
}
/** Gets the current value of the widget. */
public int getValue() { return step.getValue(); }
/** Gets the minimum value of the widget. */
public int getMinimum() { return step.getMinimum(); }
/** Gets the maximum value of the widget. */
public int getMaximum() { return step.getMaximum(); }
/** Sets the current value of the widget. */
public void setValue(int cur) {
this.cur = cur;
step.setValue(cur);
}
/** Enables or disables the widget. */
public void setEnabled(boolean enabled) {
step.setEnabled(enabled);
back.setEnabled(enabled);
forward.setEnabled(enabled);
}
/** Sets the minimum, maximum and current values of the slider. */
public void setBounds(int min, int max, int cur) {
this.min = min;
this.max = max;
this.cur = cur;
step.setMinimum(min);
step.setMaximum(max);
step.setValue(cur);
int maj;
if (max < 4) maj = 1;
else if (max < 20) maj = max / 4;
else if (max < 30) maj = max / 6;
else maj = max / 8;
step.setMajorTickSpacing(maj);
step.setMinorTickSpacing(maj / 4);
step.setPaintLabels(true);
}
/** Adds a ChangeListener to the widget. */
public void addChangeListener(ChangeListener l) {
step.addChangeListener(l);
}
/** Removes a ChangeListener from the widget. */
public void removeChangeListener(ChangeListener l) {
step.removeChangeListener(l);
}
/** ActionListener method used with JButtons. */
public void actionPerformed(ActionEvent e) {
boolean direction = (e.getSource() == back);
if (horiz == direction) {
// move back
cur--;
if (cur < min) cur = max;
}
else {
// move forward
cur++;
if (cur > max) cur = min;
}
step.setValue(cur);
updateStep();
}
/** ChangeListener method used with JSlider. */
public void stateChanged(ChangeEvent e) {
cur = step.getValue();
updateStep();
}
/**
* Takes action when the slider's current value changes.
*
* This method is a stub that can be overridden to define behavior.
*/
protected void updateStep() { }
}