improve management of axes_size and figure_size
[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 "FigureModel.h"
28 #include "HandleManagement.h"
29 #include "SetHashTable.h"
30 #include "stricmp.h"
31 #ifdef _MSC_VER
32 #include "strdup_windows.h"
33 #endif
34
35 #include "sciprint.h"
36 #include "addColor.h"
37
38 /*--------------------------------------------------------------------------*/
39 int setDefaultProperties(int _iFig, BOOL bDefaultAxes, BOOL _axesSize);
40 int getStackArgumentAsBoolean(void* _pvCtx, int* _piAddr);
41 /*--------------------------------------------------------------------------*/
42 int sci_figure(char * fname, unsigned long fname_len)
43 {
44     SciErr sciErr;
45     int* piAddr = NULL;
46     int iFig = 0;
47     int iRhs = nbInputArgument(pvApiCtx);
48     int iId = 0;
49     int iPos = 0;
50     int i = 0;
51     int iNewId = -1;
52     int iAxes = 0;
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     double* figureSize = NULL;
59     double* axesSize = NULL;
60     double* position = NULL;
61     BOOL bMenuBar = TRUE;
62     BOOL bToolBar = TRUE;
63     BOOL bInfoBar = TRUE;
64     int iMenubarType = 1; // Create a 'figure' menubar by default
65     int iToolbarType = 1; // Create a 'figure' toolbar by default
66     double dblId = 0;
67     BOOL status = FALSE;
68
69     //figure(num) -> scf(num)
70     //figure() -> scf()
71
72     //figure(x, "...", ...)
73
74     // figure()
75     if (iRhs == 0) // Auto ID
76     {
77         iFig = createNewFigureWithAxes();
78         iAxes = setDefaultProperties(iFig, TRUE, TRUE);
79         createScalarHandle(pvApiCtx, iRhs + 1, getHandle(iFig));
80         AssignOutputVariable(pvApiCtx, 1) = iRhs + 1;
81         ReturnArguments(pvApiCtx);
82         return 0;
83     }
84
85     if (iRhs == 1)
86     {
87         //figure(x);
88         sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr);
89         if (sciErr.iErr)
90         {
91             printError(&sciErr, 0);
92             Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, 1);
93             return 0;
94         }
95
96         if (isVarMatrixType(pvApiCtx, piAddr) == 0)
97         {
98             Scierror(999, _("%s: Wrong type for input argument #%d: An integer value expected.\n"), fname, 1);
99             return 0;
100         }
101
102         if (getScalarDouble(pvApiCtx, piAddr, &dblId))
103         {
104             Scierror(999, _("%s: No more memory.\n"), fname);
105             return 0;
106         }
107
108         iId = (int)(dblId + 0.5); //avoid 1.999 -> 1
109
110         //get current fig from id
111         iFig = getFigureFromIndex(iId);
112         if (iFig == 0) // Figure does not exists, create a new one
113         {
114             iFig = createNewFigureWithAxes();
115             setGraphicObjectProperty(iFig, __GO_ID__, &iId, jni_int,  1);
116             iAxes = setDefaultProperties(iFig, TRUE, TRUE);
117         }
118
119         createScalarHandle(pvApiCtx, iRhs + 1, getHandle(iFig));
120         AssignOutputVariable(pvApiCtx, 1) = iRhs + 1;
121         ReturnArguments(pvApiCtx);
122         return 0;
123     }
124
125     // Prepare property analysis
126     if (iRhs % 2 == 0)
127     {
128         //get highest value of winsid to create the new windows @ + 1
129         iNewId = getValidDefaultFigureId();
130         iPos = 0;
131     }
132     else
133     {
134         iPos = 1;
135         //figure(x, ...);
136         sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr);
137         if (sciErr.iErr)
138         {
139             printError(&sciErr, 0);
140             Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, 1);
141             return 0;
142         }
143
144         if (isVarMatrixType(pvApiCtx, piAddr) == 0)
145         {
146             Scierror(999, _("%s: Wrong type for input argument #%d: An integer value expected.\n"), fname, 1);
147             return 0;
148         }
149
150         if (getScalarDouble(pvApiCtx, piAddr, &dblId))
151         {
152             Scierror(999, _("%s: No more memory.\n"), fname);
153             return 0;
154         }
155
156         iNewId = (int)(dblId + 0.5); //avoid 1.999 -> 1
157         //get current fig from id
158         iFig = getFigureFromIndex(iId);
159         if (iFig != 0) // Figure already exists
160         {
161             bDoCreation = FALSE;
162         }
163     }
164
165     if (bDoCreation)
166     {
167         int* piAddrProp = NULL;
168         char* pstProName = NULL;
169         int* piAddrData = NULL;
170         for (i = iPos + 1 ; i <= iRhs ; i += 2)
171         {
172             //get property name
173             sciErr = getVarAddressFromPosition(pvApiCtx, i, &piAddrProp);
174             if (sciErr.iErr)
175             {
176                 Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, i);
177                 return 1;
178             }
179
180             if (getAllocatedSingleString(pvApiCtx, piAddrProp, &pstProName))
181             {
182                 Scierror(999, _("%s: Wrong size for input argument #%d: A single string expected.\n"), fname, i);
183                 return 1;
184             }
185
186             if (stricmp(pstProName, "dockable") != 0 &&
187                     stricmp(pstProName, "toolbar") != 0 &&
188                     stricmp(pstProName, "menubar") != 0 &&
189                     stricmp(pstProName, "default_axes") != 0 &&
190                     stricmp(pstProName, "visible") != 0 &&
191                     stricmp(pstProName, "figure_size") != 0 &&
192                     stricmp(pstProName, "axes_size") != 0 &&
193                     stricmp(pstProName, "position") != 0 &&
194                     stricmp(pstProName, "menubar_visible") != 0 &&
195                     stricmp(pstProName, "toolbar_visible") != 0 &&
196                     stricmp(pstProName, "infobar_visible") != 0)
197             {
198                 freeAllocatedSingleString(pstProName);
199                 continue;
200             }
201
202             //get address of value on stack
203             sciErr = getVarAddressFromPosition(pvApiCtx, i + 1, &piAddrData);
204             if (sciErr.iErr)
205             {
206                 Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, i + 1);
207                 return 1;
208             }
209
210             //check property value to compatibility
211             if (stricmp(pstProName, "dockable") == 0)
212             {
213                 bDockable = getStackArgumentAsBoolean(pvApiCtx, piAddrData);
214                 if (bDockable == -1)
215                 {
216                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "dockable", "on", "off");
217                     freeAllocatedSingleString(pstProName);
218                     return 1;
219                 }
220             }
221             else if (stricmp(pstProName, "toolbar") == 0)
222             {
223                 char* pstVal = NULL;
224                 if (isStringType(pvApiCtx, piAddrData) == FALSE || isScalar(pvApiCtx, piAddrData) == FALSE)
225                 {
226                     Scierror(999, _("%s: Wrong size for input argument #%d: A single string expected.\n"), fname, i);
227                     freeAllocatedSingleString(pstProName);
228                 }
229
230                 getAllocatedSingleString(pvApiCtx, piAddrData, &pstVal);
231
232                 if (stricmp(pstVal, "none") == 0)
233                 {
234                     iToolbarType = 0;
235                 }
236                 else if (stricmp(pstVal, "figure") == 0)
237                 {
238                     iToolbarType = 1;
239                 }
240                 else
241                 {
242                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "toolbar", "none", "figure");
243                     freeAllocatedSingleString(pstProName);
244                     freeAllocatedSingleString(pstVal);
245                     return 1;
246                 }
247
248                 freeAllocatedSingleString(pstVal);
249             }
250             else if (stricmp(pstProName, "menubar") == 0)
251             {
252                 char* pstVal = NULL;
253                 if (isStringType(pvApiCtx, piAddrData) == FALSE || isScalar(pvApiCtx, piAddrData) == FALSE)
254                 {
255                     Scierror(999, _("%s: Wrong size for input argument #%d: A single string expected.\n"), fname, i + 1);
256                     freeAllocatedSingleString(pstProName);
257                 }
258
259                 getAllocatedSingleString(pvApiCtx, piAddrData, &pstVal);
260
261                 if (stricmp(pstVal, "none") == 0)
262                 {
263                     iMenubarType = 0;
264                 }
265                 else if (stricmp(pstVal, "figure") == 0)
266                 {
267                     iMenubarType = 1;
268                 }
269                 else
270                 {
271                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "menubar", "none", "figure");
272                     freeAllocatedSingleString(pstProName);
273                     freeAllocatedSingleString(pstVal);
274                     return 1;
275                 }
276
277                 freeAllocatedSingleString(pstVal);
278             }
279             else if (stricmp(pstProName, "default_axes") == 0)
280             {
281                 bDefaultAxes = getStackArgumentAsBoolean(pvApiCtx, piAddrData);
282                 if (bDefaultAxes == -1)
283                 {
284                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "default_axes", "on", "off");
285                     freeAllocatedSingleString(pstProName);
286                     return 1;
287                 }
288             }
289             else if (stricmp(pstProName, "visible") == 0)
290             {
291                 bVisible = getStackArgumentAsBoolean(pvApiCtx, piAddrData);
292                 if (bVisible == -1)
293                 {
294                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "visible", "on", "off");
295                     freeAllocatedSingleString(pstProName);
296                     return 1;
297                 }
298             }
299             else if (stricmp(pstProName, "figure_size") == 0)
300             {
301                 int iRows = 0;
302                 int iCols = 0;
303                 if (isDoubleType(pvApiCtx, piAddrData) == FALSE)
304                 {
305                     Scierror(999, _("%s: Wrong type for input argument #%d: A double vector expected.\n"), fname, i + 1);
306                     return 1;
307                 }
308
309                 getMatrixOfDouble(pvApiCtx, piAddrData, &iRows, &iCols, &figureSize);
310                 if (iRows * iCols != 2)
311                 {
312                     Scierror(999, _("Wrong size for '%s' property: %d elements expected.\n"), "figure_size", 2);
313                     return 1;
314                 }
315             }
316             else if (stricmp(pstProName, "axes_size") == 0)
317             {
318                 int iRows = 0;
319                 int iCols = 0;
320                 if (isDoubleType(pvApiCtx, piAddrData) == FALSE)
321                 {
322                     Scierror(999, _("%s: Wrong type for input argument #%d: A double vector expected.\n"), fname, i + 1);
323                     return 1;
324                 }
325
326                 getMatrixOfDouble(pvApiCtx, piAddrData, &iRows, &iCols, &axesSize);
327                 if (iRows * iCols != 2)
328                 {
329                     Scierror(999, _("Wrong size for '%s' property: %d elements expected.\n"), "axes_size", 2);
330                     return 1;
331                 }
332             }
333             else if (stricmp(pstProName, "position") == 0)
334             {
335                 int iRows = 0;
336                 int iCols = 0;
337                 double* pdbl = NULL;
338                 if (isDoubleType(pvApiCtx, piAddrData) == FALSE)
339                 {
340                     Scierror(999, _("%s: Wrong type for input argument #%d: A double vector expected.\n"), fname, i + 1);
341                     return 1;
342                 }
343
344                 getMatrixOfDouble(pvApiCtx, piAddrData, &iRows, &iCols, &pdbl);
345                 if (iRows * iCols != 4)
346                 {
347                     Scierror(999, _("Wrong size for '%s' property: %d elements expected.\n"), "position", 4);
348                     return 1;
349                 }
350
351                 position = pdbl;
352                 axesSize = (pdbl + 2);
353             }
354             else if (stricmp(pstProName, "menubar_visible") == 0)
355             {
356                 bMenuBar = getStackArgumentAsBoolean(pvApiCtx, piAddrData);
357                 if (bMenuBar == -1)
358                 {
359                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "menubar_visible", "on", "off");
360                     freeAllocatedSingleString(pstProName);
361                     return 1;
362                 }
363             }
364             else if (stricmp(pstProName, "toolbar_visible") == 0)
365             {
366                 bToolBar = getStackArgumentAsBoolean(pvApiCtx, piAddrData);
367                 if (bToolBar == -1)
368                 {
369                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "toolbar_visible", "on", "off");
370                     freeAllocatedSingleString(pstProName);
371                     return 1;
372                 }
373             }
374             else if (stricmp(pstProName, "infobar_visible") == 0)
375             {
376                 bInfoBar = getStackArgumentAsBoolean(pvApiCtx, piAddrData);
377                 if (bInfoBar == -1)
378                 {
379                     Scierror(999, _("Wrong value for '%s' property: '%s' or '%s' expected."), "infobar_visible", "on", "off");
380                     freeAllocatedSingleString(pstProName);
381                     return 1;
382                 }
383             }
384
385         }
386
387         iFig = createFigure(bDockable, iMenubarType, iToolbarType, bDefaultAxes, bVisible, figureSize, axesSize, position, bMenuBar, bToolBar, bInfoBar);
388         setGraphicObjectProperty(iFig, __GO_ID__, &iNewId, jni_int, 1);
389         iAxes = setDefaultProperties(iFig, bDefaultAxes, figureSize || axesSize ? FALSE : TRUE);
390     }
391
392     //set(iFig, iPos, iPos + 1)
393     for (i = iPos + 1 ; i <= iRhs ; i += 2)
394     {
395         int isMatrixOfString = 0;
396         int* piAddrProp = NULL;
397         char* pstProName = NULL;
398         int* piAddrData = NULL;
399         int iRows = 0;
400         int iCols = 0;
401         void* _pvData = NULL;
402         int iType = 0;
403
404         //get property name
405         sciErr = getVarAddressFromPosition(pvApiCtx, i, &piAddrProp);
406         if (sciErr.iErr)
407         {
408             Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, i);
409             return 1;
410         }
411
412         if (getAllocatedSingleString(pvApiCtx, piAddrProp, &pstProName))
413         {
414             Scierror(999, _("%s: Wrong size for input argument #%d: A single string expected.\n"), fname, i);
415             return 1;
416         }
417
418         if (bDoCreation && (
419                     stricmp(pstProName, "dockable") == 0 ||
420                     stricmp(pstProName, "toolbar") == 0 ||
421                     stricmp(pstProName, "menubar") == 0 ||
422                     stricmp(pstProName, "default_axes") == 0 ||
423                     stricmp(pstProName, "visible") == 0 ||
424                     stricmp(pstProName, "figure_size") == 0 ||
425                     stricmp(pstProName, "axes_size") == 0 ||
426                     stricmp(pstProName, "position") == 0 ||
427                     stricmp(pstProName, "menubar_visible") == 0 ||
428                     stricmp(pstProName, "toolbar_visible") == 0 ||
429                     stricmp(pstProName, "infobar_visible") == 0))
430         {
431             // Already set creating new figure
432             // but let the set_ function fail if figure already exists
433             continue;
434         }
435
436         sciprint("prop : %s\n", pstProName);
437         //get address of value on stack
438         sciErr = getVarAddressFromPosition(pvApiCtx, i + 1, &piAddrData);
439         if (sciErr.iErr)
440         {
441             Scierror(999, _("%s: Can not read input argument #%d.\n"), fname, i + 1);
442             return 1;
443         }
444
445         getVarType(pvApiCtx, piAddrData, &iType);
446
447         if ((strcmp(pstProName, "user_data") == 0) || (stricmp(pstProName, "userdata") == 0))
448         {
449             /* in this case set_user_data_property
450              * directly uses the  third position in the stack
451              * to get the variable which is to be set in
452              * the user_data property (any data type is allowed) S. Steer */
453             _pvData = (void*)piAddrData;         /*position in the stack */
454             iRows = -1;   /*unused */
455             iCols = -1;   /*unused */
456             iType = -1;
457         }
458         else
459         {
460             switch (iType)
461             {
462                 case sci_matrix :
463                     getMatrixOfDouble(pvApiCtx, piAddrData, &iRows, &iCols, (double**)&_pvData);
464                     break;
465                 case sci_boolean :
466                     getMatrixOfBoolean(pvApiCtx, piAddrData, &iRows, &iCols, (int**)&_pvData);
467                     break;
468                 case sci_handles :
469                     getMatrixOfHandle(pvApiCtx, piAddrData, &iRows, &iCols, (long long**)&_pvData);
470                     break;
471                 case sci_strings :
472                     if (   strcmp(pstProName, "tics_labels") != 0 && strcmp(pstProName, "auto_ticks") != 0 &&
473                             strcmp(pstProName, "axes_visible") != 0 && strcmp(pstProName, "axes_reverse") != 0 &&
474                             strcmp(pstProName, "text") != 0 && stricmp(pstProName, "string") != 0 &&
475                             stricmp(pstProName, "tooltipstring") != 0) /* Added for uicontrols */
476                     {
477                         if (getAllocatedSingleString(pvApiCtx, piAddrData, (char**)&_pvData))
478                         {
479                             Scierror(999, _("%s: Wrong size for input argument #%d: A single string expected.\n"), fname, 3);
480                             return 1;
481                         }
482                         iRows = (int)strlen((char*)_pvData);
483                         iCols = 1;
484                     }
485                     else
486                     {
487                         isMatrixOfString = 1;
488                         getAllocatedMatrixOfString(pvApiCtx, piAddrData, &iRows, &iCols, (char***)&_pvData);
489                     }
490                     break;
491                 case sci_list :
492                     iCols = 1;
493                     getListItemNumber(pvApiCtx, piAddrData, &iRows);
494                     _pvData = (void*)piAddrData;         /* In this case l3 is the list position in stack */
495                     break;
496                 default :
497                     _pvData = (void*)piAddrData;         /* In this case l3 is the list position in stack */
498                     break;
499             }
500         }
501
502         callSetProperty(pvApiCtx, iFig, _pvData, iType, iRows, iCols, pstProName);
503
504         // If backgroundcolor is set :
505         // * add it to colormap => performed by callSetProperty
506         // * set background to index => performed by callSetProperty
507         // * copy value into axes background property
508         if (stricmp(pstProName, "backgroundcolor") == 0 && iAxes > 0)
509         {
510             int iBackground = 0;
511             int *piBackground = &iBackground;
512
513             getGraphicObjectProperty(iFig, __GO_BACKGROUND__, jni_int, (void **)&piBackground);
514             setGraphicObjectProperty(iAxes, __GO_BACKGROUND__, piBackground, jni_int, 1);
515         }
516
517         if (iType == sci_strings)
518         {
519             //free allacted data
520             if (isMatrixOfString == 1)
521             {
522                 freeAllocatedMatrixOfString(iRows, iCols, (char**)_pvData);
523             }
524             else
525             {
526                 freeAllocatedSingleString((char*)_pvData);
527             }
528         }
529     }
530
531     //return new created fig
532     createScalarHandle(pvApiCtx, iRhs + 1, getHandle(iFig));
533     AssignOutputVariable(pvApiCtx, 1) = iRhs + 1;
534     ReturnArguments(pvApiCtx);
535     return 0;
536 }
537 /*--------------------------------------------------------------------------*/
538 int getStackArgumentAsBoolean(void* _pvCtx, int* _piAddr)
539 {
540     if (isScalar(_pvCtx, _piAddr))
541     {
542         if (isDoubleType(_pvCtx, _piAddr))
543         {
544             double dbl = 0;
545             getScalarDouble(_pvCtx, _piAddr, &dbl);
546             return ((int)dbl == 0 ? FALSE : TRUE);
547         }
548         else if (isBooleanType(_pvCtx, _piAddr))
549         {
550             int i = 0;
551             getScalarBoolean(_pvCtx, _piAddr, &i);
552             return (i == 0 ? FALSE : TRUE);
553         }
554         else if (isStringType(_pvCtx, _piAddr))
555         {
556             int ret = 0;
557             char* pst = NULL;
558             getAllocatedSingleString(_pvCtx, _piAddr, &pst);
559
560             if (stricmp(pst, "on") == 0)
561             {
562                 ret = TRUE;
563             }
564
565             freeAllocatedSingleString(pst);
566
567             return ret;
568         }
569     }
570     return -1;
571 }
572 /*--------------------------------------------------------------------------*/
573 int setDefaultProperties(int _iFig, BOOL _bDefaultAxes, BOOL _axesSize)
574 {
575     //get figure axes
576     int iAxes = -1;
577     int iDrawing = 0;
578     int iColorIndex = 0;
579     int iFilled = 0;
580     int iAxesVisible = 0;
581     int* piAxesSize = NULL;
582     double pdblNewColor[COLOR_COMPONENT] = {0.8, 0.8, 0.8};
583
584     setGraphicObjectProperty(_iFig, __GO_IMMEDIATE_DRAWING__, &iDrawing, jni_bool, 1);
585
586     iColorIndex = addColor(_iFig, pdblNewColor);
587
588     setGraphicObjectProperty(_iFig, __GO_BACKGROUND__, &iColorIndex, jni_int, 1);
589     if (_bDefaultAxes)
590     {
591         iAxes = getOrCreateDefaultSubwin();
592         //set background in figure and axes to new ( or existting ) color
593         setGraphicObjectProperty(iAxes, __GO_BACKGROUND__, &iColorIndex, jni_int, 1);
594
595         //a.filled = "off"
596         setGraphicObjectProperty(iAxes, __GO_FILLED__, &iFilled, jni_bool, 1);
597
598         //a.axes_visible = "off"
599         setGraphicObjectProperty(iAxes, __GO_X_AXIS_VISIBLE__, &iAxesVisible, jni_bool, 1);
600         setGraphicObjectProperty(iAxes, __GO_Y_AXIS_VISIBLE__, &iAxesVisible, jni_bool, 1);
601         setGraphicObjectProperty(iAxes, __GO_Z_AXIS_VISIBLE__, &iAxesVisible, jni_bool, 1);
602     }
603
604     // axes_size
605     if (_axesSize)
606     {
607         getGraphicObjectProperty(getFigureModel(), __GO_AXES_SIZE__, jni_int_vector, (void **)&piAxesSize);
608         setGraphicObjectProperty(_iFig, __GO_AXES_SIZE__, piAxesSize, jni_int_vector, 2);
609     }
610
611     //f.immediate_drawing = "on"
612     iDrawing = 1;
613     setGraphicObjectProperty(_iFig, __GO_IMMEDIATE_DRAWING__, &iDrawing, jni_bool, 1);
614
615     return iAxes;
616 }
617 /*--------------------------------------------------------------------------*/