* Bug #13543 fixed - "slider" uicontrols did not work with the mouse wheel.
[scilab.git] / scilab / modules / gui / src / java / org / scilab / modules / gui / bridge / slider / SwingScilabSlider.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2014 - Scilab Enterprises - Antoine ELIAS
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 package org.scilab.modules.gui.bridge.slider;
14
15 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_POSITION__;
16 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_MAX__;
17 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_MIN__;
18 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_SLIDERSTEP__;
19 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_VALUE__;
20
21 import java.awt.Color;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.MouseWheelEvent;
24 import java.awt.event.MouseWheelListener;
25
26 import javax.swing.AbstractAction;
27 import javax.swing.JScrollBar;
28 import javax.swing.JSlider;
29 import javax.swing.KeyStroke;
30 import javax.swing.UIManager;
31 import javax.swing.border.Border;
32 import javax.swing.event.ChangeEvent;
33 import javax.swing.event.ChangeListener;
34
35 import org.scilab.modules.commons.OS;
36 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
37 import org.scilab.modules.gui.SwingViewObject;
38 import org.scilab.modules.gui.SwingViewWidget;
39 import org.scilab.modules.gui.events.callback.CommonCallBack;
40 import org.scilab.modules.gui.menubar.MenuBar;
41 import org.scilab.modules.gui.slider.SimpleSlider;
42 import org.scilab.modules.gui.textbox.TextBox;
43 import org.scilab.modules.gui.toolbar.ToolBar;
44 import org.scilab.modules.gui.utils.Position;
45 import org.scilab.modules.gui.utils.PositionConverter;
46 import org.scilab.modules.gui.utils.ScilabRelief;
47 import org.scilab.modules.gui.utils.ScilabSwingUtilities;
48 import org.scilab.modules.gui.utils.Size;
49
50 /**
51  * Swing implementation for Scilab Slider in GUIs
52  * @author Antoine ELIAS
53  */
54 public class SwingScilabSlider extends JSlider implements SwingViewObject, SimpleSlider {
55
56     private static final long serialVersionUID = -4262320156090829309L;
57
58     private static final int MINIMUM_VALUE = 0;
59     private static final int MAXIMUM_VALUE = 10000;
60
61     private Integer uid;
62
63     private CommonCallBack callback;
64
65     private ChangeListener changeListener;
66
67     private Border defaultBorder = null;
68
69     static {
70         if (OS.get() == OS.UNIX) {
71             // Force Slider on Unix not to display value upon
72             UIManager.put("Slider.paintValue", false);
73         }
74     }
75
76     class CtrlLeftAction extends AbstractAction {
77         private static final long serialVersionUID = -3289281207742516486L;
78
79         public void actionPerformed(ActionEvent arg0) {
80             double userMin = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MIN__);
81             double userMax = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MAX__);
82             Double[] step = (Double[]) GraphicController.getController().getProperty(uid, __GO_UI_SLIDERSTEP__);
83             int value = SwingScilabSlider.this.getValue();
84
85             double ratio = (MAXIMUM_VALUE - MINIMUM_VALUE) / (userMax - userMin);
86             int newValue = Math.max(MINIMUM_VALUE, value - (int)(step[1] * ratio));
87             setValue(newValue);
88         }
89     }
90
91     class LeftAction extends AbstractAction {
92         private static final long serialVersionUID = 2099826485447918397L;
93
94         public void actionPerformed(ActionEvent arg0) {
95             double userMin = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MIN__);
96             double userMax = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MAX__);
97             Double[] step = (Double[]) GraphicController.getController().getProperty(uid, __GO_UI_SLIDERSTEP__);
98             int value = SwingScilabSlider.this.getValue();
99
100             double ratio = (MAXIMUM_VALUE - MINIMUM_VALUE) / (userMax - userMin);
101             int newValue = Math.max(MINIMUM_VALUE, value - (int)(step[0] * ratio));
102             setValue(newValue);
103         }
104     }
105
106     class RightAction extends AbstractAction {
107         private static final long serialVersionUID = 8666161246122371904L;
108
109         public void actionPerformed(ActionEvent arg0) {
110             double userMin = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MIN__);
111             double userMax = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MAX__);
112             Double[] step = (Double[]) GraphicController.getController().getProperty(uid, __GO_UI_SLIDERSTEP__);
113             int value = SwingScilabSlider.this.getValue();
114
115             double ratio = (MAXIMUM_VALUE - MINIMUM_VALUE) / (userMax - userMin);
116             int newValue = Math.min(MAXIMUM_VALUE, value + (int)(step[0] * ratio));
117             setValue(newValue);
118         }
119     }
120
121     class CtrlRightAction extends AbstractAction {
122         private static final long serialVersionUID = -1364255463511656338L;
123
124         public void actionPerformed(ActionEvent arg0) {
125             double userMin = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MIN__);
126             double userMax = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MAX__);
127             Double[] step = (Double[]) GraphicController.getController().getProperty(uid, __GO_UI_SLIDERSTEP__);
128             int value = SwingScilabSlider.this.getValue();
129
130             double ratio = (MAXIMUM_VALUE - MINIMUM_VALUE) / (userMax - userMin);
131             int newValue = Math.min(MAXIMUM_VALUE, value + (int)(step[1] * ratio));
132             setValue(newValue);
133         }
134     }
135
136     /**
137      * Constructor
138      */
139     public SwingScilabSlider() {
140         super();
141         // needed to have slider working with GLCanvas
142         setOpaque(true);
143         setMinimum(MINIMUM_VALUE);
144         setMaximum(MAXIMUM_VALUE);
145         setValue(0);
146
147         /* some keys binding */
148         getInputMap().put(KeyStroke.getKeyStroke("DOWN"), "LeftAction");
149         getInputMap().put(KeyStroke.getKeyStroke("LEFT"), "LeftAction");
150         getActionMap().put("LeftAction", new LeftAction());
151         getInputMap().put(KeyStroke.getKeyStroke("UP"), "RightAction");
152         getInputMap().put(KeyStroke.getKeyStroke("RIGHT"), "RightAction");
153         getActionMap().put("RightAction", new RightAction());
154         getInputMap().put(KeyStroke.getKeyStroke("control UP"), "CtrlRightAction");
155         getInputMap().put(KeyStroke.getKeyStroke("control RIGHT"), "CtrlRightAction");
156         getActionMap().put("CtrlRightAction", new CtrlRightAction());
157         getInputMap().put(KeyStroke.getKeyStroke("control DOWN"), "CtrlLeftAction");
158         getInputMap().put(KeyStroke.getKeyStroke("control LEFT"), "CtrlLeftAction");
159         getActionMap().put("CtrlLeftAction", new CtrlLeftAction());
160
161
162         changeListener = new ChangeListener() {
163             public void stateChanged(ChangeEvent arg0) {
164                 updateModel();
165                 if (callback != null) {
166                     callback.actionPerformed(null);
167                 }
168             }
169         };
170         addChangeListener(changeListener);
171
172         // Fix for bug #13543
173         this.addMouseWheelListener(new MouseWheelListener() {
174             public void mouseWheelMoved(MouseWheelEvent e) {
175                 int notches = e.getWheelRotation();
176                 int step = (e.isControlDown() ? getMajorTickSpacing() : getMinorTickSpacing());
177                 if (notches < 0) {
178                     setValue(getValue() + step);
179                 } else {
180                     setValue(getValue() - step);
181                 }
182             }
183         });
184     }
185
186     /**
187      * Draws a swing Scilab Slider
188      * @see org.scilab.modules.gui.UIElement#draw()
189      */
190     public void draw() {
191         this.setVisible(true);
192         this.doLayout();
193     }
194
195     /**
196      * Gets the dimensions (width and height) of a swing Scilab Slider
197      * @return the dimensions of the Slider
198      * @see org.scilab.modules.gui.uielement.UIElement#getDims()
199      */
200     public Size getDims() {
201         return new Size(super.getSize().width, super.getSize().height);
202     }
203
204     /**
205      * Gets the position (X-coordinate and Y-coordinate) of a swing Scilab Slider
206      * @return the position of the Slider
207      * @see org.scilab.modules.gui.uielement.UIElement#getPosition()
208      */
209     public Position getPosition() {
210         return PositionConverter.javaToScilab(getLocation(), getSize(), getParent());
211     }
212
213     /**
214      * Sets the dimensions (width and height) of a swing Scilab Slider
215      * @param newSize the dimensions to set to the Slider
216      * @see org.scilab.modules.gui.uielement.UIElement#setDims(org.scilab.modules.gui.utils.Size)
217      */
218     public void setDims(Size newSize) {
219         super.setSize(newSize.getWidth(), newSize.getHeight());
220         super.doLayout(); // Usefull in case of resize
221     }
222
223     /**
224      * Sets the position (X-coordinate and Y-coordinate) of a swing Scilab Slider
225      * @param newPosition the position to set to the Slider
226      * @see org.scilab.modules.gui.uielement.UIElement#setPosition(org.scilab.modules.gui.utils.Position)
227      */
228     public void setPosition(Position newPosition) {
229         Position javaPosition = PositionConverter.scilabToJava(newPosition, getDims(), getParent());
230         setLocation(javaPosition.getX(), javaPosition.getY());
231     }
232
233     /**
234      * Add a callback to the Slider
235      * @param cb the callback to set.
236      */
237     public void setCallback(CommonCallBack cb) {
238         /* Create a callback */
239         callback = cb;
240     }
241
242     /**
243      * Setter for MenuBar
244      * @param menuBarToAdd the MenuBar associated to the Tab.
245      */
246     public void addMenuBar(MenuBar menuBarToAdd) {
247         /* Unimplemented for CheckBoxes */
248         throw new UnsupportedOperationException();
249     }
250
251     /**
252      * Setter for ToolBar
253      * @param toolBarToAdd the ToolBar associated to the Tab.
254      */
255     public void addToolBar(ToolBar toolBarToAdd) {
256         /* Unimplemented for CheckBoxes */
257         throw new UnsupportedOperationException();
258     }
259
260     /**
261      * Getter for MenuBar
262      * @return MenuBar: the MenuBar associated to the Tab.
263      */
264     public MenuBar getMenuBar() {
265         /* Unimplemented for CheckBoxes */
266         throw new UnsupportedOperationException();
267     }
268
269     /**
270      * Getter for ToolBar
271      * @return ToolBar: the ToolBar associated to the Tab.
272      */
273     public ToolBar getToolBar() {
274         /* Unimplemented for CheckBoxes */
275         throw new UnsupportedOperationException();
276     }
277
278     /**
279      * Get the text of the Slider
280      * @return the text
281      * @see org.scilab.modules.gui.widget.Widget#getText()
282      */
283     public String getText() {
284         return this.getName();
285     }
286
287     /**
288      * Set the text of the Slider
289      * @param text the text to set to the Slider
290      * @see org.scilab.modules.gui.widget.Widget#setText(java.lang.String)
291      */
292     public void setText(String text) {
293         this.setName(text);
294     }
295
296     public void setEmptyText() {
297         this.setName(null);
298     }
299     /**
300      * Set the horizontal alignment for the Slider text
301      * @param alignment the value for the alignment (See ScilabAlignment.java)
302      */
303     public void setHorizontalAlignment(String alignment) {
304         // Nothing to do here
305     }
306
307     /**
308      * Set the vertical alignment for the Slider text
309      * @param alignment the value for the alignment (See ScilabAlignment.java)
310      */
311     public void setVerticalAlignment(String alignment) {
312         // Nothing to do here
313     }
314
315     /**
316      * Set the minimum value of a Slider
317      * @param value the minimum value
318      */
319     public void setMinimumValue(double value) {
320         updateModel(); /* Update the model according to the knob position */
321     }
322
323     /**
324      * Set the maximum value of a Slider
325      * @param value the maximum value
326      */
327     public void setMaximumValue(double value) {
328         updateModel(); /* Update the model according to the knob position */
329     }
330
331     /**
332      * Set the Relief of the Slider
333      * @param reliefType the type of the relief to set (See ScilabRelief.java)
334      */
335     public void setRelief(String reliefType) {
336         if (defaultBorder == null) {
337             defaultBorder = getBorder();
338         }
339         setBorder(ScilabRelief.getBorderFromRelief(reliefType, defaultBorder));
340     }
341
342     /**
343      * Set the major tick spacing for a Slider
344      * @param space the increment value
345      */
346     public void setMajorTickSpacing(double space) {
347         double userMin = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MIN__);
348         double userMax = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MAX__);
349
350         double ratio = (MAXIMUM_VALUE - MINIMUM_VALUE) / (userMax - userMin);
351         int newspace = (int)(space * ratio);
352         super.setMajorTickSpacing(newspace);
353     }
354
355     /**
356      * Set the minor tick spacing for a Slider
357      * @param space the increment value
358      */
359     public void setMinorTickSpacing(double space) {
360         double userMin = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MIN__);
361         double userMax = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MAX__);
362
363         double ratio = (MAXIMUM_VALUE - MINIMUM_VALUE) / (userMax - userMin);
364         int newspace = (int)(space * ratio);
365         super.setMinorTickSpacing(newspace);
366     }
367
368     /**
369      * Set the slider orientation to vertical
370      */
371     public void setVertical() {
372         setOrientation(JScrollBar.VERTICAL);
373     }
374
375     /**
376      * Set the slider orientation to horizontal
377      */
378     public void setHorizontal() {
379         setOrientation(JScrollBar.HORIZONTAL);
380     }
381
382     /**
383      * Destroy the Slider
384      */
385     public void destroy() {
386         ScilabSwingUtilities.removeFromParent(this);
387     }
388
389     /**
390      * Setter for InfoBar
391      * @param infoBarToAdd the InfoBar associated to the Slider.
392      */
393     public void addInfoBar(TextBox infoBarToAdd) {
394         /* Unimplemented for Sliders */
395         throw new UnsupportedOperationException();
396     }
397
398     /**
399      * Getter for InfoBar
400      * @return the InfoBar associated to the Slider.
401      */
402     public TextBox getInfoBar() {
403         /* Unimplemented for Sliders */
404         throw new UnsupportedOperationException();
405     }
406
407     /**
408      * Set the current value of the Slider
409      * @param value the new value
410      */
411     public void setUserValue(double value) {
412         /* Remove the listener to avoid the callback to be executed */
413         removeChangeListener(changeListener);
414
415         double userMin = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MIN__);
416         double userMax = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MAX__);
417         setValue(MINIMUM_VALUE + (int) ((value - userMin) * (MAXIMUM_VALUE - MINIMUM_VALUE) / (userMax - userMin)));
418
419         /* Put back the listener */
420         addChangeListener(changeListener);
421     }
422
423     /**
424      * Set the UID
425      * @param id the UID
426      */
427     public void setId(Integer id) {
428         uid = id;
429     }
430
431     /**
432      * Get the UID
433      * @return the UID
434      */
435     public Integer getId() {
436         return uid;
437     }
438
439     /**
440      * Generic update method
441      * @param property property name
442      * @param value property value
443      */
444     public void update(int property, Object value) {
445         GraphicController controller = GraphicController.getController();
446
447         switch (property) {
448             case __GO_UI_MAX__: {
449                 Double maxValue = (Double) value;
450                 // Update the slider properties
451                 Double minValue = (Double) controller.getProperty(uid, __GO_UI_MIN__);
452                 setMaximumValue(maxValue);
453                 Double[] sliderStep = ((Double[]) controller.getProperty(uid, __GO_UI_SLIDERSTEP__));
454                 double minorSliderStep = sliderStep[0].doubleValue();
455                 double majorSliderStep = sliderStep[1].doubleValue();
456                 if (minValue <= maxValue) {
457                     setMinorTickSpacing(minorSliderStep);
458                     setMajorTickSpacing(majorSliderStep);
459                 }
460                 break;
461             }
462             case __GO_UI_MIN__ : {
463                 Double minValue = (Double)value;
464                 // Update the slider properties
465                 Double maxValue = (Double) controller.getProperty(uid, __GO_UI_MAX__);
466                 setMinimumValue(minValue);
467                 Double[] sliderStep = ((Double[]) controller.getProperty(uid, __GO_UI_SLIDERSTEP__));
468                 double minorSliderStep = sliderStep[0].doubleValue();
469                 double majorSliderStep = sliderStep[1].doubleValue();
470                 if (minValue <= maxValue) {
471                     setMinorTickSpacing(minorSliderStep);
472                     setMajorTickSpacing(majorSliderStep);
473                 }
474                 break;
475             }
476             case __GO_POSITION__ : {
477                 Double[] dblValues = SwingViewWidget.updatePosition(this, uid, value);
478                 if (dblValues[2].intValue() > dblValues[3].intValue()) {
479                     setHorizontal();
480                 } else {
481                     setVertical();
482                 }
483                 break;
484             }
485             case __GO_UI_SLIDERSTEP__ : {
486                 Double[] sliderStep = ((Double[]) value);
487                 double minorSliderStep = sliderStep[0].doubleValue();
488                 double majorSliderStep = sliderStep[1].doubleValue();
489                 setMinorTickSpacing(minorSliderStep);
490                 setMajorTickSpacing(majorSliderStep);
491                 break;
492             }
493             case __GO_UI_VALUE__ : {
494                 Double[] doubleValue = ((Double[]) value);
495                 if (doubleValue.length != 0) {
496                     setUserValue(doubleValue[0]);
497                 } else {
498                     Double minValue = (Double) controller.getProperty(uid, __GO_UI_MIN__);
499                     setUserValue(minValue);
500                 }
501                 break;
502             }
503             default: {
504                 SwingViewWidget.update(this, property, value);
505                 break;
506             }
507         }
508     }
509
510     /**
511      * Update values in the model when needed
512      */
513     private void updateModel() {
514         Double[] value = new Double[1];
515         double userMin = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MIN__);
516         double userMax = (Double) GraphicController.getController().getProperty(uid, __GO_UI_MAX__);
517         value[0] = userMin + ((getValue() - MINIMUM_VALUE) * (userMax - userMin) / (MAXIMUM_VALUE - MINIMUM_VALUE));
518         GraphicController.getController().setProperty(uid, __GO_UI_VALUE__, value);
519     }
520
521     public void resetBackground() {
522         Color color = (Color)UIManager.getLookAndFeelDefaults().get("Slider.background");
523         if (color != null) {
524             setBackground(color);
525         }
526     }
527
528     public void resetForeground() {
529         Color color = (Color)UIManager.getLookAndFeelDefaults().get("Slider.foreground");
530         if (color != null) {
531             setForeground(color);
532         }
533     }
534 }