fix trouble on figure_id with non axes windows
[scilab.git] / scilab / modules / gui / sci_gateway / c / sci_figure.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2014 - Scilab Enterprises - Antoine ELIAS
4  * Copyright (C) 2014 - Scilab Enterprises - Bruno JOFRET
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 #include "gw_gui.h"
15 #include "MALLOC.h"
16 #include "api_scilab.h"
17 #include "localization.h"
18 #include "Scierror.h"
19 #include "createGraphicObject.h"
20 #include "BuildObjects.h"
21 #include "setGraphicObjectProperty.h"
22 #include "getGraphicObjectProperty.h"
23 #include "graphicObjectProperties.h"
24 #include "CurrentFigure.h"
25 #include "CurrentSubwin.h"
26 #include "FigureList.h"
27 #include "HandleManagement.h"
28 #include "SetHashTable.h"
29 #include "stricmp.h"
30 #ifdef _MSC_VER
31 #include "strdup_windows.h"
32 #endif
33
34 #include "sciprint.h"
35
36 #define COLOR_COMPONENT 3
37 /*--------------------------------------------------------------------------*/
38 void setDefaultProperties(int _iFig);
39 int addColor(int _iFig, double* _pdblColor);
40 /*--------------------------------------------------------------------------*/
41 int sci_figure(char * fname, unsigned long fname_len)
42 {
43     SciErr sciErr;
44     int* piAddr = NULL;
45     int iFig = 0;
46     int iRhs = nbInputArgument(pvApiCtx);
47     int iId = 0;
48     int iPos = 0;
49     int i = 0;
50     int iNewId = -1;
51     int iAxes = 0;
52     int* piAxes = &iAxes;
53     int iPropertyOffset = 0;
54     BOOL bDoCreation = TRUE;
55     BOOL bVisible = TRUE; // Create a visible figure by default
56     BOOL bDockable = TRUE; // Create a dockable figure by default
57     BOOL bDefaultAxes = TRUE; // Create an Axes by default
58     int iMenubarType = 1; // Create a 'figure' menubar by default
59     int iToolbarType = 1; // Create a 'figure' toolbar by default
60     double dblId = 0;
61
62     //figure(num) -> scf(num)
63     //figure() -> scf()
64
65     //figure(x, "...", ...)
66
67     // figure()
68     if (iRhs == 0) // Auto ID
69     {
70         iFig = createNewFigureWithAxes();
71         setDefaultProperties(iFig);
72         createScalarHandle(pvApiCtx, iRhs + 1, getHandle(iFig));
73         AssignOutputVariable(pvApiCtx, 1) = iRhs + 1;
74         ReturnArguments(pvApiCtx);
75         return 0;
76     }
77
78     if (iRhs == 1)
79     {
80         //figure(x);
81         sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr);
82         if (sciErr.iErr)
83         {
84             printError(&sciErr, 0);
85             Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, 1);
86             return 0;
87         }
88
89         if (isVarMatrixType(pvApiCtx, piAddr) == 0)
90         {
91             Scierror(999, _("%s: Wrong type for input argument #%d: An integer value expected.\n"), fname, 1);
92             return 0;
93         }
94
95         if (getScalarDouble(pvApiCtx, piAddr, &dblId))
96         {
97             Scierror(999, _("%s: No more memory.\n"), fname);
98             return 0;
99         }
100
101         iId = (int)(dblId + 0.5); //avoid 1.999 -> 1
102
103         //get current fig from id
104         iFig = getFigureFromIndex(iId);
105         if (iFig == 0) // Figure does not exists, create a new one
106         {
107             iFig = createNewFigureWithAxes();
108             setGraphicObjectProperty(iFig, __GO_ID__, &iId, jni_int,  1);
109             setDefaultProperties(iFig);
110         }
111
112         createScalarHandle(pvApiCtx, iRhs + 1, getHandle(iFig));
113         AssignOutputVariable(pvApiCtx, 1) = iRhs + 1;
114         ReturnArguments(pvApiCtx);
115         return 0;
116     }
117
118     // Prepare property analysis
119     if (iRhs % 2 == 0)
120     {
121         //get highest value of winsid to create the new windows @ + 1
122         iNewId = getValidDefaultFigureId();
123         iPos = 0;
124     }
125     else
126     {
127         iPos = 1;
128         //figure(x, ...);
129         sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr);
130         if (sciErr.iErr)
131         {
132             printError(&sciErr, 0);
133             Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, 1);
134             return 0;
135         }
136
137         if (isVarMatrixType(pvApiCtx, piAddr) == 0)
138         {
139             Scierror(999, _("%s: Wrong type for input argument #%d: An integer value expected.\n"), fname, 1);
140             return 0;
141         }
142
143         if (getScalarDouble(pvApiCtx, piAddr, &dblId))
144         {
145             Scierror(999, _("%s: No more memory.\n"), fname);
146             return 0;
147         }
148
149         iNewId = (int)(dblId + 0.5); //avoid 1.999 -> 1
150         //get current fig from id
151         iFig = getFigureFromIndex(iId);
152         if (iFig != 0) // Figure already exists
153         {
154             bDoCreation = TRUE;
155         }
156     }
157
158     if (bDoCreation)
159     {
160         int* piAddrProp = NULL;
161         char* pstProName = NULL;
162         int* piAddrData = NULL;
163         char* pstPropVal = NULL;
164         for (i = iPos + 1 ; i <= iRhs ; i += 2)
165         {
166             //get property name
167             sciErr = getVarAddressFromPosition(pvApiCtx, i, &piAddrProp);
168             if (sciErr.iErr)
169             {
170                 Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, i);
171                 return 1;
172             }
173
174             if (getAllocatedSingleString(pvApiCtx, piAddrProp, &pstProName))
175             {
176                 Scierror(999, _("%s: Wrong size for input argument #%d: A single string expected.\n"), fname, i);
177                 return 1;
178             }
179             if (stricmp(pstProName, "dockable") != 0
180                     && stricmp(pstProName, "toolbar") != 0
181                     && stricmp(pstProName, "menubar") != 0
182                     && stricmp(pstProName, "default_axes") != 0
183                     && stricmp(pstProName, "visible") != 0 )
184             {
185                 freeAllocatedSingleString(pstProName);
186                 continue;
187             }
188             //get address of value on stack
189             sciErr = getVarAddressFromPosition(pvApiCtx, i + 1, &piAddrData);
190             if (sciErr.iErr)
191             {
192                 Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, i + 1);
193                 return 1;
194             }
195             if (getAllocatedSingleString(pvApiCtx, piAddrData, (char**)&pstPropVal))
196             {
197                 Scierror(999, _("%s: Wrong size for input argument #%d: A single string expected.\n"), fname, 3);
198                 return 1;
199             }
200             //check property value to compatibility
201             if (stricmp(pstProName, "dockable") == 0)
202             {
203                 if (stricmp(pstPropVal, "on") == 0)
204                 {
205                     bDockable = TRUE;
206                 }
207                 else if (stricmp(pstPropVal, "off") == 0)
208                 {
209                     bDockable = FALSE;
210                 }
211                 else
212                 {
213                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "dockable", "on", "off");
214                     freeAllocatedSingleString(pstProName);
215                     freeAllocatedSingleString(pstPropVal);
216                     return 1;
217                 }
218             }
219             else if (stricmp(pstProName, "toolbar") == 0)
220             {
221                 if (stricmp(pstPropVal, "none") == 0)
222                 {
223                     iToolbarType = 0;
224                 }
225                 else if (stricmp(pstPropVal, "figure") == 0)
226                 {
227                     iToolbarType = 1;
228                 }
229                 else
230                 {
231                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "toolbar", "none", "figure");
232                     freeAllocatedSingleString(pstProName);
233                     freeAllocatedSingleString(pstPropVal);
234                     return 1;
235                 }
236             }
237             else if (stricmp(pstProName, "menubar") == 0)
238             {
239                 if (stricmp(pstPropVal, "none") == 0)
240                 {
241                     iMenubarType = 0;
242                 }
243                 else if (stricmp(pstPropVal, "figure") == 0)
244                 {
245                     iMenubarType = 1;
246                 }
247                 else
248                 {
249                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "menubar", "none", "figure");
250                     freeAllocatedSingleString(pstProName);
251                     freeAllocatedSingleString(pstPropVal);
252                     return 1;
253                 }
254             }
255             else if (stricmp(pstProName, "default_axes") == 0)
256             {
257                 if (stricmp(pstPropVal, "on") == 0)
258                 {
259                     bDefaultAxes = TRUE;
260                 }
261                 else if (stricmp(pstPropVal, "off") == 0)
262                 {
263                     bDefaultAxes = FALSE;
264                 }
265                 else
266                 {
267                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "default_axes", "on", "off");
268                     freeAllocatedSingleString(pstProName);
269                     freeAllocatedSingleString(pstPropVal);
270                     return 1;
271                 }
272             }
273             else if (stricmp(pstProName, "visible") == 0)
274             {
275                 if (stricmp(pstPropVal, "on") == 0)
276                 {
277                     bVisible = TRUE;
278                 }
279                 else if (stricmp(pstPropVal, "off") == 0)
280                 {
281                     bVisible = FALSE;
282                 }
283                 else
284                 {
285                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "visible", "on", "off");
286                     freeAllocatedSingleString(pstProName);
287                     freeAllocatedSingleString(pstPropVal);
288                     return 1;
289                 }
290             }
291             freeAllocatedSingleString(pstPropVal);
292         }
293         iFig = createFigure(bDockable, iMenubarType, iToolbarType, bDefaultAxes, bVisible);
294         setGraphicObjectProperty(iFig, __GO_ID__, &iNewId, jni_int, 1);
295
296     }
297
298     //set(iFig, iPos, iPos + 1)
299     for (i = iPos + 1 ; i <= iRhs ; i += 2)
300     {
301         int isMatrixOfString = 0;
302         int* piAddrProp = NULL;
303         char* pstProName = NULL;
304         int* piAddrData = NULL;
305         int iRows = 0;
306         int iCols = 0;
307         void* _pvData = NULL;
308         int iType = 0;
309
310         //get property name
311         sciErr = getVarAddressFromPosition(pvApiCtx, i, &piAddrProp);
312         if (sciErr.iErr)
313         {
314             Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, i);
315             return 1;
316         }
317
318         if (getAllocatedSingleString(pvApiCtx, piAddrProp, &pstProName))
319         {
320             Scierror(999, _("%s: Wrong size for input argument #%d: A single string expected.\n"), fname, i);
321             return 1;
322         }
323
324         if (bDoCreation &&
325                 (stricmp(pstProName, "dockable") == 0 ||
326                  stricmp(pstProName, "menubar") == 0 ||
327                  stricmp(pstProName, "toolbar") == 0))
328         {
329             // Already set creating new figure
330             // but let the set_ function fail if figure already exists
331             continue;
332         }
333
334         //check property value to compatibility
335         if (stricmp(pstProName, "backgroundcolor") == 0)
336         {
337             freeAllocatedSingleString(pstProName);
338             pstProName = strdup("background");
339         }
340         else if (stricmp(pstProName, "foregroundcolor") == 0)
341         {
342             freeAllocatedSingleString(pstProName);
343             pstProName = strdup("foreground");
344         }
345
346         //get address of value on stack
347         sciErr = getVarAddressFromPosition(pvApiCtx, i + 1, &piAddrData);
348         if (sciErr.iErr)
349         {
350             Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, i + 1);
351             return 1;
352         }
353
354         getVarType(pvApiCtx, piAddrData, &iType);
355
356         if ((strcmp(pstProName, "user_data") == 0) || (stricmp(pstProName, "userdata") == 0))
357         {
358             /* in this case set_user_data_property
359              * directly uses the  third position in the stack
360              * to get the variable which is to be set in
361              * the user_data property (any data type is allowed) S. Steer */
362             _pvData = (void*)piAddrData;         /*position in the stack */
363             iRows = -1;   /*unused */
364             iCols = -1;   /*unused */
365             iType = -1;
366         }
367         else
368         {
369             switch (iType)
370             {
371                 case sci_matrix :
372                     getMatrixOfDouble(pvApiCtx, piAddrData, &iRows, &iCols, (double**)&_pvData);
373                     break;
374                 case sci_boolean :
375                     getMatrixOfBoolean(pvApiCtx, piAddrData, &iRows, &iCols, (int**)&_pvData);
376                     break;
377                 case sci_handles :
378                     getMatrixOfHandle(pvApiCtx, piAddrData, &iRows, &iCols, (long long**)&_pvData);
379                     break;
380                 case sci_strings :
381                     if (   strcmp(pstProName, "tics_labels") != 0 && strcmp(pstProName, "auto_ticks") != 0 &&
382                             strcmp(pstProName, "axes_visible") != 0 && strcmp(pstProName, "axes_reverse") != 0 &&
383                             strcmp(pstProName, "text") != 0 && stricmp(pstProName, "string") != 0 &&
384                             stricmp(pstProName, "tooltipstring") != 0) /* Added for uicontrols */
385                     {
386                         if (getAllocatedSingleString(pvApiCtx, piAddrData, (char**)&_pvData))
387                         {
388                             Scierror(999, _("%s: Wrong size for input argument #%d: A single string expected.\n"), fname, 3);
389                             return 1;
390                         }
391                         iRows = (int)strlen((char*)_pvData);
392                         iCols = 1;
393                     }
394                     else
395                     {
396                         isMatrixOfString = 1;
397                         getAllocatedMatrixOfString(pvApiCtx, piAddrData, &iRows, &iCols, (char***)&_pvData);
398                     }
399                     break;
400                 case sci_list :
401                     iCols = 1;
402                     getListItemNumber(pvApiCtx, piAddrData, &iRows);
403                     _pvData = (void*)piAddrData;         /* In this case l3 is the list position in stack */
404                     break;
405                 default :
406                     _pvData = (void*)piAddrData;         /* In this case l3 is the list position in stack */
407                     break;
408             }
409         }
410
411         callSetProperty(pvApiCtx, iFig, _pvData, iType, iRows, iCols, pstProName);
412         if (iType == sci_strings)
413         {
414             //free allacted data
415             if (isMatrixOfString == 1)
416             {
417                 freeAllocatedMatrixOfString(iRows, iCols, (char**)_pvData);
418             }
419             else
420             {
421                 freeAllocatedSingleString((char*)_pvData);
422             }
423         }
424     }
425
426     //return new created fig
427     createScalarHandle(pvApiCtx, iRhs + 1, getHandle(iFig));
428     AssignOutputVariable(pvApiCtx, 1) = iRhs + 1;
429     ReturnArguments(pvApiCtx);
430     return 0;
431 }
432 /*--------------------------------------------------------------------------*/
433 void setDefaultProperties(int _iFig)
434 {
435     //get figure axes
436     int iAxes = getOrCreateDefaultSubwin();
437     int iDrawing = 0;
438     int iColorIndex = 0;
439     int iFilled = 0;
440     int iAxesVisible = 0;
441     double pdblNewColor[COLOR_COMPONENT] = {0.8, 0.8, 0.8};
442
443     setGraphicObjectProperty(_iFig, __GO_IMMEDIATE_DRAWING__, &iDrawing, jni_bool, 1);
444
445     iColorIndex = addColor(_iFig, pdblNewColor);
446
447     //set background in figure and axes to new ( or existting ) color
448     setGraphicObjectProperty(_iFig, __GO_BACKGROUND__, &iColorIndex, jni_int, 1);
449     setGraphicObjectProperty(iAxes, __GO_BACKGROUND__, &iColorIndex, jni_int, 1);
450
451     //a.filled = "off"
452     setGraphicObjectProperty(iAxes, __GO_FILLED__, &iFilled, jni_bool, 1);
453
454     //a.axes_visible = "off"
455     setGraphicObjectProperty(iAxes, __GO_X_AXIS_VISIBLE__, &iAxesVisible, jni_bool, 1);
456     setGraphicObjectProperty(iAxes, __GO_Y_AXIS_VISIBLE__, &iAxesVisible, jni_bool, 1);
457     setGraphicObjectProperty(iAxes, __GO_Z_AXIS_VISIBLE__, &iAxesVisible, jni_bool, 1);
458
459     //f.immediate_drawing = "on"
460     iDrawing = 1;
461     setGraphicObjectProperty(_iFig, __GO_IMMEDIATE_DRAWING__, &iDrawing, jni_bool, 1);
462 }
463 /*--------------------------------------------------------------------------*/
464 int addColor(int _iFig, double* _pdblNewColor)
465 {
466     int iColorIndex = 0;
467     int i = 0, j = 0;
468     int iColorMapSize = 0;
469     int* piColorMapSize = &iColorMapSize;
470     double* pdblColorMap = NULL;
471     //for new figure, we have to set figure and axes background to [0.8 0.8 0.8]
472     //to do that, we have to update figure.colormap to add new color if not exist.
473     //or get index of color in current color_map
474
475     //first get figure.color_map
476     getGraphicObjectProperty(_iFig, __GO_COLORMAP_SIZE__, jni_int, (void**)&piColorMapSize);
477     getGraphicObjectProperty(_iFig, __GO_COLORMAP__, jni_double_vector, (void **)&pdblColorMap);
478
479     //check if newColor already in coloMap
480     for (i = 0 ; i < iColorMapSize ; i++)
481     {
482         BOOL bFound = TRUE;
483         double* pdblCurrentColor = pdblColorMap + i;
484         for (j = 0 ; j < COLOR_COMPONENT ; j++)
485         {
486             if (*(pdblCurrentColor + j * iColorMapSize) != _pdblNewColor[j])
487             {
488                 bFound = FALSE;
489                 break;
490             }
491         }
492
493         if (bFound)
494         {
495             iColorIndex = i + 1;
496             break;
497         }
498     }
499
500     //not found in current color map
501     if (iColorIndex == 0)
502     {
503         int iNewColorMapSize = (iColorMapSize + 1) * COLOR_COMPONENT;
504         double* pdblNewColorMap = (double*)MALLOC(sizeof(double) * iNewColorMapSize);
505         //we have to add the new color at the end of the current color map
506         for (i = 0 ; i < COLOR_COMPONENT ; i++)
507         {
508             memcpy(pdblNewColorMap + i * (iColorMapSize + 1),
509                    pdblColorMap + (i * iColorMapSize),
510                    iColorMapSize * sizeof(double));
511
512             pdblNewColorMap[i * (iColorMapSize + 1) + iColorMapSize] = _pdblNewColor[i];
513         }
514
515         setGraphicObjectProperty(_iFig, __GO_COLORMAP__, pdblNewColorMap, jni_double_vector, iNewColorMapSize);
516
517         iColorIndex = iColorMapSize + 1;
518     }
519     return iColorIndex;
520 }
521 /*--------------------------------------------------------------------------*/