001 package nl.cwi.sen1.gui.plugin;
002
003 import java.awt.Color;
004 import java.awt.Dimension;
005 import java.awt.event.MouseAdapter;
006 import java.awt.event.MouseEvent;
007
008 import javax.swing.BorderFactory;
009 import javax.swing.Box;
010 import javax.swing.BoxLayout;
011 import javax.swing.JLabel;
012 import javax.swing.JPanel;
013 import javax.swing.JSlider;
014 import javax.swing.event.ChangeEvent;
015 import javax.swing.event.ChangeListener;
016
017 import nl.cwi.sen1.util.Preferences;
018 import prefuse.util.force.Force;
019 import prefuse.util.force.ForceSimulator;
020
021 /* A panel with sliders to configure a ForceSimulator. Adapted from
022 * the prefuse implementation.
023 *
024 */
025 public class GraphForcePanel extends JPanel {
026 private ForceSimulator fsim;
027
028 public GraphForcePanel(ForceSimulator fsim, Preferences prefs) {
029 this.fsim = fsim;
030 this.setBackground(Color.WHITE);
031 initUI(prefs);
032 }
033
034 private void initUI(Preferences prefs) {
035 this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
036 Force[] forces = fsim.getForces();
037 // create a bordered box for every force, containing a
038 // configurator for every parameter of that force
039 for (int i = 0; i < forces.length; i++) {
040 Force f = forces[i];
041 Box box = new Box(BoxLayout.Y_AXIS);
042
043 // We use the class name and the parameter name to get
044 // properties from the preferences
045 String name = f.getClass().getName();
046 name = name.substring(name.lastIndexOf(".") + 1);
047
048 String label = prefs.getString("force." + name + ".label");
049 box.setBorder(BorderFactory.createTitledBorder(label));
050
051 for (int j = 0; j < f.getParameterCount(); j++) {
052 String parName = f.getParameterName(j);
053 final float min = prefs.getFloat("force." + name + "."
054 + parName + ".min");
055 final float max = prefs.getFloat("force." + name + "."
056 + parName + ".max");
057 final float def = prefs.getFloat("force." + name + "."
058 + parName + ".default");
059
060 final JSlider slider = createSlider(f, j, min, max, def);
061
062 final String parLabel = prefs.getString("force." + name + "."
063 + parName + ".label");
064 JLabel tag = new JLabel(parLabel);
065 tag.setPreferredSize(new Dimension(100, 20));
066 tag.setMaximumSize(new Dimension(100, 20));
067 tag.setToolTipText("click to return to default");
068 tag.addMouseListener(new MouseAdapter() {
069 public void mouseClicked(MouseEvent e) {
070 slider.setValue(percentage(def, min, max));
071 }
072 });
073
074 Box paramBox = new Box(BoxLayout.X_AXIS);
075 paramBox.add(tag);
076 paramBox.add(Box.createHorizontalStrut(10));
077 paramBox.add(Box.createHorizontalGlue());
078 paramBox.add(slider);
079 box.add(paramBox);
080 }
081 this.add(box);
082 }
083 this.add(Box.createVerticalGlue());
084 }
085
086 private static int percentage(float value, float min, float max) {
087 // first normalize the range to start at zero
088 max = max - min;
089
090 // then compute the percentage
091 value = value - min;
092 return (int) ((value / max) * 100);
093 }
094
095 private static float value(int percentage, float min, float max) {
096 float value;
097 // first normalize the range to start at zero
098 max = max - min;
099
100 // compute the value
101 value = (((float) percentage) / 100) * max;
102
103 // shift range back
104 value += min;
105
106 return value;
107 }
108
109 private JSlider createSlider(Force f, int param, final float min,
110 final float max, final float def) {
111 final JSlider slider = new JSlider(0, 100);
112 slider.setBackground(Color.WHITE);
113
114 // We store both a reference to the force and the index of the property
115 // in the widget
116 slider.putClientProperty("force", f);
117 slider.putClientProperty("param", new Integer(param));
118 slider.setToolTipText("" + def);
119 slider.setValue(percentage(def, min, max));
120
121 slider.addChangeListener(new ChangeListener() {
122 public void stateChanged(ChangeEvent event) {
123 JSlider s = (JSlider) event.getSource();
124
125 // retrieve the force object, and the index of the property we
126 // want
127 Force f = (Force) s.getClientProperty("force");
128 Integer param = (Integer) s.getClientProperty("param");
129
130 // forward the new value to the force, and update the tooltip
131 float val = value(s.getValue(), min, max);
132 f.setParameter(param.intValue(), val);
133 s.setToolTipText("" + val);
134 }
135 });
136
137 return slider;
138 }
139 }