Add new positions for datatips (left, right, upper, lower).
[scilab.git] / scilab / modules / graphic_objects / src / java / org / scilab / modules / graphic_objects / datatip / Datatip.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Pedro Arthur dos S. Souza
4  * Copyright (C) 2012 - Caio Lucas dos S. Souza
5  *
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at
10  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
11  *
12  */
13
14 package org.scilab.modules.graphic_objects.datatip;
15
16 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_3COMPONENT__;
17 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_AUTOORIENTATION__;
18 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_BOX_MODE__;
19 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DATA__;
20 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DISPLAY_FNC__;
21 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_INTERP_MODE__;
22 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_LABEL_MODE__;
23 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_ORIENTATION__;
24 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_INDEXES__;
25
26 import java.text.DecimalFormat;
27 import java.text.DecimalFormatSymbols;
28
29 import org.scilab.forge.scirenderer.ruler.graduations.UserDefinedFormat;
30
31 import org.scilab.modules.action_binding.InterpreterManagement;
32 import org.scilab.modules.graphic_objects.PolylineData;
33 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
34 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
35 import org.scilab.modules.graphic_objects.graphicObject.Visitor;
36 import org.scilab.modules.graphic_objects.textObject.Text;
37 import org.scilab.modules.localization.Messages;
38
39 public class Datatip extends Text {
40
41     /** false = datatip text box is hidden*/
42     Boolean tipBoxMode;
43     /** false = datatip label is hidden*/
44     Boolean tipLabelMode;
45     /** false = display only (X, Y), true = display (X, Y, Z)*/
46     Boolean use3component;
47     /** false = no interpolation between point segments*/
48     Boolean interpMode;
49     /** Displayed number format*/
50     DecimalFormat tipTextFormat;
51     /** Display function*/
52     String displayFnc;
53     /** For automatic update the datatip orientation*/
54     Boolean autoOrientation;
55     /* index of data in parent object ( polyline, plot3d, fac3d*/
56     /* size = 1 for polyline and 2 for others*/
57     Integer dataIndex;
58     Double ratio;
59
60
61     enum DatatipObjectProperty { TIP_DATA, TIP_BOX_MODE, TIP_LABEL_MODE, TIP_ORIENTATION, TIP_AUTOORIENTATION, TIP_3COMPONENT, TIP_INTERP_MODE, TIP_DISPLAY_FNC, TIP_INDEXES};
62     enum TipOrientation { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, LEFT, RIGHT, TOP, BOTTOM;
63
64                           /**
65                            * Transform a integer to a TipOrientation enum.
66                            */
67     public static TipOrientation intToEnum(Integer i) {
68         switch (i) {
69             case 0:
70                 return TipOrientation.TOP_LEFT;
71             case 1:
72                 return TipOrientation.TOP_RIGHT;
73             case 2:
74                 return TipOrientation.BOTTOM_LEFT;
75             case 3:
76                 return TipOrientation.BOTTOM_RIGHT;
77             case 4:
78                 return TipOrientation.LEFT;
79             case 5:
80                 return TipOrientation.RIGHT;
81             case 6:
82                 return TipOrientation.TOP;
83             case 7:
84                 return TipOrientation.BOTTOM;
85             default:
86                 return TipOrientation.TOP_RIGHT;
87         }
88     }
89
90                         };
91
92     TipOrientation currentOrientation;
93
94     /**
95      * Initializes the datatip, setup format, orientation and mark.
96      */
97     public Datatip() {
98         super();
99         use3component = false;
100         autoOrientation = true;
101         setOrientationAsEnum(TipOrientation.TOP_RIGHT);
102         DecimalFormat fb = new DecimalFormat("#.####E00");
103         DecimalFormatSymbols decimalFormatSymbols = fb.getDecimalFormatSymbols();
104         decimalFormatSymbols.setDecimalSeparator('.');
105         decimalFormatSymbols.setExponentSeparator("e");
106         decimalFormatSymbols.setGroupingSeparator('\u00A0');
107         fb.setDecimalFormatSymbols(decimalFormatSymbols);
108         tipTextFormat = new UserDefinedFormat(fb, "%g", 1, 0);
109
110         tipBoxMode = true;
111         tipLabelMode = true;
112         interpMode = true;
113         displayFnc = "";
114         ratio = 0.;
115         dataIndex = Integer.MIN_VALUE;
116         setVisible(true);
117         setBox(true);
118         setLineMode(true);
119         setFillMode(true);
120         setBackground(-2);
121         setClipState(1);
122
123         setMarkMode(true);
124         setMarkSize(8);
125         setMarkBackground(-1);
126         setMarkForeground(-1);
127         setMarkStyle(11);
128     }
129
130     @Override
131     public void accept(Visitor visitor) {
132         visitor.visit(this);
133     }
134
135     /**
136      * Convert the property name to the DatatipObjectProperty enum.
137      */
138     public Object getPropertyFromName(int propertyName) {
139         switch (propertyName) {
140             case __GO_DATATIP_DATA__:
141                 return DatatipObjectProperty.TIP_DATA;
142             case __GO_DATATIP_BOX_MODE__:
143                 return DatatipObjectProperty.TIP_BOX_MODE;
144             case __GO_DATATIP_LABEL_MODE__:
145                 return DatatipObjectProperty.TIP_LABEL_MODE;
146             case __GO_DATATIP_ORIENTATION__:
147                 return DatatipObjectProperty.TIP_ORIENTATION;
148             case __GO_DATATIP_3COMPONENT__:
149                 return DatatipObjectProperty.TIP_3COMPONENT;
150             case __GO_DATATIP_AUTOORIENTATION__:
151                 return DatatipObjectProperty.TIP_AUTOORIENTATION;
152             case __GO_DATATIP_INTERP_MODE__:
153                 return DatatipObjectProperty.TIP_INTERP_MODE;
154             case __GO_DATATIP_DISPLAY_FNC__:
155                 return DatatipObjectProperty.TIP_DISPLAY_FNC;
156             case __GO_DATATIP_INDEXES__ :
157                 return DatatipObjectProperty.TIP_INDEXES;
158             default:
159                 return super.getPropertyFromName(propertyName);
160         }
161     }
162
163     /**
164      * @return the datatip property
165      */
166     public Object getProperty(Object property) {
167         if (property instanceof DatatipObjectProperty) {
168             switch ((DatatipObjectProperty) property) {
169                 case TIP_DATA:
170                     return getTipData();
171                 case TIP_BOX_MODE:
172                     return getTipBoxMode();
173                 case TIP_LABEL_MODE:
174                     return getTipLabelMode();
175                 case TIP_ORIENTATION:
176                     return getOrientation();
177                 case TIP_3COMPONENT:
178                     return isUsing3Component();
179                 case TIP_AUTOORIENTATION:
180                     return isAutoOrientationEnabled();
181                 case TIP_INTERP_MODE:
182                     return getInterpMode();
183                 case TIP_DISPLAY_FNC:
184                     return getDisplayFunction();
185                 case TIP_INDEXES:
186                     return getIndexes();
187             }
188         }
189
190         return super.getProperty(property);
191     }
192
193     /**
194      * Set the datatip property
195      * @param property the property
196      * @param value the new property value.
197      */
198     public UpdateStatus setProperty(Object property, Object value) {
199         if (property instanceof DatatipObjectProperty) {
200             switch ((DatatipObjectProperty) property) {
201                 case TIP_BOX_MODE:
202                     return setTipBoxMode((Boolean) value);
203                 case TIP_LABEL_MODE:
204                     return setTipLabelMode((Boolean) value);
205                 case TIP_ORIENTATION:
206                     return setOrientation((Integer) value);
207                 case TIP_3COMPONENT:
208                     return setUse3Component((Boolean) value);
209                 case TIP_AUTOORIENTATION:
210                     return setAutoOrientation((Boolean) value);
211                 case TIP_INTERP_MODE:
212                     return setInterpMode((Boolean) value);
213                 case TIP_DISPLAY_FNC:
214                     return setDisplayFunction((String) value);
215                 case TIP_INDEXES:
216                     return setIndexes((Double[]) value);
217             }
218         }
219
220         return super.setProperty(property, value);
221     }
222
223     /**
224      * Get the current tip data
225      * @return the tip data
226      */
227     public Double[] getTipData() {
228         final double[] dataX = (double[]) PolylineData.getDataX(getParent());
229         final double[] dataY = (double[]) PolylineData.getDataY(getParent());
230
231         if (use3component) {
232             final double[] dataZ = (double[]) PolylineData.getDataZ(getParent());
233
234             if (dataX.length < dataIndex + 2 || dataY.length < dataIndex + 2 || dataZ.length < dataIndex + 2) {
235                 if (dataX.length >= 1 && dataY.length >= 1 && dataZ.length >= 1) {
236                     return new Double[] {dataX[dataX.length - 1], dataY[dataY.length - 1], dataZ[dataZ.length - 1]};
237                 } else {
238                     return new Double[] {0., 0., 0.};
239                 }
240             }
241
242             //get pt0 and pt1 from polyline data
243             final double[] pt0 = new double[] {dataX[dataIndex], dataY[dataIndex], dataZ[dataIndex]};
244             final double[] pt1 = new double[] {dataX[dataIndex + 1], dataY[dataIndex + 1], dataZ[dataIndex + 1]};
245
246             final double x = pt0[0] + (pt1[0] - pt0[0]) * ratio;
247             final double y = pt0[1] + (pt1[1] - pt0[1]) * ratio;
248             final double z = pt0[2] + (pt1[2] - pt0[2]) * ratio;
249
250             return new Double[] {x, y, z};
251         } else {
252             if (dataX.length < dataIndex + 2 || dataY.length < dataIndex + 2) {
253                 if (dataX.length >= 1 && dataY.length >= 1) {
254                     return new Double[] {dataX[dataX.length - 1], dataY[dataY.length - 1], 0.};
255                 } else {
256                     return new Double[] {0., 0., 0.};
257                 }
258             }
259
260             //get pt0 and pt1 from polyline data
261             final double[] pt0 = new double[] {dataX[dataIndex], dataY[dataIndex]};
262             final double[] pt1 = new double[] {dataX[dataIndex + 1], dataY[dataIndex + 1]};
263
264             final double x = pt0[0] + (pt1[0] - pt0[0]) * ratio;
265             final double y = pt0[1] + (pt1[1] - pt0[1]) * ratio;
266
267             return new Double[] {x, y, 0.};
268         }
269     }
270
271     /**
272      * Get the current textbox orientation as an integer
273      * @return current orientation.
274      */
275     public Integer getOrientation() {
276         return getOrientationAsEnum().ordinal();
277     }
278
279     /**
280      * Get the current oriantation as a enum
281      * @return the current orientation
282      */
283     public TipOrientation getOrientationAsEnum() {
284         return currentOrientation;
285     }
286
287     /**
288      * Set the current orientation (updating the text position)
289      * @param orientation the new orientation (integer).
290      */
291     public UpdateStatus setOrientation(Integer orientation) {
292         currentOrientation = TipOrientation.intToEnum(orientation);
293         return UpdateStatus.Success;
294     }
295
296     /**
297      * Set the current orientation (updating the text position)
298      * @param orientation the new orientation (TipOrientation enum).
299      */
300     public UpdateStatus setOrientationAsEnum(TipOrientation orientation) {
301         currentOrientation = orientation;
302         return UpdateStatus.Success;
303     }
304
305     /**
306      * @return true if the datatip is displaying the Z component, false otherwise.
307      */
308     public Boolean isUsing3Component() {
309         return use3component;
310     }
311
312     /**
313      * If true set the Z component to be displayed.
314      * @param useZ True to enable display the Z component, false to disable.
315      */
316     public UpdateStatus setUse3Component(Boolean useZ) {
317         use3component = useZ;
318         updateText();
319         return UpdateStatus.Success;
320     }
321
322
323     public Boolean isAutoOrientationEnabled() {
324         return autoOrientation;
325     }
326
327     public UpdateStatus setAutoOrientation(Boolean status) {
328         autoOrientation = status;
329         return UpdateStatus.Success;
330     }
331
332     /**
333      * Update the text from the datatip base on current tipData value.
334      */
335     public void updateText() {
336         //if display function is empty look in parent
337         //if parent is empty too use default print
338
339         String fnc = getDisplayFunction();
340         if (fnc == null || fnc.equals("")) {
341             //look in parent
342             fnc = (String) GraphicController.getController().getProperty(getParent(), GraphicObjectProperties.__GO_DATATIP_DISPLAY_FNC__);
343             if (fnc == null || fnc.equals("")) {
344                 String[] textArray = new String[] {"X:", "Y:", "Z:"};
345                 Double[] tipData = getTipData();
346                 textArray[0] += tipTextFormat.format(tipData[0]);
347                 textArray[1] += tipTextFormat.format(tipData[1]);
348                 textArray[2] += tipTextFormat.format(tipData[2]);
349
350                 Integer[] dim = new Integer[2];
351                 dim[0] = use3component ? 3 : 2;
352                 dim[1] = 1;
353                 setTextArrayDimensions(dim);
354                 setTextStrings(textArray);
355                 return;
356             }
357         }
358
359         String errMsg =  Messages.gettext("Wrong value for '%s' property: A valid function name expected.\n");
360         errMsg = errMsg.replace("'", "''");
361         errMsg = errMsg.replace("\n", "\\n");
362         String updateCommand = "try;" +
363                                "GDZa786XBSq7899SHKp=getcallbackobject(" + getIdentifier() + ");" +
364                                "set(GDZa786XBSq7899SHKp,\"text\"," + fnc + "(GDZa786XBSq7899SHKp));" +
365                                "clear(\"GDZa786XBSq7899SHKp\");" +
366                                "catch;" +
367                                "set(GDZa786XBSq7899SHKp,\"display_function\",\"\");" +
368                                "set(GDZa786XBSq7899SHKp.parent,\"display_function\",\"\");" +
369                                "clear(\"GDZa786XBSq7899SHKp\");" +
370                                "error(msprintf(\"" + errMsg + "\", \"display_function\"));" +
371                                "end;";
372         InterpreterManagement.requestScilabExec(updateCommand);
373     }
374
375     public Boolean getTipBoxMode() {
376         return tipBoxMode;
377     }
378
379     public Boolean getTipLabelMode() {
380         return tipLabelMode;
381     }
382
383     public Boolean getInterpMode() {
384         return interpMode;
385     }
386
387     public String getDisplayFunction() {
388         return displayFnc;
389     }
390
391     public UpdateStatus setTipBoxMode(Boolean mode) {
392         tipBoxMode = mode;
393         setBox(tipBoxMode);
394         return UpdateStatus.Success;
395     }
396
397     public UpdateStatus setTipLabelMode(Boolean mode) {
398         tipLabelMode = mode;
399         return UpdateStatus.Success;
400     }
401
402     public UpdateStatus setInterpMode(Boolean mode) {
403         interpMode = mode;
404         return UpdateStatus.Success;
405     }
406
407     public UpdateStatus setDisplayFunction(String fnc) {
408         displayFnc = fnc;
409         updateText();
410         return UpdateStatus.Success;
411     }
412
413     @Override
414     public Double[] getPosition() {
415         return getTipData();
416     }
417
418     public UpdateStatus setIndexes(Double[] value) {
419         if (value[0].intValue() != dataIndex || !value[1].equals(ratio)) {
420             dataIndex = value[0].intValue();
421             ratio = new Double(value[1]);
422             updateText();
423
424             return UpdateStatus.Success;
425         }
426
427         return UpdateStatus.NoChange;
428     }
429
430     public Integer getIndexes() {
431         return dataIndex;
432     }
433
434     /**
435      * @return Type as String
436      */
437     public Integer getType() {
438         return GraphicObjectProperties.__GO_DATATIP__;
439     }
440 }