package lcm.util;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class ParameterGUI
{
HashMap<String, PValue> parammap = new HashMap<String, PValue>();
JPanel panel = new JPanel(new GridBagLayout());
int row = 0;
GridBagConstraints gA, gB, gC, gD, gBC, gCD, gBCD, gABCD;
ArrayList<ParameterListener> listeners = new ArrayList<ParameterListener>();
boolean showvars;
/** This makes a text field yellow until they've pressed return;
it's a reminder that you need to hit return for the changes to
your text field to apply.
**/
static void setupJTextField(JTextField jtf)
{
JTFListener l = new JTFListener(jtf);
jtf.addActionListener(l);
jtf.addCaretListener(l);
jtf.addKeyListener(l);
}
static class JTFListener extends KeyAdapter implements ActionListener, CaretListener
{
JTextField jtf;
JTFListener(JTextField jtf)
{
this.jtf=jtf;
}
public void keyPressed(KeyEvent e)
{
jtf.setBackground(Color.yellow);
}
public void actionPerformed(ActionEvent e)
{
jtf.setBackground(Color.white);
}
public void caretUpdate(CaretEvent e)
{
}
}
/** Parent interface of all value elements **/
abstract class PValue
{
String name; // name of element, e.g., "logthresh"
String desc; // description, e.g., "Logarithmic threshold"
PValue(String name, String desc)
{
this.name = name;
this.desc = desc;
}
abstract void setEnabled(boolean enabled);
}
/** parse the integer in string s, or if it fails, return 'default' **/
static final int parseInteger(String s, int val)
{
try {
return Integer.parseInt(s);
} catch (Exception ex) {
return val;
}
}
/** parse the integer in string s, or if it fails, return 'default' **/
static final double parseDouble(String s, double val)
{
try {
return Double.parseDouble(s);
} catch (Exception ex) {
return val;
}
}
class ActionNotifier implements ActionListener
{
String name;
public ActionNotifier(String name)
{
this.name = name;
}
public void actionPerformed(ActionEvent e)
{
notifyListeners(name);
}
}
class BooleanValue extends PValue
{
JCheckBox jcb;
boolean value;
BooleanValue(String name, String desc, boolean value)
{
super(name, desc);
this.value = value;
}
JCheckBox getCheckBox()
{
if (jcb == null)
{
jcb = new JCheckBox(desc, value);
jcb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setBooleanValue(jcb.isSelected());
}});
}
return jcb;
}
boolean getBooleanValue()
{
return value;
}
void setBooleanValue(boolean v)
{
if (v==value)
return;
value = v;
notifyListeners(name);
}
void setEnabled(boolean v)
{
jcb.setEnabled(v);
}
}
class IntegerValue extends PValue
{
JSlider slider;
JTextField textField;
JLabel label;
int min, max;
int value;
IntegerValue(String name, String desc, int min, int max, int value)
{
super(name, desc);
this.min = min;
this.max = max;
this.value = value;
}
JSlider getSlider()
{
if (slider == null)
{
slider = new JSlider(min, max, value);
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
setIntegerValue(slider.getValue());
}});
}
return slider;
}
JLabel getLabel()
{
if (label == null)
label = new JLabel(""+value);
return label;
}
JTextField getTextField()
{
if (textField == null) {
textField = new JTextField(""+value);
setupJTextField(textField);
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setIntegerValue(parseInteger(textField.getText(), value));
}});
}
return textField;
}
int getIntegerValue()
{
return value;
}
void setIntegerValue(int v)
{
if (v<min)
v=min;
if (v>max)
v=max;
if (v == value)
return;
value = v;
if (slider != null)
slider.setValue(v);
if (textField != null)
textField.setText(""+v);
if (label != null)
label.setText(""+v);
notifyListeners(name);
}
void setMinMax(int min, int max)
{
this.min = min;
this.max = max;
if (slider != null)
{
slider.setMinimum(min);
slider.setMaximum(max);
}
}
void setEnabled(boolean v)
{
if (slider!=null)
slider.setEnabled(v);
if (textField!=null)
textField.setEnabled(v);
}
}
class DoubleValue extends PValue
{
JSlider slider;
JTextField textField;
JLabel label;
double min, max;
double value;
int ivalue; // scaled values used for slider
static final int SLIDER_CLICKS = 100000;
double stepsize;
String svalue; // string representation of value.
DoubleValue(String name, String desc, double min, double max, double value)
{
super(name, desc);
this.min = min;
this.max = max;
this.value = value;
updateSliderValue();
}
void updateSliderValue()
{
ivalue = (int) (SLIDER_CLICKS*(value-min)/(max-min));
if (slider != null)
slider.setValue(ivalue);
stepsize = (max-min)/SLIDER_CLICKS;
}
JSlider getSlider()
{
if (slider == null)
{
slider = new JSlider(0, SLIDER_CLICKS, ivalue);
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
setDoubleValue(((double)slider.getValue()+.5)/SLIDER_CLICKS*(max-min)+min);
}});
}
return slider;
}
JLabel getLabel()
{
if (label == null)
label = new JLabel(""+value);
return label;
}
JTextField getTextField()
{
if (textField == null) {
textField = new JTextField(""+value);
setupJTextField(textField);
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setDoubleValue(parseDouble(textField.getText(), value));
}});
}
return textField;
}
double getDoubleValue()
{
return value;
}
void setDoubleValue(double v)
{
if (v<min)
v=min;
if (v>max)
v=max;
if (v == value)
return;
value = v;
updateSliderValue();
{
int digits = (int) (-Math.log(stepsize)/Math.log(10))+1;
if (digits<0)
digits=0;
svalue=String.format("%."+digits+"f",value);
}
if (textField != null)
{
textField.setText(svalue);
}
if (label != null)
{
label.setText(svalue);
}
notifyListeners(name);
}
void setMinMax(double min, double max)
{
this.min = min;
this.max = max;
updateSliderValue();
}
void setEnabled(boolean v)
{
if (slider!=null)
slider.setEnabled(v);
if (textField!=null)
textField.setEnabled(v);
}
}
class StringValue extends PValue
{
JTextField textField;
JComboBox comboBox;
String value;
String values[];
int idx; // if values is set, idx is such that value=values[idx].
public StringValue(String name, String desc, String values[], String value)
{
super(name, desc);
this.value = value;
this.values = values;
updateIndex();
}
JTextField getTextField()
{
if (textField == null) {
textField = new JTextField(value);
setupJTextField(textField);
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String v = textField.getText();
setStringValue(v);
}});
}
return textField;
}
JComboBox getComboBox()
{
assert(values != null);
if (comboBox == null) {
comboBox = new JComboBox(values);
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setStringValue(values[comboBox.getSelectedIndex()]);
}});
comboBox.setSelectedIndex(idx);
}
return comboBox;
}
String getStringValue()
{
return value;
}
void updateIndex()
{
if (values!=null)
{
idx = -1;
for (int i = 0; i < values.length; i++)
{
if (value.equals(values[i]))
idx = i;
}
if (idx == -1)
System.out.println("Warning: illegal string value specified: "+value);
}
}
void setStringValue(String v)
{
if (v.equals(value))
return;
value = v;
updateIndex();
if (textField != null)
textField.setText(v);
if (comboBox != null)
comboBox.setSelectedIndex(idx);
notifyListeners(name);
}
void setEnabled(boolean v)
{
if (textField!=null)
textField.setEnabled(v);
}
}
/////////////////////////////////////////////////////////////////////////////
public ParameterGUI()
{
this(true);
}
// Our grid:
//
// 0 1 2 3
// AAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBB CCCCCC DDDDDD
// gA gB gC gD
//
// gCD spans columns C and D.
// gBCD spans columsn B, C, and D. (etc)
public ParameterGUI(boolean showvars)
{
this.showvars = showvars;
gA = new GridBagConstraints();
gA.gridx = 0;
gA.weightx = 0.05;
gA.fill=GridBagConstraints.HORIZONTAL;
gB = new GridBagConstraints();
gB.gridx = 1;
gB.weightx = 1;
gB.fill=GridBagConstraints.HORIZONTAL;
gC = new GridBagConstraints();
gC.gridx = 2;
gC.weightx = .1;
gC.fill=GridBagConstraints.HORIZONTAL;
gD = new GridBagConstraints();
gD.gridx = 3;
gD.weightx = .05;
// gD.fill=GridBagConstraints.HORIZONTAL;
gD.anchor = GridBagConstraints.CENTER;
gBC = new GridBagConstraints();
gBC.gridx = 1;
gBC.gridwidth = 2;
gBC.weightx = gB.weightx + gC.weightx;
gBC.fill=GridBagConstraints.HORIZONTAL;
gCD = new GridBagConstraints();
gCD.gridx = 2;
gCD.gridwidth = 2;
gCD.weightx = gC.weightx + gD.weightx;
gCD.fill=GridBagConstraints.HORIZONTAL;
gCD.anchor = GridBagConstraints.EAST;
gBCD = new GridBagConstraints();
gBCD.gridx = 1;
gBCD.gridwidth = 3;
gBCD.weightx = gB.weightx + gC.weightx + gD.weightx;
gBCD.fill=GridBagConstraints.HORIZONTAL;
gBCD.anchor = GridBagConstraints.EAST;
gABCD = new GridBagConstraints();
gABCD.gridx = 0;
gABCD.gridwidth = 4;
gABCD.weightx = gA.weightx + gB.weightx + gC.weightx + gD.weightx;
gABCD.fill=GridBagConstraints.HORIZONTAL;
}
protected void notifyListeners(String name)
{
for (ParameterListener pl : listeners)
pl.parameterChanged(name);
}
public void addListener(ParameterListener l)
{
listeners.add(l);
}
public void removeListeners()
{
listeners.clear();
}
public void addInt(String name, String desc, int value)
{
addInt(name, desc, -Integer.MAX_VALUE, Integer.MAX_VALUE, value);
}
public void addInt(String name, String desc, int min, int max, int value)
{
IntegerValue val = new IntegerValue(name, desc, -Integer.MAX_VALUE, Integer.MAX_VALUE, value);
parammap.put(name, val);
gA.gridy = row;
gBCD.gridy = row;
panel.add(new JLabel(desc), gA);
panel.add(val.getTextField(), gBCD);
row++;
}
public void addIntSlider(String name, String desc, int min, int max, int value)
{
IntegerValue val = new IntegerValue(name, desc, min, max, value);
parammap.put(name, val);
gA.gridy = row;
gBC.gridy = row;
gD.gridy = row;
panel.add(new JLabel(desc), gA);
panel.add(val.getSlider(), gBC);
panel.add(val.getLabel(), gD);
row++;
}
public void addDouble(String name, String desc, double value)
{
addDouble(name, desc, -Double.MAX_VALUE, Double.MAX_VALUE, value);
}
public void addDouble(String name, String desc, double min, double max, double value)
{
DoubleValue val = new DoubleValue(name, desc, min, max, value);
parammap.put(name, val);
gA.gridy = row;
gBCD.gridy = row;
panel.add(new JLabel(desc), gA);
panel.add(val.getTextField(), gBCD);
row++;
}
public void addDoubleSlider(String name, String desc, double min, double max, double value)
{
DoubleValue val = new DoubleValue(name, desc, min, max, value);
parammap.put(name, val);
gA.gridy = row;
gBC.gridy = row;
gD.gridy = row;
panel.add(new JLabel(desc), gA);
panel.add(val.getSlider(), gBC);
panel.add(val.getLabel(), gD);
row++;
}
public void addString(String name, String desc, String value)
{
StringValue val = new StringValue(name, desc, null, value);
parammap.put(name, val);
gA.gridy = row;
gBCD.gridy = row;
panel.add(new JLabel(desc), gA);
panel.add(val.getTextField(), gBCD);
row++;
}
public void addChoice(String name, String desc, String values[], int value)
{
StringValue val = new StringValue(name, desc, values, values[value]);
parammap.put(name, val);
gA.gridy = row;
gBCD.gridy = row;
panel.add(new JLabel(desc), gA);
panel.add(val.getComboBox(), gBCD);
row++;
}
public void addBoolean(String name, String desc, boolean value)
{
BooleanValue val = new BooleanValue(name, desc, value);
parammap.put(name, val);
gA.gridy = row;
gBCD.gridy = row;
panel.add(new JLabel(desc), gA);
panel.add(val.getCheckBox(), gBCD);
row++;
}
public void addButton(String name, String desc)
{
addButtons(name, desc);
}
public void addButtons(Object... args)
{
JPanel p = new JPanel();
p.setLayout(new GridLayout(1, args.length/2));
for (int i = 0; i < args.length/2; i++)
{
String name = (String) args[i*2];
String desc = (String) args[i*2+1];
JButton button = new JButton(desc);
button.addActionListener(new ActionNotifier(name));
p.add(button);
}
gABCD.gridy = row;
panel.add(p, gABCD);
row++;
}
public void addCheckBoxes(Object... args)
{
JPanel p = new JPanel();
p.setLayout(new GridLayout(1, args.length/3));
for (int i = 0; i < args.length/3; i++)
{
String name = (String) args[i*3+0];
String desc = (String) args[i*3+1];
boolean value = (Boolean) args[i*3+2];
BooleanValue bv = new BooleanValue(name, desc, value);
parammap.put(name, bv);
p.add(bv.getCheckBox());
}
gABCD.gridy = row;
panel.add(p, gABCD);
row++;
}
public double gd(String name)
{
PValue p = parammap.get(name);
assert(p!=null);
assert(p instanceof DoubleValue);
return ((DoubleValue) p).getDoubleValue();
}
public void sd(String name, double v)
{
PValue p = parammap.get(name);
assert(p!=null);
assert(p instanceof DoubleValue);
((DoubleValue) p).setDoubleValue(v);
}
public int gi(String name)
{
PValue p = parammap.get(name);
assert(p!=null);
if (p instanceof StringValue)
return ((StringValue) p).idx;
assert(p instanceof IntegerValue);
return ((IntegerValue) p).getIntegerValue();
}
public void si(String name, int v)
{
PValue p = parammap.get(name);
assert(p!=null);
if (p instanceof StringValue)
{
StringValue sv = (StringValue) p;
assert (v < sv.values.length);
sv.setStringValue(sv.values[v]);
}
else if (p instanceof IntegerValue)
{
((IntegerValue) p).setIntegerValue(v);
}
else
{
assert(false);
}
}
public void setMinMax(String name, int min, int max)
{
PValue p = parammap.get(name);
assert(p!=null);
assert(p instanceof IntegerValue);
((IntegerValue) p).setMinMax(min, max);
}
public void setMinMax(String name, double min, double max)
{
PValue p = parammap.get(name);
assert(p!=null);
assert(p instanceof DoubleValue);
((DoubleValue) p).setMinMax(min, max);
}
public String gs(String name)
{
PValue p = parammap.get(name);
assert(p!=null);
assert(p instanceof StringValue);
return ((StringValue) p).getStringValue();
}
public void ss(String name, String v)
{
PValue p = parammap.get(name);
assert(p!=null);
assert(p instanceof StringValue);
((StringValue) p).setStringValue(v);
}
public boolean gb(String name)
{
PValue p = parammap.get(name);
assert(p!=null);
assert(p instanceof BooleanValue);
return ((BooleanValue) p).getBooleanValue();
}
public void sb(String name, boolean v)
{
PValue p = parammap.get(name);
assert(p!=null);
assert(p instanceof BooleanValue);
((BooleanValue) p).setBooleanValue(v);
}
public void setEnabled(String name, boolean e)
{
PValue p = parammap.get(name);
assert(p!=null);
p.setEnabled(e);
}
public Container getPanel()
{
return panel;
}
public static void main(String[] args)
{
JFrame f = new JFrame("ParameterGUI Test");
f.setLayout(new BorderLayout());
f.setSize(400,400);
ParameterGUI pg = new ParameterGUI();
pg.addDouble("Double Value", "A double value", 3.1415926);
pg.addInt("IntValue1", "An integer value", 45);
pg.addIntSlider("IntValue2", "An integer value", 100, 1000, 999);
pg.addDoubleSlider("DoubleSlider", "A sliding double", -1, 1, 0.5);
pg.addDoubleSlider("DoubleSlider2", "Another sliding double",2500000, 3000000, 2500000);
pg.addString("StringValue1", "A string value", "Hi");
pg.addString("StringValue2", "A string value", "world");
pg.addChoice("Combo", "A combo box", new String[] {"Choice 1", "Choice 2", "Choice 3"}, 1);
pg.addBoolean("BoolVal1","A boolean value", true);
pg.addBoolean("BoolVal2","A boolean value", false);
pg.addButton("Button", "button one");
pg.addButtons("Buttons", "button one",
"button2", "button two",
"button3", "button three");
pg.addCheckBoxes("name1", "Checkbox 1", true,
"name2", "Checkbox 2", false);
pg.addListener(new ParameterListener() {
public void parameterChanged(String name)
{
System.out.println("Changed "+name);
}
});
f.add(pg.getPanel(), BorderLayout.CENTER);
f.setVisible(true);
}
}