1 /***************************************************************************
2                           gdlwidget.cpp  -  GDL widget system implementation
3                              -------------------
4     begin                : Fri May 7 2004
5     copyright            : (C) 2004 by Marc Schellens
6     email                : m_schellens@users.sourceforge.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "includefirst.hpp"
19 
20 #ifdef HAVE_LIBWXWIDGETS
21 
22 #include <memory>
23 
24 #include <wx/grid.h>
25 #include <wx/gbsizer.h>
26 #include <wx/wrapsizer.h>
27 #include <wx/textctrl.h>
28 #include <wx/menuitem.h>
29 
30 #include "basegdl.hpp"
31 #include "dstructgdl.hpp"
32 
33 #include "dinterpreter.hpp"
34 
35 
36 #include "gdlwxstream.hpp"
37 
38 #include "gdlwidget.hpp"
39 
40 #include "widget.hpp"
41 #include "graphicsdevice.hpp"
42 
43 //must arrive after "gdlwidget.hpp"
44 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
45 #include <random>
46 #include <chrono>
47 #endif
48 
49 //abbrevs to avoid sending size events when changing sizes
50 #define START_CHANGESIZE_NOEVENT \
51 WidgetIDT id;\
52 gdlwxFrame* local_topFrame;\
53 bool reconnect=this->DisableSizeEvents(local_topFrame,id);
54 
55 #define END_CHANGESIZE_NOEVENT if (reconnect) EnableSizeEvents(local_topFrame,id);
56 
57 #define START_ADD_EVENTUAL_FRAME \
58 wxScrolled<wxPanel>* saveWidgetPanel = widgetPanel;\
59 wxSizer* frameSizer;\
60 if (frameWidth > 0) {\
61   framePanel = new wxPanel(widgetPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, gdlBORDER_EXT);\
62   frameSizer = new wxBoxSizer(wxVERTICAL);\
63   framePanel->SetSizer(frameSizer);\
64   widgetPanel = static_cast<wxScrolled<wxPanel>*>(framePanel);\
65 }
66 
67 #define END_ADD_EVENTUAL_FRAME \
68   if (frameWidth > 0) {\
69     theWxContainer = widgetPanel;\
70     frameSizer->Add(static_cast<wxWindow*> (theWxWidget), ALLOWSTRETCH, wxALL|wxEXPAND , frameWidth);\
71     frameSizer->Fit(static_cast<wxWindow*> (theWxWidget));\
72     framePanel->Fit();\
73     widgetPanel = saveWidgetPanel;\
74     }
75 
76 #define TIDY_WIDGET(xxx) \
77   this->setFont();\
78   if (widgetSizer) {\
79     /*if we create a widget after the topwidget has been realized, insure the insertion is IDL-compliant for multicolumns, using the following; */\
80     /* 1) recompute the base siser taking into account the additional widget to be inserted */\
81     /* 2) recreate the adequate sizer */\
82     /* 3) re-add all child windows (including this one) */\
83     if (this->IsRealized()) {\
84       GDLWidgetBase* b = static_cast<GDLWidgetBase*> (gdlParent);\
85       b->ReorderForANewWidget(static_cast<wxWindow*> (theWxContainer), DONOTALLOWSTRETCH, widgetStyle | wxALL, b->getSpace());\
86     } else widgetSizer->Add(static_cast<wxWindow*> (theWxContainer), DONOTALLOWSTRETCH, widgetStyle | wxALL, xxx);\
87   } else {\
88     static_cast<wxWindow*> (theWxContainer)->SetPosition(wOffset);\
89   }\
90   widgetPanel->FitInside();
91 
92 #define UPDATE_WINDOW { if (this->IsRealized()) UpdateGui(); }
93 #define REALIZE_IF_NEEDED { if (this->IsRealized()) {this->OnRealize(); UpdateGui();} }
94 
95 //a few useful defaut pixmaps:
96 static const char * pixmap_unchecked[] = {
97 "13 13 14 1",
98 " 	c None",
99 ".	c #CCCED3",
100 "+	c #838793",
101 "@	c #C4C7CF",
102 "#	c #F5F5F5",
103 "$	c #F6F6F6",
104 "%	c #F7F7F7",
105 "&	c #F9F9F9",
106 "*	c #FAFAFA",
107 "=	c #FBFBFB",
108 "-	c #FCFCFC",
109 ";	c #FDFDFD",
110 ">	c #FEFEFE",
111 ",	c #FFFFFF",
112 ".+++++++++++.",
113 "+@@@@@@@@@@@+",
114 "+@##########+",
115 "+@$$$$$$$$$$+",
116 "+@%%%%%%%%%%+",
117 "+@&&&&&&&&&&+",
118 "+@**********+",
119 "+@==========+",
120 "+@----------+",
121 "+@;;;;;;;;;;+",
122 "+@>>>>>>>>>>+",
123 "+@,,,,,,,,,,+",
124 ".+++++++++++."};
125 
126 static const char * pixmap_checked[] = {
127 "13 13 38 1",
128 " 	c None",
129 ".	c #CCCED3",
130 "+	c #838793",
131 "@	c #C4C7CF",
132 "#	c #F5F5F5",
133 "$	c #BBBBBB",
134 "%	c #131313",
135 "&	c #0C0C0C",
136 "*	c #F6F6F6",
137 "=	c #BEBEBE",
138 "-	c #030303",
139 ";	c #060606",
140 ">	c #B4B4B4",
141 ",	c #F7F7F7",
142 "'	c #C6C6C6",
143 ")	c #080808",
144 "!	c #000000",
145 "~	c #C0C0C0",
146 "{	c #020202",
147 "]	c #363636",
148 "^	c #F9F9F9",
149 "/	c #505050",
150 "(	c #2C2C2C",
151 "_	c #545454",
152 ":	c #606060",
153 "<	c #010101",
154 "[	c #FAFAFA",
155 "}	c #FBFBFB",
156 "|	c #333333",
157 "1	c #1D1D1D",
158 "2	c #FCFCFC",
159 "3	c #C4C4C4",
160 "4	c #FDFDFD",
161 "5	c #B9B9B9",
162 "6	c #FEFEFE",
163 "7	c #5E5E5E",
164 "8	c #777777",
165 "9	c #FFFFFF",
166 ".+++++++++++.",
167 "+@@@@@@@@@@@+",
168 "+@######$%&#+",
169 "+@*****=-;**+",
170 "+@$>,,')!~,,+",
171 "+@{!]^/!(^^^+",
172 "+@_!!:<![[[[+",
173 "+@}|!!!1}}}}+",
174 "+@22)!!32222+",
175 "+@445!)44444+",
176 "+@6667866666+",
177 "+@9999999999+",
178 ".+++++++++++."};
179 
180 
181 const WidgetIDT GDLWidget::NullID = 0;
182 
183 // instantiation
184 WidgetListT GDLWidget::widgetList;
185 wxImageList *gdlDefaultTreeStateImages;
186 wxImageList *gdlDefaultTreeImages;
187 
188 GDLEventQueue GDLWidget::eventQueue; // the event queue
189 GDLEventQueue GDLWidget::readlineEventQueue; // for process at command line level
190 bool GDLWidget::wxIsOn=false;
191 bool GDLWidget::handlersOk=false;
192 wxFont GDLWidget::defaultFont=wxNullFont; //the font defined by widget_control,default_font.
193 wxFont GDLWidget::systemFont=wxNullFont;  //the initial system font. This to behave as IDL
194 
195 
Purge()196 void GDLEventQueue::Purge()
197 {
198   for ( SizeT i = 0; i < dq.size( ); ++i )
199     delete dq[i];
200   dq.clear( );
201   //   isEmpty = true;
202 }
203 
204 // removes all events for hierarchy staring at 'parentID' and below
Purge(WidgetIDT parentID)205 void GDLEventQueue::Purge( WidgetIDT parentID) {
206   //establish a list of children:
207   GDLWidget* w = GDLWidget::GetWidget(parentID);
208   DLongGDL* list = w->GetAllHeirs();
209   for (long i = dq.size() - 1; i >= 0; --i) {
210     DStructGDL* ev = dq[i];
211     static int idIx = 0; // ev->Desc( )->TagIndex( "ID" ); //always 0
212     DLong id = (*static_cast<DLongGDL*> (ev->GetTag(idIx, 0)))[0];
213     //all events pertaining to any heirs of 'parentID' including 'parentID' are removed:
214     for (DLong testid = 0; testid < list->N_Elements(); ++testid) {
215       if (id == (*list)[testid]) {
216 //        std::cerr<<"event "<<id<<" purged."<<std::endl;
217         delete ev;
218         dq.erase(dq.begin() + i);
219       }
220     }
221   }
222   GDLDelete(list);
223   //   isEmpty = true;
224 }
225 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
RandomWxColour()226 inline wxColour RandomWxColour() {
227   unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
228   std::default_random_engine generator (seed);
229 
230   std::uniform_int_distribution<int> distribution(0,255);
231   int r = distribution(generator);
232   int g = distribution(generator);
233   int b = distribution(generator);
234   return wxColour(r,g,b);
235 }
236 #endif
237 
238 //this seem to respect the order of preference if variuos align_xxx are passed to the widget.
labelTextAlignment()239 inline int GDLWidget::labelTextAlignment()
240 {//this concerns only how the thext is written in the label.
241   // Top and bottom are not allowed in IDL.
242    if ( alignment & gdlwALIGN_RIGHT ) return (wxALIGN_RIGHT|wxST_NO_AUTORESIZE);
243    if ( alignment & gdlwALIGN_CENTER ) return (wxALIGN_CENTRE_HORIZONTAL|wxST_NO_AUTORESIZE);
244    if ( alignment & gdlwALIGN_LEFT ) return (wxALIGN_LEFT|wxST_NO_AUTORESIZE);
245    return wxALIGN_CENTRE_HORIZONTAL|wxST_NO_AUTORESIZE;
246 }
247 
buttonTextAlignment()248 inline int GDLWidget::buttonTextAlignment()
249 { //this concerns only how the thext is written in the button. Apparently wxBU_RIGHT does not work, and center is absent.
250   // Top and bottom are not allowed in IDL.
251       if ( alignment & gdlwALIGN_RIGHT ) return wxBU_EXACTFIT|wxBU_RIGHT; //right does not work.
252       if ( alignment & gdlwALIGN_CENTER ) return wxBU_EXACTFIT; //center does not exist
253       if ( alignment & gdlwALIGN_LEFT ) return wxBU_EXACTFIT|wxBU_LEFT; //default, works
254       return wxBU_EXACTFIT;
255 }
256 
widgetAlignment()257 inline int GDLWidgetLabel::widgetAlignment()
258 {
259   long myAlign = alignment;
260   if (myAlign == gdlwALIGN_NOT) {
261     myAlign = this->GetMyParentBaseWidget()->getChildrenAlignment();
262 }
263   //wxALIGN_LEFT and TOP is in fact wxALIGN_NOT as this is the default alignment
264   if (myAlign == gdlwALIGN_NOT) return wxALIGN_CENTER;
265   //left is top by default and right is bottom. So define left as top and remove top if bottom, etc.
266   //ignore sets that do not concern the current layout (vetrtical or horizontal)
267   if (this->GetMyParentBaseWidget()->IsVertical()) { //col=1 left, center, right
268     if (myAlign & gdlwALIGN_CENTER) return wxALIGN_CENTER_HORIZONTAL;
269     if (myAlign & gdlwALIGN_LEFT) return wxALIGN_LEFT;
270     if (myAlign & gdlwALIGN_RIGHT) return wxALIGN_RIGHT;
271     if (myAlign & gdlwALIGN_TOP) return wxALIGN_LEFT;
272     if (myAlign & gdlwALIGN_BOTTOM) return wxALIGN_RIGHT;
273   } else if (this->GetMyParentBaseWidget()->IsHorizontal()) { //row=1
274     if (myAlign & gdlwALIGN_CENTER) return wxALIGN_CENTER_VERTICAL;
275     if (myAlign & gdlwALIGN_TOP) return wxALIGN_TOP;
276     if (myAlign & gdlwALIGN_BOTTOM) return wxALIGN_BOTTOM;
277     if (myAlign & gdlwALIGN_LEFT) return wxALIGN_TOP;
278     if (myAlign & gdlwALIGN_RIGHT) return wxALIGN_BOTTOM;
279   } else {
280     if (myAlign & gdlwALIGN_CENTER) return wxALIGN_CENTER_HORIZONTAL;
281     if (myAlign & gdlwALIGN_LEFT) return wxALIGN_LEFT;
282     if (myAlign & gdlwALIGN_RIGHT) return wxALIGN_RIGHT;
283     if (myAlign & gdlwALIGN_TOP) return wxALIGN_LEFT;
284     if (myAlign & gdlwALIGN_BOTTOM) return wxALIGN_RIGHT;
285   }
286   return 0;
287 }
288 
widgetAlignment()289 inline int GDLWidget::widgetAlignment()
290 {
291   long myAlign = alignment;
292   if (myAlign == gdlwALIGN_NOT) {
293     myAlign = this->GetMyParentBaseWidget()->getChildrenAlignment();
294   }
295   //wxALIGN_LEFT and TOP is in fact wxALIGN_NOT as this is the default alignment
296   long expand=wxEXPAND;
297   if (this->IsLabel()) expand=0; //labels are not expanded
298   if (this->IsDraw()) expand=0; //draw are not expanded
299   if (myAlign == gdlwALIGN_NOT) return expand|wxALIGN_LEFT|wxALIGN_TOP;
300   //left is top by default and right is bottom. So define left as top and remove top if bottom, etc.
301   //ignore sets that do not concern the current layout (vetrtical or horizontal)
302   if (this->GetMyParentBaseWidget()->IsVertical()) { //col=1 left, center, right
303     if (myAlign & gdlwALIGN_CENTER) return wxALIGN_CENTER_HORIZONTAL;
304     if (myAlign & gdlwALIGN_LEFT) return wxALIGN_LEFT;
305     if (myAlign & gdlwALIGN_RIGHT) return wxALIGN_RIGHT;
306     if (myAlign & gdlwALIGN_TOP) return wxALIGN_LEFT;
307     if (myAlign & gdlwALIGN_BOTTOM) return wxALIGN_RIGHT;
308   } else if (this->GetMyParentBaseWidget()->IsHorizontal()) { //row=1
309     if (myAlign & gdlwALIGN_CENTER) return wxALIGN_CENTER_VERTICAL;
310     if (myAlign & gdlwALIGN_TOP) return wxALIGN_TOP;
311     if (myAlign & gdlwALIGN_BOTTOM) return wxALIGN_BOTTOM;
312     if (myAlign & gdlwALIGN_LEFT) return wxALIGN_TOP;
313     if (myAlign & gdlwALIGN_RIGHT) return wxALIGN_BOTTOM;
314   }
315   return 0;
316 }
317 
setFont()318  void GDLWidget::setFont() {
319    wxWindow* w = dynamic_cast<wxWindow*> (this->GetWxWidget());
320    if (w != NULL) w->SetFont(font); //may be menu: this is ok
321  }
setFont(wxObject * o)322  void GDLWidget::setFont(wxObject* o) {
323    wxWindow* w = dynamic_cast<wxWindow*> (o);
324    if (w != NULL) w->SetFont(font);
325 }
326 
AddABaseSizer(DLong col,DLong row,bool grid,long space)327 inline wxSizer* AddABaseSizer(DLong col, DLong row, bool grid, long space)
328 {
329   if (row <= 0 && col <= 0) return NULL;
330   //This to mimic the disposal of children in IDL's Bases, where the 'packing' is more clever
331   //than in wxWidgets, we will ALWAYS use a ROW gridding, where the number of rows is
332   //deduced from the number of cols and of children when this number is known...
333   //..which is not the case for us until the wigdet is realized, and ReorderWidgets() is called.
334   //So the col >1 case below is a bit irrelevant as it will be recomputed.
335   //In this case (col >1) we do not create a base Sizer, it will be created in ReorderWidgets().
336   //We also need to use a BoxSizer for col==1 or row==1 as only BoxSizer is able to strectch correctly.
337   if (row==1 && space < 1) {
338     wxBoxSizer* s=new wxBoxSizer(wxHORIZONTAL);
339     return s;
340 }
341   if (col==1 && space < 1) {
342     wxBoxSizer* s=new wxBoxSizer(wxVERTICAL);
343     return s;
344   }
345   // grid behaviour of Motif (IDL) is not as perfect as wxWidget's. We cannot use wxGridSizer here,
346   // the trick is to set only the non-flexible grow mode
347 
348   if (row>0) {
349     wxFlexGridSizer* s=new wxFlexGridSizer(row,0,space,space);
350     if (grid) {
351       s->SetFlexibleDirection(wxVERTICAL);
352       s->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL);
353     }
354     return s;
355   }
356 //  if (col>0) { //will be treated only at realize time, since default order is not good.
357 //    return NULL;
358 //  }
359    if (col>0) {
360     wxFlexGridSizer* s=new wxFlexGridSizer(0,col,space,space);
361     if (grid) {
362       s->SetFlexibleDirection(wxHORIZONTAL);
363       s->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL);
364     }
365     return s;
366   }
367   return NULL;
368 }
369 
370 //returns the current (widget or default) fontSize, taking care a typical width is returned instead of 0 as it is the case for variable pitch fonts, at least under windows
getFontSize()371 inline wxSize GDLWidget::getFontSize() {
372   wxSize fontSize = defaultFont.GetPixelSize();
373   if (!font.IsSameAs(wxNullFont)) fontSize = font.GetPixelSize();
374   // under Windows, as of today: problem getting sizes
375   if (fontSize.x < 1 || fontSize.y < 1 ) { //do it ourselves
376     wxScreenDC dc;
377     dc.SetFont(font);
378     fontSize=dc.GetTextExtent(wxString('M'));
379   }
380   return fontSize;
381 }
382 
383 // return the size of text (pixels) as it will take if displayed with current or given font
calculateTextScreenSize(std::string & s,wxFont testFont)384 wxSize GDLWidget::calculateTextScreenSize(std::string &s, wxFont testFont) {
385   wxFont f=font; //current font
386   if (testFont!=wxNullFont) f = testFont;
387   wxScreenDC dc;
388   dc.SetFont(f);
389   return dc.GetTextExtent(wxString(s.c_str( ), wxConvUTF8));
390 }
391 
computeWidgetSize()392 inline wxSize GDLWidgetText::computeWidgetSize()
393 {
394   wxWindow* me = dynamic_cast<wxWindow*> (this->GetWxWidget());
395   //widget text size is in LINES in Y and CHARACTERS in X. But overridden by scr_xsize et if present
396   wxRealPoint widgetSize = wxRealPoint(-1,-1);
397 //  wxSize fontSize = getFontSize();
398   static std::string testExtent("M");
399   wxSize fontSize=calculateTextScreenSize(testExtent); //use text extent of an EM for realistic fontSize.
400   int lineHeight=fontSize.y;
401   if (textSize.x > 0) {
402     widgetSize.x = (textSize.x) * fontSize.x;
403   } else {
404       widgetSize.x = maxlinelength*fontSize.x;//add 2 char wide for border.
405       textSize.x=maxlinelength;
406       if (textSize.x < 20) {
407         textSize.x=20;
408         widgetSize.x = (textSize.x) * fontSize.x;
409       }
410   }
411 
412   if (textSize.y > 1) {
413     widgetSize.y = textSize.y * lineHeight;
414   } else {
415     widgetSize.y = lineHeight;
416     textSize.y = 1;
417   }
418   if (textSize.y ==1) widgetSize.y+=2*gdlTEXT_SPACE; //for margin
419   if (scrolled && textSize.y >1) widgetSize.x+=gdlSCROLL_WIDTH_Y;
420 
421   //if multiline and no hscroll, a x-axis scrollbar will be adde by wxWidgets if longestLineSize cannot be shown, and we cannot do anything about it.
422   if (!scrolled) {if (textSize.y > 1 && (textSize.x < maxlinelength) )  widgetSize.y += gdlSCROLL_HEIGHT_X; }
423   else if (textSize.y > 1 && widgetSize.x < (maxlinelength*fontSize.x+gdlSCROLL_WIDTH_Y) ) {
424     widgetSize.y += gdlSCROLL_HEIGHT_X;
425   }
426   widgetSize.x+=2*gdlTEXT_SPACE; //for margin
427 
428   //but..
429   if (wScreenSize.x > 0) widgetSize.x = wScreenSize.x;
430   if (wScreenSize.y > 0) widgetSize.y = wScreenSize.y;
431 
432   int x = ceil(widgetSize.x);
433   int y = ceil(widgetSize.y);
434   //memorize the current textSize, in characters.
435   initialSize=textSize;
436   return wxSize(x, y);
437 }
438 
computeWidgetSize()439 inline wxSize GDLWidgetList::computeWidgetSize()
440 {
441   //default wxChoice sizing is 2 lines, lines are well-separated. default IDL is only 1 line. Thus we need to fix sizes
442 
443   //widget text size is in LINES in Y and CHARACTERS in X. But overridden by scr_xsize et if present
444   wxRealPoint widgetSize = wxRealPoint(-1,-1);
445   wxSize fontSize = getFontSize();
446   //based on experience, actual line height is 1.2 times font y size for fonts > 20 but 1.5 for smaller fonts
447   int lineHeight=(fontSize.y<20)?fontSize.y*1.5:fontSize.y*1.2;
448   if (wSize.x > 0) {
449     widgetSize.x = (wSize.x+1) * fontSize.x;
450   } else {
451     widgetSize.x = ( maxlinelength+1 ) * fontSize.x;
452   }
453 
454   if (wSize.y > 0) {
455     widgetSize.y = wSize.y * lineHeight;
456   } else {
457     widgetSize.y = lineHeight;
458   }
459 
460   if (wSize.x > 0 && maxlinelength > wSize.x) widgetSize.y += gdlSCROLL_HEIGHT_X;
461   if (nlines > wSize.y) widgetSize.x += gdlSCROLL_WIDTH_Y;
462   widgetSize.y += 10;
463   //but..
464   if (wScreenSize.x > 0 ) widgetSize.x = wScreenSize.x;  //we need an integer value
465   if (wScreenSize.y > 0) widgetSize.y = wScreenSize.y;
466 
467   int x=ceil(widgetSize.x); int y=ceil(widgetSize.y);
468   return wxSize(x,y);
469 }
470 
computeWidgetSize()471 inline wxSize GDLWidgetLabel::computeWidgetSize()
472 {
473   if (wSize.x > 0 || wSize.y > 0 || wScreenSize.x > 0 || wScreenSize.y > 0) dynamicResize=-1;
474   //widget label size is in pixels.
475   wxSize widgetSize = wSize; //start with wanted values.
476   wxSize fontSize = getFontSize();
477   //based on experience, actual line height is 1.2 times font y size for fonts > 20 but 1.5 for smaller fonts
478   int lineHeight = fontSize.y+2*gdlLABEL_SPACE ; //(fontSize.y < 20) ? fontSize.y * 1.2 : fontSize.y * 1.2;
479 
480   if (wSize.x < 0) widgetSize.x =  calculateTextScreenSize(value).x+2*fontSize.x;//add 2 char wide for border. //fontSize.x*(value.size());
481   if (wSize.y < 0) widgetSize.y = lineHeight;
482 
483   if (wScreenSize.x > 0) widgetSize.x = wScreenSize.x;
484   if (wScreenSize.y > 0) widgetSize.y = wScreenSize.y;
485 
486   if (sunken) {widgetSize.y+=1; widgetSize.x+=1;}
487 
488   return widgetSize;
489 }
490 
computeWidgetSize()491 inline wxSize GDLWidgetMenuBarButton::computeWidgetSize()
492 {
493   if (wSize.x > 0 || wSize.y > 0 || wScreenSize.x > 0 || wScreenSize.y > 0) dynamicResize=-1;
494   //widget label size is in pixels.
495   wxSize widgetSize = wSize; //start with wanted values.
496   wxSize fontSize = getFontSize();
497   //based on experience, actual line height is 1.2 times font y size for fonts > 20 but 1.5 for smaller fonts
498   int lineHeight = 2*fontSize.y;
499   std::string s=valueWxString.ToStdString();
500   if (wSize.x < 0) widgetSize.x =  calculateTextScreenSize(s).x+2*fontSize.x;//add 2 char wide for border. //fontSize.x*(value.size());
501   if (wSize.y < 0) widgetSize.y = lineHeight;
502 
503   if (wScreenSize.x > 0) widgetSize.x = wScreenSize.x;
504   if (wScreenSize.y > 0) widgetSize.y = wScreenSize.y;
505 
506   return widgetSize;
507 }
computeWidgetSize()508 inline wxSize GDLWidget::computeWidgetSize()
509 {
510 //here is a good place to make dynamic widgets static, since dynamic_resize is permitted only if size is not given.
511   if (wSize.x > 0 || wSize.y > 0 || wScreenSize.x > 0 || wScreenSize.y > 0) dynamicResize=-1;
512   wxSize widgetSize;
513   if ( wSize.x > 0 ) widgetSize.x = wSize.x*unitConversionFactor.x;
514   else widgetSize.x = wxDefaultSize.x;
515 //but..
516   if (wScreenSize.x > 0) widgetSize.x=wScreenSize.x;
517 
518   if ( wSize.y > 0 )  widgetSize.y = wSize.y * unitConversionFactor.y;
519   else widgetSize.y = wxDefaultSize.y;
520 //but..
521    if (wScreenSize.y > 0) widgetSize.y=wScreenSize.y;
522 
523   return widgetSize;
524 }
525 
UpdateGui()526 void GDLWidget::UpdateGui()
527 {
528   //needed to recompute sizes in case of a change of realized widgets or any size change.
529   START_CHANGESIZE_NOEVENT
530 
531   WidgetIDT actID = parentID;
532   while ( actID != GDLWidget::NullID ) {
533     GDLWidget *widget = GetWidget( actID );
534       wxPanel* p=widget->GetPanel();
535     if (p) {
536       wxSizer* s = p->GetSizer();
537       if (s) s->Fit(p);
538       else { //force widget having the panel to adopt correct sizes
539         p->Fit();
540         GDLWidgetContainer* myParentContainer = static_cast<GDLWidgetContainer*> (widget->GetMyParentBaseWidget());
541         if (myParentContainer != NULL) {
542           wxWindow* w = static_cast<wxWindow*> (widget->GetParentPanel());
543           assert(w != NULL);
544           wxSize wSize = w->GetSize();
545           wxSize mySize = p->GetSize();
546           // if w.x or w.y was SET BY USER it is a requested size, that we should not change
547           wxSize desiredSize;
548           if (myParentContainer->xFree()) desiredSize.x = max(mySize.x, wSize.x);
549           else {
550             desiredSize.x = wSize.x;
551           }
552           if (myParentContainer->yFree()) desiredSize.y = max(mySize.y, wSize.y);
553           else {
554             desiredSize.y = wSize.y;
555           }
556           w->SetSize(desiredSize);
557           w->SetMinSize(desiredSize);
558         }
559       }
560     }
561     actID = widget->parentID;
562   }
563   this->GetMyTopLevelFrame()->Fit();
564   END_CHANGESIZE_NOEVENT
565 #ifdef __WXMAC__
566   wxTheApp->Yield();
567 #else
568   wxGetApp().MainLoop(); //central loop for wxEvents!
569 #endif
570 }
571 
572 //Alternate version if there were sizing problems with the one above.
573 //void GDLWidget::UpdateGui()
574 //{
575 //  START_CHANGESIZE_NOEVENT
576 //
577 //  // go back to top parent widget while resizing each BASE containers since there must be some update needed.
578 //  WidgetIDT actID = widgetID;
579 //  while ( actID != GDLWidget::NullID ) {
580 //    GDLWidget *widget = GetWidget( actID ); //Not Necessarily a Base
581 //    if (widget->IsBase()) {
582 //      wxPanel* p=widget->GetPanel();
583 //      wxWindow* thisBaseOuterPanel=dynamic_cast<wxWindow*>(widget->GetWxContainer());
584 //      wxWindow* thisBaseInnerPanel=dynamic_cast<wxWindow*>(widget->GetWxWidget());
585 //      assert((p==thisBaseOuterPanel)||(p==thisBaseInnerPanel));
586 //      GDLWidgetBase* b=static_cast<GDLWidgetBase*>(widget);
587 //      if (b->IsScrolled()) thisBaseInnerPanel->FitInside(); else thisBaseInnerPanel->Fit();
588 //      while (thisBaseOuterPanel!=thisBaseInnerPanel) {
589 //        wxSizer* s=thisBaseInnerPanel->GetContainingSizer();
590 //        assert (s); //must exist as there are always sizers between theWxContainer ans theWxWidget
591 //        s->FitInside(thisBaseInnerPanel);
592 //        thisBaseInnerPanel=thisBaseInnerPanel->GetParent();
593 //      }
594 //    }
595 //    actID = widget->parentID;
596 //  }
597 //  this->GetMyTopLevelFrame()->Fit();
598 //  END_CHANGESIZE_NOEVENT
599 //}
600 
601 // widget from ID
GetWidget(WidgetIDT widID)602 GDLWidget* GDLWidget::GetWidget( WidgetIDT widID)
603 {
604   if ( widID == GDLWidget::NullID ) return NULL;
605   WidgetListT::iterator it = widgetList.find( widID );
606   if ( it == widgetList.end( ) ) return NULL;
607   return it->second;
608 }
609 
610 // widget parent from ID
GetParent(WidgetIDT widID)611 GDLWidget* GDLWidget::GetParent( WidgetIDT widID)
612 {
613   GDLWidget *widget = GetWidget( widID );
614   if ( widget == NULL )
615     return NULL;
616   WidgetIDT parentID = widget->parentID;
617   GDLWidget *parent = GetWidget( parentID );
618   return parent;
619 }
620 // widget parent
GetMyParent()621 GDLWidget* GDLWidget::GetMyParent( ){return GetWidget( parentID ); }
622 
EnableWidgetUpdate(bool update)623 void  GDLWidget::EnableWidgetUpdate(bool update){
624    wxWindow * me = dynamic_cast<wxWindow*>(theWxWidget);
625    if (me) {if (update) {if ( me->IsFrozen()) me->Thaw(); else me->Refresh(); } else me->Freeze();} else cerr<<"freezing unknown widget\n";
626 }
627 
GetMyBaseWidget()628 GDLWidgetBase* GDLWidget::GetMyBaseWidget()
629 {
630   WidgetIDT actID = widgetID;
631   while ( 1 ) {
632     GDLWidget* widget = GetWidget( actID );
633     if ( widget == NULL )
634       return NULL;
635     if ( widget->IsBase( ) )
636       return static_cast<GDLWidgetBase*> (widget);
637     assert( widget->parentID != GDLWidget::NullID );
638     actID = widget->parentID;
639   }
640 }
641 
642 // this widget's first parent base widget
GetMyParentBaseWidget()643 GDLWidgetBase* GDLWidget::GetMyParentBaseWidget( )
644 {
645   WidgetIDT actID =  parentID;
646   while ( 1 ) {
647     GDLWidget* widget = GetWidget( actID );
648     if ( widget == NULL )
649       return NULL;
650     if ( widget->IsBase( ) )
651       return static_cast<GDLWidgetBase*> (widget);
652     assert( widget->parentID != GDLWidget::NullID );
653     actID = widget->parentID;
654   }
655 }
656 
GetBaseId(WidgetIDT widID)657 WidgetIDT GDLWidget::GetBaseId( WidgetIDT widID)
658 {
659   GDLWidget *widget;
660   WidgetIDT actID = widID;
661   while ( 1 ) {
662     GDLWidget* widget = GetWidget( actID );
663     if ( widget == NULL )
664       return GDLWidget::NullID;
665     if ( widget->IsBase( ) )
666       return actID;
667     assert( widget->parentID != GDLWidget::NullID );
668     actID = widget->parentID;
669   }
670 }
671 
GetTopLevelBaseWidget(WidgetIDT widID)672 GDLWidgetTopBase* GDLWidget::GetTopLevelBaseWidget( WidgetIDT widID)
673 {
674   WidgetIDT actID = widID;
675   while ( 1 ) {
676     GDLWidget *widget = GetWidget( actID );
677     if ( widget == NULL )
678       return (GDLWidgetTopBase*)GDLWidget::NullID;
679     if ( widget->parentID == GDLWidget::NullID )
680       return static_cast<GDLWidgetTopBase*> (widget);
681     else
682       actID = widget->parentID;
683   }
684 }
685 
GetMyTopLevelBaseWidget()686 GDLWidgetTopBase* GDLWidget::GetMyTopLevelBaseWidget()
687 {
688   WidgetIDT actID = this->GetWidgetID();
689   while ( 1 ) {
690     GDLWidget *widget = GetWidget( actID );
691     if ( widget == NULL )
692       return (GDLWidgetTopBase*)GDLWidget::NullID;
693     if ( widget->parentID == GDLWidget::NullID )
694       return static_cast<GDLWidgetTopBase*> (widget);
695     else
696       actID = widget->parentID;
697   }
698 }
699 
GetMyTopLevelFrame()700 gdlwxFrame* GDLWidget::GetMyTopLevelFrame()
701 {
702   WidgetIDT actID = this->GetWidgetID();
703   while ( 1 ) {
704     GDLWidget *widget = GetWidget( actID );
705     if ( widget == NULL )
706       return (gdlwxFrame*) NULL;
707     if ( widget->parentID == GDLWidget::NullID )
708       return static_cast<GDLWidgetTopBase*>(widget)->GetTopFrame();
709     else
710       actID = widget->parentID;
711   }
712 }
GetIdOfTopLevelBase(WidgetIDT widID)713 WidgetIDT GDLWidget::GetIdOfTopLevelBase( WidgetIDT widID)
714 {
715   WidgetIDT actID = widID;
716   while ( 1 ) {
717     GDLWidget *widget = GetWidget( actID );
718     if ( widget == NULL )
719       return GDLWidget::NullID;
720     if ( widget->parentID == GDLWidget::NullID )
721       return actID;
722     else
723       actID = widget->parentID;
724   }
725 }
726 
727 /**
728   @brief        content of theWxWidget has changed, make size changes appear if Dynamic property Set
729  */
RefreshDynamicWidget()730 void GDLWidget::RefreshDynamicWidget() {
731     if (this->IsDynamicResize()) {
732       if (theWxContainer && theWxContainer!=theWxWidget) {
733         wxPanel* p=static_cast<wxPanel*>(theWxContainer);
734         wxWindow* w=static_cast<wxWindow*>(theWxWidget);
735         if (p) {
736           wxSizer* s=p->GetSizer();
737           if (s) s->Fit(w);  else p->Fit();
738         }
739       }
740       UpdateGui();
741     }
742 }
743 
SendWidgetTimerEvent(DDouble secs)744 void GDLWidget::SendWidgetTimerEvent(DDouble secs) {
745   WidgetIDT* id = new WidgetIDT(widgetID);
746   int millisecs = floor(secs * 1000.0);
747   if (theWxWidget) { //we nee a handle on a wxWindow object...
748     wxWindow* w = dynamic_cast<wxWindow*> (theWxWidget);
749     assert(w != NULL);
750     w->GetEventHandler()->SetClientData(id);
751     if (m_windowTimer == NULL) {
752       m_windowTimer = new wxTimer(w->GetEventHandler(), widgetID);
753     }
754 #ifdef GDL_DEBUG_WIDGETS
755     std::cerr << "sending event," << widgetID << "," << m_windowTimer << std::endl;
756 #endif
757     m_windowTimer->StartOnce(millisecs);
758   }
759 }
760 
ClearEvents()761 void GDLWidget::ClearEvents() {
762   if (!this->GetXmanagerActiveCommand()) eventQueue.Purge(this->GetWidgetID());
763   else readlineEventQueue.Purge(this->GetWidgetID());
764 }
765 
HandleWidgetEvents()766 void GDLWidget::HandleWidgetEvents()
767 {
768   //make one loop for wxWidgets Events. Forcibly, as HandleWidgetEvents() is called by the readline eventLoop, we are in a non-blocked case.
769 #ifdef __WXMAC__
770   wxTheApp->Yield();
771 #else
772   wxGetApp().MainLoop(); //central loop for wxEvents!
773 #endif
774   //treat our GDL events...
775     DStructGDL* ev = NULL;
776     while( (ev = GDLWidget::readlineEventQueue.Pop()) != NULL)
777     {
778 //        static int idIx = ev->Desc( )->TagIndex( "ID" ); // 0
779 //        static int topIx = ev->Desc( )->TagIndex( "TOP" ); // 1
780 //        static int handlerIx = ev->Desc( )->TagIndex( "HANDLER" ); // 2
781 //        assert( idIx == 0 );
782 //        assert( topIx == 1 );
783 //        assert( handlerIx == 2 );
784 
785       ev = CallEventHandler( ev );
786 
787       if( ev != NULL)
788       {
789         int idIx = ev->Desc( )->TagIndex( "ID" );
790         assert( idIx == 0 );
791         WidgetIDT id = (*static_cast<DLongGDL*> (ev->GetTag( idIx, 0 )))[0];
792         Warning( "Unhandled event. ID: " + i2s( id ) );
793         GDLDelete( ev );
794         ev = NULL;
795       }
796     }
797     if (wxIsBusy()) wxEndBusyCursor( );
798 }
799 
PushEvent(WidgetIDT baseWidgetID,DStructGDL * ev)800 void GDLWidget::PushEvent( WidgetIDT baseWidgetID, DStructGDL* ev) {
801   // Get XmanagerActiveCommand status
802   GDLWidget *baseWidget = GDLWidget::GetWidget( baseWidgetID );
803   if ( baseWidget != NULL ) {
804     bool xmanActCom = baseWidget->GetXmanagerActiveCommand( );
805     if ( !xmanActCom ) { //blocking: events in eventQueue.
806       //     wxMessageOutputStderr().Printf(_T("eventQueue.Push: %d\n"),baseWidgetID);
807       eventQueue.PushBack( ev );
808     } else { //non-Blocking: events in readlineeventQueue.
809       //     wxMessageOutputStderr().Printf(_T("readLineEventQueue.Push: %d\n"),baseWidgetID);
810       readlineEventQueue.PushBack( ev );
811     }
812   } else cerr << "NULL baseWidget (possibly Destroyed?) found in GDLWidget::PushEvent( WidgetIDT baseWidgetID=" << baseWidgetID << ", DStructGDL* ev=" << ev << "), please report!\n";
813 }
814 
InformAuthorities(const std::string & message)815 void GDLWidget::InformAuthorities(const std::string& message){
816         // create GDL event struct
817         DStructGDL* ev = new DStructGDL( "*WIDGET_RUNTIME_ERROR*" );
818         ev->InitTag( "ID", DLongGDL( 0) );
819         ev->InitTag( "TOP", DLongGDL( 0 ) );
820         ev->InitTag( "HANDLER", DLongGDL( 0 ) );
821         ev->InitTag( "MESSAGE", DStringGDL(message) );
822           readlineEventQueue.PushFront( ev ); // push front (will be handled next)
823     }
824 
GetXmanagerBlock()825 bool GDLWidget::GetXmanagerBlock()
826 {
827   bool xmanBlock = false;
828   WidgetListT::iterator it;
829   // (*it).first is widgetID
830   // (*it).second is pointer to widget
831 
832   bool managed;
833   bool xmanActCom;
834 
835 #ifdef GDL_DEBUG_WIDGETS
836   std::cout << "+ GetXmanagerBlock: widgetList:" << std::endl;
837   for ( it = widgetList.begin( ); it != widgetList.end( ); ++it ) {
838     std::cout << (*it).first << ": " << (*it).second->widgetID << "  parentID: " <<
839     (*it).second->parentID << "  uname: " << (*it).second->uName << std::endl;
840   }
841   std::cout << "- GetXmanagerBlock: widgetList end" << std::endl;
842 #endif
843   for ( it = widgetList.begin( ); it != widgetList.end( ); ++it ) {
844     // Only consider base widgets
845     if ( (*it).second->parentID == GDLWidget::NullID ) {
846       managed = (*it).second->GetManaged( );
847       xmanActCom = (*it).second->GetXmanagerActiveCommand( );
848     }
849     if ( managed && !xmanActCom ) {
850       xmanBlock = true;
851       break;
852     }
853   }
854   return xmanBlock;
855 }
GetNumberOfWidgets()856 DLong GDLWidget::GetNumberOfWidgets() {
857   WidgetListT::iterator it;
858   DLong result=0;
859   for ( it = widgetList.begin( ); it != widgetList.end( ); ++it ) result++;
860   return result;
861 }
GetWidgetsList()862 BaseGDL* GDLWidget::GetWidgetsList() {
863   DLong nw=GetNumberOfWidgets();
864   if (nw<=0) return new DLongGDL(0);
865   WidgetListT::iterator it;
866   SizeT index=0;
867   DLongGDL* result=new DLongGDL(nw,BaseGDL::NOZERO);
868   for ( it = widgetList.begin( ); it != widgetList.end( ); ++it ) {
869     (*result)[index]=(*it).second->widgetID; index++;
870   }
871   return result;
872 }
GetManagedWidgetsList()873 BaseGDL* GDLWidget::GetManagedWidgetsList() {
874   DLong nw=GetNumberOfWidgets();
875   if (nw<=0) return new DLongGDL(0);
876   WidgetListT::iterator it;
877   SizeT index;
878   for (index=0, it = widgetList.begin( ); it != widgetList.end( ); ++it ) {
879     if ((*it).second->GetManaged() == true) index++;
880   }
881   if (index<=0) return new DLongGDL(0);
882   DLongGDL* result=new DLongGDL(index,BaseGDL::NOZERO);
883   for (index=0, it = widgetList.begin( ); it != widgetList.end( ); ++it ) {
884     if ((*it).second->GetManaged() == true) (*result)[index++]=(*it).second->widgetID;
885   }
886   return result;
887 }
888 
GetAllHeirs()889 DLongGDL* GDLWidget::GetAllHeirs(){
890   std::vector<WidgetIDT> widgetIDList;
891   std::vector<bool> has_children;
892   widgetIDList.push_back(this->widgetID);
893   if (this->NChildren() > 0) has_children.push_back(true);
894   else has_children.push_back(false);
895   //loop on this list, and add recursively all children when widget is a container.
896   SizeT currentVectorSize = widgetIDList.size();
897   while (1) {
898     for (SizeT i = 0; i < currentVectorSize; i++) {
899       if (has_children.at(i)) {
900         has_children.at(i) = false;
901         GDLWidget *widget = GDLWidget::GetWidget(widgetIDList.at(i));
902         DLongGDL* list = static_cast<GDLWidgetContainer*> (widget)->GetChildrenList();
903         for (SizeT j = 0; j < list->N_Elements(); j++) {
904           widgetIDList.push_back((*list)[j]);
905           if (GDLWidget::GetWidget((*list)[j])->NChildren() > 0) has_children.push_back(true);
906           else has_children.push_back(false);
907         }
908       }
909     }
910     if (widgetIDList.size() == currentVectorSize) break; //no changes
911     currentVectorSize = widgetIDList.size();
912   }
913   DLongGDL* result = new DLongGDL(currentVectorSize, BaseGDL::NOZERO);
914   for (SizeT i = 0; i < currentVectorSize ; ++i) (*result)[i] = widgetIDList[i];
915   return result;
916 }
917 
918 //
InitWx()919 bool GDLWidget::InitWx()
920 { if (wxTheApp == NULL) { //not already initialized
921 if (!wxInitialize()) {
922     std::cerr << "WARNING: wxWidgets not initializing, widget-related commands will not be available." << std::endl;
923     return false;
924   }
925 } else {std::cerr << "INFO: wxWidgets already initialized (in 3rd party library?), pursue with fingers crossed" << std::endl; }
926   wxInitAllImageHandlers(); //do it here once for all
927   return true;
928 }
929 // Init
Init()930 void GDLWidget::Init()
931 {
932  //set system font to something sensible now that wx is ON:
933   if (forceWxWidgetsUglyFonts)
934     systemFont = wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL) ;//  identical for me to GDLWidget::setDefaultFont(wxFont("Monospace 8"));
935 #if __WXMSW__ //update for windows:
936     bool ok=systemFont.SetNativeFontInfoUserDesc(wxString("consolas 8"));  //consolas 8 is apparently the one most identical to linux courier 8 and IDL X11 default font.
937     if (!ok) systemFont = wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL) ;
938 #endif
939     else systemFont = *wxSMALL_FONT; // close to IDL in size, but nicer (not fixed).
940 
941   //initially defaultFont and systemFont are THE SAME.
942   defaultFont=systemFont;
943   SetWxStarted();
944   //use a phantom window to retrieve th exact size of scrollBars wxWidget give wrong values.
945    gdlwxPhantomFrame* test = new gdlwxPhantomFrame();
946    test->Hide();
947    test->Realize();
948    test->Destroy();
949   //initialize default image lists for trees:
950   // Make an image list containing small icons
951   wxSize ImagesSize(DEFAULT_TREE_IMAGE_SIZE,DEFAULT_TREE_IMAGE_SIZE);
952   gdlDefaultTreeImages = new wxImageList(ImagesSize.x, ImagesSize.y, true);
953   //order must be same as enum definition!
954   gdlDefaultTreeImages->Add(wxArtProvider::GetBitmap(wxART_NORMAL_FILE, wxART_OTHER, ImagesSize)); //gdlWxTree_ITEM,/gdlWxTree_ITEM_SELECTED (IDL give the same image)
955   gdlDefaultTreeImages->Add(wxArtProvider::GetBitmap(wxART_FOLDER, wxART_OTHER, ImagesSize)); //gdlWxTree_FOLDER
956   gdlDefaultTreeImages->Add(wxArtProvider::GetBitmap(wxART_FOLDER_OPEN, wxART_OTHER, ImagesSize)); //gdlWxTree_FOLDER_OPEN
957 
958   wxSize StateImageSize=wxIcon(pixmap_unchecked).GetSize(); //
959   gdlDefaultTreeStateImages = new wxImageList(StateImageSize.x, StateImageSize.y, true);
960   gdlDefaultTreeStateImages->Add(wxIcon(pixmap_unchecked)); //gdlWxTree_UNCHECKED
961   gdlDefaultTreeStateImages->Add(wxIcon(pixmap_checked)); //gdlWxTree_UNCHECKED
962 }
963 // UnInit
UnInit()964 void GDLWidget::UnInit() {
965   if (wxIsStarted()) {
966     WidgetListT::iterator it;
967     for (it = widgetList.begin(); it != widgetList.end(); ++it) {
968       GDLWidget* w = (*it).second;
969       if (w != NULL) delete w;
970     }
971     GDLWidget::HandleWidgetEvents();
972     // the following cannot be done: once unitialized, the wxWidgets library cannot be safely initilized again.
973     //    wxUninitialize( );
974     delete gdlDefaultTreeImages;
975     delete gdlDefaultTreeStateImages;
976     UnsetWxStarted(); //reset handlersOk too.
977   }
978 }
979 
ConnectToDesiredEvents()980 void GDLWidget::ConnectToDesiredEvents(){
981   wxWindow* w=dynamic_cast<wxWindow*>(theWxWidget);
982   assert (w!=NULL);
983   //connect to general events
984   w->Connect(widgetID, wxEVT_TIMER, wxTimerEventHandler(gdlwxFrame::OnWidgetTimer)); //always.
985   if ( eventFlags & GDLWidget::EV_TRACKING ) {
986     w->Connect(widgetID,wxEVT_ENTER_WINDOW, wxMouseEventHandler(gdlwxFrame::OnEnterWindow));
987     w->Connect(widgetID,wxEVT_LEAVE_WINDOW, wxMouseEventHandler(gdlwxFrame::OnLeaveWindow));
988   }
989   if ( eventFlags & GDLWidget::EV_CONTEXT ) w->Connect(widgetID,wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(gdlwxFrame::OnContextEvent));
990   if ( eventFlags & GDLWidget::EV_KBRD_FOCUS ) {
991       w->Connect(widgetID,wxEVT_SET_FOCUS, wxFocusEventHandler(gdlwxFrame::OnKBRDFocusChange));
992       w->Connect(widgetID,wxEVT_KILL_FOCUS, wxFocusEventHandler(gdlwxFrame::OnKBRDFocusChange));
993   }
994   for (int i = 0; i < desiredEventsList.size(); ++i) {
995       desiredEventsList[i]->w->Connect(widgetID, desiredEventsList[i]->t, desiredEventsList[i]->f);
996   }
997 // useful to have no event yet produced at this stage?
998 //  w->DeletePendingEvents();
999 }
1000 
DisableSizeEvents(gdlwxFrame * & tlbFrame,WidgetIDT & id)1001  bool GDLWidget::DisableSizeEvents(gdlwxFrame* &tlbFrame,WidgetIDT &id) {
1002   GDLWidgetBase *tlb = this->GetMyTopLevelBaseWidget();
1003   tlbFrame = tlb->GetMyTopLevelFrame();
1004   id = tlb->GetWidgetID();
1005   bool disconnect = ((tlb->GetEventFlags() & GDLWidget::EV_SIZE) == GDLWidget::EV_SIZE);
1006   if (disconnect) tlbFrame->Disconnect(id, wxEVT_SIZE, gdlSIZE_EVENT_HANDLER);
1007   return disconnect;
1008 }
1009 
EnableSizeEvents(gdlwxFrame * & tlbFrame,WidgetIDT & id)1010  void GDLWidget::EnableSizeEvents(gdlwxFrame* &tlbFrame,WidgetIDT &id) {
1011   if (tlbFrame) tlbFrame->Connect(id, wxEVT_SIZE, gdlSIZE_EVENT_HANDLER);
1012 }
1013 //initialize static member
1014 int GDLWidget::gdl_lastControlId=0;
1015 
GDLWidget(WidgetIDT p,EnvT * e,BaseGDL * vV,DULong eventFlags_)1016 GDLWidget::GDLWidget( WidgetIDT p, EnvT* e, BaseGDL* vV, DULong eventFlags_)
1017 : theWxWidget( NULL )
1018 , theWxContainer(NULL)
1019 , widgetID (0)
1020 , parentID( p )
1021 , uValue( NULL )
1022 , vValue( vV )
1023 , scrolled(false)
1024 , sensitive(true)
1025 , managed( false )
1026 , eventFlags( eventFlags_ )
1027 , exclusiveMode( 0 )
1028 , wOffset(wxDefaultPosition)
1029 , wSize(wxDefaultSize)
1030 , wScreenSize(wxDefaultSize)
1031 , widgetSizer( NULL )
1032 , widgetPanel( NULL )
1033 , framePanel( NULL )
1034 , widgetType(GDLWidget::WIDGET_UNKNOWN)
1035 , widgetName("")
1036 , groupLeader(GDLWidget::NullID)
1037 , unitConversionFactor(wxRealPoint(1.0,1.0)) //no conversion at start.
1038 , frameWidth(0)
1039 , font(defaultFont)
1040 , valid(true)
1041 , alignment(gdlwALIGN_NOT)
1042 , widgetStyle(wxSTRETCH_NOT)
1043 , dynamicResize(0) //unset
1044 , eventFun("")
1045 , eventPro("")
1046 , killNotify("")
1047 , notifyRealize("")
1048 , proValue("")
1049 , funcValue("")
1050 , uName("")
1051 {
1052   m_windowTimer = NULL;
1053 
1054   if ( e != NULL ) GetCommonKeywords( e ); else DefaultValuesInAbsenceofEnv();
1055 
1056 // was   widgetID =  wxWindow::NewControlId( ); // but some scripts use the fact that widget ids are positive (graffer.pro)
1057   widgetID = GDLNewControlId( );
1058 
1059   if ( parentID != GDLWidget::NullID ) {
1060 
1061     GDLWidget* gdlParent = GetWidget( parentID );
1062     assert( gdlParent != NULL);
1063 
1064     // a col or row sizer means no offset
1065     if (GetParentSizer()) wOffset=wxDefaultPosition;
1066     //there is a ParentID, so widgetPanel:
1067     widgetPanel=GetParentPanel();
1068 
1069     if ( gdlParent->IsContainer( ) ) { //only case, include some buttons
1070       GDLWidgetContainer* base = dynamic_cast<GDLWidgetContainer*> (gdlParent);
1071       base->AddChildID( widgetID );
1072     }
1073     else if ( gdlParent->IsMenu( ) )
1074     {
1075       GDLWidgetMenu* menu = dynamic_cast<GDLWidgetMenu*> (gdlParent);
1076       if (menu) menu->AddChildID( widgetID );
1077     }
1078     else if ( gdlParent->IsMenuBar( ) )
1079     {
1080        GDLWidgetMenuBar* mb = dynamic_cast<GDLWidgetMenuBar*> (gdlParent);
1081        mb->AddChildID( widgetID );
1082     }
1083 //    else if ( gdlParent->IsTree( ) )
1084 //    {
1085 //      // do nothing
1086 //    }//    else {    assert(false);} //other widgets are parent of popups, assert should be removed.
1087   }
1088 
1089   widgetList.insert( widgetList.end( ), std::pair<WidgetIDT, GDLWidget*>(widgetID, this) );
1090 #ifdef GDL_DEBUG_WIDGETS
1091   wxMessageOutputStderr( ).Printf( _T( "inserted: ID: %d  parentID: %d\n" ), widgetID, parentID );
1092 #endif
1093   if (groupLeader != GDLWidget::NullID) {
1094     GDLWidget* leader=this->GetWidget(groupLeader);
1095     if (leader) leader->AddToFollowers(widgetID);
1096   }
1097 }
1098 
SetSensitive(bool value)1099 void GDLWidget::SetSensitive(bool value)
1100 {
1101     sensitive = value;
1102     wxWindow *me=dynamic_cast<wxWindow*>(theWxWidget);
1103     if (me) {if (value) me->Enable(); else me->Disable();}
1104 }
1105 
GetSensitive()1106 bool GDLWidget::GetSensitive()
1107 {
1108   return sensitive;
1109 }
1110 
GetXmanagerActiveCommand()1111 bool GDLWidget::GetXmanagerActiveCommand() {
1112   GDLWidgetTopBase* w = GetMyTopLevelBaseWidget();
1113   return w->GetXmanagerActiveCommand();
1114 }
1115 
GetSibling()1116 DLong GDLWidget::GetSibling()
1117 {
1118   if ( parentID == GDLWidget::NullID ) {return 0;}
1119   GDLWidget * parent=GetWidget(parentID);
1120   if (parent->IsContainer() || parent->IsMenuBar() || parent->IsMenu() || parent->IsTree()) {
1121     return parent->GetTheSiblingOf(widgetID);
1122   }
1123   return 0;
1124 }
SetFocus()1125 void GDLWidget::SetFocus() //gives focus to the CHILD of the panel.
1126 {
1127   wxWindow *me=dynamic_cast<wxWindow*>(this->GetWxWidget()); if (me!=NULL) me->SetFocus(); else cerr<<"Setting Focus for unknown widget!\n";
1128 }
SetWidgetPosition(DLong posx,DLong posy)1129   void GDLWidget::SetWidgetPosition(DLong posx, DLong posy){
1130   // -1: not set ---> keep the same
1131     wxWindow* me=static_cast<wxWindow*>(theWxContainer);
1132     if (me) {
1133       wxPoint where=me->GetPosition();
1134       if (posx >= 0) where.x=posx;
1135       if (posy >= 0) where.y=posy;
1136       me->Move(where);
1137     } else cerr<<"set offset on non-existent widget!"<<endl;
1138 
1139     UPDATE_WINDOW;
1140 
1141   }
1142 
SetWidgetSize(DLong sizex,DLong sizey)1143 void GDLWidget::SetWidgetSize(DLong sizex, DLong sizey) //in pixels. Always.
1144 {
1145   START_CHANGESIZE_NOEVENT
1146 
1147   //although 2 values are passed, one only may be set by the user.
1148   //the code is:
1149   // -1: not set --> keep the same
1150   // 0 : set, and means: do your best.
1151   // > 0 : imposed size.
1152 
1153   //Sizes are in pixels. Units must be converted before calling this function.
1154   wxWindow* me=dynamic_cast<wxWindow*>(theWxWidget);
1155   if (me==NULL) {
1156 #ifdef GDL_DEBUG_WIDGETS
1157   wxMessageOutputStderr( ).Printf( _T( "GDLWidget::SetSize of non wxWindow %s\n"),this->GetWidgetName().c_str());
1158 #endif
1159   return;
1160   }
1161   //a graphic window cannot be larger than the base widget it is in, if the base widget size has been fixed
1162   wxSize currentSize=me->GetSize();
1163   wxSize currentBestSize=me->GetBestSize();
1164 #ifdef GDL_DEBUG_WIDGETS
1165   wxMessageOutputStderr( ).Printf( _T( "GDLWidget::SetSize currentSize=%d,%d (%s)\n"),currentSize.x,currentSize.y,this->GetWidgetName().c_str());
1166 #endif
1167   //unprecised sizes do not change
1168   if (sizex == -1) sizex = currentSize.x;
1169   if (sizey == -1) sizey = currentSize.y;
1170 
1171   if (widgetSizer) {
1172     //passed zeroes = mr sizer, do your best..
1173     if (sizex == 0) sizex = -1;
1174     if (sizey == 0) sizey = -1;
1175   } else {
1176     //passed zeroes = your best is to keep best size (in cache, value defined at creation)
1177     if (sizex == 0) sizex = currentBestSize.x;
1178     if (sizey == 0) sizey = currentBestSize.y;
1179   }
1180   wSize.x = sizex;
1181   wSize.y = sizey;
1182   me->SetSize(wSize);
1183   //the sizer takes care of the eventual frame
1184   me->SetMinSize(wSize);
1185   //framed bases may have a complicated frame around, to be resized:
1186   if (theWxContainer != theWxWidget) {
1187     wxWindow* container = dynamic_cast<wxWindow*> (theWxContainer);
1188     wxSizer* s=me->GetSizer();
1189     if (s) s->Fit(me); else container->Fit();
1190   }
1191   UpdateGui();
1192 
1193   END_CHANGESIZE_NOEVENT
1194 
1195 
1196 #ifdef GDL_DEBUG_WIDGETS
1197   wxMessageOutputStderr( ).Printf( _T( "GDLWidget::SetSize %d,%d (%s)\n"),sizex,sizey,this->GetWidgetName().c_str());
1198 #endif
1199 }
1200 
SetWidgetScreenSize(DLong sizex,DLong sizey)1201 void GDLWidget::SetWidgetScreenSize(DLong sizex, DLong sizey) //in pixels. Always.
1202 {
1203   START_CHANGESIZE_NOEVENT
1204 
1205   //although 2 values are passed, one only may be set by the user.
1206   //the code is:
1207   // -1: not set --> keep the same
1208   // 0 : set, and means: do your best.
1209   // > 0 : imposed size.
1210 
1211   //Sizes are in pixels. Units must be converted before calling this function.
1212   wxWindow* me = dynamic_cast<wxWindow*> (theWxWidget);
1213   if (me == NULL) {
1214 #ifdef GDL_DEBUG_WIDGETS
1215     wxMessageOutputStderr().Printf(_T("GDLWidget::SetSize of non wxWindow %s\n"), this->GetWidgetName().c_str());
1216 #endif
1217     return;
1218   }
1219   //a graphic window cannot be larger than the base widget it is in, if the base widget size has been fixed
1220   wxSize currentSize = me->GetSize();
1221   wxSize currentBestSize = me->GetBestSize();
1222 #ifdef GDL_DEBUG_WIDGETS
1223   wxMessageOutputStderr().Printf(_T("GDLWidget::SetSize currentSize=%d,%d (%s)\n"), currentSize.x, currentSize.y, this->GetWidgetName().c_str());
1224 #endif
1225   //unprecised sizes do not change
1226   if (sizex == -1) sizex = currentSize.x;
1227   if (sizey == -1) sizey = currentSize.y;
1228 
1229   if (widgetSizer) {
1230     //passed zeroes = mr sizer, do your best..
1231     if (sizex == 0) sizex = -1;
1232     if (sizey == 0) sizey = -1;
1233   } else {
1234     //passed zeroes = your best is to keep best size (in cache, value defined at creation)
1235     if (sizex == 0) sizex = currentBestSize.x;
1236     if (sizey == 0) sizey = currentBestSize.y;
1237   }
1238   wSize.x = sizex;
1239   wSize.y = sizey;
1240   me->SetSize(wSize); //includes scrollbars.
1241   //the sizer takes care of the eventual frame
1242   me->SetMinSize(wSize); //includes scrollbars.
1243   //framed bases may have a complicated frame around, to be resized:
1244   if (theWxContainer != theWxWidget) {
1245     wxWindow* container = dynamic_cast<wxWindow*> (theWxContainer);
1246     wxSizer* s = me->GetSizer();
1247     if (s) s->Fit(me);
1248     else container->Fit();
1249   }
1250   UpdateGui();
1251 
1252   END_CHANGESIZE_NOEVENT
1253 
1254 
1255 #ifdef GDL_DEBUG_WIDGETS
1256     wxMessageOutputStderr().Printf(_T("GDLWidget::SetSize %d,%d (%s)\n"), sizex, sizey, this->GetWidgetName().c_str());
1257 #endif
1258 }
1259 
SetBaseTitle(std::string & title_)1260 void GDLWidgetTabbedBase::SetBaseTitle(std::string &title_)
1261 {
1262   GDLWidgetTab* parentTab=dynamic_cast<GDLWidgetTab*>(this->GetMyParent());
1263   if (parentTab) {
1264     wxNotebook* wxParent = dynamic_cast<wxNotebook*> (parentTab->GetWxWidget( ));
1265     wxParent->SetPageText(wxParent->FindPage(static_cast<wxWindow*>(theWxWidget)),wxString(title_.c_str(), wxConvUTF8));
1266   }
1267 #ifdef GDL_DEBUG_WIDGETS
1268   else wxMessageOutputStderr( ).Printf( _T( "GDLWidgetTabbedBase::SetBaseTitle() no parent tab exists? %d\n"));
1269 #endif
1270 }
1271 
~GDLWidgetTabbedBase()1272 GDLWidgetTabbedBase::~GDLWidgetTabbedBase()
1273 {
1274 #ifdef GDL_DEBUG_WIDGETS
1275   std::cout << "~GDLWidgetTabbedBase(" << widgetID << ")" << std::endl;
1276 #endif
1277   GDLWidgetTab* parentTab=static_cast<GDLWidgetTab*>(this->GetMyParent());
1278   if (parentTab) { //may be already destroyed.
1279     wxNotebook* wxParent = static_cast<wxNotebook*> (parentTab->GetWxWidget( ));
1280     //whereAmI?
1281     myPage=wxParent->FindPage(static_cast<wxWindow*>(theWxContainer));
1282     if (wxParent) wxParent->RemovePage(myPage); //do not delete the page, GDL will delete the contents itself, widget per widget.
1283   }
1284 #ifdef GDL_DEBUG_WIDGETS
1285   else wxMessageOutputStderr( ).Printf( _T( "~GDLWidgetTabbedBase() no parent tab exists? %d\n"));
1286 #endif
1287 }
1288 
Realize(bool map,bool use_default)1289 void GDLWidget::Realize( bool map, bool use_default) {  GetMyTopLevelBaseWidget()->Realize(map, use_default); }
1290 
Realize(bool map,bool use_default)1291 void GDLWidgetTopBase::Realize(bool map, bool use_default) {
1292 #ifdef GDL_DEBUG_WIDGETS
1293     wxMessageOutputStderr().Printf(_T("GDLWidgetTopBase:Realize: %d\n"), widgetID);
1294 #endif
1295   if (use_default) map = GetMap();
1296 
1297   OnRealize();
1298 
1299  if (map) topFrame->Show() ; //endShowRequestEvent();
1300   else topFrame->Hide(); //SendHideRequestEvent();
1301   realized=true;
1302 }
1303 
IsRealized()1304 bool GDLWidget::IsRealized() {
1305     GDLWidgetTopBase *tlb = GetMyTopLevelBaseWidget();
1306     gdlwxFrame* topFrame = tlb->GetTopFrame();
1307     return (tlb->IsTopLevelRealized());
1308   }
OnRealize()1309   void GDLWidgetContainer::OnRealize() {
1310 #ifdef GDL_DEBUG_WIDGETS
1311     wxMessageOutputStderr().Printf(_T("GDLWidgetContainer::OnRealize: %d\n"), widgetID);
1312 #endif
1313     //setFont() will set the font for this widget and children if FONT= is present in the WIDGET_XXX command (and is supported)
1314   this->setFont();
1315   this->SetSensitive(sensitive);
1316 
1317   for (std::deque<WidgetIDT>::reverse_iterator c = children.rbegin(); c != children.rend(); ++c) {
1318 //  for (std::deque<WidgetIDT>::iterator c = children.begin(); c != children.end(); ++c) {
1319    GDLWidget* w = GetWidget(*c);
1320    if (w != NULL)
1321     w->OnRealize();
1322   }
1323 
1324   wxPanel* p=static_cast<wxPanel*> (theWxContainer);
1325   if (p) {
1326     wxSizer* s = p->GetSizer();
1327     if (s) s->Fit(p);
1328     else {
1329       p->Fit();
1330       if (this->GetParentSizer() == NULL) { //force size of parent since we cannot leave it to a nonexistent parent sizer.
1331         GDLWidgetContainer* myParentContainer = static_cast<GDLWidgetContainer*> (this->GetMyParentBaseWidget());
1332         if (myParentContainer != NULL) {
1333           wxWindow* w = static_cast<wxWindow*> (this->GetParentPanel());
1334           assert(w != NULL);
1335           wxSize wSize = w->GetSize();
1336           wxSize mySize = p->GetSize();
1337           // if w.x or w.y was SET BY USER it is a requested size, that we should not change
1338           wxSize desiredSize;
1339           if (myParentContainer->xFree()) desiredSize.x = max(mySize.x, wSize.x);
1340           else {
1341             desiredSize.x = wSize.x;
1342           }
1343           if (myParentContainer->yFree()) desiredSize.y = max(mySize.y, wSize.y);
1344           else {
1345             desiredSize.y = wSize.y;
1346           }
1347           w->SetSize(desiredSize);
1348           w->SetMinSize(desiredSize);
1349         }
1350       }
1351     }
1352   }
1353 #ifdef GDL_DEBUG_WIDGETS
1354     else wxMessageOutputStderr().Printf(_T("Unknown Container for (%s) widget ID %d\n"), widgetName, widgetID);
1355 #endif
1356 
1357   if (notifyRealize != "") { //insure it is called once only for this.
1358    std::string note = notifyRealize;
1359    notifyRealize.clear();
1360    CallEventPro(note, new DLongGDL(widgetID));
1361   }
1362   //define Events Last (TBC).
1363   ConnectToDesiredEvents();
1364  }
1365 
OnRealize()1366 void GDLWidgetMenu::OnRealize() {
1367   //setFont() will set the font for this widget and children if FONT= is present in the WIDGET_XXX command (and is supported)
1368   this->setFont();
1369   this->SetSensitive(sensitive);
1370 
1371   //Menu children are menus or entries, *NOT* any widget.
1372   for (std::deque<WidgetIDT>::reverse_iterator c = children.rbegin(); c != children.rend(); ++c) {
1373 //  for (std::deque<WidgetIDT>::iterator c = children.begin(); c != children.end(); ++c) {
1374    GDLWidgetMenu* w = dynamic_cast<GDLWidgetMenu*>(GetWidget(*c));
1375    if (w != NULL)
1376     w->OnRealize();
1377   }
1378 
1379   if (notifyRealize != "") { //insure it is called once only for this.
1380    std::string note = notifyRealize;
1381    notifyRealize.clear();
1382    CallEventPro(note, new DLongGDL(widgetID));
1383   }
1384  }
1385 
1386 #define GetSysC(x)   { col=wxSystemSettings::GetColour(x); r=col.Red();g=col.Green();b=col.Blue(); (*val)[0]=r;(*val)[1]=g;(*val)[2]=b; }
getSystemColours()1387 BaseGDL * GDLWidget::getSystemColours()
1388 {
1389   DStructGDL* colo = new DStructGDL( "WIDGET_SYSTEM_COLORS");
1390   DIntGDL*  val=new DIntGDL( dimension(3), BaseGDL::NOZERO);
1391   int  r,g,b;
1392   wxColour col;
1393   GetSysC(wxSYS_COLOUR_3DDKSHADOW );
1394   colo->InitTag("DARK_SHADOW_3D",(*val));
1395   colo->InitTag("SHADOW_3D", (*val));
1396   GetSysC(wxSYS_COLOUR_3DLIGHT );
1397   colo->InitTag("FACE_3D", (*val));
1398   colo->InitTag("LIGHT_EDGE_3D", (*val));
1399   colo->InitTag("LIGHT_3D", (*val));
1400   GetSysC(wxSYS_COLOUR_ACTIVEBORDER  );
1401   colo->InitTag("ACTIVE_BORDER", (*val));
1402   GetSysC(wxSYS_COLOUR_ACTIVECAPTION   );
1403   colo->InitTag("ACTIVE_CAPTION", (*val));
1404   GetSysC(wxSYS_COLOUR_APPWORKSPACE    );
1405   colo->InitTag("APP_WORKSPACE", (*val));
1406   GetSysC(wxSYS_COLOUR_DESKTOP     );
1407   colo->InitTag("DESKTOP", (*val));
1408   GetSysC(wxSYS_COLOUR_BTNTEXT     );
1409   colo->InitTag("BUTTON_TEXT", (*val));
1410   GetSysC(wxSYS_COLOUR_CAPTIONTEXT     );
1411   colo->InitTag("CAPTION_TEXT", (*val));
1412   GetSysC(wxSYS_COLOUR_GRAYTEXT     );
1413   colo->InitTag("GRAY_TEXT", (*val));
1414   GetSysC(wxSYS_COLOUR_HIGHLIGHT     );
1415   colo->InitTag("HIGHLIGHT", (*val));
1416   GetSysC(wxSYS_COLOUR_HIGHLIGHTTEXT     );
1417   colo->InitTag("HIGHLIGHT_TEXT", (*val));
1418   GetSysC(wxSYS_COLOUR_INACTIVEBORDER     );
1419   colo->InitTag("INACTIVE_BORDER", (*val));
1420   GetSysC(wxSYS_COLOUR_INACTIVECAPTION     );
1421   colo->InitTag("INACTIVE_CAPTION", (*val));
1422   GetSysC(wxSYS_COLOUR_INACTIVECAPTIONTEXT     );
1423   colo->InitTag("INACTIVE_CAPTION_TEXT", (*val));
1424   GetSysC(wxSYS_COLOUR_INFOBK     );
1425   colo->InitTag("TOOLTIP_BK", (*val));
1426   GetSysC(wxSYS_COLOUR_INFOTEXT     );
1427   colo->InitTag("TOOLTIP_TEXT", (*val));
1428   GetSysC(wxSYS_COLOUR_MENU     );
1429   colo->InitTag("MENU", (*val));
1430   GetSysC(wxSYS_COLOUR_MENUTEXT     );
1431   colo->InitTag("MENU_TEXT", (*val));
1432   GetSysC(wxSYS_COLOUR_SCROLLBAR     );
1433   colo->InitTag("SCROLLBAR", (*val));
1434   GetSysC(wxSYS_COLOUR_WINDOW     );
1435   colo->InitTag("WINDOW_BK", (*val));
1436   GetSysC(wxSYS_COLOUR_WINDOWFRAME     );
1437   colo->InitTag("WINDOW_FRAME", (*val));
1438   GetSysC(wxSYS_COLOUR_WINDOWTEXT     );
1439   colo->InitTag("WINDOW_TEXT", (*val));
1440   return colo;
1441 }
1442 
~GDLWidget()1443 GDLWidget::~GDLWidget()
1444 {
1445 #ifdef GDL_DEBUG_WIDGETS
1446       std::string state=(this->IsValid())?" ":"(Already destroyed) ";
1447       std::cout << "~GDLWidget "+state+"("<< widgetID <<")"<< std::endl;
1448 #endif
1449 
1450   if (!this->IsValid()) return; //to avoid crashing if asserts are not honored
1451   //unvalidate widget to prevent some further actions
1452   this->SetUnValid();
1453   if (m_windowTimer) {if (m_windowTimer->IsRunning()) m_windowTimer->Stop();}
1454 
1455   // call KILL_NOTIFY procedures
1456   this->OnKill();
1457 
1458   // kill followers (here?)
1459   // delete all followers (in reverse order ?)
1460   while (!followers.empty()) {
1461 #ifdef GDL_DEBUG_WIDGETS
1462       std::cout << "~GDLWidget("<< widgetID <<"): destroy follower "<< followers.back()<< endl;
1463 #endif
1464       GDLWidget* follower=GetWidget(followers.back()); followers.pop_back();
1465     if (follower) delete follower;
1466   }
1467 
1468   GDLWidget* gdlParent = GetMyParent();
1469   if (gdlParent) { //not the TLB
1470     gdlParent->RemoveIfFollower(widgetID);
1471 
1472 //    UpdateGui();  //way too long! use a more subtle command!
1473 
1474   } else {
1475     static_cast<GDLWidgetTopBase*>(this)->GetTopFrame()->Hide();
1476     static_cast<GDLWidgetTopBase*>(this)->GetTopFrame()->Destroy(); //delete topBase
1477   }
1478 
1479   GDLDelete(uValue);
1480   GDLDelete(vValue);
1481   uName.clear();
1482   proValue.clear();
1483   funcValue.clear();
1484   eventPro.clear(); // event handler PRO
1485   eventFun.clear(); // event handler FUN
1486   notifyRealize.clear();
1487   killNotify.clear();
1488   valid=false; //if not, is in the process of being destroyed (prevent reentrance).
1489 
1490   widgetList.erase(widgetID);
1491   desiredEventsList.clear();
1492   followers.clear();
1493   widgetName.clear();
1494 
1495   theWxContainer=NULL;
1496   theWxWidget=NULL;
1497   widgetSizer=NULL;
1498   widgetPanel=NULL;
1499   framePanel=NULL;
1500 }
1501 
Raise()1502 void GDLWidget::Raise()
1503 {
1504   this->GetMyTopLevelFrame()->Raise();
1505 }
1506 
Lower()1507 void GDLWidget::Lower()
1508 {
1509   this->GetMyTopLevelFrame()->Lower();
1510 }
1511 
GetGeometry(wxRealPoint fact)1512 DStructGDL* GDLWidget::GetGeometry(wxRealPoint fact)
1513 {
1514   if (!this->IsRealized()) this->Realize(true,false);//necessary if a geometry request is done previous to the command widget_control,xxx,,/Realize !
1515   GDLWidgetBase* container = static_cast<GDLWidgetBase*> (this->GetMyParent());
1516   assert(container != NULL);
1517   int ixsize = 0, iysize = 0, iscr_xsize = 0, iscr_ysize = 0;
1518   DFloat xsize = 0;
1519   DFloat ysize = 0;
1520   DFloat scr_xsize = 0;
1521   DFloat scr_ysize = 0;
1522   DFloat xoffset = 0;
1523   DFloat yoffset = 0;
1524   DFloat margin = 0;
1525 
1526   DStructGDL* ex = new DStructGDL("WIDGET_GEOMETRY");
1527 
1528   wxWindow* test = dynamic_cast<wxWindow*> (theWxContainer);
1529   if (test==NULL) return ex;
1530   wxRect r=test->GetRect();
1531 //  std::cerr<<"CONTAINER: x: "<<r.x<<", y: "<<r.y<<", width="<<r.width<<", height="<<r.height<<std::endl;
1532   xoffset = r.x ;
1533   yoffset = r.y ;
1534   wxWindow* w = dynamic_cast<wxWindow*> (theWxWidget);
1535   if (w==NULL) return ex;
1536   wxRect z=w->GetRect();
1537 //  std::cerr<<"WIDGET: x: "<<z.x<<", y: "<<z.y<<", width="<<z.width<<", height="<<z.height<<std::endl;
1538 
1539   iscr_xsize = z.width;
1540   iscr_ysize = z.height;
1541   wxSize s=w->GetClientSize();
1542   ixsize = s.x; if (ixsize < 1) ixsize=iscr_xsize; //Patch for OSX where s.x is 0
1543   iysize = s.y; if (iysize < 1) iysize=iscr_ysize; //Patch for OSX where s.y is 0
1544 
1545   if (theWxWidget == theWxContainer) margin=0; else {
1546     margin=(r.width-z.width)/2; //Rect is about the container, which is the widgetPanel and not the frame depending on case.
1547   }
1548 
1549   if (this->IsInCharacters()) {
1550   wxSize fontSize = getFontSize();
1551   xsize = ixsize / fontSize.x;
1552   ysize = iysize / fontSize.y;
1553   } else {
1554   //size is in pixels, pass in requested units (1.0 default)
1555   xsize = ixsize / fact.x;
1556   ysize = iysize / fact.y;
1557   }
1558   scr_xsize = iscr_xsize / fact.x;
1559   scr_ysize = iscr_ysize / fact.y;
1560   xoffset /= fact.x;
1561   yoffset /= fact.y;
1562   margin /= fact.x;
1563 
1564   ex->InitTag("XOFFSET", DFloatGDL(xoffset));
1565   ex->InitTag("YOFFSET", DFloatGDL(yoffset));
1566   ex->InitTag("XSIZE", DFloatGDL(xsize));
1567   ex->InitTag("YSIZE", DFloatGDL(ysize));
1568   ex->InitTag("SCR_XSIZE", DFloatGDL(scr_xsize));
1569   ex->InitTag("SCR_YSIZE", DFloatGDL(scr_ysize));
1570   ex->InitTag("MARGIN", DFloatGDL(margin));
1571 //special DRAW:
1572   if (this->IsDraw()) {
1573     wxSize d=w->GetVirtualSize();
1574     DFloat dxsize=d.x;
1575     DFloat dysize=d.y;
1576     ex->InitTag("DRAW_XSIZE", DFloatGDL(dxsize/fact.x));
1577     ex->InitTag("DRAW_YSIZE", DFloatGDL(dysize/fact.y));
1578   }
1579 
1580   return ex;
1581 }
1582 
GDLWidgetContainer(WidgetIDT parentID,EnvT * e,ULong eventFlags_)1583 GDLWidgetContainer::GDLWidgetContainer( WidgetIDT parentID, EnvT* e, ULong eventFlags_)
1584 : GDLWidget( parentID, e, NULL, eventFlags_),xfree(true),yfree(true)
1585 {
1586 }
1587 
~GDLWidgetContainer()1588   GDLWidgetContainer::~GDLWidgetContainer()
1589 {
1590 #ifdef GDL_DEBUG_WIDGETS
1591   std::cout << "~GDLWidgetContainer(" << widgetID <<")"<< std::endl;
1592 #endif
1593 
1594   // delete all children (in reverse order ?)
1595   while (!children.empty()) {
1596     GDLWidget* child=GetWidget(children.back()); children.pop_back();
1597 
1598      if (child) {
1599 #ifdef GDL_DEBUG_WIDGETS
1600       std::cout << "~GDLWidgetContainer, deleting child ID #" << child->GetWidgetID() << " of container  #" << widgetID << std::endl;
1601 #endif
1602       //special case for WIDGET_DRAW: delete from 'wdelete' command-like:
1603       if (child->IsDraw()) {
1604         gdlwxGraphicsPanel* draw=static_cast<gdlwxGraphicsPanel*>(child->GetWxWidget());
1605         draw->DeleteUsingWindowNumber(); //just emit quivalent to "wdelete,winNum".
1606       } else delete child;
1607      }
1608   }
1609 
1610   if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy(); //which is the panel.
1611 }
1612 
1613 #ifdef PREFERS_MENUBAR
~GDLWidgetMenuBar()1614    GDLWidgetMenuBar::~GDLWidgetMenuBar() {
1615 #ifdef GDL_DEBUG_WIDGETS
1616   std::cout << "~GDLWidgetMenuBar(" << widgetID << ")" << std::endl;
1617 #endif
1618 
1619   // delete all children (in reverse order ?)
1620   while (!children.empty()) {
1621     GDLWidget* child=GetWidget(children.back()); children.pop_back();
1622     if (child) {
1623 #ifdef GDL_DEBUG_WIDGETS
1624       std::cout << "~GDLWidgetMenuBar, deleting child ID #" << child->GetWidgetID() << " of container  #" << widgetID << std::endl;
1625 #endif
1626       delete child;
1627     }
1628   }
1629   //remove wxWidgets MBAR from wxFrame container otherwise wxFrame will attempt to destroy it again and segfault
1630   dynamic_cast<wxMenuBar*> (theWxWidget)->GetFrame()->SetMenuBar(NULL);
1631  }
1632 #else
~GDLWidgetMenuBar()1633    GDLWidgetMenuBar::~GDLWidgetMenuBar() {
1634 #ifdef GDL_DEBUG_WIDGETS
1635   std::cout << "~GDLWidgetMenuBar(" << widgetID << ")" << std::endl;
1636 #endif
1637 
1638   // delete all children (in reverse order ?)
1639   while (!children.empty()) {
1640     GDLWidget* child=GetWidget(children.back()); children.pop_back();
1641     if (child) {
1642 #ifdef GDL_DEBUG_WIDGETS
1643       std::cout << "~GDLWidgetMenuBar, deleting child ID #" << child->GetWidgetID() << " of container  #" << widgetID << std::endl;
1644 #endif
1645       delete child;
1646     }
1647   }
1648   //toolbar can be removed
1649   dynamic_cast<wxToolBar*> (theWxWidget)->Destroy();
1650  }
1651 #endif
1652  /*********************************************************/
1653 // for WIDGET_BASE
1654 /*********************************************************/
GDLWidgetBase(WidgetIDT parentID,EnvT * e,ULong eventFlags_,bool mapWid,DLong col,DLong row,int exclusiveMode_,const DString & resource_name,const DString & rname_mbar,const DString & title_,const DString & display_name,int xpad_,int ypad_,DLong x_scroll_size,DLong y_scroll_size,bool grid_layout,long children_alignment,int space_)1655 GDLWidgetBase::GDLWidgetBase(WidgetIDT parentID, EnvT* e, ULong eventFlags_,
1656   bool mapWid,
1657   DLong col, DLong row,
1658   int exclusiveMode_,
1659   const DString& resource_name, const DString& rname_mbar,
1660   const DString& title_,
1661   const DString& display_name,
1662   int xpad_, int ypad_,
1663   DLong x_scroll_size, DLong y_scroll_size, bool grid_layout, long children_alignment, int space_)
1664 : GDLWidgetContainer(parentID, e, eventFlags_)
1665 , lastRadioSelection(NullID)
1666 , nrows(row)
1667 , ncols(col)
1668 , grid(grid_layout)
1669 , childrenAlignment(children_alignment)
1670 , space(space_)
1671 , xpad(xpad_)
1672 , ypad(ypad_)
1673 , doMap(mapWid) {
1674   // All bases can receive events: EV_CONTEXT, EV_KBRD_FOCUS, EV_TRACKING
1675 
1676   wSize = computeWidgetSize();
1677 //get immediately rid of scroll sizes in case of scroll or not... Here is the logic:
1678 
1679   if (x_scroll_size > 0) {scrolled=true;x_scroll_size*=unitConversionFactor.x;x_scroll_size+=gdlSCROLL_WIDTH_Y;}
1680   if (y_scroll_size > 0) {scrolled=true;y_scroll_size*=unitConversionFactor.y;y_scroll_size+=gdlSCROLL_HEIGHT_X;}
1681   if (scrolled) {
1682     if (x_scroll_size < 1) x_scroll_size = gdlDEFAULT_XSIZE+gdlSCROLL_WIDTH_Y;
1683     if (y_scroll_size < 1) y_scroll_size = gdlDEFAULT_YSIZE+gdlSCROLL_HEIGHT_X;
1684   }
1685   wScrollSize = scrolled ? wxSize(x_scroll_size , y_scroll_size ) : wSize; //y_scroll_size + gdlSCROLL_HEIGHT_X);
1686   xfree=(wScrollSize.x <= 0);
1687   yfree=(wScrollSize.y <= 0);
1688   // Set exclusiveMode
1689   // If exclusive then set to -1 to signal first radiobutton
1690   if ( exclusiveMode_ == BGEXCLUSIVE )
1691   this->SetExclusiveMode( BGEXCLUSIVE1ST );
1692   else
1693     this->SetExclusiveMode( exclusiveMode_ );
1694 
1695   // COLUMN is default if col=0 and row=0 for exclusive etc bases.
1696   if ( this->GetExclusiveMode() != BGNORMAL ) {
1697     if (ncols < 1 && nrows <1 ) ncols=1;
1698   }
1699 
1700 }
1701 
1702 // generic creation of a base in which widgets will be put.
1703 //
1704 // defines widgetPanel which is the (scrolled) panel in which children will be Added.
1705 // widgetPanel may be a panel inside a (scrolled) panel used to mimic padding if necessary. In ths case it is the padding panel that is scrolled.
1706 // Further, all this casn be inside a frame.
1707 //
1708 // define the widgetSizer, the sizer that children will 'obey' (that will govern overall placement and size of children)
1709 // the widgetSizer may be NULL, in which case the placement of children inside the panel will be governed by their respective size and position,
1710 // but if widgetSizer exist, then everytime a new child is created, it must be invoked to resize/reposition this child.
1711 //
CreateBase(wxWindow * parent)1712 void GDLWidgetBase::CreateBase(wxWindow* parent){
1713 //the container is as ScrollPanel
1714   bool doFrame=true; //!(this->IsTopBase()); //IDL Prevents topBases to be framed (?).
1715   if (doFrame && frameWidth > 0) {
1716     wxScrolled<wxPanel>* frame = new wxScrolled<wxPanel>(parent, wxID_ANY, wOffset, wxDefaultSize, gdlBORDER_EXT);
1717     theWxContainer=frame;
1718 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
1719     frame->SetBackgroundColour(wxColour(0x60, 0xe0, 0x94)); //vert clair
1720 #endif
1721     wxBoxSizer* panelsz = new wxBoxSizer(wxVERTICAL);
1722     frame->SetSizer(panelsz);
1723 // Fancy variant:
1724 //    int mode = wxBORDER_NONE;
1725 //    int width = 2; //the size of wxBORDER_SUNKEN
1726 //    if (frameWidth > 2) {
1727 //      mode = wxBORDER_SIMPLE;
1728 //      width = 3;
1729 //    }
1730 //    if (frameWidth > 3) {
1731 //      mode = wxBORDER_RAISED;
1732 //      width = 4;
1733 //    }
1734 //    wxPanel* frame_inside = new wxPanel(frame, wxID_ANY, wxDefaultPosition, wxDefaultSize, mode);
1735 //    sz->Add(frame_inside, FRAME_ALLOWSTRETCH, wxALL, frameWidth - width);
1736 //
1737 //    wxBoxSizer* sz_inside = new wxBoxSizer(wxVERTICAL);
1738 //    frame_inside->SetSizer(sz_inside);
1739 //    widgetPanel = new wxScrolledWindow(frame_inside, wxID_ANY, wOffset, wxDefaultSize);
1740     if (xpad > 0 || ypad > 0) {
1741       wxScrolled<wxPanel>* padxpady = new wxScrolled<wxPanel>(frame);
1742 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
1743       padxpady->SetBackgroundColour(wxColour(0xa7, 0x3d, 0x0f)); //orange fonce
1744 #endif
1745       wxGridBagSizer* sz = new wxGridBagSizer(ypad, xpad);
1746       padxpady->SetSizer(sz);
1747       sz->SetEmptyCellSize(wxSize(0, 0));
1748       if (xpad > 1) sz->Add(0, 0, wxGBPosition(1, 2));
1749       if (ypad > 1) sz->Add(0, 0, wxGBPosition(2, 1));
1750 
1751       widgetPanel = new wxScrolledWindow(padxpady, widgetID, wOffset, wxDefaultSize);
1752       sz->Add(widgetPanel, wxGBPosition(1, 1));
1753 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
1754       widgetPanel->SetBackgroundColour(RandomWxColour());
1755 #endif
1756       //    widgetPanel->SetVirtualSize(wSize);
1757       padxpady->SetSize(wScrollSize);
1758       padxpady->SetMinSize(wScrollSize);
1759       //Just Enable scrollBars if scrolling is necessary
1760       if (scrolled) {
1761         padxpady->SetScrollbars(gdlSCROLL_RATE, gdlSCROLL_RATE, wSize.x / gdlSCROLL_RATE, wSize.y / gdlSCROLL_RATE);
1762         padxpady->ShowScrollbars(wxSHOW_SB_ALWAYS, wxSHOW_SB_ALWAYS);
1763       }
1764       panelsz->Add(padxpady, FRAME_ALLOWSTRETCH, wxALL | wxEXPAND, frameWidth);//gdlFRAME_MARGIN);
1765       panelsz->Fit(padxpady);
1766     } else {
1767       widgetPanel = new wxScrolledWindow(frame, widgetID, wOffset, wxDefaultSize);
1768 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
1769       widgetPanel->SetBackgroundColour(RandomWxColour());
1770 #endif
1771       //    widgetPanel->SetVirtualSize(wSize);
1772       widgetPanel->SetSize(wScrollSize);
1773       widgetPanel->SetMinSize(wScrollSize);
1774       //Just Enable scrollBars if scrolling is necessary
1775       if (scrolled) {
1776         widgetPanel->SetScrollbars(gdlSCROLL_RATE, gdlSCROLL_RATE, wSize.x / gdlSCROLL_RATE, wSize.y / gdlSCROLL_RATE);
1777         widgetPanel->ShowScrollbars(wxSHOW_SB_ALWAYS, wxSHOW_SB_ALWAYS);
1778       }
1779       panelsz->Add(widgetPanel, FRAME_ALLOWSTRETCH, wxALL | wxEXPAND, frameWidth);//gdlFRAME_MARGIN);
1780       panelsz->Fit(widgetPanel);
1781     }
1782     theWxWidget = widgetPanel;
1783   } else {
1784     if (xpad > 0 || ypad > 0 ) {
1785       wxScrolled<wxPanel>* padxpady = new wxScrolled<wxPanel>(parent);
1786       theWxContainer = padxpady;
1787   #ifdef GDL_DEBUG_WIDGETS_COLORIZE
1788       padxpady->SetBackgroundColour(wxColour(0xa7, 0x3d, 0x0f)); //orange fonce
1789   #endif
1790       wxGridBagSizer* sz = new wxGridBagSizer(ypad, xpad);
1791       padxpady->SetSizer(sz);
1792       sz->SetEmptyCellSize(wxSize(0, 0));
1793       if (xpad > 1) sz->Add(0, 0, wxGBPosition(1, 2));
1794       if (ypad > 1) sz->Add(0, 0, wxGBPosition(2, 1));
1795 
1796       widgetPanel = new wxScrolledWindow(padxpady, widgetID, wOffset, wxDefaultSize);
1797       sz->Add(widgetPanel, wxGBPosition(1, 1));
1798 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
1799       widgetPanel->SetBackgroundColour(RandomWxColour());
1800 #endif
1801       //    widgetPanel->SetVirtualSize(wSize);
1802       padxpady->SetSize(wScrollSize);
1803       padxpady->SetMinSize(wScrollSize);
1804       //Just Enable scrollBars if scrolling is necessary
1805       if (scrolled) {
1806         padxpady->SetScrollbars(gdlSCROLL_RATE, gdlSCROLL_RATE, wSize.x / gdlSCROLL_RATE, wSize.y / gdlSCROLL_RATE);
1807         padxpady->ShowScrollbars(wxSHOW_SB_ALWAYS, wxSHOW_SB_ALWAYS);
1808       }
1809     } else {
1810       widgetPanel = new wxScrolledWindow(parent, widgetID, wOffset, wxDefaultSize);
1811       theWxContainer = widgetPanel;
1812 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
1813       widgetPanel->SetBackgroundColour(RandomWxColour());
1814 #endif
1815     //    widgetPanel->SetVirtualSize(wSize);
1816       widgetPanel->SetSize(wScrollSize);
1817       widgetPanel->SetMinSize(wScrollSize);
1818       //Just Enable scrollBars if scrolling is necessary
1819       if (scrolled) {
1820         widgetPanel->SetScrollbars(gdlSCROLL_RATE, gdlSCROLL_RATE, wSize.x / gdlSCROLL_RATE, wSize.y / gdlSCROLL_RATE);
1821         widgetPanel->ShowScrollbars(wxSHOW_SB_ALWAYS, wxSHOW_SB_ALWAYS);
1822       }
1823     }
1824 
1825     theWxWidget = widgetPanel;
1826   }
1827 
1828 
1829 //define inside sizer.
1830   widgetSizer = AddABaseSizer(ncols, nrows, grid, space);
1831   if (widgetSizer) widgetPanel->SetSizer(widgetSizer);
1832 
1833   wxSizer* parentSizer = parent->GetSizer();
1834   if (parentSizer) parentSizer->Add(static_cast<wxWindow*>(theWxContainer), DONOTALLOWSTRETCH, wxALL | widgetAlignment(), gdlSPACE);
1835   }
1836 
SetWidgetSize(DLong sizex,DLong sizey)1837  void GDLWidgetBase::SetWidgetSize(DLong sizex, DLong sizey)
1838 {
1839   START_CHANGESIZE_NOEVENT
1840 
1841   wxWindow* me=dynamic_cast<wxWindow*>(theWxWidget);
1842   if (me==NULL) {
1843 #ifdef GDL_DEBUG_WIDGETS
1844   wxMessageOutputStderr( ).Printf( _T( "GDLWidget::SetSize of non wxWindow %s\n"),this->GetWidgetName().c_str());
1845 #endif
1846   return;
1847   }
1848   //a graphic window cannot be larger than the base widget it is in, if the base widget size has been fixed
1849   wxSize currentVirtualSize=me->GetVirtualSize();
1850   wxSize currentSize=me->GetSize();
1851 #ifdef GDL_DEBUG_WIDGETS
1852   wxMessageOutputStderr( ).Printf( _T( "GDLWidgetBase::SetSize currentSize=%d,%d\n"),currentSize.x,currentSize.y);
1853 #endif
1854 
1855   if (widgetSizer) {
1856     //passed zeroes = mr sizer, do your best..
1857     if (sizex == 0) sizex = -1;
1858     if (sizey == 0) sizey = -1;
1859   } else {
1860     //passed zeroes = your best is to keep best size (in cache, value defined at creation)
1861     if (sizex == 0) sizex = scrolled?currentSize.x:currentVirtualSize.x;
1862     if (sizey == 0) sizey = scrolled?currentSize.y:currentVirtualSize.y;
1863   }
1864   wxSize theSize=wxSize(sizex,sizey);
1865   if (scrolled) theSize += wxSize(gdlSCROLL_HEIGHT_X, gdlSCROLL_WIDTH_Y);
1866   me->SetSize( theSize );
1867 
1868  //framed bases may have a complicated frame around, to be resized:
1869   if (theWxContainer != theWxWidget) { //framed -> has a sizer
1870     wxWindow* container=dynamic_cast<wxWindow*>(theWxContainer);
1871     wxWindow* contained=dynamic_cast<wxWindow*>(theWxWidget);
1872     container->GetSizer()->Fit(contained);
1873   }
1874 
1875   UPDATE_WINDOW;
1876 
1877   END_CHANGESIZE_NOEVENT
1878 
1879 #ifdef GDL_DEBUG_WIDGETS
1880   wxMessageOutputStderr( ).Printf( _T( "GDLWidgetBase::SetSize %d,%d (%s)\n"),sizex,sizey,this->GetWidgetName().c_str());
1881 #endif
1882 }
1883 /*********************************************************/
1884 // special TOP WIDGET_BASE
1885 /*********************************************************/
1886 
GDLWidgetTopBase(EnvT * e,ULong eventFlags_,bool mapWid,WidgetIDT & mBarIDInOut,bool modal_,DLong frame_attr,DLong col,DLong row,int exclusiveMode_,bool floating,const DString & resource_name,const DString & rname_mbar,const DString & title_,const DString & display_name,int xpad_,int ypad_,DLong x_scroll_size,DLong y_scroll_size,bool grid_layout,long children_alignment,int space_)1887 GDLWidgetTopBase::GDLWidgetTopBase( EnvT* e, ULong eventFlags_,
1888 bool mapWid,
1889 WidgetIDT& mBarIDInOut, bool modal_, DLong frame_attr,
1890 DLong col, DLong row,
1891 int exclusiveMode_,
1892 bool floating,
1893 const DString& resource_name, const DString& rname_mbar,
1894 const DString& title_,
1895 const DString& display_name,
1896 int xpad_, int ypad_,
1897 DLong x_scroll_size, DLong y_scroll_size, bool grid_layout, long children_alignment, int space_)
1898 : GDLWidgetBase( GDLWidget::NullID, e, eventFlags_, mapWid, col, row, exclusiveMode_, resource_name, rname_mbar, title_, display_name, xpad_, ypad_, x_scroll_size, y_scroll_size, grid_layout, children_alignment, space_)
1899 , mbarID(mBarIDInOut)
1900 , xmanActCom(false)
1901 , modal(modal_)
1902 , realized(false)
1903 {
1904 
1905   // All bases can receive events: EV_CONTEXT, EV_KBRD_FOCUS, EV_TRACKING
1906 
1907 //on wxMAC, frame will not appear if style is not exactly this (!!!)
1908 #ifdef __WXMAC__
1909 long style = (wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxRESIZE_BORDER | wxCAPTION | wxCLOSE_BOX);
1910 #else
1911   long style=wxDEFAULT_FRAME_STYLE|wxFRAME_TOOL_WINDOW; //wxFRAME_TOOL_WINDOW to NOT get focus. See behaviour of 'P' (photometry) while using ATV (atv.pro).
1912   if (frame_attr) {
1913     style=0;
1914     if (!(frame_attr & 1)) style |= (wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxRESIZE_BORDER| wxCAPTION);
1915     if (!(frame_attr & 2)) style |=wxSYSTEM_MENU;
1916     if (!(frame_attr & 4)) style |=wxCAPTION;
1917     if (!(frame_attr & 8)) style |=wxCLOSE_BOX;
1918     //style 16 not supported.
1919   }
1920   if (floating) {
1921     if (this->GetWidget(groupLeader)==NULL) e->Throw("FLOATING top level bases must have a group leader specified.");
1922     style |= wxFRAME_TOOL_WINDOW|wxSTAY_ON_TOP ; //wxFRAME_FLOAT_ON_PARENT will destroy the parent widget!!
1923   }
1924 #endif
1925 
1926   // Top Level Base Widget: can receive special events: tlb_size, tlb_move, tlb_icon and tlb_kill. cannot be framed.
1927   wxString titleWxString;
1928   if (title_.size() < 1) titleWxString = wxString("GDL");
1929   else titleWxString = wxString(title_.c_str(), wxConvUTF8);
1930   if (floating) {
1931     wxWindow* parent=static_cast<wxWindow*>(this->GetWidget(groupLeader)->GetWxWidget());
1932     //make it really above parent:
1933     wxRect x=parent->GetScreenRect();
1934     if (wOffset.x < 0) wOffset.x =x.x+x.width/2;
1935     if (wOffset.y < 0) wOffset.y =x.y+x.height/2;
1936   }
1937   topFrame = new gdlwxFrame(NULL, this, widgetID, titleWxString, wOffset, wxDefaultSize, style);
1938 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
1939   topFrame->SetBackgroundColour(wxColour(0x81, 0x46, 0xf1)); //violet
1940 #endif
1941 
1942   //Base Frame inherits default font -- then each widget will possibly get its own font when /FONT is possible
1943   topFrame->SetFont(defaultFont);
1944 
1945   if (mbarID != 0) {
1946 #if PREFERS_MENUBAR
1947     GDLWidgetMenuBar* mBar = new GDLWidgetMenuBar(widgetID, e);
1948     mbarID = mBar->GetWidgetID();
1949     mBarIDInOut = mbarID;
1950     wxMenuBar* me = dynamic_cast<wxMenuBar*> (mBar->GetWxWidget());
1951     if (me) topFrame->SetMenuBar(me);
1952     else cerr << "Warning: GDLWidgetBase::GDLWidgetBase: Non-existent menubar widget!\n";
1953 #else
1954     GDLWidgetMenuBar* mBar = new GDLWidgetMenuBar(topFrame, widgetID, e);
1955     mbarID = mBar->GetWidgetID();
1956     mBarIDInOut = mbarID;
1957 #endif
1958   }
1959   wxSizer* tfSizer=new wxBoxSizer(wxVERTICAL);
1960   topFrame->SetSizer(tfSizer);
1961   CreateBase(topFrame); //define widgetPanel, widgetSizer, theWxWidget and theWxContainer.
1962   //it is the FRAME that manage all events. Here we dedicate particularly the tlb_* events:
1963   // note that we have the choice for Size Event Handler for Frames, but need to change also is widgets.cpp
1964   if (eventFlags & GDLWidget::EV_SIZE) this->AddToDesiredEvents(wxEVT_SIZE, gdlSIZE_EVENT_HANDLER, topFrame); //this->AddToDesiredEvents(wxEVT_SIZE, wxSizeEventHandler(GDLFrame::OnSizeWithTimer),topFrame);
1965   if (eventFlags & GDLWidget::EV_MOVE) this->AddToDesiredEvents(wxEVT_MOVE, wxMoveEventHandler(gdlwxFrame::OnMove), topFrame);
1966   if (eventFlags & GDLWidget::EV_ICONIFY) this->AddToDesiredEvents(wxEVT_ICONIZE, wxIconizeEventHandler(gdlwxFrame::OnIconize), topFrame);
1967   if (eventFlags & GDLWidget::EV_KILL) {
1968     this->AddToDesiredEvents(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(gdlwxFrame::OnCloseFrame), topFrame);
1969   } else {
1970     this->AddToDesiredEvents(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(gdlwxFrame::OnUnhandledCloseFrame), topFrame);
1971   }
1972  this->AddToDesiredEvents(wxEVT_SHOW_REQUEST, wxCommandEventHandler(gdlwxFrame::OnShowRequest), topFrame);
1973  this->AddToDesiredEvents(wxEVT_HIDE_REQUEST, wxCommandEventHandler(gdlwxFrame::OnShowRequest), topFrame);
1974  //UPDATE_WINDOW; REALIZE_IF_NEEDED //no use here
1975  //this->Realize(false);
1976 }
1977 
widgetAlignment()1978 inline int GDLWidgetTopBase::widgetAlignment() {
1979     long myAlign = alignment;
1980     //there is no parent for topBase...
1981 //    if (myAlign == gdlwALIGN_NOT) {
1982 //      myAlign = this->GetMyParentBaseWidget()->getChildrenAlignment();
1983 //    }
1984     //wxALIGN_LEFT and TOP is in fact wxALIGN_NOT as this is the default alignment
1985     if (myAlign == gdlwALIGN_NOT) return wxALIGN_CENTER;
1986     //left is top by default and right is bottom. So define left as top and remove top if bottom, etc.
1987     //ignore sets that do not concern the current layout (vetrtical or horizontal)
1988     if (this->IsVertical()) { //col=1 left, center, right
1989       if (myAlign & gdlwALIGN_CENTER) return wxALIGN_CENTER_HORIZONTAL;
1990       if (myAlign & gdlwALIGN_LEFT) return wxALIGN_LEFT;
1991       if (myAlign & gdlwALIGN_RIGHT) return wxALIGN_RIGHT;
1992       if (myAlign & gdlwALIGN_TOP) return wxALIGN_LEFT;
1993       if (myAlign & gdlwALIGN_BOTTOM) return wxALIGN_RIGHT;
1994     } else if (this->IsHorizontal()) { //row=1
1995       if (myAlign & gdlwALIGN_CENTER) return wxALIGN_CENTER_VERTICAL;
1996       if (myAlign & gdlwALIGN_TOP) return wxALIGN_TOP;
1997       if (myAlign & gdlwALIGN_BOTTOM) return wxALIGN_BOTTOM;
1998       if (myAlign & gdlwALIGN_LEFT) return wxALIGN_TOP;
1999       if (myAlign & gdlwALIGN_RIGHT) return wxALIGN_BOTTOM;
2000     }
2001     return 0;
2002   }
2003 
~GDLWidgetTopBase()2004 GDLWidgetTopBase::~GDLWidgetTopBase() {
2005 #ifdef GDL_DEBUG_WIDGETS
2006   std::cout << "~GDLWidgetTopBase(" << widgetID << ")" << std::endl;
2007 #endif
2008   topFrame->NullGDLOwner();
2009 
2010   //IMPORTANT: unxregister TLB if was managed
2011   if (this->GetManaged()) CallEventPro("UNXREGISTER", new DLongGDL(widgetID)); //UNXREGISTER defined in XMANAGER.PRO
2012 
2013   //send RIP
2014   // create GDL event struct
2015   DStructGDL* ev = new DStructGDL("*TOPLEVEL_DESTROYED*");
2016   ev->InitTag("ID", DLongGDL(widgetID));
2017   ev->InitTag("TOP", DLongGDL(widgetID));
2018   ev->InitTag("HANDLER", DLongGDL(0));
2019   if (this->GetXmanagerActiveCommand() || !this->GetManaged()) {
2020     readlineEventQueue.PushFront(ev); // push front (will be handled next)
2021   } else {
2022     eventQueue.PushFront(ev); // push front (will be handled next)
2023   }
2024 }
2025 /*********************************************************/
2026 // Context Menu pseudo-base
2027 /*********************************************************/
GDLWidgetContextBase(WidgetIDT parentID,EnvT * e,ULong eventFlags_,bool mapWid,DLong col,DLong row,int exclusiveMode_,const DString & resource_name,const DString & rname_mbar,const DString & title_,const DString & display_name,int xpad_,int ypad_,DLong x_scroll_size,DLong y_scroll_size,bool grid_layout,long children_alignment,int space_)2028 GDLWidgetContextBase::GDLWidgetContextBase( WidgetIDT parentID, EnvT* e, ULong eventFlags_,
2029 bool mapWid,
2030 DLong col, DLong row,
2031 int exclusiveMode_,
2032 const DString& resource_name, const DString& rname_mbar,
2033 const DString& title_,
2034 const DString& display_name,
2035 int xpad_, int ypad_,
2036 DLong x_scroll_size, DLong y_scroll_size, bool grid_layout, long children_alignment, int space_)
2037 : GDLWidgetMenu(parentID, e, new DStringGDL(title_), eventFlags_, NULL)
2038 {
2039 GDLWidget* gdlParent = GetWidget( parentID );
2040     assert( gdlParent != NULL);
2041     gdlParent->AddToFollowers(widgetID); //very important, the transient must be deleted if the associated widget is deleted!
2042     wxWindow* parentWindow=dynamic_cast<wxWindow*>(gdlParent->GetWxWidget());
2043     assert( parentWindow != NULL);
2044   //get default value: a menu. May be NULL here
2045     wxMenu *menu = new wxMenu();
2046   theWxContainer = menu; //is not a window
2047   theWxWidget = menu;
2048   buttonType = MENU;
2049 
2050 //  UPDATE_WINDOW; REALIZE_IF_NEEDED; //no use (TBC)
2051 }
2052 
~GDLWidgetContextBase()2053 GDLWidgetContextBase::~GDLWidgetContextBase() {
2054 #ifdef GDL_DEBUG_WIDGETS
2055   std::cout << "~GDLWidgetContextBase(" << widgetID << ")" << std::endl;
2056 #endif
2057 }
2058 /*********************************************************/
2059 // Normal WIDGET_BASE but Tab hosted
2060 /*********************************************************/
GDLWidgetTabbedBase(WidgetIDT parentID,EnvT * e,ULong eventFlags_,bool mapWid,DLong col,DLong row,int exclusiveMode_,const DString & resource_name,const DString & rname_mbar,const DString & title_,const DString & display_name,int xpad_,int ypad_,DLong x_scroll_size,DLong y_scroll_size,bool grid_layout,long children_alignment,int space_)2061 GDLWidgetTabbedBase::GDLWidgetTabbedBase(WidgetIDT parentID, EnvT* e, ULong eventFlags_,
2062   bool mapWid,
2063   DLong col, DLong row,
2064   int exclusiveMode_,
2065   const DString& resource_name, const DString& rname_mbar,
2066   const DString& title_,
2067   const DString& display_name,
2068   int xpad_, int ypad_,
2069   DLong x_scroll_size, DLong y_scroll_size, bool grid_layout, long children_alignment, int space_)
2070 : GDLWidgetBase(parentID, e, eventFlags_, mapWid, col, row, exclusiveMode_, resource_name, rname_mbar, title_, display_name, xpad_, ypad_, x_scroll_size, y_scroll_size, grid_layout, children_alignment, space_)
2071 , myPage(-1)
2072 {
2073   //for historical logic reasons, there must be a container panel child of the tab, that will contain the actual widget, a panel.
2074   //the container is a scrolledwindow OR just a panel.
2075   //it would have been simpler to use just a wxScrolled<> for each container, and have it scroll or not depending on GDLWidget::scrolled.
2076   //this would accessorily eliminate the use of 'scrollSizer' and 'scrollPanel'.
2077   //but this has consequences in all the creation/deletion chain, to be done in time.
2078   GDLWidgetTab* parent = static_cast<GDLWidgetTab*> (GetWidget(parentID));
2079   assert(parent != NULL);
2080 
2081   wxNotebook* parentTab = dynamic_cast<wxNotebook*> (parent->GetWxWidget());
2082   assert(parentTab != NULL);
2083 
2084   wxString titleWxString = wxString(title_.c_str(), wxConvUTF8);
2085   wxSizer* sz=new wxBoxSizer(wxVERTICAL);
2086 //  wxPanel* p=new wxPanel(parentTab, wxID_ANY, wxDefaultPosition, wxDefaultSize);
2087 //  p->SetSize(wScrollSize);
2088   if (nrows < 1 && ncols < 1 && frameWidth < 1) frameWidth=1; //set framewidth (temporary) in this case to get good result
2089   CreateBase(parentTab);
2090 //  sz->Add(w,DONOTALLOWSTRETCH, wxALL | wxEXPAND, 0);
2091 //  p->SetSizer(sz);
2092 //  theWxContainer=p;
2093 //
2094 //  theWxWidget = p;
2095   wxWindow* w=static_cast<wxWindow*>(theWxContainer); //defined in CreateBase.
2096   myPage=parentTab->GetPageCount();
2097 //  parentTab->AddPage(w, titleWxString);
2098   parentTab->InsertPage(myPage, w, titleWxString);
2099 //  myPage=parentTab->FindPage(w);
2100 
2101 //  UPDATE_WINDOW
2102   REALIZE_IF_NEEDED
2103 }
2104 /*********************************************************/
2105 // Normal WIDGET_BASE
2106 
2107 /*********************************************************/
GDLWidgetNormalBase(WidgetIDT parentID,EnvT * e,ULong eventFlags_,bool mapWid,DLong col,DLong row,int exclusiveMode_,const DString & resource_name,const DString & rname_mbar,const DString & title_,const DString & display_name,int xpad_,int ypad_,DLong x_scroll_size,DLong y_scroll_size,bool grid_layout,long children_alignment,int space_)2108 GDLWidgetNormalBase::GDLWidgetNormalBase(WidgetIDT parentID, EnvT* e, ULong eventFlags_,
2109   bool mapWid,
2110   DLong col, DLong row,
2111   int exclusiveMode_,
2112   const DString& resource_name, const DString& rname_mbar,
2113   const DString& title_,
2114   const DString& display_name,
2115   int xpad_, int ypad_,
2116   DLong x_scroll_size, DLong y_scroll_size, bool grid_layout, long children_alignment, int space_)
2117 : GDLWidgetBase(parentID, e, eventFlags_, mapWid, col, row, exclusiveMode_, resource_name, rname_mbar, title_, display_name, xpad_, ypad_, x_scroll_size, y_scroll_size, grid_layout, children_alignment, space_) {
2118   // If parent base widget exists ....
2119   GDLWidget* gdlParent = GetWidget(parentID);
2120   assert(gdlParent != NULL);
2121   wxWindow* wxParent = dynamic_cast<wxWindow*> (GetParentPanel());
2122   assert(wxParent != NULL);
2123   CreateBase(wxParent);
2124 
2125 //  UPDATE_WINDOW
2126   REALIZE_IF_NEEDED
2127 }
2128 
GetGeometry(wxRealPoint fact)2129 DStructGDL* GDLWidgetBase::GetGeometry(wxRealPoint fact) {
2130   if (!this->IsRealized()) this->Realize(true, false); //necessary if a geometry request is done previous to the command widget_control,xxx,,/Realize !
2131   int panel_xoff = 0;
2132   int panel_yoff = 0;
2133 
2134   int ixsize = 0, iysize = 0, iscr_xsize = 0, iscr_ysize = 0;
2135   DFloat xsize = 0;
2136   DFloat ysize = 0;
2137   DFloat scr_xsize = 0;
2138   DFloat scr_ysize = 0;
2139   DFloat xoffset = 0;
2140   DFloat yoffset = 0;
2141   DFloat margin = 0;
2142   //reported size includes xpad and ypad.
2143   int ixpad=this->getXPad();
2144   int iypad=this->getYPad();
2145   DStructGDL* ex = new DStructGDL("WIDGET_GEOMETRY");
2146 
2147   wxWindow* w = dynamic_cast<wxWindow*> (theWxContainer);
2148   if (w == NULL) return ex;
2149   if (frameWidth > 0 && (ixpad>0 || iypad >0)) w=w->GetChildren()[0]; //padxpady is the first child of frame
2150   wxRect z = w->GetRect();
2151 
2152   margin=frameWidth;
2153   GDLWidgetBase* container = static_cast<GDLWidgetBase*> (this->GetMyParent());
2154   if (container == NULL) { //TLB
2155 //    w->GetScreenPosition(&panel_xoff, &panel_yoff);
2156     xoffset = panel_xoff+margin;
2157     yoffset = panel_yoff+margin;
2158   } else {
2159     xoffset = z.x+margin;
2160     yoffset = z.y+margin;
2161   }
2162   iscr_xsize = z.width-2*margin;
2163   iscr_ysize = z.height-2*margin;
2164   wxSize s = w->GetClientSize();
2165   ixsize = s.x-2*margin;
2166   iysize = s.y-2*margin;
2167   //size is in pixels, pass in requested units (1.0 default)
2168   xsize = ixsize / fact.x;
2169   ysize = iysize / fact.y;
2170   scr_xsize = iscr_xsize / fact.x;
2171   scr_ysize = iscr_ysize / fact.y;
2172   xoffset /= fact.x;
2173   yoffset /= fact.y;
2174   margin /= fact.x;
2175 
2176   ex->InitTag("XOFFSET", DFloatGDL(xoffset));
2177   ex->InitTag("YOFFSET", DFloatGDL(yoffset));
2178   ex->InitTag("XSIZE", DFloatGDL(xsize));
2179   ex->InitTag("YSIZE", DFloatGDL(ysize));
2180   ex->InitTag("SCR_XSIZE", DFloatGDL(scr_xsize));
2181   ex->InitTag("SCR_YSIZE", DFloatGDL(scr_ysize));
2182   ex->InitTag("MARGIN", DFloatGDL(margin));
2183 
2184   //reported size includes xpad and ypad.
2185   DFloat xpad=ixpad/ fact.x;
2186   DFloat ypad=iypad/ fact.y;
2187   DFloat space=this->getSpace()/ fact.x;
2188   ex->InitTag( "XPAD", DFloatGDL( xpad ) );
2189   ex->InitTag( "YPAD", DFloatGDL( ypad ) );
2190   ex->InitTag( "SPACE", DFloatGDL( space) );
2191   return ex;
2192 }
2193 
2194 //DStructGDL* GDLWidgetBase::GetGeometry(wxRealPoint fact)
2195 //{
2196 //  if (!this->IsRealized()) this->Realize(true,false);//necessary if a geometry request is done previous to the command widget_control,xxx,,/Realize !
2197 //  //the only way to get accurate positions seems to get the screen position of the Panel
2198 //  //in which the window is (the Panel is the useful part of the Base) and substract them from the
2199 //  //screen position of the siwget itself. And get the margin (=frame) size if any.
2200 //  //for Bases, one has also to retrieve xpad,ypad and space;
2201 //  int panel_xoff = 0;
2202 //  int panel_yoff = 0;
2203 //
2204 //  GDLWidgetBase* container = static_cast<GDLWidgetBase*> (this->GetMyParent());
2205 //  if (container != NULL) { //not TLB
2206 //    wxPanel* p = dynamic_cast<wxPanel*> (container->GetPanel());
2207 //    p->GetScreenPosition(&panel_xoff, &panel_yoff);
2208 //  }
2209 //  int ixsize = 0, iysize = 0, iscr_xsize = 0, iscr_ysize = 0;
2210 //  int widget_xoff = 0;
2211 //  int widget_yoff = 0;
2212 //  DFloat xsize = 0;
2213 //  DFloat ysize = 0;
2214 //  DFloat scr_xsize = 0;
2215 //  DFloat scr_ysize = 0;
2216 //  DFloat xoffset = 0;
2217 //  DFloat yoffset = 0;
2218 //  DFloat margin = frameWidth;
2219 //
2220 //  wxWindow* test = dynamic_cast<wxWindow*> (theWxWidget);
2221 //
2222 //  if (test != NULL) {
2223 //    //offsets. easy.
2224 //    test->GetScreenPosition(&widget_xoff, &widget_yoff);
2225 //    xoffset = widget_xoff - panel_xoff;
2226 //    yoffset = widget_yoff - panel_yoff;
2227 //
2228 //    test->GetSize(&iscr_xsize, &iscr_ysize); //contains frame size if framed
2229 //
2230 //    ixsize = iscr_xsize; //with scrollbars, if any, and frames
2231 //    iysize = iscr_ysize;
2232 //
2233 //    //reported size includes xpad and ypad.
2234 //    DFloat xpad=this->getXPad()/ fact.x;
2235 //    DFloat ypad=this->getYPad()/ fact.y;
2236 //    DFloat space=this->getSpace()/ fact.x;
2237 //    //offset is including xpad,ypad
2238 //    xoffset -= xpad;
2239 //    yoffset -= ypad;
2240 //    //size is in pixels, pass in requested units (1.0 default)
2241 //    xsize = ixsize / fact.x + 2*margin;
2242 //    ysize = iysize / fact.y + 2*margin;
2243 //    scr_xsize = iscr_xsize / fact.x;
2244 //    scr_ysize = iscr_ysize / fact.y;
2245 //    xoffset /= fact.x;
2246 //    yoffset /= fact.y;
2247 //    margin /= fact.x;
2248 //  }
2249 //
2250 //  DStructGDL* ex = new DStructGDL("WIDGET_GEOMETRY");
2251 //  ex->InitTag("XOFFSET", DFloatGDL(xoffset));
2252 //  ex->InitTag("YOFFSET", DFloatGDL(yoffset));
2253 //  ex->InitTag("XSIZE", DFloatGDL(xsize));
2254 //  ex->InitTag("YSIZE", DFloatGDL(ysize));
2255 //  ex->InitTag("SCR_XSIZE", DFloatGDL(scr_xsize));
2256 //  ex->InitTag("SCR_YSIZE", DFloatGDL(scr_ysize));
2257 //  ex->InitTag("MARGIN", DFloatGDL(margin));
2258 //  ex->InitTag( "XPAD", DFloatGDL( xpad ) );
2259 //  ex->InitTag( "YPAD", DFloatGDL( ypad ) );
2260 //  ex->InitTag( "SPACE", DFloatGDL( space) );
2261 //  return ex;
2262 //}
2263 
2264 //// called from event handling thread
2265 //// sends a destroy event for itself
2266 //void GDLWidgetTopBase::SelfDestroy()
2267 //{
2268 //  assert( parentID == NullID );
2269 //  // create GDL event struct
2270 //  DStructGDL* ev = new DStructGDL( "*WIDGET_DESTROY*" );
2271 //  ev->InitTag( "ID", DLongGDL( widgetID ) );
2272 //  ev->InitTag( "TOP", DLongGDL( widgetID ) );
2273 //  ev->InitTag( "HANDLER", DLongGDL( 0 ) );
2274 //  if ( this->GetXmanagerActiveCommand( ) || !this->GetManaged() ){
2275 //    readlineEventQueue.PushFront( ev ); // push front (will be handled next)
2276 //  } else {
2277 //    eventQueue.PushFront( ev ); // push front (will be handled next)
2278 //  }
2279 //}
2280 
mapBase(bool val)2281   void GDLWidgetBase::mapBase(bool val){
2282     wxWindow* me=dynamic_cast<wxWindow*>(theWxContainer);
2283     if (me) me->Show(val); else {cerr<<"Warning: GDLWidgetBase::mapBase(): Non-existent widget!\n"; return;}
2284   }
mapBase(bool val)2285   void GDLWidgetTopBase::mapBase(bool val){
2286     topFrame->Show(val);
2287   }
mapBase(bool val)2288   void GDLWidgetTabbedBase::mapBase(bool val){
2289     //Note: it is impossible to reproduce the IDL behaviour (tab is present but void) with wxWidgets unless doing ridiculously complicated things.
2290     wxWindow* me=dynamic_cast<wxWindow*>(theWxContainer);
2291     if (me) me->Show(val); else {cerr<<"Warning: GDLWidgetTabbedBase::mapBase(): Non-existent widget!\n"; return;}
2292   }
2293   // Order in which widgets are plotted is different btw wxWindow and IDL if one does not do the following tricks:
DoReorderColWidgets(int code,int style,int border)2294   void GDLWidgetBase::DoReorderColWidgets(int code,int style, int border) {
2295   int nchild = this->NChildren();
2296   //get children list...
2297   DLongGDL* gdlwList= GetChildrenList();
2298   // set up window list, get existing code, style and border for each of the children
2299   std::vector<int> proportionlist;
2300   std::vector<wxWindow*> windowlist;
2301   std::vector<int> flaglist;
2302   std::vector<int> borderlist;
2303   for (int i = 0; i < nchild; ++i) {
2304     GDLWidget* g=GetWidget((*gdlwList)[i]);
2305     wxWindow* w=static_cast<wxWindow*>(g->GetWxContainer());
2306     windowlist.push_back(w);
2307     wxSizerItem* s=widgetSizer->GetItem(w);
2308     if (s==NULL) { //this is a new window that has not yet been added (the widget is Realized) : use passed values
2309       proportionlist.push_back(code);
2310       flaglist.push_back(style);
2311       borderlist.push_back(border);
2312     } else { //use existing values
2313       proportionlist.push_back(s->GetProportion());
2314       flaglist.push_back(s->GetFlag());
2315       borderlist.push_back(s->GetBorder());
2316     }
2317   }
2318   GDLDelete(gdlwList);
2319 
2320   //compute new positions (align items along column 1, then 2 etc... when wxWidget will insert them col1,col2,col1,col2, etc..)
2321   int local_nchild=nchild;
2322   // method for COL=n , row is growing
2323   //This should be called only for /COL => nrows is 0
2324   int local_ncols = ncols;
2325   int local_nrows = local_nchild / local_ncols;
2326   if (local_nrows * local_ncols < local_nchild) local_nrows++;
2327   //how many filled cols?
2328   int reste = (local_ncols * local_nrows) - local_nchild;
2329   int filledcols = local_ncols - reste;
2330 
2331   //we create the corresponding flexigridsizer, destroy the previous one, assign back to widgetSizer
2332   wxFlexGridSizer* newWidgetSizer = new wxFlexGridSizer(local_nrows, local_ncols, border, border);
2333   widgetPanel->SetSizer(newWidgetSizer, true);
2334   widgetPanel->SetAutoLayout(true);
2335   if (grid) {
2336     newWidgetSizer->SetFlexibleDirection(wxHORIZONTAL);
2337     newWidgetSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL);
2338   }
2339   widgetSizer = newWidgetSizer;
2340 
2341   //so the first 'filledcols' will be filled, the rest will have (apparently) one row less.
2342   //we have to insert a place holder in the list of childrens at each index corresponding to the last row, starting at the first incomplete column.
2343   //widgets indexes are k=icol*local_nrows+jrow, compute a new indexlist where empty indexes are those jumped
2344 
2345 
2346   int list[local_ncols * local_nrows];
2347   int i = 0;
2348   int k = 0;
2349   int avoidrow = (reste == 0) ? local_nrows : local_nrows - 1;
2350   int lastfilledcol = (reste == 0) ? local_ncols : filledcols - 1;
2351   //  list of indexes as displayed in colums (idl) with -1 when there should be a void.
2352   for (int icol = 0; icol < local_ncols; icol++) {
2353     for (int jrow = 0; jrow < local_nrows; jrow++) {
2354       if ((icol > lastfilledcol) && (jrow == avoidrow)) {
2355         list[k++] = -1;
2356       } else {
2357         list[k++] = i++;
2358       }
2359     }
2360   }
2361 
2362   //find transposed values: read list in transposed order, use a local_nrows stride.
2363   int stride = local_nrows;
2364   int outer_stride = local_ncols*local_nrows;
2365   for (k = 0, i = 0; i < nchild; ++i) {
2366     widgetSizer->Add(windowlist[list[k]], proportionlist[list[k]],flaglist[list[k]],borderlist[list[k]]);
2367     k += stride;
2368     if (k >= outer_stride) {
2369       k -= outer_stride;
2370       k++;
2371     }
2372   }
2373 }
2374 
ReorderWidgets()2375 void GDLWidgetBase::ReorderWidgets()
2376 {
2377   // NULL widget Sizer means 1) no row no col was asked for (so, no sizer) or, if col>1, we have to create the sizer here and add children in specific order.
2378   // do *not* forget to give back the sizer pointer instead of the previous NULL to the base widget!
2379   if (widgetSizer == NULL) return;
2380   if (ncols > 1) DoReorderColWidgets(0,0,space); //need to reorder widget for /COL only
2381 }
2382 
ReorderForANewWidget(wxWindow * w,int code,int style,int border)2383 void GDLWidgetBase::ReorderForANewWidget(wxWindow* w, int code,int style, int border)
2384 {
2385   if (widgetSizer == NULL) return;
2386   if (ncols > 1 ) DoReorderColWidgets(code, style, border); //need to reorder widget for /COL only
2387   else widgetSizer->Add(w, code, style, border ); // just add widget in sizer for /ROW
2388 }
2389 /*********************************************************/
2390 // for WIDGET_TAB
2391 /*********************************************************/
GDLWidgetTab(WidgetIDT p,EnvT * e,ULong eventFlags_,DLong location,DLong multiline)2392 GDLWidgetTab::GDLWidgetTab( WidgetIDT p, EnvT* e, ULong eventFlags_, DLong location, DLong multiline )
2393 : GDLWidgetContainer( p, e, eventFlags_ ) {
2394 
2395   scrolled=false; //TAB has no Scrolled.
2396 
2397 //  GDLWidget* gdlParent = GetWidget( parentID );
2398 //  widgetPanel =  GetParentPanel( );
2399 
2400   wxSizer* parentSizer = GetParentSizer( );
2401 
2402   long style = wxNB_TOP;
2403   if ( location == 1 ) style = wxNB_BOTTOM;
2404   if ( location == 2 ) style = wxNB_LEFT;
2405   if ( location == 3 ) style = wxNB_RIGHT;
2406 
2407   if ( multiline != 0 )
2408     style |= wxNB_MULTILINE; //works only for WINDOWS.
2409 
2410   wxPanel* panel_if_framed;
2411   wxPanel* container=widgetPanel; //default container if no intervening panels
2412   wxSizer* framesizer=NULL;
2413   wxNotebook * notebook;
2414   if (frameWidth>0) { //frame
2415     panel_if_framed=new wxPanel(container, wxID_ANY, wOffset, wxDefaultSize, gdlBORDER_EXT);
2416     theWxContainer =  panel_if_framed;
2417     framesizer=new wxBoxSizer(wxVERTICAL);
2418     panel_if_framed->SetSizer(framesizer);
2419     container=panel_if_framed; //becomes container for further widgets
2420     if (parentSizer) parentSizer->Add(container, DONOTALLOWSTRETCH, widgetAlignment(),gdlFRAME_MARGIN); //add to parent sizer
2421     notebook = new wxNotebook( container, widgetID, wxDefaultPosition, computeWidgetSize( ), style );
2422     theWxWidget = notebook;
2423     framesizer->Add(notebook,DONOTALLOWSTRETCH,wxALL,frameWidth);
2424   } else {
2425     notebook = new wxNotebook( container, widgetID, wOffset, computeWidgetSize( ), style );
2426     theWxContainer = theWxWidget = notebook;
2427     if (parentSizer) parentSizer->Add(notebook,DONOTALLOWSTRETCH,widgetAlignment()|wxALL, gdlSPACE);
2428   }
2429   //wxNotebook DOES NOT USE a sizer.
2430   this->AddToDesiredEvents(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,wxNotebookEventHandler(gdlwxFrame::OnPageChanged),notebook);
2431 }
~GDLWidgetTab()2432 GDLWidgetTab::~GDLWidgetTab() {
2433 #ifdef GDL_DEBUG_WIDGETS
2434   std::cout << "~GDLWidgetTab(" << widgetID << ")" << std::endl;
2435 #endif
2436 }
2437 
GetTabNumber()2438 BaseGDL* GDLWidgetTab::GetTabNumber(){
2439   wxNotebook * notebook=dynamic_cast<wxNotebook*>(theWxWidget);
2440   assert( notebook != NULL);
2441   return new DIntGDL(notebook->GetPageCount());
2442 }
2443 
GetTabCurrent()2444 BaseGDL* GDLWidgetTab::GetTabCurrent(){
2445   wxNotebook * notebook=dynamic_cast<wxNotebook*>(theWxWidget);
2446   assert( notebook != NULL);
2447   return new DIntGDL(notebook->GetSelection());
2448 }
2449 
SetTabCurrent(int val)2450 void GDLWidgetTab::SetTabCurrent(int val){
2451   wxNotebook * notebook=dynamic_cast<wxNotebook*>(theWxWidget);
2452   assert( notebook != NULL);
2453   if (val<notebook->GetPageCount()){
2454 //   notebook->GetPage(val)->Raise();
2455    notebook->ChangeSelection(val);
2456   }
2457 }
2458 
GetTabMultiline()2459 BaseGDL* GDLWidgetTab::GetTabMultiline(){
2460   wxNotebook * notebook=dynamic_cast<wxNotebook*>(theWxWidget);
2461   assert( notebook != NULL);
2462   return new DIntGDL(notebook->GetExtraStyle()&wxNB_MULTILINE);
2463 }
2464 
2465 
2466 /*********************************************************/
2467 // for WIDGET_TABLE
2468 /*********************************************************/
2469 //overrides method to label the columns & lines
GetRowLabelValue(int row)2470   wxString wxGridTableBase::GetRowLabelValue( int row )
2471 {
2472     wxString s;
2473 
2474     // RD: Starting the rows at zero confuses users,
2475     // no matter how much it makes sense to us geeks.
2476     // GD: So IDL and GDL are for geeks.
2477     s << row ;
2478 
2479     return s;
2480 }
GetColLabelValue(int col)2481   wxString wxGridTableBase::GetColLabelValue( int col )
2482 {
2483     wxString s;
2484     s << col ;
2485 
2486     return s;
2487 }
2488 
GDLWidgetTable(WidgetIDT p,EnvT * e,DByteGDL * alignment_,DStringGDL * amPm_,DByteGDL * backgroundColor_,DByteGDL * foregroundColor_,DStringGDL * columnLabels_,int majority_,DLongGDL * columnWidth_,DStringGDL * daysOfWeek_,bool disjointSelection_,DByteGDL * editable_,DStringGDL * format_,DStringGDL * month_,bool noColumnHeaders_,bool noRowHeaders_,bool resizeableColumns_,bool resizeableRows_,DLongGDL * rowHeights_,DStringGDL * rowLabels_,BaseGDL * value_,DLong xScrollSize_,DLong yScrollSize_,DStringGDL * valueAsStrings_,DULong eventFlags_)2489 GDLWidgetTable::GDLWidgetTable( WidgetIDT p, EnvT* e,
2490 DByteGDL* alignment_,
2491 DStringGDL* amPm_,
2492 DByteGDL* backgroundColor_,
2493 DByteGDL* foregroundColor_,
2494 DStringGDL* columnLabels_,
2495 int majority_,
2496 DLongGDL* columnWidth_,
2497 DStringGDL* daysOfWeek_,
2498 bool disjointSelection_,
2499 DByteGDL* editable_,
2500 DStringGDL* format_,
2501 //bool ignoreAccelerators_,
2502 DStringGDL* month_,
2503 bool noColumnHeaders_,
2504 bool noRowHeaders_,
2505 bool resizeableColumns_,
2506 bool resizeableRows_,
2507 DLongGDL* rowHeights_,
2508 DStringGDL* rowLabels_,
2509 //DLong tabMode_,
2510 BaseGDL* value_,
2511 DLong xScrollSize_,
2512 DLong yScrollSize_,
2513 DStringGDL* valueAsStrings_,
2514 DULong eventFlags_
2515 )
2516 : GDLWidget( p, e, value_, eventFlags_ )
2517 , table_alignment( alignment_ )
2518 , amPm( amPm_ )
2519 , backgroundColor( backgroundColor_ )
2520 , foregroundColor( foregroundColor_ )
2521 , columnLabels( columnLabels_ )
2522 , majority ( majority_ )
2523 , columnWidth( columnWidth_ )
2524 , daysOfWeek( daysOfWeek_ )
2525 , disjointSelection( disjointSelection_ )
2526 , editable( editable_)
2527 , format( format_ )
2528 //, ignoreAccelerators( ignoreAccelerators_ )
2529 , month( month_ )
2530 , noColumnHeaders( noColumnHeaders_ )
2531 , noRowHeaders( noRowHeaders_ )
2532 , resizeableColumns( resizeableColumns_ )
2533 , resizeableRows( resizeableRows_ )
2534 , rowHeights( rowHeights_ )
2535 , rowLabels( rowLabels_ )
2536 //, tabMode( tabMode_ )
2537 , x_scroll_size( xScrollSize_ )
2538 , y_scroll_size( yScrollSize_)
2539 , valueAsStrings( valueAsStrings_ )
2540 , updating(false)
2541 {
2542   GDLWidget* gdlParent = GetWidget( parentID );
2543   widgetPanel = GetParentPanel( );
2544   widgetSizer = GetParentSizer( );
2545 
2546   //due to subtle problems in the absence of a frame around, a 0 or negative frame becomes a frame=1
2547 //  if (frameWidth <1) frameWidth=1;
2548 
2549   START_ADD_EVENTUAL_FRAME
2550 
2551   widgetStyle=widgetAlignment();
2552 
2553 //at this stage, valueAsStrings is OK dim 1 or 2 BUT vVALUE MAY BE NULL!
2554 SizeT numRows,numCols;
2555 if (valueAsStrings->Rank()==1) {
2556   numRows=1;
2557   numCols=valueAsStrings->Dim(0); //lines
2558 } else {
2559   numRows=valueAsStrings->Dim(1);
2560   numCols=valueAsStrings->Dim(0);
2561 }
2562 SizeT grid_nrows=(wSize.y<=0)?numRows:wSize.y;
2563 SizeT grid_ncols=(wSize.x<=0)?numCols:wSize.x;
2564 
2565   wxGridGDL *grid = new wxGridGDL( widgetPanel, widgetID, wxDefaultPosition, wxDefaultSize);
2566 //important:set wxWidget here. (fonts)
2567   theWxContainer = theWxWidget = grid;
2568 // important: use adapted font for further sizes & shapes. Define font for labels AND  cells.
2569   this->setFont();
2570  //Column Width Before creating
2571 bool hasColumnWidth=(columnWidth!=NULL);
2572 if (hasColumnWidth) { //one value set for all?
2573   if (columnWidth->N_Elements()==1) {
2574     grid->SetDefaultColSize((*columnWidth)[0]*unitConversionFactor.x) ;
2575     hasColumnWidth=false;
2576   }
2577 }
2578 //RowHeight
2579 bool hasRowHeights=(rowHeights!=NULL);
2580 if (hasRowHeights) { //one value set for all?
2581   if (rowHeights->N_Elements()==1) {
2582     grid->SetDefaultRowSize((*rowHeights)[0]*unitConversionFactor.y) ;
2583     hasRowHeights=false;
2584   }
2585 }
2586 //Alignment
2587 bool hasAlignment=(table_alignment!=NULL);
2588 if (hasAlignment) {
2589   if (table_alignment->N_Elements()==1) { //singleton case
2590     switch( (*table_alignment)[0] ){
2591       case 0:
2592         grid->SetDefaultCellAlignment(wxALIGN_LEFT,wxALIGN_CENTRE); break;
2593       case 1:
2594         grid->SetDefaultCellAlignment(wxALIGN_CENTRE,wxALIGN_CENTRE); break;
2595       case 2:
2596         grid->SetDefaultCellAlignment(wxALIGN_RIGHT,wxALIGN_CENTRE);
2597     }
2598     hasAlignment=false; //otherwise will be treated cell by cell below!
2599   }
2600 }
2601 //General Editability
2602 bool isEditable=(editable!=NULL);
2603 if (isEditable) {
2604   if (editable->N_Elements()==1) { //singleton case
2605     if ((*editable)[0]==0) isEditable=false;
2606     else {grid->EnableEditing(true); isEditable=false;}
2607   }
2608 } else grid->EnableEditing(false);
2609 if (isEditable) grid->EnableEditing(true); //since now isEditable means "individually editable", which needs global editing set.
2610 //Single Background Colour
2611 bool isBackgroundColored=(backgroundColor!=NULL);
2612 if (isBackgroundColored) { //one value set for all?
2613   if (backgroundColor->N_Elements()==3) {
2614     grid->SetDefaultCellBackgroundColour(wxColour((*backgroundColor)[0],(*backgroundColor)[1],(*backgroundColor)[2])) ;
2615     isBackgroundColored=false;
2616   }
2617 }
2618 //Single Text Colour
2619 bool isForegroundColored=(foregroundColor!=NULL);
2620 if (isForegroundColored) { //one value set for all?
2621   if (foregroundColor->N_Elements()==3) {
2622     grid->SetDefaultCellTextColour(wxColour((*foregroundColor)[0],(*foregroundColor)[1],(*foregroundColor)[2])) ;
2623     isForegroundColored=false;
2624   }
2625 }
2626 //No column Headers
2627 if (noColumnHeaders) grid->SetColLabelSize(0);
2628 //No row Headers
2629 if (noRowHeaders) grid->SetRowLabelSize(0);
2630 //end General Setup
2631 int selmode = wxGrid::wxGridSelectCells; //wxWidgets's modes do not reflect IDL's. We trick the selections according to modes in eventhandler.
2632 if (!resizeableColumns) grid->DisableDragColSize();
2633 if (!resizeableRows) grid->DisableDragRowSize();
2634 grid->CreateGrid( grid_nrows, grid_ncols, static_cast<wxGrid::wxGridSelectionModes>(selmode));
2635 // Set grid cell contents as strings. Note that there may be less or more cells than valueAsStrings, due to possibly different wSize.x,wSize.y :
2636 
2637       for ( int ival=0, i=0; i<grid_nrows; ++i, ++ival) for (int jval=0, j=0; j<grid_ncols; ++j, ++jval)
2638       {
2639         if (ival < numRows && jval < numCols ) {
2640           StrTrim((*valueAsStrings)[jval*numRows+ival]);
2641           grid->SetCellValue( i, j ,wxString(((*valueAsStrings)[jval*numRows+ival]).c_str(), wxConvUTF8 ) );
2642         }
2643       }
2644 
2645 //Editability
2646 //take too long as soon as table has a more than a few elements. Fixme!
2647 //if (isEditable) {SizeT k=0; for (SizeT irow=0; irow< grid_nrows; ++irow) for (SizeT icol=0; icol< grid_ncols; ++icol) {grid->SetReadOnly( irow, icol, ((*editable)[k%editable->N_Elements()]==0));++k;}}
2648 //colors per element
2649 if (isBackgroundColored) this->DoBackgroundColor();
2650 if (isForegroundColored) this->DoForegroundColor();
2651 if (hasColumnWidth) this->DoColumnWidth();
2652 if (hasRowHeights) this->DoRowHeights();
2653 //treat other alignment cases.
2654 if (hasAlignment) this->DoAlign();
2655 
2656 if (columnLabels!=NULL)this->DoColumnLabels();
2657 if (rowLabels!=NULL) this->DoRowLabels();
2658 
2659 //get back on sizes. Do we enforce some size or scroll_size, in columns/rows:
2660 int currentColLabelHeight = grid->GetColLabelSize();
2661 int currentRowLabelWidth = grid->GetRowLabelSize();
2662 
2663 int fullsizex=currentRowLabelWidth;
2664 int fullsizey=currentColLabelHeight;
2665 for (SizeT i=0; i< numCols ; ++i) fullsizex+=(i<grid_ncols)?grid->GetColSize(i):grid->GetDefaultColSize();
2666 for (SizeT j=0; j< numRows ; ++j) fullsizey+=(j<grid_nrows)?grid->GetRowHeight(j):grid->GetDefaultRowSize();
2667 
2668 int visiblesizex=currentRowLabelWidth;
2669 int visiblesizey=currentColLabelHeight;
2670 for (SizeT i=0; i< grid_ncols ; ++i) visiblesizex+=grid->GetColSize(i);
2671 for (SizeT j=0; j< grid_nrows ; ++j) visiblesizey+=grid->GetRowHeight(j);
2672 
2673 int sizex=-1;
2674 int sizey=-1;
2675 int scr_sizex=-1;
2676 int scr_sizey=-1;
2677   if ( wSize.x > 0 ) { sizex = visiblesizex; //size in columns given
2678   } else {sizex=fullsizex;}
2679   if ( wSize.y > 0 ) { sizey = visiblesizey; //size in rows given
2680   } else {sizey=fullsizey;}
2681   if ( x_scroll_size > 0 ) { //scroll size is in columns
2682     scrolled=true;
2683     scr_sizex=currentRowLabelWidth+gdlSCROLL_HEIGHT_X;
2684     for (SizeT i=0; i< x_scroll_size ; ++i) scr_sizex+=grid->GetColSize(i);
2685     scr_sizex=min(scr_sizex,fullsizex);
2686     if (y_scroll_size <=0) y_scroll_size=x_scroll_size;
2687   }
2688   if ( y_scroll_size > 0 ) { //rows
2689     scrolled=true;
2690     scr_sizey=currentColLabelHeight+gdlSCROLL_WIDTH_Y;
2691     for (SizeT j=0; j< y_scroll_size ; ++j) scr_sizey+=grid->GetRowHeight(j);
2692     scr_sizey=min(scr_sizey,fullsizey);
2693   }
2694 //fix size if relevant
2695 if (scrolled && scr_sizex == -1) scr_sizex = (sizex>0)?sizex:fullsizex;
2696 if (scrolled && scr_sizey == -1) scr_sizey = (sizey>0)?sizey:fullsizey;
2697 //wScrXSize etc to be considered since sizes are not in pixels:
2698 if (wScreenSize.x>0) {scr_sizex=wScreenSize.x; scrolled=true;}
2699 if (wScreenSize.y>0) {scr_sizey=wScreenSize.y; scrolled=true;}
2700 //wxGrid IS a scrolled window
2701 if (scrolled) {
2702   grid->ShowScrollbars(wxSHOW_SB_ALWAYS,wxSHOW_SB_ALWAYS);
2703   grid->SetInitialSize(wxSize(scr_sizex, scr_sizey));
2704 } else {
2705   if (wSize.x>0||wSize.y>0) {
2706     grid->SetInitialSize(wxSize(sizex,sizey));
2707 }
2708 }
2709 grid->SetScrollLineX(grid->GetColSize(0));
2710 grid->SetScrollLineY(grid->GetRowHeight(0));
2711 
2712 END_ADD_EVENTUAL_FRAME
2713 TIDY_WIDGET(gdlBORDER_SPACE);
2714 
2715       this->AddToDesiredEvents( wxEVT_GRID_COL_SIZE,wxGridSizeEventHandler(wxGridGDL::OnTableColResizing),grid);
2716       this->AddToDesiredEvents( wxEVT_GRID_ROW_SIZE,wxGridSizeEventHandler(wxGridGDL::OnTableRowResizing),grid);
2717       this->AddToDesiredEvents( wxEVT_GRID_RANGE_SELECT,wxGridRangeSelectEventHandler(wxGridGDL::OnTableRangeSelection),grid);
2718       this->AddToDesiredEvents( wxEVT_GRID_SELECT_CELL,wxGridEventHandler(wxGridGDL::OnTableCellSelection),grid);
2719 //      this->AddToDesiredEvents( wxEVT_GRID_CELL_LEFT_CLICK,wxGridEventHandler(wxGridGDL::OnTableCellSelection),grid);
2720 
2721 // UPDATE_WINDOW
2722  REALIZE_IF_NEEDED
2723 }
2724 
IsSomethingSelected()2725 bool GDLWidgetTable::IsSomethingSelected(){
2726   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
2727   assert( grid != NULL);
2728   return grid->IsSomethingSelected();
2729 }
2730 
GetSelection()2731 DLongGDL* GDLWidgetTable::GetSelection( ) {
2732   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
2733   assert( grid != NULL);
2734   SizeT k = 0;
2735   DLongGDL * sel;
2736   std::vector<wxPoint> list = grid->GetSelectedDisjointCellsList( );
2737   if ( disjointSelection ) { //pairs lists
2738     if ( list.size( ) < 1 ) {sel = new DLongGDL( 2, BaseGDL::ZERO ); sel->Dec(); return sel;} //returns [-1,-1] if nothing selected
2739     SizeT dims[2];
2740     dims[0] = 2;
2741     dims[1] = list.size( );
2742     dimension dim( dims, 2 );
2743     sel = new DLongGDL( dim );
2744     for ( std::vector<wxPoint>::iterator it = list.begin( ); it != list.end( ); ++it ) {
2745       (*sel)[k++] = (*it).y;
2746       (*sel)[k++] = (*it).x;
2747     }
2748   } else { //4 values
2749     wxGridCellCoordsArray selectionTL = grid->GetSelectionBlockTopLeft( );
2750     wxGridCellCoordsArray selectionBR = grid->GetSelectionBlockBottomRight( );
2751     sel = new DLongGDL( 4, BaseGDL::ZERO ); sel->Dec(); //will return [-1,-1,-1,-1] if nothing selected
2752     if (!selectionTL.IsEmpty() && !selectionBR.IsEmpty()){ //ok with a block...
2753       //LEFT TOP BOTTOM RIGHT
2754       (*sel)[0] = selectionTL[0].GetCol( );
2755       (*sel)[1] = selectionTL[0].GetRow( );
2756       (*sel)[2] = selectionBR[0].GetCol( );
2757       (*sel)[3] = selectionBR[0].GetRow( );
2758     } else {
2759       //try columns, rows, and singletons
2760       wxArrayInt selectionRow=grid->GetSelectedRows();
2761       wxArrayInt selectionCol=grid->GetSelectedCols();
2762       if ( selectionRow.GetCount() >0 ) {
2763         (*sel)[0] = 0;
2764         (*sel)[1] = selectionRow[0];
2765         (*sel)[2] = grid->GetNumberCols()-1;
2766         (*sel)[3] = selectionRow[selectionRow.GetCount()-1];
2767       } else if ( selectionCol.GetCount() >0 ) {
2768         (*sel)[0] = selectionCol[0];
2769         (*sel)[1] = 0;
2770         (*sel)[2] = selectionCol[selectionCol.GetCount()-1];
2771         (*sel)[3] = grid->GetNumberRows()-1;
2772       } else {
2773         wxGridCellCoordsArray cellSelection = grid->GetSelectedCells( );
2774         if (cellSelection.size()>0) {
2775          int row = cellSelection[0].GetRow();
2776          int col = cellSelection[0].GetCol();
2777         (*sel)[0] = col;
2778         (*sel)[1] = row;
2779         (*sel)[2] = col;
2780         (*sel)[3] = row;
2781         }
2782       }
2783       return sel;
2784     }
2785 
2786   }
2787   return sel;
2788 }
2789 
ClearSelection()2790 void GDLWidgetTable::ClearSelection()
2791 {
2792   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
2793   assert( grid != NULL);
2794   updating=true;
2795   grid->ClearSelection();
2796   updating=false;
2797 }
2798 
DoAlign()2799 void GDLWidgetTable::DoAlign() {
2800   if (table_alignment->N_Elements( )==0) {return;}
2801   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
2802   assert( grid != NULL);
2803   int nRows = grid->GetNumberRows( );
2804   int nCols = grid->GetNumberCols( );
2805   SizeT k = 0;
2806   grid->BeginBatch();
2807   for ( SizeT i = 0; i < nRows; ++i ) {
2808     for ( SizeT j = 0; j < nCols; ++j ) {
2809       switch ( (*table_alignment)[k % table_alignment->N_Elements( )] ) {
2810         case 0:
2811           grid->SetCellAlignment( i, j, wxALIGN_LEFT, wxALIGN_CENTRE );
2812           break;
2813         case 1:
2814           grid->SetCellAlignment( i, j, wxALIGN_CENTRE, wxALIGN_CENTRE );
2815           break;
2816         case 2:
2817           grid->SetCellAlignment( i, j, wxALIGN_RIGHT, wxALIGN_CENTRE );
2818       }
2819       k++;
2820       if ( table_alignment->N_Elements( ) > 1 ) if ( k == table_alignment->N_Elements( ) ) break;
2821     }
2822     if ( table_alignment->N_Elements( ) > 1 ) if ( k == table_alignment->N_Elements( ) ) break;
2823   }
2824   grid->EndBatch();
2825 }
2826 
DoAlign(DLongGDL * selection)2827 void GDLWidgetTable::DoAlign(DLongGDL* selection) {
2828   if (table_alignment->N_Elements( )==0) {return;}
2829   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
2830   assert( grid != NULL);
2831   SizeT k = 0;
2832   grid->BeginBatch();
2833   if (selection->Rank()==0) { //use current wxWidgets selection
2834    std::vector<wxPoint> list=grid->GetSelectedDisjointCellsList();
2835    for ( std::vector<wxPoint>::iterator it = list.begin(); it !=list.end(); ++it) {
2836      int ali;
2837       switch ( (*table_alignment)[k % table_alignment->N_Elements( )] ) {
2838         case 0:
2839           ali = wxALIGN_LEFT;
2840           break;
2841         case 1:
2842           ali = wxALIGN_CENTRE;
2843           break;
2844         case 2:
2845           ali = wxALIGN_RIGHT;
2846       }
2847       grid->SetCellAlignment( (*it).x, (*it).y, ali, wxALIGN_CENTRE );
2848       k++;
2849     }
2850   } else { //use the passed selection, mode-dependent:
2851     if (disjointSelection) { //pairs lists
2852       for (SizeT n=0,l=0; n<selection->Dim(1); ++n) {
2853         int col = (*selection)[l++];
2854         int row = (*selection)[l++];
2855         int ali;
2856         switch ( (*table_alignment)[k % table_alignment->N_Elements( )] ) {
2857           case 0:
2858             ali = wxALIGN_LEFT;
2859             break;
2860           case 1:
2861             ali = wxALIGN_CENTRE;
2862             break;
2863           case 2:
2864             ali = wxALIGN_RIGHT;
2865         }
2866         grid->SetCellAlignment( row, col, ali, wxALIGN_CENTRE );
2867         k++;
2868       }
2869     }else{ //4 values
2870      int colTL = (*selection)[0];
2871      int rowTL = (*selection)[1];
2872      int colBR = (*selection)[2];
2873      int rowBR = (*selection)[3];
2874      for ( int i=rowTL; i<=rowBR; ++i) for (int j=colTL; j<=colBR; ++j)
2875      {
2876         int ali;
2877         switch ( (*table_alignment)[k % table_alignment->N_Elements( )] ) {
2878           case 0:
2879             ali = wxALIGN_LEFT;
2880             break;
2881           case 1:
2882             ali = wxALIGN_CENTRE;
2883             break;
2884           case 2:
2885             ali = wxALIGN_RIGHT;
2886         }
2887         grid->SetCellAlignment( i, j, ali, wxALIGN_CENTRE );
2888         k++;
2889      }
2890     }
2891   }
2892   grid->EndBatch();
2893 
2894 }
2895 
DoBackgroundColor()2896 void GDLWidgetTable::DoBackgroundColor() {
2897   SizeT nbColors=backgroundColor->N_Elements( );
2898   if (nbColors==0) {return;}
2899   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
2900   assert( grid != NULL);
2901   int nRows = grid->GetNumberRows( );
2902   int nCols = grid->GetNumberCols( );
2903   SizeT k=0;
2904   grid->BeginBatch();
2905   for (SizeT i=0; i< nRows; ++i) for (SizeT j=0; j< nCols; ++j) //Row by Row, from top.
2906   {
2907    grid->SetCellBackgroundColour( i, j, wxColour((*backgroundColor)[k%nbColors],(*backgroundColor)[k%nbColors+1],(*backgroundColor)[k%nbColors+2]));
2908    k+=3;
2909   }
2910   grid->EndBatch();
2911 
2912 }
DoBackgroundColor(DLongGDL * selection)2913 void GDLWidgetTable::DoBackgroundColor(DLongGDL* selection) {
2914   SizeT nbColors=backgroundColor->N_Elements( );
2915   if (nbColors==0) {return;}
2916   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
2917   assert( grid != NULL);
2918   grid->BeginBatch();
2919 
2920   SizeT k=0;
2921 
2922   if (selection->Rank()==0) { //use current wxWidgets selection
2923    std::vector<wxPoint> list=grid->GetSelectedDisjointCellsList();
2924    for ( std::vector<wxPoint>::iterator it = list.begin(); it !=list.end(); ++it) {
2925     grid->SetCellBackgroundColour( (*it).x, (*it).y, wxColour((*backgroundColor)[k%nbColors],(*backgroundColor)[k%nbColors+1],(*backgroundColor)[k%nbColors+2]));
2926     k+=3;
2927     }
2928   } else { //use the passed selection, mode-dependent:
2929     if (disjointSelection) { //pairs lists
2930       for (SizeT n=0,l=0; n<selection->Dim(1); ++n) {
2931         int col = (*selection)[l++];
2932         int row = (*selection)[l++];
2933         grid->SetCellBackgroundColour( row, col, wxColour((*backgroundColor)[k%nbColors],(*backgroundColor)[k%nbColors+1],(*backgroundColor)[k%nbColors+2]));
2934         k+=3;
2935       }
2936     }else{ //4 values
2937      int colTL = (*selection)[0];
2938      int rowTL = (*selection)[1];
2939      int colBR = (*selection)[2];
2940      int rowBR = (*selection)[3];
2941      for ( int i=rowTL; i<=rowBR; ++i) for (int j=colTL; j<=colBR; ++j)
2942      {
2943        grid->SetCellBackgroundColour( i, j, wxColour((*backgroundColor)[k%nbColors],(*backgroundColor)[k%nbColors+1],(*backgroundColor)[k%nbColors+2]));
2944        k+=3;
2945      }
2946     }
2947   }
2948 
2949   grid->EndBatch();
2950 
2951 }
2952 
DoForegroundColor()2953 void GDLWidgetTable::DoForegroundColor() {
2954   SizeT nbColors=foregroundColor->N_Elements( );
2955   if (nbColors==0) {return;}
2956   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
2957   assert( grid != NULL);
2958   int nRows = grid->GetNumberRows( );
2959   int nCols = grid->GetNumberCols( );
2960   SizeT k=0;
2961   grid->BeginBatch();
2962   for (SizeT i=0; i< nRows; ++i) for (SizeT j=0; j< nCols; ++j) //Row by Row, from top.
2963   {
2964     grid->SetCellTextColour( i, j, wxColour((*foregroundColor)[k%nbColors],(*foregroundColor)[k%nbColors+1],(*foregroundColor)[k%nbColors+2]));
2965     k+=3;
2966   }
2967   grid->EndBatch();
2968 
2969 }
2970 
2971 
DoForegroundColor(DLongGDL * selection)2972 void GDLWidgetTable::DoForegroundColor(DLongGDL* selection) {
2973   SizeT nbColors=foregroundColor->N_Elements( );
2974   if (nbColors==0) {return;}
2975   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
2976   assert( grid != NULL);
2977   grid->BeginBatch();
2978 
2979   SizeT k=0;
2980 
2981   if (selection->Rank()==0) { //use current wxWidgets selection
2982    std::vector<wxPoint> list=grid->GetSelectedDisjointCellsList();
2983    for ( std::vector<wxPoint>::iterator it = list.begin(); it !=list.end(); ++it) {
2984     grid->SetCellTextColour( (*it).x, (*it).y, wxColour((*foregroundColor)[k%nbColors],(*foregroundColor)[k%nbColors+1],(*foregroundColor)[k%nbColors+2]));
2985     k+=3;
2986     }
2987   } else { //use the passed selection, mode-dependent:
2988     if (disjointSelection) { //pairs lists
2989       for (SizeT n=0,l=0; n<selection->Dim(1); ++n) {
2990         int col = (*selection)[l++];
2991         int row = (*selection)[l++];
2992         grid->SetCellTextColour( row, col, wxColour((*foregroundColor)[k%nbColors],(*foregroundColor)[k%nbColors+1],(*foregroundColor)[k%nbColors+2]));
2993         k+=3;
2994       }
2995     }else{ //4 values
2996      int colTL = (*selection)[0];
2997      int rowTL = (*selection)[1];
2998      int colBR = (*selection)[2];
2999      int rowBR = (*selection)[3];
3000      for ( int i=rowTL; i<=rowBR; ++i) for (int j=colTL; j<=colBR; ++j)
3001      {
3002        grid->SetCellTextColour( i, j, wxColour((*foregroundColor)[k%nbColors],(*foregroundColor)[k%nbColors+1],(*foregroundColor)[k%nbColors+2]));
3003        k+=3;
3004      }
3005     }
3006   }
3007 
3008   grid->EndBatch();
3009 
3010 }
3011 
DoColumnLabels()3012 void GDLWidgetTable::DoColumnLabels( ) {
3013   if (columnLabels->N_Elements( )==0) {return;}
3014   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3015   assert( grid != NULL);
3016   int nCols = grid->GetNumberCols( );
3017   grid->BeginBatch();
3018   if ( columnLabels->N_Elements( ) == 1 ) { //singleton case
3019     if ( static_cast<DString> ((*columnLabels)[0]).length( ) == 0 ) {
3020       for ( SizeT j = 0; j < nCols; ++j ) grid->SetColLabelValue( j, wxEmptyString );
3021     } else {
3022       for ( SizeT j = 0; j < nCols; ++j ) {
3023         if ( j > (columnLabels->N_Elements( ) - 1) ) break;
3024         grid->SetColLabelValue( j, wxString( static_cast<DString> ((*columnLabels)[j]).c_str( ), wxConvUTF8 ) );
3025       }
3026     }
3027   } else {
3028     for ( SizeT j = 0; j < nCols; ++j ) {
3029       if ( j > (columnLabels->N_Elements( ) - 1) ) break;
3030       grid->SetColLabelValue( j, wxString( static_cast<DString> ((*columnLabels)[j]).c_str( ), wxConvUTF8 ) );
3031     }
3032   }
3033   grid->EndBatch();
3034 
3035 }
3036 
DoColumnWidth()3037 void GDLWidgetTable::DoColumnWidth( ) {
3038   if (columnWidth->N_Elements( )==0) {return;}
3039   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3040   assert( grid != NULL);
3041   int nCols = grid->GetNumberCols( );
3042   grid->BeginBatch();
3043   if ( columnWidth->N_Elements( ) == 1 ) for ( SizeT j = 0; j < nCols; ++j ) grid->SetColSize(j,(*columnWidth)[0]*unitConversionFactor.x);
3044   else {
3045       for ( SizeT j = 0; j < nCols; ++j ) {
3046         if ( j > (columnWidth->N_Elements( ) - 1) ) break;
3047         grid->SetColSize(j,(*columnWidth)[j]*unitConversionFactor.x);
3048       }
3049   }
3050   grid->EndBatch();
3051 }
3052 
DoColumnWidth(DLongGDL * selection)3053 void GDLWidgetTable::DoColumnWidth( DLongGDL* selection ) {
3054   SizeT nbCols = columnWidth->N_Elements( );
3055   if ( nbCols == 0 ) {return;}
3056   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3057   assert( grid != NULL);
3058   grid->BeginBatch( );
3059 
3060   SizeT k=0;
3061 
3062   if ( selection->Rank( ) == 0 ) { //use current wxWidgets selection
3063    wxArrayInt list=grid->GetSortedSelectedColsList();
3064    //find concerned cols
3065    for ( int it = 0; it <list.GetCount(); ++it) {
3066        grid->SetColSize( list[it], (*columnWidth)[it % nbCols]*unitConversionFactor.x);
3067     }
3068   } else { //use the passed selection, mode-dependent:
3069      if (disjointSelection) { //pairs lists
3070      std::vector<int> allCols;
3071      std::vector<int>::iterator iter;
3072      //find concerned cols
3073      for ( SizeT n=0, l=0 ; n<selection->Dim(1); ++n) {
3074         int col = (*selection)[l++];l++;
3075         allCols.push_back(col);
3076       }
3077      std::sort (allCols.begin(), allCols.end());
3078      int theCol=-1;
3079      for ( iter = allCols.begin(); iter !=allCols.end(); ++iter) {
3080         if ((*iter)!=theCol) {
3081           theCol=(*iter);
3082                   //if index is -1, we want to size the label column instead of the grid columns.
3083           if (theCol==-1)  grid->SetRowLabelSize((*columnWidth)[k % nbCols]*unitConversionFactor.x);
3084           else if (theCol>=0 && theCol<grid->GetNumberCols())  grid->SetColSize( theCol, (*columnWidth)[k % nbCols]*unitConversionFactor.x );
3085           k++;
3086         }
3087       }
3088     } else { //4 values
3089      int colTL = (*selection)[0];
3090      int colBR = (*selection)[2];
3091      for (int j=colTL; j<=colBR; ++j)
3092      {
3093        //if index is -1, we want to size the label column instead of the grid columns.
3094        if (j==-1)  grid->SetRowLabelSize((*columnWidth)[k % nbCols]*unitConversionFactor.x);
3095        else if (j>=0 && j<grid->GetNumberCols())  grid->SetColSize( j, (*columnWidth)[k % nbCols]*unitConversionFactor.x );
3096        k++;
3097      }
3098     }
3099   }
3100 
3101   grid->EndBatch( );
3102 }
3103 
GetColumnWidth(DLongGDL * selection)3104 DFloatGDL* GDLWidgetTable::GetColumnWidth(DLongGDL* selection){
3105   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3106   assert( grid != NULL);
3107   SizeT k=0;
3108   int nCols = grid->GetNumberCols( );
3109 
3110   if ( selection == NULL) {
3111     DFloatGDL* res=new DFloatGDL(dimension(nCols));
3112     for ( SizeT j = 0; j < nCols; ++j ) (*res)[j]=grid->GetColSize(j);
3113     return res;
3114   } else if ( selection->Rank( ) == 0 ) { //use current wxWidgets selection
3115     wxArrayInt list=grid->GetSortedSelectedColsList();
3116    //find concerned cols
3117     if (list.GetCount()==0) return NULL;
3118    DFloatGDL* res=new DFloatGDL(dimension(list.GetCount()));
3119    for ( int it = 0; it <list.GetCount(); ++it) {
3120        (*res)[it]=grid->GetColSize( list[it] );
3121     }
3122    return res;
3123   } else { //use the passed selection, mode-dependent:
3124     if (disjointSelection) { //pairs lists
3125      std::vector<int> allCols;
3126      std::vector<int>::iterator iter;
3127      std::vector<int> theCols;
3128      //find concerned cols
3129      for ( SizeT n=0, l=0 ; n<selection->Dim(1); ++n) {
3130         int col = (*selection)[l++];l++;
3131         allCols.push_back(col);
3132       }
3133      std::sort (allCols.begin(), allCols.end());
3134      int theCol=-1;
3135      for ( iter = allCols.begin(); iter !=allCols.end(); ++iter) {
3136         if ((*iter)!=theCol) {
3137           theCol=(*iter);
3138           k++;
3139           theCols.push_back(theCol);
3140         }
3141       }
3142      //final list:
3143      if (theCols.size()==0) return NULL;
3144      DFloatGDL* res=new DFloatGDL(dimension(theCols.size()));
3145      for ( iter = theCols.begin(); iter !=theCols.end(); ++iter) {
3146        (*res)[k++]=grid->GetColSize( (*iter));
3147       }
3148      return res;
3149     } else { //4 values
3150      int colTL = (*selection)[0];
3151      int colBR = (*selection)[2];
3152      int count = colBR-colTL+1;
3153      if (count==0) return NULL;
3154      DFloatGDL* res=new DFloatGDL(dimension(count));
3155      for (int j=colTL; j<=colBR; ++j)
3156      {
3157        (*res)[k++]=grid->GetColSize(j);
3158      }
3159     }
3160   }
3161   return new DFloatGDL(0); //to keep compiler happy
3162 }
GetRowHeight(DLongGDL * selection)3163 DFloatGDL* GDLWidgetTable::GetRowHeight(DLongGDL* selection){
3164   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3165   assert( grid != NULL);
3166   SizeT k=0;
3167   int nRows = grid->GetNumberRows( );
3168 
3169   if ( selection == NULL) {
3170     DFloatGDL* res=new DFloatGDL(dimension(nRows));
3171     for ( SizeT i = 0; i < nRows; ++i ) (*res)[i]=grid->GetRowSize(i);
3172     return res;
3173   } else if ( selection->Rank( ) == 0 ) { //use current wxWidgets selection
3174     wxArrayInt list=grid->GetSortedSelectedRowsList();
3175    //find concerned rows
3176     if (list.GetCount()==0) return NULL;
3177    DFloatGDL* res=new DFloatGDL(dimension(list.GetCount()));
3178    for ( int it = 0; it <list.GetCount(); ++it) {
3179        (*res)[it]=grid->GetRowSize( list[it] );
3180     }
3181    return res;
3182   } else { //use the passed selection, mode-dependent:
3183     if (disjointSelection) { //pairs lists
3184      std::vector<int> allRows;
3185      std::vector<int>::iterator iter;
3186      std::vector<int> theRows;
3187      //find concerned rows
3188      for ( SizeT n=0, l=0 ; n<selection->Dim(1); ++n) {
3189         int row = (*selection)[l++];l++;
3190         allRows.push_back(row);
3191       }
3192      std::sort (allRows.begin(), allRows.end());
3193      int theRow=-1;
3194      for ( iter = allRows.begin(); iter !=allRows.end(); ++iter) {
3195         if ((*iter)!=theRow) {
3196           theRow=(*iter);
3197           k++;
3198           theRows.push_back(theRow);
3199         }
3200       }
3201      //final list:
3202      if (theRows.size()==0) return NULL;
3203      DFloatGDL* res=new DFloatGDL(dimension(theRows.size()));
3204      for ( iter = theRows.begin(); iter !=theRows.end(); ++iter) {
3205        (*res)[k++]=grid->GetRowSize( (*iter));
3206       }
3207      return res;
3208     } else { //4 values
3209      int rowTL = (*selection)[1];
3210      int rowBR = (*selection)[3];
3211      int count = rowBR-rowTL+1;
3212      if (count==0) return NULL;
3213      DFloatGDL* res=new DFloatGDL(dimension(count));
3214      for (int j=rowTL; j<=rowBR; ++j)
3215      {
3216        (*res)[k++]=grid->GetRowSize(j);
3217      }
3218     }
3219   }
3220   return new DFloatGDL(0); //to keep compiler happy
3221 }
3222 
DoRowHeights()3223 void GDLWidgetTable::DoRowHeights( ) {
3224   if (rowHeights->N_Elements( )==0) {return;}
3225   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3226   assert( grid != NULL);
3227   int nRows = grid->GetNumberRows( );
3228   grid->BeginBatch();
3229   if ( rowHeights->N_Elements( ) == 1 ) for ( SizeT i = 0; i < nRows; ++i ) grid->SetRowSize(i,(*rowHeights)[0]*unitConversionFactor.y);
3230   else {
3231       for ( SizeT i = 0; i < nRows; ++i ) {
3232         if ( i > (rowHeights->N_Elements( ) - 1) ) break;
3233         grid->SetRowSize(i,(*rowHeights)[i]*unitConversionFactor.y);
3234       }
3235   }
3236   grid->EndBatch();
3237 }
3238 
DoRowHeights(DLongGDL * selection)3239 void GDLWidgetTable::DoRowHeights( DLongGDL* selection ) {
3240   SizeT nbRows = rowHeights->N_Elements( );
3241   if ( nbRows == 0 ) { return; }
3242   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3243   assert( grid != NULL);
3244   grid->BeginBatch( );
3245 
3246   SizeT k=0;
3247 
3248   if ( selection->Rank( ) == 0 ) { //use current wxWidgets selection
3249    wxArrayInt list=grid->GetSortedSelectedRowsList();
3250    for ( int it = 0; it <list.GetCount(); ++it) {
3251        if (list[it]<grid->GetNumberRows())  grid->SetRowSize( list[it], (*rowHeights)[it % nbRows]*unitConversionFactor.y );
3252     }
3253   } else { //use the passed selection, mode-dependent:
3254     if (disjointSelection) { //pairs lists
3255      std::vector<int> allRows;
3256      std::vector<int>::iterator iter;
3257      for ( SizeT n=0, l=0 ; n<selection->Dim(1); ++n) {
3258        l++;
3259        int row = (*selection)[l++];
3260        allRows.push_back(row);
3261       }
3262      std::sort (allRows.begin(), allRows.end());
3263      int theRow=-1;
3264      for ( iter = allRows.begin(); iter !=allRows.end(); ++iter) {
3265         if ((*iter)!=theRow) {
3266           theRow=(*iter);
3267          //if index is -1, we want to size the label column instead of the grid columns.
3268           if (theRow==-1)  grid->SetColLabelSize((*columnWidth)[k % nbRows]*unitConversionFactor.x);
3269           else if (theRow>=0 && theRow<grid->GetNumberRows()) grid->SetRowSize( theRow, (*rowHeights)[k % nbRows] *unitConversionFactor.y);
3270           k++;
3271         }
3272       }
3273     } else { //4 values
3274      int rowTL = (*selection)[1];
3275      int rowBR = (*selection)[3];
3276      for (int i=rowTL; i<=rowBR; ++i)
3277      {
3278        //if index is -1, we want to size the label column instead of the grid columns.
3279        if (i==-1)  grid->SetColLabelSize((*columnWidth)[k % nbRows]*unitConversionFactor.x);
3280        else if (i>=0 && i<grid->GetNumberRows()) grid->SetRowSize( i, (*rowHeights)[k % nbRows]*unitConversionFactor.y );
3281        k++;
3282      }
3283     }
3284   }
3285 
3286   grid->EndBatch( );
3287 }
3288 
DoRowLabels()3289 void GDLWidgetTable::DoRowLabels( ) {
3290   if (rowLabels->N_Elements( )==0) {return;}
3291   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3292   assert( grid != NULL);
3293   int nRows = grid->GetNumberRows( );
3294   grid->BeginBatch();
3295   if ( rowLabels->N_Elements( ) == 1 ) { //singleton case
3296     if ( static_cast<DString> ((*rowLabels)[0]).length( ) == 0 ) {
3297       for ( SizeT i = 0; i < nRows; ++i ) grid->SetRowLabelValue( i, wxEmptyString );
3298     } else {
3299       for ( SizeT i = 0; i < nRows; ++i ) {
3300         if ( i > (rowLabels->N_Elements( ) - 1) ) break;
3301         grid->SetRowLabelValue( i, wxString( static_cast<DString> ((*rowLabels)[i]).c_str( ), wxConvUTF8 ) );
3302       }
3303     }
3304   } else {
3305     for ( SizeT i = 0; i < nRows; ++i ) {
3306       if ( i > (rowLabels->N_Elements( ) - 1) ) break;
3307       grid->SetRowLabelValue( i, wxString( static_cast<DString> ((*rowLabels)[i]).c_str( ), wxConvUTF8 ) );
3308     }
3309   }
3310   grid->EndBatch();
3311 }
3312 
DeleteColumns(DLongGDL * selection)3313 void GDLWidgetTable::DeleteColumns(DLongGDL* selection) {
3314   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3315   assert( grid != NULL);
3316   grid->BeginBatch( );
3317 
3318   if ( selection==NULL || selection->Rank( ) == 0 ) { //use current wxWidgets selection
3319    wxArrayInt list=grid->GetSortedSelectedColsList();
3320    //delete in reverse order to avoid column-numbering problems
3321    for ( int it = list.GetCount()-1; it >-1 ; --it) {
3322        grid->DeleteCols( list[it], 1, true);
3323     }
3324   } else { //use the passed selection, mode-dependent:
3325     if (disjointSelection) { //pairs lists
3326      std::vector<int> allCols;
3327      std::vector<int>::reverse_iterator riter;
3328      //find concerned cols
3329      for ( SizeT n=0, l=0 ; n<selection->Dim(1); ++n) {
3330         int col = (*selection)[l++];l++;
3331         allCols.push_back(col);
3332       }
3333      std::sort (allCols.begin(), allCols.end());
3334      int theCol=-1;
3335      for ( riter = allCols.rbegin(); riter !=allCols.rend(); ++riter) {
3336         if ((*riter)!=theCol) {
3337           theCol=(*riter);
3338           grid->DeleteCols( theCol, 1, true);
3339         }
3340       }
3341     } else { //4 values, cols are contiguous, easy.
3342      int colTL = (*selection)[0];
3343      int colBR = (*selection)[2];
3344      int count=colBR-colTL+1;
3345      grid->DeleteCols( colTL , count, true );
3346     }
3347   }
3348 
3349   grid->EndBatch( );
3350 }
InsertColumns(DLong count,DLongGDL * selection)3351 bool GDLWidgetTable::InsertColumns(DLong count, DLongGDL* selection) {
3352   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3353   assert( grid != NULL);
3354   bool success;
3355   grid->BeginBatch( );
3356 
3357   if ( selection==NULL ){ //add count to rightmost position
3358     int pos=grid->GetNumberCols();
3359     success=grid->InsertCols(pos,count,true);
3360    // Set new grid cell contents TBD FIXME!
3361    {SizeT k=0; for (SizeT i=0; i< grid->GetNumberRows(); ++i) for (SizeT j=pos; j<grid->GetNumberCols() ; ++j) {grid->SetCellValue( i, j, wxString( "0" , wxConvUTF8 ) );++k;}}
3362   }
3363   else if (selection->Rank( ) == 0 ) { //add left of current wxWidgets selection
3364    wxArrayInt list=grid->GetSortedSelectedColsList();
3365    //insert to left of first one
3366    success=grid->InsertCols( list[0], count, true);
3367   } else { //use the passed selection, mode-dependent:
3368     if (disjointSelection) { //pairs lists
3369      std::vector<int> allCols;
3370      //find concerned cols
3371      for ( SizeT n=0, l=0 ; n<selection->Dim(1); ++n) {
3372         int col = (*selection)[l++];l++;
3373         allCols.push_back(col);
3374       }
3375      std::sort (allCols.begin(), allCols.end());
3376      success=grid->InsertCols( *(allCols.begin()), 1, true);
3377     } else { //4 values, cols are contiguous, easy.
3378      int colTL = (*selection)[0];
3379      success=grid->InsertCols( colTL , count, true );
3380     }
3381   }
3382 
3383   grid->EndBatch( );
3384   return success;
3385 }
3386 
DeleteRows(DLongGDL * selection)3387 void GDLWidgetTable::DeleteRows(DLongGDL* selection) {
3388   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3389   assert( grid != NULL);
3390   grid->BeginBatch( );
3391 
3392   if ( selection==NULL || selection->Rank( ) == 0 ) { //use current wxWidgets selection
3393    wxArrayInt list=grid->GetSortedSelectedRowsList();
3394    //delete in reverse order to avoid column-numbering problems
3395    for ( int it = list.GetCount()-1; it >-1 ; --it) {
3396        grid->DeleteRows( list[it], 1, true);
3397     }
3398   } else { //use the passed selection, mode-dependent:
3399     if (disjointSelection) { //pairs lists
3400      std::vector<int> allRows;
3401      std::vector<int>::reverse_iterator riter;
3402      //find concerned Rows
3403      for ( SizeT n=0, l=0 ; n<selection->Dim(1); ++n) {
3404         int row = (*selection)[l++];l++;
3405         allRows.push_back(row);
3406       }
3407      std::sort (allRows.begin(), allRows.end());
3408      int theRow=-1;
3409      for ( riter = allRows.rbegin(); riter !=allRows.rend(); ++riter) {
3410         if ((*riter)!=theRow) {
3411           theRow=(*riter);
3412           grid->DeleteRows( theRow, 1, true);
3413         }
3414       }
3415     } else { //4 values, Rows are contiguous, easy.
3416      int rowTL = (*selection)[1];
3417      int rowBR = (*selection)[3];
3418      int count=rowBR-rowTL+1;
3419      grid->DeleteRows( rowTL , count, true );
3420     }
3421   }
3422 
3423   grid->EndBatch( );
3424 }
3425 
InsertRows(DLong count,DLongGDL * selection)3426 bool GDLWidgetTable::InsertRows(DLong count, DLongGDL* selection) {
3427   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3428   assert( grid != NULL);
3429   bool success;
3430   grid->BeginBatch( );
3431 
3432   if ( selection==NULL ){ //add count to rightmost position
3433     int pos=grid->GetNumberRows();
3434     success=grid->InsertRows(pos,count,true);
3435    // Set new grid cell contents TBD FIXME!
3436    {SizeT k=0; for (SizeT i=pos; i<grid->GetNumberRows(); ++i) for (SizeT j=0; j<grid->GetNumberCols() ; ++j) {grid->SetCellValue( i, j, wxString( "0" , wxConvUTF8 ) );++k;}}
3437   }
3438   else if (selection->Rank( ) == 0 ) { //add left of current wxWidgets selection
3439    wxArrayInt list=grid->GetSortedSelectedRowsList();
3440    //insert to left of first one
3441    success=grid->InsertRows( list[0], count, true);
3442   } else { //use the passed selection, mode-dependent:
3443     if (disjointSelection) { //pairs lists
3444      std::vector<int> allRows;
3445      //find concerned rows
3446      for ( SizeT n=0, l=0 ; n<selection->Dim(1); ++n) {
3447         int row = (*selection)[l++];l++;
3448         allRows.push_back(row);
3449       }
3450      std::sort (allRows.begin(), allRows.end());
3451      success=grid->InsertRows( *(allRows.begin()), 1, true);
3452     } else { //4 values, cols are contiguous, easy.
3453      int rowTL = (*selection)[1];
3454      success=grid->InsertRows( rowTL , count, true );
3455     }
3456   }
3457 
3458   grid->EndBatch( );
3459   return success;
3460 }
3461 
SetTableValues(DStringGDL * val,DLongGDL * selection)3462 void GDLWidgetTable::SetTableValues(DStringGDL* val, DLongGDL* selection)
3463 {
3464   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3465   assert( grid != NULL);
3466 
3467   grid->BeginBatch();
3468 
3469   if ( selection==NULL ){ //reset table to everything. val replaces valueAsStrings.
3470     GDLDelete(valueAsStrings);
3471     valueAsStrings=val->Dup();
3472     SizeT numRows,numCols;
3473     if (valueAsStrings->Rank()==1) {
3474       numRows=1;
3475       numCols=valueAsStrings->Dim(0); //lines
3476     } else {
3477       numRows=valueAsStrings->Dim(1);
3478       numCols=valueAsStrings->Dim(0);
3479     }
3480     grid->ClearGrid();
3481     int curr_rows=grid->GetNumberRows();
3482     int curr_cols=grid->GetNumberCols();
3483     //adjust rows and cols:
3484     if (numRows > curr_rows) grid->AppendRows(numRows-curr_rows);
3485     if (numCols > curr_cols) grid->AppendCols(numCols-curr_cols);
3486     // Set grid cell contents as strings
3487     {SizeT k=0; for (SizeT i=0; i<numRows ; ++i) for (SizeT j=0; j< numCols; ++j) {grid->SetCellValue( i, j, wxString(((*valueAsStrings)[k]).c_str(), wxConvUTF8 ) );++k;}}
3488 
3489   } else { //use the wxWidget selection or the passed selection, mode-dependent:
3490     if (disjointSelection) { //pairs lists
3491       if (selection->Rank()==0) {
3492         std::vector<wxPoint> list=grid->GetSelectedDisjointCellsList();
3493         SizeT k=0;
3494         for (std::vector<wxPoint>::iterator it = list.begin(); it !=list.end(); ++it) {
3495           grid->SetCellValue( (*it).x, (*it).y ,wxString(((*val)[k++]).c_str(), wxConvUTF8 ) );
3496           if (k==val->N_Elements()) break;
3497         }
3498        } else {
3499         for (SizeT k=0,n=0,l=0; n<selection->Dim(1); ++n) {
3500           int col = (*selection)[l++];
3501           int row = (*selection)[l++];
3502           grid->SetCellValue( row, col ,wxString(((*val)[k++]).c_str(), wxConvUTF8 ) );
3503           if (k==val->N_Elements()) break;
3504         }
3505       }
3506     } else { //IDL maintains the 2D-structure of val!
3507       SizeT numRows,numCols;
3508       if (val->Rank()==1) {
3509         numRows=1;
3510         numCols=val->Dim(0); //lines
3511       } else {
3512         numRows=val->Dim(1);
3513         numCols=val->Dim(0);
3514       }
3515       int colTL,colBR,rowTL,rowBR;
3516       if (selection->Rank()==0) {
3517         wxArrayInt block=grid->GetSelectedBlockOfCells();
3518         //normally only ONE block is available.
3519         colTL = block[0];
3520         rowTL = block[1];
3521         colBR = block[2];
3522         rowBR = block[3];
3523       } else {
3524         colTL = (*selection)[0];
3525         rowTL = (*selection)[1];
3526         colBR = (*selection)[2];
3527         rowBR = (*selection)[3];
3528       }
3529       for ( int ival=0, i=rowTL; i<=rowBR; ++i, ++ival) for (int jval=0, j=colTL; j<=colBR; ++j, ++jval)
3530       {
3531         if (ival < numRows && jval < numCols ) grid->SetCellValue( i, j ,wxString(((*val)[jval*numRows+ival]).c_str(), wxConvUTF8 ) );
3532       }
3533     }
3534   }
3535   grid->EndBatch( );
3536 }
GetTableValuesAsStruct(DLongGDL * selection)3537 BaseGDL* GDLWidgetTable::GetTableValuesAsStruct(DLongGDL* selection)
3538 {
3539   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3540   assert( grid != NULL);
3541   BaseGDL* res;
3542   int numRows=valueAsStrings->Dim(0);
3543   int numCols=valueAsStrings->Dim(1);
3544   DStringGDL* stringres=this->GetTableValues(selection);
3545   if (stringres==NULL) return NULL; //pass error back.
3546 
3547   if ( selection==NULL ){ //just convert
3548     res=vValue->Dup();
3549     stringstream is;
3550 //    if (majority == GDLWidgetTable::ROW_MAJOR ) {
3551 //      BaseGDL* tmp=static_cast<BaseGDL*>(stringres)->Transpose(NULL);
3552 //      GDLDelete(stringres);
3553 //      stringres=static_cast<DStringGDL*>(tmp);
3554 //      for( SizeT i = 0; i < stringres->N_Elements(); i++)  is << (*stringres)[ i] << '\n';
3555 //    } else {
3556       for( SizeT i = 0; i < stringres->N_Elements(); i++)  is << (*stringres)[ i] << '\n';
3557 //    }
3558     res->FromStream( is);
3559   }
3560   else { //use the wxWidget selection or the passed selection, mode-dependent:
3561     if (disjointSelection) { //pairs lists
3562       std::vector<wxPoint> list;
3563       if (selection->Rank()==0) { //use current wxWidgets selection. Result is a STRUCT
3564         list=grid->GetSelectedDisjointCellsList();
3565       } else {                   //make equivalent vector.
3566         for (SizeT k=0,n=0,l=0; n<selection->Dim(1); ++n) {
3567           int col = (*selection)[l++];
3568           int row = (*selection)[l++];
3569           list.push_back(wxPoint(row,col));
3570         }
3571       }
3572       SizeT k=0;
3573       DStructGDL*  typecodes = new DStructGDL( "GDL_TYPECODES_AS_STRUCT");
3574       // creating the output anonymous structure
3575       DStructDesc* res_desc = new DStructDesc("$truct");
3576       for ( std::vector<wxPoint>::iterator it = list.begin(); it !=list.end(); ++it, ++k) {
3577         //get tag values:
3578         BaseGDL* tested;
3579         if (majority == GDLWidgetTable::ROW_MAJOR )
3580           tested=static_cast<DStructGDL*>(vValue)->GetTag((*it).y); //table columns are tags
3581         else
3582           tested=static_cast<DStructGDL*>(vValue)->GetTag((*it).x); //table rows are tags
3583         stringstream os;
3584         os << std::setfill ('_') << std::setw (12) << k ; //as IDL does
3585         std::string tagName;
3586         os >> tagName;
3587         res_desc->AddTag(tagName, typecodes->GetTag(tested->Type()));
3588       }
3589       stringstream is;
3590       for( SizeT i = 0; i < stringres->N_Elements(); i++)  is << (*stringres)[ i] << '\n';
3591       res = new DStructGDL(res_desc, dimension());
3592       res->FromStream( is);
3593     } else { //IDL maintains the 2D-structure of val!
3594       int colTL,colBR,rowTL,rowBR;
3595       if (selection->Rank()==0) {
3596         wxArrayInt block=grid->GetSelectedBlockOfCells();
3597         //normally only ONE block is available.
3598         colTL = block[0];
3599         rowTL = block[1];
3600         colBR = block[2];
3601         rowBR = block[3];
3602       } else {
3603         colTL = (*selection)[0];
3604         rowTL = (*selection)[1];
3605         colBR = (*selection)[2];
3606         rowBR = (*selection)[3];
3607       }
3608       //complication: if only one row (col) is selected, result is an array of <type>.
3609       //else result is a structure with correct tag names. Very clever!
3610       if ((majority == GDLWidgetTable::ROW_MAJOR && colTL==colBR)||(majority == GDLWidgetTable::COLUMN_MAJOR && rowTL==rowBR)) {
3611         DType what=GDL_BYTE;
3612         SizeT size;
3613         if (majority == GDLWidgetTable::ROW_MAJOR && colTL==colBR) {
3614           what=static_cast<DStructGDL*>(vValue)->GetTag(colTL)->Type();
3615           size=rowBR-rowTL+1;
3616         } else if (rowTL==rowBR) {
3617           what=static_cast<DStructGDL*>(vValue)->GetTag(rowTL)->Type();
3618           size=colBR-colTL+1;
3619         }
3620         switch(what) {
3621           case GDL_STRING:
3622             res=new DStringGDL(dimension(size));
3623             break;
3624           case GDL_BYTE:
3625             res=new DByteGDL(dimension(size));
3626             break;
3627           case GDL_INT:
3628             res=new DIntGDL(dimension(size));
3629             break;
3630           case GDL_LONG:
3631             res=new DLongGDL(dimension(size));
3632             break;
3633           case GDL_FLOAT:
3634             res=new DFloatGDL(dimension(size));
3635             break;
3636           case GDL_DOUBLE:
3637             res=new DDoubleGDL(dimension(size));
3638             break;
3639           case GDL_COMPLEX:
3640             res=new DComplexGDL(dimension(dimension(size)));
3641             break;
3642           case GDL_COMPLEXDBL:
3643             res=new DComplexDblGDL(dimension(size));
3644             break;
3645           case GDL_UINT:
3646             res=new DUIntGDL(dimension(size));
3647             break;
3648           case GDL_ULONG:
3649             res=new DULongGDL(dimension(size));
3650             break;
3651           case GDL_LONG64:
3652             res=new DLong64GDL(dimension(size));
3653             break;
3654           case GDL_ULONG64:
3655             res=new DULong64GDL(dimension(size));
3656             break;
3657           default:
3658             cerr<<"Unhandled Table Type, please report!"<<endl;
3659             return NULL; //signal error
3660         }
3661       } else { //create dedicated struct
3662         DStructGDL*  typecodes = new DStructGDL( "GDL_TYPECODES_AS_STRUCT");
3663         // creating the output anonymous structure
3664         DStructDesc* res_desc = new DStructDesc("$truct");
3665         SizeT size;
3666         if (majority == GDLWidgetTable::ROW_MAJOR) { //data is in rows of structures. Columns are tags
3667           size=rowBR-rowTL+1;
3668           for (SizeT j=colTL; j<=colBR; ++j) {
3669           //get tag values:
3670             BaseGDL* tested;
3671             std::string tagName;
3672             tested=static_cast<DStructGDL*>(vValue)->GetTag(j);
3673             tagName=static_cast<DStructGDL*>(vValue)->Desc()->TagName(j); //preserve tag names
3674             res_desc->AddTag(tagName, typecodes->GetTag(tested->Type()));
3675           }
3676         } else {
3677           size=colBR-colTL+1;
3678           for (SizeT i=rowTL; i<=rowBR; ++i) {
3679           //get tag values:
3680             BaseGDL* tested;
3681             std::string tagName;
3682             tested=static_cast<DStructGDL*>(vValue)->GetTag(i);
3683             tagName=static_cast<DStructGDL*>(vValue)->Desc()->TagName(i); //preserve tag names
3684             res_desc->AddTag(tagName, typecodes->GetTag(tested->Type()));
3685           }
3686         }
3687         //create res with correct dim:
3688         res = new DStructGDL(res_desc, dimension(size));
3689       }
3690       //populate res:
3691       stringstream is;
3692       for( SizeT i = 0; i < stringres->N_Elements(); i++)  is << (*stringres)[ i] << '\n';
3693       res->FromStream( is);
3694     }
3695   }
3696   return res;
3697 }
3698 
GetTableValues(DLongGDL * selection)3699 DStringGDL* GDLWidgetTable::GetTableValues(DLongGDL* selection)
3700 {
3701   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3702   assert( grid != NULL);
3703 
3704   DStringGDL * stringres;
3705   int numRows=valueAsStrings->Dim(0);
3706   int numCols=valueAsStrings->Dim(1);
3707 
3708   if ( selection==NULL ){
3709     int ncols=grid->GetNumberCols();
3710     int nrows=grid->GetNumberCols();
3711 
3712     SizeT dims[2];
3713     dims[1]=(nrows>numRows)?numRows:nrows;
3714     dims[0]=(ncols>numCols)?numCols:ncols;
3715     dimension dim(dims,2);
3716     stringres=new DStringGDL(dim);
3717 
3718     for ( int ival=0, i=0; i<nrows; ++i, ++ival) for (int jval=0, j=0; j<ncols; ++j, ++jval)
3719     {
3720       if (ival < numRows && jval < numCols ) (*stringres)[jval*numRows+ival]= grid->GetCellValue( i, j).mb_str(wxConvUTF8);
3721     }
3722   } else { //use the wxWidget selection or the passed selection, mode-dependent:
3723     if (disjointSelection) { //pairs lists
3724       if (selection->Rank()==0) { //use current wxWidgets selection
3725         std::vector<wxPoint> list=grid->GetSelectedDisjointCellsList();
3726         stringres=new DStringGDL(list.size());
3727         SizeT k=0;
3728         for ( std::vector<wxPoint>::iterator it = list.begin(); it !=list.end(); ++it) {
3729           if ((*it).x >= numRows || (*it).y >= numCols) return static_cast<DStringGDL*>(NULL);
3730           (*stringres)[k++]=grid->GetCellValue( (*it).x, (*it).y ).mb_str(wxConvUTF8);
3731         }
3732       } else {
3733         stringres=new DStringGDL(selection->Dim(1));
3734         for (SizeT k=0,n=0,l=0; n<selection->Dim(1); ++n) {
3735           int col = (*selection)[l++];
3736           int row = (*selection)[l++];
3737           if ( row >= numRows || col >= numCols) return static_cast<DStringGDL*>(NULL);
3738           (*stringres)[k++]=grid->GetCellValue( row, col).mb_str(wxConvUTF8);
3739         }
3740       }
3741     } else { //IDL maintains the 2D-structure of val!
3742       int colTL,colBR,rowTL,rowBR;
3743       if (selection->Rank()==0) {
3744         wxArrayInt block=grid->GetSelectedBlockOfCells();
3745         //normally only ONE block is available.
3746         colTL = block[0];
3747         rowTL = block[1];
3748         colBR = block[2];
3749         rowBR = block[3];
3750       } else {
3751         colTL = (*selection)[0];
3752         rowTL = (*selection)[1];
3753         colBR = (*selection)[2];
3754         rowBR = (*selection)[3];
3755       }
3756       SizeT dims[2];
3757       dims[1]=(rowBR-rowTL+1);
3758       dims[0]=(colBR-colTL+1);
3759       dimension dim(dims,2);
3760       stringres=new DStringGDL(dim);
3761       for (SizeT k=0,i=rowTL; i<=rowBR; ++i) for (SizeT j=colTL; j<=colBR; ++j)
3762       {
3763         if ( i >= numRows || j >= numCols) return static_cast<DStringGDL*>(NULL);
3764         (*stringres)[k++]=grid->GetCellValue(i, j).mb_str(wxConvUTF8);
3765       }
3766     }
3767   }
3768   //convention: if value is of type struct, string array will always be row_major. thus if we are column major, transpose return string array
3769   if (vValue->Type()==GDL_STRUCT && majority==GDLWidgetTable::COLUMN_MAJOR) return static_cast<DStringGDL*>(stringres->Transpose(NULL))->Dup();
3770   else return stringres;
3771 }
3772 
SetSelection(DLongGDL * selection)3773 void GDLWidgetTable::SetSelection(DLongGDL* selection)
3774 {
3775   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3776   assert( grid != NULL);
3777   grid->BeginBatch( );
3778   updating=true; //prevent sending unwanted events
3779   grid->ClearSelection();
3780   wxPoint firstVisible=wxPoint(0,0);
3781   if (disjointSelection) { //pairs lists
3782     SizeT k=0;
3783     for (SizeT i=0; i< selection->Dim(1); ++i) {
3784       int col=(*selection)[k++];
3785       int row=(*selection)[k++];
3786       grid->SelectBlock(row,col,row,col,true);
3787       if (k==2) {firstVisible.x=row;firstVisible.y=col;}
3788     }
3789   } else {
3790      int colTL = (*selection)[0];
3791      int rowTL = (*selection)[1];
3792      int colBR = (*selection)[2];
3793      int rowBR = (*selection)[3];
3794      grid->SelectBlock(rowTL,colTL,rowBR,colBR,false);
3795      firstVisible.x=rowTL;firstVisible.y=colTL;
3796   }
3797   grid->EndBatch( );
3798   grid->MakeCellVisible(firstVisible.x,firstVisible.y);
3799   updating=false; //allow events
3800 }
SetTableView(DLongGDL * pos)3801 void GDLWidgetTable::SetTableView(DLongGDL* pos)
3802 {
3803   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3804   assert( grid != NULL);
3805   grid->MakeCellVisible((*pos)[1],(*pos)[0]);
3806 }
EditCell(DLongGDL * pos)3807 void GDLWidgetTable::EditCell(DLongGDL* pos)
3808 {
3809   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3810   assert( grid != NULL);
3811   grid->SetReadOnly((*pos)[0],(*pos)[1],false);
3812 }
SetTableNumberOfColumns(DLong ncols)3813 void GDLWidgetTable::SetTableNumberOfColumns( DLong ncols){
3814   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3815   assert( grid != NULL);
3816   grid->BeginBatch( );
3817   int old_ncols=grid->GetNumberCols();
3818   int numRows=valueAsStrings->Dim(0);
3819   int numCols=valueAsStrings->Dim(1);
3820   if (ncols > old_ncols) {
3821     grid->AppendCols(ncols-old_ncols);
3822     if (numCols > old_ncols) {
3823       int colTL,colBR,rowTL,rowBR;
3824       colTL=old_ncols-1;
3825       colBR=ncols-1;
3826       rowTL=0;
3827       rowBR=grid->GetNumberRows()-1;
3828       for ( int i=rowTL; i<=rowBR; ++i) for (int j=colTL; j<=colBR; ++j)
3829       {
3830         if (i < numRows && j < numCols ) grid->SetCellValue( i, j ,wxString(((*valueAsStrings)[j*numRows+i]).c_str(), wxConvUTF8 ) );
3831       }
3832     }
3833   }
3834   else if (ncols < old_ncols) grid->DeleteCols(ncols,old_ncols-ncols);
3835   grid->EndBatch( );
3836 }
SetTableNumberOfRows(DLong nrows)3837 void GDLWidgetTable::SetTableNumberOfRows( DLong nrows){
3838   wxGridGDL * grid = dynamic_cast<wxGridGDL*> (theWxWidget);
3839   assert( grid != NULL);
3840   grid->BeginBatch( );
3841   SizeT old_nrows=grid->GetNumberRows();
3842   int numRows=valueAsStrings->Dim(0);
3843   int numCols=valueAsStrings->Dim(1);
3844   if (nrows > old_nrows) {
3845     grid->AppendRows(nrows-old_nrows);
3846     if (numRows > old_nrows) {
3847       int colTL,colBR,rowTL,rowBR;
3848       colTL=0;
3849       colBR=grid->GetNumberCols()-1;
3850       rowTL=old_nrows-1;
3851       rowBR=nrows-1;
3852       for ( int i=rowTL; i<=rowBR; ++i) for (int j=colTL; j<=colBR; ++j)
3853       {
3854         if (i < numRows && j < numCols ) grid->SetCellValue( i, j ,wxString(((*valueAsStrings)[j*numRows+i]).c_str(), wxConvUTF8 ) );
3855       }
3856     }
3857   }
3858   else if (nrows < old_nrows) grid->DeleteRows(nrows,old_nrows-nrows);
3859   grid->EndBatch( );
3860 }
GetGeometry(wxRealPoint fact)3861 DStructGDL* GDLWidgetTable::GetGeometry(wxRealPoint fact)
3862 {
3863   if (!this->IsRealized()) this->Realize(true,false);//necessary if a geometry request is done previous to the command widget_control,xxx,,/Realize !
3864   GDLWidgetBase* container = static_cast<GDLWidgetBase*> (this->GetMyParent());
3865   assert(container != NULL);
3866   int ixsize = 0, iysize = 0, iscr_xsize = 0, iscr_ysize = 0;
3867   DFloat xsize = 0;
3868   DFloat ysize = 0;
3869   DFloat scr_xsize = 0;
3870   DFloat scr_ysize = 0;
3871   DFloat xoffset = 0;
3872   DFloat yoffset = 0;
3873   DFloat margin = 0;
3874 
3875   DStructGDL* ex = new DStructGDL("WIDGET_GEOMETRY");
3876 
3877   wxWindow* test = dynamic_cast<wxWindow*> (theWxContainer);
3878   if (test==NULL) return ex;
3879   wxRect r=test->GetRect();
3880   xoffset = r.x ;
3881   yoffset = r.y ;
3882   wxGrid* w = dynamic_cast<wxGrid*> (theWxWidget);
3883   if (w==NULL) return ex;
3884   wxRect z=w->GetRect();
3885 
3886   iscr_xsize = z.width;
3887   iscr_ysize = z.height;
3888   wxSize s=w->GetClientSize();
3889   ixsize = s.x;
3890   iysize = s.y;
3891 
3892   if (theWxWidget == theWxContainer) margin=0; else {
3893     margin=(r.width-z.width)/2; //Rect is about the container, which is the widgetPanel and not the frame depending on case.
3894   }
3895   //size is in columns
3896   int rowsize=w->GetRowSize(0);
3897   int rowlabelsize=w->GetRowLabelSize();
3898   int colsize=w->GetColSize(0);
3899   int collabelsize=w->GetColLabelSize();
3900   xsize =  (ixsize-rowlabelsize) / colsize  ;
3901   ysize =  (iysize-collabelsize) / rowsize  ;
3902 
3903   scr_xsize = iscr_xsize / fact.x;
3904   scr_ysize = iscr_ysize / fact.y;
3905   xoffset /= fact.x;
3906   yoffset /= fact.y;
3907   margin /= fact.x;
3908 
3909   ex->InitTag("XOFFSET", DFloatGDL(xoffset));
3910   ex->InitTag("YOFFSET", DFloatGDL(yoffset));
3911   ex->InitTag("XSIZE", DFloatGDL(xsize));
3912   ex->InitTag("YSIZE", DFloatGDL(ysize));
3913   ex->InitTag("SCR_XSIZE", DFloatGDL(scr_xsize));
3914   ex->InitTag("SCR_YSIZE", DFloatGDL(scr_ysize));
3915   ex->InitTag("MARGIN", DFloatGDL(margin));
3916 
3917   return ex;
3918 }
3919 
setFont()3920 void GDLWidgetTable::setFont() {
3921    wxGrid* g = dynamic_cast<wxGrid*> (this->GetWxWidget());
3922    if (g != NULL) {
3923     if (!font.IsSameAs(wxNullFont)) {
3924      g->SetLabelFont(font);
3925      g->SetDefaultCellFont(font);
3926     } else {
3927      g->SetLabelFont(defaultFont);
3928      g->SetDefaultCellFont(defaultFont);
3929     }
3930    }
3931   }
~GDLWidgetTable()3932 GDLWidgetTable::~GDLWidgetTable()
3933 {
3934 #ifdef GDL_DEBUG_WIDGETS
3935   std::cout << "~GDLWidgetTable(" << widgetID << ")" << std::endl;
3936 #endif
3937   if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
3938 
3939   GDLDelete( table_alignment );
3940   GDLDelete( editable );
3941   GDLDelete( amPm );
3942   GDLDelete( backgroundColor );
3943   GDLDelete( foregroundColor );
3944   GDLDelete( columnLabels );
3945   GDLDelete( columnWidth );
3946   GDLDelete( daysOfWeek );
3947   GDLDelete( format );
3948   GDLDelete( month );
3949   GDLDelete( rowHeights );
3950   GDLDelete( rowLabels );
3951   GDLDelete( valueAsStrings );
3952 }
3953 
3954 /*********************************************************/
3955 // for WIDGET_TREE
3956 /*********************************************************/
3957 
GDLWidgetTree(WidgetIDT p,EnvT * e,BaseGDL * value_,DULong eventFlags_,wxBitmap * bitmap,DLong dragability,DLong dropability,bool expanded_,bool folder_,DLong treeindex,DString & dragNotify_)3958 GDLWidgetTree::GDLWidgetTree( WidgetIDT p, EnvT* e, BaseGDL* value_, DULong eventFlags_
3959 ,wxBitmap* bitmap
3960 ,DLong dragability
3961 ,DLong dropability
3962 ,bool expanded_
3963 ,bool folder_
3964 ,DLong treeindex
3965 ,DString &dragNotify_
3966 )
3967 : GDLWidget( p, e, value_, eventFlags_ )
3968 ,droppable(dropability ) //inherited
3969 ,draggable(dragability ) //inherited
3970 ,expanded(expanded_)
3971 ,myRoot(NULL)
3972 ,treeItemData(NULL)
3973 ,has_checkbox(false)
3974 ,folder(folder_)
3975 ,mask(false)
3976 ,dragNotify( dragNotify_)
3977 {
3978 
3979   //checkbox is inherited
3980 
3981   static int CHECKBOX = e->KeywordIx("CHECKBOX");
3982   static int CHECKED = e->KeywordIx("CHECKED");
3983   bool checkbox_asked = false;
3984   if (e->KeywordPresent(CHECKBOX)){
3985     checkbox_asked = true;
3986     DLong value=0;
3987     e->AssureLongScalarKWIfPresent(CHECKBOX,value);
3988     has_checkbox = (value>0);
3989   }
3990   bool checked = (has_checkbox && e->KeywordSet(CHECKED));
3991 
3992   GDLWidget* gdlParent = GetWidget( parentID );
3993   widgetPanel = GetParentPanel( );
3994   widgetSizer = GetParentSizer( );
3995   DStringGDL* value=static_cast<DStringGDL*>(vValue);
3996 
3997   //define the base tree widget globally here
3998   wxTreeCtrlGDL* myTreeRoot;
3999   if ( gdlParent->IsBase( ) ) {
4000     folder=true; //IS A FOLDER!
4001     static int NO_BITMAPS = e->KeywordIx("NO_BITMAPS");
4002     noBitmaps = e->KeywordSet(NO_BITMAPS);
4003     static int MULTIPLE = e->KeywordIx("MULTIPLE");
4004     multiple = e->KeywordSet(MULTIPLE);
4005 
4006     wxImageList *stateImages = gdlDefaultTreeStateImages;
4007     wxImageList *images = gdlDefaultTreeImages;
4008     START_ADD_EVENTUAL_FRAME
4009 
4010     // a tree widget is always inside a scrolled window, whose ScrollSize is 200 pixels by default
4011     if ( wSize.x <= 0 ) wSize.x = 200; //yes, has a default value!
4012     if ( wSize.y <= 0 ) wSize.y = 200;
4013 
4014     wSize=computeWidgetSize( ); //this is a SetClientSize
4015 
4016     long style = wxTR_HAS_BUTTONS|wxTR_LINES_AT_ROOT|wxTR_HIDE_ROOT; //OK
4017     if (multiple) style |= wxTR_MULTIPLE; //widget is insensitive, FIXME
4018     //we have no root, create one.
4019     myTreeRoot = new wxTreeCtrlGDL(widgetPanel, widgetID, wxDefaultPosition, wxDefaultSize, style );
4020     theWxContainer = theWxWidget = myTreeRoot;
4021     //All lists are set always. Checkboxes will be hidden if checkbox is not present
4022     myTreeRoot->SetImageList(images);
4023     myTreeRoot->SetStateImageList(stateImages);
4024 
4025     myRoot=this;
4026     treeItemData=new wxTreeItemDataGDL(widgetID, myTreeRoot);
4027 //    if (bitmap) {
4028 //      int index=images->Add(*bitmap);
4029 //      treeItemID = tree->AddRoot(wxString( (*value)[0].c_str( ), wxConvUTF8 ),  index ,-1, treeItemData);
4030 //    } else { //use open and closed folder icons
4031       treeItemID = myTreeRoot->AddRoot(wxString( (*value)[0].c_str( ), wxConvUTF8 ),  0 ,1, treeItemData);
4032 //    }
4033 //    tree->SetItemImage(treeItemID,(folder)?(expanded?gdlWxTree_FOLDER_OPEN:gdlWxTree_FOLDER):gdlWxTree_ITEM);
4034 // checkbox is not visible for root//    if (has_checkbox) tree->SetItemState(treeItemID,(checked==true)); else tree->SetItemState(treeItemID,wxTREE_ITEMSTATE_NONE); //CHECKED,UNCHECKE,NOT_VISIBLE
4035     widgetStyle=widgetAlignment( );
4036     if (dropability == -1) droppable=0; //this for root only
4037     if (dragability == -1) draggable=0; //this for root only
4038     if (dragNotify=="<inherit>") dragNotify="<default>";
4039 //do not expand root if hidden: will assert() in wxWidgets! //    if (expanded) tree->Expand(treeItemID);
4040     myTreeRoot->SetClientSize(wSize);
4041     myTreeRoot->SetMinClientSize(wSize);
4042 //    tree->ShowScrollbars(wxSHOW_SB_ALWAYS,wxSHOW_SB_ALWAYS); //possibly useful.
4043     END_ADD_EVENTUAL_FRAME
4044     TIDY_WIDGET(gdlBORDER_SPACE)
4045 
4046       //does not work, fixme. Replaced by global setting in gdlwidgeteventhandler
4047       //    this->AddToDesiredEvents(wxEVT_COMMAND_TREE_ITEM_ACTIVATED,wxTreeEventHandler(wxTreeCtrlGDL::OnItemActivated),myTreeRoot);
4048       //    this->AddToDesiredEvents(wxEVT_COMMAND_TREE_BEGIN_DRAG,wxTreeEventHandler(wxTreeCtrlGDL::OnBeginDrag),myTreeRoot);
4049       //    this->AddToDesiredEvents(wxEVT_COMMAND_TREE_END_DRAG,wxTreeEventHandler(wxTreeCtrlGDL::OnItemDropped),myTreeRoot);
4050       //    this->AddToDesiredEvents(wxEVT_COMMAND_TREE_ITEM_COLLAPSED,wxTreeEventHandler(wxTreeCtrlGDL::OnItemCollapsed),myTreeRoot);
4051       //    this->AddToDesiredEvents(wxEVT_COMMAND_TREE_ITEM_EXPANDED,wxTreeEventHandler(wxTreeCtrlGDL::OnItemExpanded),myTreeRoot);
4052       //    this->AddToDesiredEvents(wxEVT_COMMAND_TREE_SEL_CHANGED,wxTreeEventHandler(wxTreeCtrlGDL::OnItemSelected),myTreeRoot);
4053 
4054   } else {
4055 //    static int TOOLTIP = e->KeywordIx( "TOOLTIP" );
4056 //  DString toolTip;
4057 //  e->AssureStringScalarKWIfPresent( TOOLTIP, toolTip );
4058 
4059     GDLWidgetTree* parentTree = static_cast<GDLWidgetTree*> (gdlParent);
4060     assert( parentTree != NULL);
4061     theWxWidget = parentTree->GetWxWidget( );
4062     myRoot =  parentTree->GetMyRootGDLWidgetTree();
4063     bool nobitmaps=myRoot->IsUsingBitmaps();
4064 
4065     myTreeRoot = dynamic_cast<wxTreeCtrlGDL*> (theWxWidget);
4066     assert( myTreeRoot != NULL);
4067     treeItemData=new wxTreeItemDataGDL(widgetID,myTreeRoot);
4068     theWxContainer=NULL; //this is not a widget
4069 
4070     //if parent has checkbox, I have a checkbox too unless has_checkbox is false
4071     bool parent_has_checkbox=parentTree->HasCheckBox();
4072     if (!checkbox_asked) has_checkbox=(parent_has_checkbox);
4073     //if treeindex is present, it must be < the number of children (otherwise baoum, thank you wxWidgets)
4074     if (treeindex > -1 ) {
4075       //possible?
4076       if (parentTree->IsFolder()) {
4077         unsigned int count = myTreeRoot->GetChildrenCount(parentTree->treeItemID, false);
4078         if (treeindex >= count) treeindex = count;
4079       } else e->Throw("Parent tree widget is not a folder.");
4080     }
4081     if (nobitmaps) {
4082         if (treeindex > -1 ) treeItemID = myTreeRoot->InsertItem( parentTree->treeItemID, treeindex, wxString( (*value)[0].c_str( ), wxConvUTF8 ) ,-1,-1, treeItemData);
4083         else treeItemID = myTreeRoot->AppendItem( parentTree->treeItemID, wxString( (*value)[0].c_str( ), wxConvUTF8 ) ,-1,-1, treeItemData);
4084     }
4085     else if (bitmap) {
4086    //images (default vs. custom: problem of sizes: wxWidgets ENFORCES an uniform scaling)
4087       int imindex=myTreeRoot->GetImageList()->Add(wxBitmap((*bitmap).ConvertToImage().Rescale(DEFAULT_TREE_IMAGE_SIZE,DEFAULT_TREE_IMAGE_SIZE)));
4088       if (treeindex > -1 ) treeItemID = myTreeRoot->InsertItem( parentTree->treeItemID, treeindex, wxString( (*value)[0].c_str( ), wxConvUTF8 ) ,imindex,imindex, treeItemData);
4089       else treeItemID = myTreeRoot->AppendItem( parentTree->treeItemID, wxString( (*value)[0].c_str( ), wxConvUTF8 ) ,imindex,imindex, treeItemData);
4090     } else {     //since no image is a bit disappointing use our internal wxWigdets icons
4091       if (folder) { //use open and closed folder icons
4092         if (treeindex > -1 ) treeItemID = myTreeRoot->InsertItem( parentTree->treeItemID, treeindex, wxString( (*value)[0].c_str( ), wxConvUTF8 ) ,TREE_BITMAP_FOLDER,TREE_BITMAP_FOLDER_OPEN, treeItemData);
4093         else treeItemID = myTreeRoot->AppendItem( parentTree->treeItemID, wxString( (*value)[0].c_str( ), wxConvUTF8 ) ,TREE_BITMAP_FOLDER,TREE_BITMAP_FOLDER_OPEN, treeItemData);
4094       } //or normal file
4095       else if (treeindex > -1) treeItemID = myTreeRoot->InsertItem( parentTree->treeItemID, treeindex, wxString( (*value)[0].c_str( ), wxConvUTF8 ) ,TREE_BITMAP_ITEM,TREE_BITMAP_ITEM_SELECTED, treeItemData);
4096       else  treeItemID = myTreeRoot->AppendItem( parentTree->treeItemID, wxString( (*value)[0].c_str( ), wxConvUTF8 ) ,TREE_BITMAP_ITEM,TREE_BITMAP_ITEM_SELECTED, treeItemData);
4097     }
4098 
4099     if (has_checkbox) myTreeRoot->SetItemState(treeItemID,(checked==true)); else myTreeRoot->SetItemState(treeItemID,wxTREE_ITEMSTATE_NONE); //CHECKED,UNCHECKE,NOT_VISIBLE
4100     //expand if requested:
4101     if (expanded)  {
4102       myTreeRoot->SetItemHasChildren( treeItemID, true); //TRICK! to enable folder opened or closed BY CONSTRUCTION.
4103      DoExpand(true);
4104     }
4105 //    if (tooltip) DO SOMETHING! FIXME.
4106     if (this->IsRealized()){
4107       myTreeRoot->Refresh();
4108     }
4109   }
4110 
4111 
4112     //    UPDATE_WINDOW
4113     REALIZE_IF_NEEDED
4114 }
GetDropability()4115   bool GDLWidgetTree::GetDropability() {
4116     int enabledrop=droppable;
4117     GDLWidgetTree* root=myRoot;
4118     GDLWidgetTree* w=this;
4119     while (enabledrop < 0 && w!=root) {
4120       w=static_cast<GDLWidgetTree*>(w->GetMyParent());
4121       enabledrop=w->GetDroppableValue();
4122     }
4123     return (enabledrop == 1);
4124   }
GetDragability()4125   bool GDLWidgetTree::GetDragability() {
4126     int enabledrag=draggable;
4127     GDLWidgetTree* root=myRoot;
4128     GDLWidgetTree* w=this;
4129     while (enabledrag < 0 && w!=root) {
4130       w=static_cast<GDLWidgetTree*>(w->GetMyParent());
4131       enabledrag=w->GetDraggableValue();
4132     }
4133     return (enabledrag == 1);
4134   }
DoExpand(bool what)4135   void GDLWidgetTree::DoExpand(bool what){
4136     expanded=what;
4137     if (what) treeItemData->myTree->Expand(treeItemID); else treeItemData->myTree->Collapse(treeItemID);
4138     treeItemData->myTree->Refresh();
4139   }
Select(bool select)4140   void GDLWidgetTree::Select(bool select){
4141     if (this->myRoot->GetWidgetID() != widgetID ) treeItemData->myTree->SelectItem(treeItemID,select); //root is not selectable
4142     treeItemData->myTree->Refresh();
4143   }
SetTreeIndex(DLong where)4144   void GDLWidgetTree::SetTreeIndex(DLong where) {
4145     GDLWidgetTree* parentTree = static_cast<GDLWidgetTree*> (GetWidget( parentID ));
4146     if (parentTree->IsFolder()){ //is Folder
4147       wxTreeCtrlGDL* myTreeRoot=dynamic_cast<wxTreeCtrlGDL*> (theWxWidget);
4148       assert( myTreeRoot != NULL);
4149       wxTreeItemId currentId = this->treeItemID;
4150       //where should i put it?
4151       unsigned int count = myTreeRoot->GetChildrenCount(parentTree->treeItemID, false);
4152       DLong treeindex=count;
4153       if (where > -1 && where <= treeindex) treeindex =where; //will start putting at 'treeindex'
4154       wxString s=myTreeRoot->GetItemText(currentId);
4155       int imindex=myTreeRoot->GetItemImage(currentId);
4156       wxTreeItemId newId=myTreeRoot->InsertItem( parentTree->treeItemID, treeindex, s ,imindex,imindex, treeItemData);
4157       //we heve to suppress treeItemData from where it was previously attached otherwise it will be destroyed and bang!
4158       myTreeRoot->SetItemData(currentId,NULL);
4159       if (this->HasCheckBox()) myTreeRoot->SetItemState(newId,this->IsChecked()); // else myTreeRoot->SetItemState(treeItemID,wxTREE_ITEMSTATE_NONE); //CHECKED,UNCHECKE,NOT_VISIBLE
4160       if (expanded)  {
4161          myTreeRoot->SetItemHasChildren( newId, true); //TRICK! to enable folder opened or closed BY CONSTRUCTION.
4162          myTreeRoot->Expand(newId);
4163        }
4164       // give back treeItemID to transferred GDLTreeWidget:
4165       this->SetItemID(newId);
4166       //Children?
4167       count = myTreeRoot->GetChildrenCount(currentId,false);
4168       if (count == 0) {
4169         myTreeRoot->Delete(currentId);
4170         return;
4171       }
4172       //build full list of children, call this on each GDLWidgetTree:
4173       wxArrayTreeItemIds list;
4174       wxTreeItemIdValue cookie;
4175       wxTreeItemId id = myTreeRoot->GetFirstChild(currentId, cookie);
4176       do {
4177         list.Add(id);
4178         id = myTreeRoot->GetNextSibling(id);
4179       } while (id.IsOk());
4180       int nb=list.Count();
4181       for (int i=0; i< count ; ++i) {
4182         id=list[i];
4183         wxTreeItemDataGDL* d=static_cast<wxTreeItemDataGDL*>(myTreeRoot->GetItemData(id));
4184         static_cast<GDLWidgetTree*>(GDLWidget::GetWidget(d->widgetID))->SetTreeIndex(-1); //added at the end
4185       }
4186       myTreeRoot->Delete(currentId);
4187       myTreeRoot->Refresh();
4188     } //else throw GDLException("Parent tree widget is not a folder."); //IDL just forgets.
4189   }
OnRealize()4190 void GDLWidgetTree::OnRealize(){
4191    GDLWidgetTree* root=this->GetMyRootGDLWidgetTree();
4192    if (this==root) {
4193      wxTreeCtrlGDL* ctrl=static_cast<wxTreeCtrlGDL*>(this->GetWxWidget());
4194      wxTreeItemId id=ctrl->GetFirstVisibleItem 	( 		) 	;
4195      if (id) ctrl->SetFocusedItem(id);
4196    }
4197 }
GetTreeIndex()4198 DInt GDLWidgetTree::GetTreeIndex()
4199 {
4200   DInt count=0;
4201   wxTreeCtrlGDL* tree=dynamic_cast<wxTreeCtrlGDL*>(theWxWidget);
4202   assert( tree != NULL);
4203   wxTreeItemId  id=this->treeItemID;
4204   wxTreeItemId prev_id=tree->GetPrevSibling(id);
4205   while (prev_id.IsOk()){
4206     count++;
4207     id=prev_id;
4208     prev_id=tree->GetPrevSibling(id);
4209   }
4210   return count;
4211 }
4212 
~GDLWidgetTree()4213 GDLWidgetTree::~GDLWidgetTree()
4214 {
4215 #ifdef GDL_DEBUG_WIDGETS
4216   std::cout << "~GDLWidgetTree: (" << widgetID <<")"<< std::endl;
4217 #endif
4218   //the wxWidget points to  the parent branch. A leaf has wxContainer=NULL. //If we are on a leaf, set thewxWidget to NULL at the end, as it would be doubly destroyed in ~GDLWidget otherwise.
4219 
4220   wxTreeCtrlGDL* tree = dynamic_cast<wxTreeCtrlGDL*> (theWxWidget);
4221   if (tree) { // container-type behaviour: kill gdl childrens
4222     wxTreeItemId id = this->treeItemID;
4223     if (id.IsOk()) {
4224       wxTreeItemIdValue cookie;
4225       wxTreeItemId child = tree->GetFirstChild(id, cookie);
4226       while (child.IsOk()) {
4227         WidgetIDT childID = dynamic_cast<wxTreeItemDataGDL*> (tree->GetItemData(child))->widgetID;
4228         GDLWidgetTree* GDLchild = static_cast<GDLWidgetTree*> (GDLWidget::GetWidget(childID));
4229         child = tree->GetNextSibling(child); //nextChild did not find the last (?) nextSibling does the job.
4230 #ifdef GDL_DEBUG_WIDGETS
4231         std::cout << "~GDLWidgetTree, deleting item ID #" << childID << " of tree widget #" << widgetID << std::endl;
4232 #endif
4233         delete GDLchild;
4234       }
4235       treeItemID.Unset();
4236       tree->Delete(id);
4237     }
4238     tree->Refresh();
4239   }
4240   //after all children destroyed, destroy my wx counterpart
4241   if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
4242 }
4243 
SetValue(DString val)4244 void GDLWidgetTree::SetValue(DString val)
4245 {
4246   GDLDelete(vValue);
4247   vValue=new DStringGDL(val);
4248   wxTreeCtrlGDL* tree=dynamic_cast<wxTreeCtrlGDL*>(theWxWidget);
4249   assert( tree != NULL);
4250   tree->SetItemText(treeItemID, wxString( val.c_str( ), wxConvUTF8 ));
4251   tree->Refresh();
4252 }
4253 
SetBitmap(wxBitmap * bitmap)4254 void GDLWidgetTree::SetBitmap(wxBitmap* bitmap) {
4255   //images (default vs. custom: problem of sizes: wxWidgets ENFORCES an uniform scaling)
4256   wxTreeCtrlGDL* myTreeRoot=treeItemData->myTree;
4257   wxBitmap b=wxBitmap((*bitmap).ConvertToImage().Rescale(DEFAULT_TREE_IMAGE_SIZE, DEFAULT_TREE_IMAGE_SIZE));
4258   int myimindex = myTreeRoot->GetItemImage(treeItemID, wxTreeItemIcon_Normal);
4259   if (myimindex < TREE_BITMAP_END) { //this is a 'default' image, do not overwrite, add a new one
4260     int imindex=myTreeRoot->GetImageList()->Add(b);
4261     for (wxTreeItemIcon i=wxTreeItemIcon_Normal; i< wxTreeItemIcon_Max; i=wxTreeItemIcon(i+1)) myTreeRoot->SetItemImage(treeItemID,imindex,i);
4262   } else {
4263     myTreeRoot->GetImageList()->Replace(myimindex,b);
4264   }
4265   myTreeRoot->Refresh();
4266 }
4267 
ReturnBitmapAsBytes()4268 DByteGDL* GDLWidgetTree::ReturnBitmapAsBytes() {
4269   wxTreeCtrlGDL* myTreeRoot = treeItemData->myTree;
4270   int myimindex = myTreeRoot->GetItemImage(treeItemID, wxTreeItemIcon_Normal);
4271   if (myimindex < TREE_BITMAP_END) { //this is a 'default' image,return 0
4272     return new DByteGDL(0);
4273   } else {
4274     wxImage image=myTreeRoot->GetImageList()->GetBitmap(myimindex).ConvertToImage().Mirror(false); //Mirror=FlIP necessary!!!
4275     unsigned char* pixels=image.GetData();
4276     wxSize sz=image.GetSize();
4277     DByteGDL* res=new DByteGDL(dimension(sz.x,sz.y,3), BaseGDL::NOZERO); //in fact [3,N,M] RGBRGB...
4278     SizeT k=0;
4279     SizeT jump=sz.x*sz.y;
4280     for (SizeT i=0; i< sz.x*sz.y; ++i) {(*res)[i]=pixels[k++];(*res)[i+jump]=pixels[k++]; (*res)[i+2*jump]=pixels[k++];}//[N,M,3]
4281     return res;
4282   }
4283 }
4284 
IsSelectedID()4285 WidgetIDT GDLWidgetTree::IsSelectedID() {
4286   return treeItemData->myTree->IsSelected(treeItemID);
4287 }
4288 
IsDragSelectedID()4289 WidgetIDT GDLWidgetTree::IsDragSelectedID() { //must return
4290   wxTreeItemId test = treeItemID;
4291   wxTreeCtrlGDL* myTreeRoot = treeItemData->myTree;
4292   if (!myTreeRoot->IsSelected(test)) return 0;
4293   do {
4294     test = myTreeRoot->GetItemParent(test);
4295   } while (test.IsOk() && !myTreeRoot->IsSelected(test));
4296   if (!test.IsOk()) {
4297     return 1; //no parent was selected
4298   }
4299   return 0;
4300 }
4301 
GetAllSelectedID()4302 DLongGDL* GDLWidgetTree::GetAllSelectedID() {
4303   //tree must be root
4304   GDLWidgetTree* myGdlTreeRoot = this->GetMyRootGDLWidgetTree();
4305   assert(myGdlTreeRoot == this);
4306   wxTreeCtrlGDL* myTreeRoot = treeItemData->myTree;
4307   wxArrayTreeItemIds list;
4308   int nb = myTreeRoot->GetSelections(list);
4309   if (nb == 0) return new DLongGDL(-1);
4310   DLongGDL* res = new DLongGDL(dimension(nb), BaseGDL::NOZERO);
4311   for (int i = 0; i < nb; ++i) {
4312     wxTreeItemDataGDL* data = static_cast<wxTreeItemDataGDL*> (myTreeRoot->GetItemData(list[i]));
4313     (*res)[i] = data->GetWidgetID();
4314   }
4315   return res;
4316 }
4317 //called with root tree only. As soon as a folder is selected, childrens must not be returned as they are supposed to be 'included' in whatever action
4318 //is done with this list.
GetAllDragSelectedID()4319   DLongGDL* GDLWidgetTree::GetAllDragSelectedID(){
4320     //tree must be root
4321   GDLWidgetTree* myGdlTreeRoot = this->GetMyRootGDLWidgetTree();
4322   assert(myGdlTreeRoot==this);
4323   wxTreeCtrlGDL* myTreeRoot = treeItemData->myTree;
4324   wxArrayTreeItemIds list1;
4325   int nb = myTreeRoot->GetSelections(list1);
4326   if (nb == 0) return new DLongGDL(-1);
4327   wxArrayTreeItemIds list2;
4328   for (int i = 0; i < nb; ++i) { //test whether itemid's list of parent is selected. if one parent is lecetd, drop it else add in list2.
4329     wxTreeItemId test=list1[i];
4330     do {
4331       test=myTreeRoot->GetItemParent(test);
4332     } while (test.IsOk() && !myTreeRoot->IsSelected(test));
4333       if (!test.IsOk()) {
4334       list2.Add(list1[i]); //no parent was selected
4335       }
4336   }
4337   nb=list2.Count();
4338   if (nb == 0) return new DLongGDL(-1);
4339   DLongGDL* res = new DLongGDL(dimension(nb), BaseGDL::NOZERO);
4340   for (int i = 0; i < nb; ++i) {
4341     wxTreeItemDataGDL* data = static_cast<wxTreeItemDataGDL*> (myTreeRoot->GetItemData(list2[i]));
4342     (*res)[i] = data->GetWidgetID();
4343   }
4344   return res;
4345 }
4346 
4347 
NChildren() const4348 DLong GDLWidgetTree::NChildren() const {
4349   wxTreeCtrlGDL* myTreeRoot=treeItemData->myTree;
4350   return myTreeRoot->GetChildrenCount(treeItemID,false);
4351 }
GetChild(DLong childIx) const4352 WidgetIDT GDLWidgetTree::GetChild(DLong childIx) const { //childIx is not used here
4353   wxTreeCtrlGDL* myTreeRoot=treeItemData->myTree;
4354   wxTreeItemIdValue cookie;
4355   wxTreeItemId id=myTreeRoot->GetFirstChild(treeItemID,cookie);
4356   if (!id.IsOk()) return 0;
4357   return static_cast<wxTreeItemDataGDL*>(myTreeRoot->GetItemData(id))->widgetID;
4358 }
GetChildrenList() const4359 DLongGDL* GDLWidgetTree::GetChildrenList() const {
4360   wxTreeCtrlGDL* myTreeRoot=treeItemData->myTree;
4361   int n=myTreeRoot->GetChildrenCount(treeItemID,false);
4362   if (n<1) return new DLongGDL(0);
4363   wxTreeItemIdValue cookie;
4364   DLongGDL* ret=new DLongGDL(dimension(n),BaseGDL::NOZERO);
4365   wxTreeItemId id=myTreeRoot->GetFirstChild(treeItemID,cookie);
4366   (*ret)[0]=static_cast<wxTreeItemDataGDL*>(myTreeRoot->GetItemData(id))->widgetID;
4367   for (int i=1; i<n; ++i) {
4368     id=myTreeRoot->GetNextChild(treeItemID,cookie);
4369     assert (id.IsOk());
4370     (*ret)[i]=static_cast<wxTreeItemDataGDL*>(myTreeRoot->GetItemData(id))->widgetID;
4371   }
4372   return ret;
4373 }
GetTheSiblingOf(DLong myId)4374 DLong GDLWidgetTree::GetTheSiblingOf(DLong myId) {  //GetTheSibling is called by widget_info() using the parent widget (a container). This is not our case here.
4375   // retrieve My infos, not parent's:
4376   GDLWidgetTree* me=static_cast<GDLWidgetTree*>(GDLWidget::GetWidget(myId));
4377   if (me==NULL) return 0; else return me->Sibling(); //call Sibling with good 'this'
4378 }
Sibling()4379 DLong GDLWidgetTree::Sibling() { //uses NextSibling, which may be 0.
4380   wxTreeCtrlGDL* myTreeRoot=treeItemData->myTree;
4381   wxTreeItemId id=myTreeRoot->GetNextSibling(treeItemID);
4382   if (!id.IsOk()) return 0;
4383   return static_cast<wxTreeItemDataGDL*>(myTreeRoot->GetItemData(id))->widgetID;
4384 }
4385 /*********************************************************/
4386 // for WIDGET_SLIDER
4387 /*********************************************************/
GDLWidgetSlider(WidgetIDT p,EnvT * e,DLong value_,DULong eventFlags_,DLong minimum_,DLong maximum_,bool vertical,bool suppressValue,DString & title_)4388 GDLWidgetSlider::GDLWidgetSlider( WidgetIDT p, EnvT* e, DLong value_
4389 , DULong eventFlags_
4390 , DLong minimum_
4391 , DLong maximum_
4392 , bool vertical
4393 , bool suppressValue
4394 , DString &title_ )
4395 : GDLWidget( p, e, NULL, eventFlags_ )
4396 , value( value_ ) //should disappear , duplicates vValue!
4397 , minimum( minimum_ )
4398 , maximum( maximum_ )
4399 , title( title_)
4400 {
4401   GDLWidget* gdlParent = GetWidget( parentID );
4402   widgetPanel = GetParentPanel( );
4403   widgetSizer = GetParentSizer( );
4404 
4405   START_ADD_EVENTUAL_FRAME
4406 
4407   if (( wSize.x <= 0 ) && !vertical) wSize.x=100; //yes, has a default value!
4408   if (( wSize.y <= 0 ) && vertical) wSize.y=100;
4409 
4410   long style = wxSL_HORIZONTAL;
4411   if ( vertical ) style = wxSL_VERTICAL;
4412   if ( !suppressValue ) {
4413 #if wxCHECK_VERSION(2,9,1)
4414     style |= wxSL_VALUE_LABEL;
4415 #else
4416     style |= wxSL_LABELS;
4417 #endif
4418   }
4419 
4420   widgetStyle=widgetAlignment();
4421   const wxString s=wxString( title.c_str( ), wxConvUTF8 );
4422   wxSlider* slider;
4423 
4424 //get defined sizes if any
4425   wSize=computeWidgetSize( );
4426 // this is the size in absence of text:
4427   wxSize slidersize=(vertical)?wxSize(-1,wSize.y):wxSize(wSize.x,-1);
4428   bool hastitle=(s.size()>0);
4429 //// A gdlSlider is a comboPanel containing a wxStaticText (eventually) plus a slider.
4430   //if text or frame, we need a panel containing the wxVERTICAL association. frame is sunken if /FRAME, or NONE
4431   if (hastitle) {
4432     wxPanel* comboPanel=new wxPanel(widgetPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
4433     wxSizer* combosz = new wxBoxSizer(wxVERTICAL);
4434     comboPanel->SetSizer(combosz);
4435     theWxContainer = comboPanel; //else stays as panel_if_framed.
4436     comboPanel->SetFont(font); //enable fancy font
4437     //little difficulty: insure that combo widget size is correct in presence of (fancy) text.
4438     int w=0;
4439     int h=0;
4440     int d=0;
4441     int lead=0;
4442     comboPanel->GetTextExtent(s,&w,&h,&d,&lead,&font);
4443     slidersize=(vertical)?wxSize(-1,wSize.y-h-3*gdlSPACE):wxSize(max(wSize.x,w),-1);
4444     slider= new wxSlider( comboPanel, widgetID, value, minimum, maximum, wxDefaultPosition, wxDefaultSize, style);
4445     slider->SetSize(slidersize);
4446     slider->SetMinSize(slidersize);
4447     combosz->Add(slider,DONOTALLOWSTRETCH,wxEXPAND) ; //wxALL|(vertical)?wxALIGN_CENTRE_HORIZONTAL:widgetStyle,gdlSPACE);
4448     wxStaticText *theTitle=new wxStaticText(comboPanel,wxID_ANY,s);
4449     combosz->Add(theTitle,DONOTALLOWSTRETCH,widgetStyle|wxALL,gdlSPACE);
4450     combosz->AddSpacer(5);
4451     comboPanel->Fit();
4452     theWxWidget=comboPanel; //to trick ADD EVENTUAL FRAME
4453   } else {
4454     slider= new wxSlider( widgetPanel, widgetID, value, minimum, maximum, wxDefaultPosition, wxDefaultSize, style);
4455     slider->SetSize(slidersize);
4456     slider->SetMinSize(slidersize);
4457     theWxContainer = theWxWidget=slider;
4458     widgetPanel->Fit();
4459   }
4460 
4461   END_ADD_EVENTUAL_FRAME
4462   theWxWidget=slider; //no trick anymore!
4463   TIDY_WIDGET(gdlBORDER_SPACE)
4464 //  UPDATE_WINDOW
4465   REALIZE_IF_NEEDED
4466   this->AddToDesiredEvents( wxEVT_SCROLL_CHANGED,wxScrollEventHandler(gdlwxFrame::OnThumbRelease),slider);
4467   //dynamically select drag, saves resources! (note: there is no widget_control,/drag for sliders)
4468   if ( eventFlags & GDLWidget::EV_DRAG ) this->AddToDesiredEvents( wxEVT_SCROLL_THUMBTRACK,wxScrollEventHandler(gdlwxFrame::OnThumbTrack),slider);
4469 }
ControlSetValue(DLong v)4470 void GDLWidgetSlider::ControlSetValue(DLong v){
4471   value=v;
4472   wxSlider* s=dynamic_cast<wxSlider*>(theWxWidget);
4473   assert( s != NULL);
4474   s->SetValue(v);
4475 }
4476 
ControlSetMinValue(DLong v)4477 void GDLWidgetSlider::ControlSetMinValue(DLong v) {
4478   value = v;
4479   wxSlider* s = dynamic_cast<wxSlider*> (theWxWidget);
4480   assert(s != NULL);
4481   s->SetRange(v, s->GetMax());
4482 }
4483 
ControlSetMaxValue(DLong v)4484 void GDLWidgetSlider::ControlSetMaxValue(DLong v) {
4485   value = v;
4486   wxSlider* s = dynamic_cast<wxSlider*> (theWxWidget);
4487   assert(s != NULL);
4488   s->SetRange(s->GetMin(),v);
4489 }
4490 
~GDLWidgetSlider()4491 GDLWidgetSlider::~GDLWidgetSlider(){
4492   title.clear();
4493 #ifdef GDL_DEBUG_WIDGETS
4494   std::cout << "~GDLWidgetSlider(" << widgetID <<")"<< std::endl;
4495 #endif
4496   if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
4497 }
4498 
GDLWidgetButton(WidgetIDT p,EnvT * e,DStringGDL * value,DULong eventflags,wxBitmap * bitmap_)4499 GDLWidgetButton::GDLWidgetButton( WidgetIDT p, EnvT* e,
4500 DStringGDL* value , DULong eventflags, wxBitmap* bitmap_)
4501 : GDLWidget( p, e, value, eventflags )
4502 , buttonType( UNDEFINED )
4503 , buttonBitmap(bitmap_)
4504 , buttonState(false)
4505 , menuItem(NULL)
4506 , valueWxString( wxString((*value)[0].c_str(), wxConvUTF8) )
4507 {
4508   if (valueWxString.Length() < 1) valueWxString=wxT(" ");
4509 }
4510 
4511 
~GDLWidgetButton()4512 GDLWidgetButton::~GDLWidgetButton() {
4513 #ifdef GDL_DEBUG_WIDGETS
4514   std::cout << "~GDLWidgetButton(" << widgetID << ")" << std::endl;
4515 #endif
4516   if (buttonBitmap) delete buttonBitmap;
4517 }
4518 
4519 //a normal button.
GDLWidgetNormalButton(WidgetIDT p,EnvT * e,DStringGDL * value,DULong eventflags,wxBitmap * bitmap_,DStringGDL * buttonToolTip)4520 GDLWidgetNormalButton::GDLWidgetNormalButton(WidgetIDT p, EnvT* e,
4521   DStringGDL* value, DULong eventflags,  wxBitmap* bitmap_, DStringGDL* buttonToolTip)
4522 : GDLWidgetButton(p, e, value, eventflags, bitmap_)
4523 {
4524   GDLWidget* gdlParent = GetWidget(parentID);
4525   widgetPanel = GetParentPanel();
4526   widgetSizer = GetParentSizer();
4527 
4528   START_ADD_EVENTUAL_FRAME
4529 
4530   widgetStyle = widgetAlignment();
4531   wSize = computeWidgetSize();
4532   long style=wxBORDER_NONE;
4533   //we deliberately prevent exclusive buttons when bitmap are present (exclusive buttons w/ pixmap do not exist in wxWidgets.
4534   if (gdlParent->GetExclusiveMode() == BGNORMAL || bitmap_) {
4535     if (bitmap_) {
4536       wxBitmapButton *button = new wxBitmapButton(widgetPanel, widgetID, *bitmap_, wxDefaultPosition, wxDefaultSize, style);
4537       theWxContainer = theWxWidget = button;
4538       buttonType = BITMAP;
4539       this->AddToDesiredEvents(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(gdlwxFrame::OnButton), button);
4540     } else {
4541       wxButton *button = new wxButton(widgetPanel, widgetID, valueWxString,wxDefaultPosition, wxDefaultSize, buttonTextAlignment());
4542       theWxContainer = theWxWidget = button;
4543       buttonType = NORMAL;
4544       this->AddToDesiredEvents(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(gdlwxFrame::OnButton), button);
4545     }
4546   } else if (gdlParent->GetExclusiveMode() == BGEXCLUSIVE1ST) {
4547     wxRadioButton *radioButton = new wxRadioButton(widgetPanel, widgetID, valueWxString,  wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
4548     gdlParent->SetExclusiveMode(1);
4549     GDLWidgetBase* b = static_cast<GDLWidgetBase*> (gdlParent);
4550     if (b) b->SetLastRadioSelection(widgetID);
4551     else cerr << "Warning GDLWidgetNormalButton::GDLWidgetNormalButton(): widget type confusion(1)\n";
4552 
4553     theWxContainer = theWxWidget = radioButton;
4554     this->AddToDesiredEvents(wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler(gdlwxFrame::OnRadioButton), radioButton);
4555     buttonType = RADIO;
4556   } else if (gdlParent->GetExclusiveMode() == BGEXCLUSIVE) {
4557     wxRadioButton *radioButton = new wxRadioButton(widgetPanel, widgetID, valueWxString, wxDefaultPosition, wxDefaultSize);
4558     theWxContainer = theWxWidget = radioButton;
4559     this->AddToDesiredEvents(wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler(gdlwxFrame::OnRadioButton), radioButton);
4560     buttonType = RADIO;
4561   } else if (gdlParent->GetExclusiveMode() == BGNONEXCLUSIVE) {
4562     wxCheckBox *checkBox = new wxCheckBox(widgetPanel, widgetID, valueWxString,  wxDefaultPosition, wxDefaultSize);
4563     theWxContainer = theWxWidget = checkBox;
4564     this->AddToDesiredEvents(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(gdlwxFrame::OnCheckBox), checkBox);
4565     buttonType = CHECKBOX;
4566   } else cerr << "Warning GDLWidgetNormalButton::GDLWidgetNormalButton(): widget type confusion(2)\n";
4567   wxWindow *win = static_cast<wxWindow*> (theWxWidget);
4568   if (win && buttonToolTip) win->SetToolTip(wxString((*buttonToolTip)[0].c_str(), wxConvUTF8));
4569 
4570   END_ADD_EVENTUAL_FRAME
4571 
4572   win->SetSize(wSize);
4573   win->SetMinSize(wSize);
4574 
4575   TIDY_WIDGET(gdlBORDER_SPACE)
4576 //  UPDATE_WINDOW
4577   REALIZE_IF_NEEDED
4578 
4579 
4580 }
4581 
SetButtonWidgetLabelText(const DString & value_)4582 void GDLWidgetNormalButton::SetButtonWidgetLabelText(const DString& value_) {
4583   if (theWxWidget != NULL) {
4584     wxAnyButton *b = dynamic_cast<wxAnyButton*> (theWxWidget);
4585     b->SetLabelText(wxString(value_.c_str(), wxConvUTF8));
4586     // Should switch to version > 2.9 now!
4587 #if wxCHECK_VERSION(2,9,1)
4588     b->SetBitmap(wxBitmap(1, 1));
4589 #endif
4590     if (this->IsDynamicResize()) {
4591       this->SetWidgetSize(0,0);
4592 //      this->RefreshDynamicWidget();
4593     }
4594   }
4595 }
4596 
~GDLWidgetNormalButton()4597 GDLWidgetNormalButton::~GDLWidgetNormalButton() {
4598 #ifdef GDL_DEBUG_WIDGETS
4599   std::cout << "~GDLWidgetNormalButton(" << widgetID << ")" << std::endl;
4600 #endif
4601   if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
4602 }
4603 
4604 //this type of buttons use a container
GDLWidgetMenu(WidgetIDT p,EnvT * e,DStringGDL * value,DULong eventflags,wxBitmap * bitmap_)4605 GDLWidgetMenu::GDLWidgetMenu(WidgetIDT p, EnvT* e,
4606   DStringGDL* value, DULong eventflags, wxBitmap* bitmap_)
4607 : GDLWidgetButton(p, e, value, eventflags, bitmap_)
4608 {
4609 }
4610 
~GDLWidgetMenu()4611 GDLWidgetMenu::~GDLWidgetMenu() {
4612 #ifdef GDL_DEBUG_WIDGETS
4613   std::cout << "~GDLWidgetMenu(" << widgetID << ")" << std::endl;
4614 #endif
4615   // delete all children (in reverse order ?)
4616   while (!children.empty()) {
4617     GDLWidget* child = GetWidget(children.back());
4618     children.pop_back();
4619     if (child) {
4620 #ifdef GDL_DEBUG_WIDGETS
4621       std::cout << "~GDLWidgetMenu(" << widgetID << "): removing child: ID=" << child->GetWidgetID() << std::endl;
4622 #endif
4623       delete child;
4624     } else {
4625 #ifdef GDL_DEBUG_WIDGETS
4626       std::cout << "~GDLWidgetMenu(" << widgetID << "): ignoring unexisting child: ID=" << child->GetWidgetID() << std::endl;
4627 #endif
4628     }
4629   }
4630 }
4631 
4632 //this type of buttons use a container
GDLWidgetSubMenu(WidgetIDT p,EnvT * e,DStringGDL * value,DULong eventflags,bool hasSeparatorAbove,wxBitmap * bitmap_)4633 GDLWidgetSubMenu::GDLWidgetSubMenu(WidgetIDT p, EnvT* e,
4634   DStringGDL* value, DULong eventflags, bool hasSeparatorAbove, wxBitmap* bitmap_)
4635 : GDLWidgetMenu(p, e, value, eventflags, bitmap_)
4636 , addSeparatorAbove( hasSeparatorAbove)
4637 , the_sep(NULL)
4638 {
4639   GDLWidget* gdlParent = GetWidget(parentID);
4640 
4641   //get default value: a menu. May be NULL here
4642   wxMenu *menu = dynamic_cast<wxMenu*> (gdlParent->GetWxWidget());
4643   wxMenu* submenu = new wxMenu();
4644   if (addSeparatorAbove) the_sep=menu->AppendSeparator();
4645   menuItem = new wxMenuItem(menu, widgetID, valueWxString, wxEmptyString, wxITEM_NORMAL, submenu );
4646   if (bitmap_) menuItem->SetBitmap(*bitmap_);
4647   menu->Append(menuItem);
4648   menu->Enable(menuItem->GetId(), sensitive);
4649   theWxContainer = menu; //is not a window: special treatment
4650   theWxWidget = submenu;
4651   buttonType = MENU;
4652   //No UPDATE_WINDOW see menu entry.
4653 
4654 }
4655 
SetSensitive(bool value)4656 void GDLWidgetSubMenu::SetSensitive(bool value) {
4657   sensitive = value;
4658   if (menuItem) menuItem->Enable(value);
4659 }
4660 
SetButtonWidgetLabelText(const DString & value_)4661 void GDLWidgetSubMenu::SetButtonWidgetLabelText( const DString& value_ ) {
4662   if (menuItem && value_.length() > 0 ) menuItem->SetItemLabel( wxString(value_.c_str( ), wxConvUTF8 ) ); //avoid null strings asserts!
4663 }
4664 
SetButtonWidgetBitmap(wxBitmap * bitmap_)4665 void GDLWidgetSubMenu::SetButtonWidgetBitmap( wxBitmap* bitmap_ ) {
4666     if ( menuItem ) {
4667       menuItem->SetBitmap( *bitmap_ ); //probably only MsW
4668     }
4669 }
4670 
~GDLWidgetSubMenu()4671 GDLWidgetSubMenu::~GDLWidgetSubMenu() {
4672 #ifdef GDL_DEBUG_WIDGETS
4673   std::cout << "~GDLWidgetSubMenu(" << widgetID << ")" << std::endl;
4674 #endif
4675   GDLWidgetMenu* gdlParent = dynamic_cast<GDLWidgetMenu*> (GetWidget(parentID));
4676   if (gdlParent) gdlParent->RemoveChild(widgetID);
4677 
4678   if (menuItem) {
4679 #ifdef GDL_DEBUG_WIDGETS
4680     std::cout << "~GDLWidgetSubMenu(" << widgetID << "): attempting to remove submenu #" << menuItem->GetId() << " from menu " << parentID << std::endl;
4681 #endif
4682     wxMenu* menu = dynamic_cast<wxMenu*> (theWxContainer);
4683     menu->Remove(menuItem);
4684     if (addSeparatorAbove) menu->Remove(the_sep);
4685   }
4686 }
4687 
4688 //this type of buttons use a container
GDLWidgetMenuEntry(WidgetIDT p,EnvT * e,DStringGDL * value,DULong eventflags,bool hasSeparatorAbove,wxBitmap * bitmap_,bool checked_type)4689 GDLWidgetMenuEntry::GDLWidgetMenuEntry(WidgetIDT p, EnvT* e,
4690   DStringGDL* value, DULong eventflags, bool hasSeparatorAbove, wxBitmap* bitmap_, bool checked_type)
4691 : GDLWidgetButton(p, e, value, eventflags, bitmap_)
4692 , addSeparatorAbove( hasSeparatorAbove)
4693 , checkedState(false) //unchecked at start
4694 , the_sep(NULL)
4695 {
4696   GDLWidget* gdlParent = GetWidget(parentID);
4697   if (bitmap_) checked_type=false; //wxWidgets does not like checked bitmaps
4698   //get default value: a menu. May be NULL here
4699   wxMenu *menu = dynamic_cast<wxMenu*> (gdlParent->GetWxWidget());
4700   if (addSeparatorAbove) the_sep=menu->AppendSeparator();
4701   menuItem = new wxMenuItem(menu, widgetID, valueWxString,wxEmptyString, checked_type?wxITEM_CHECK:wxITEM_NORMAL);
4702   if (bitmap_) menuItem->SetBitmap(*bitmap_);
4703   menu->Append(menuItem);
4704   menu->Enable(menuItem->GetId(), sensitive);
4705   theWxContainer = menu; //is not a window
4706   theWxWidget = menuItem;
4707   buttonType = ENTRY;
4708   //NO UPDATE WINDOW as menu are dynamical on stack.
4709 }
4710 
SetSensitive(bool value)4711 void GDLWidgetMenuEntry::SetSensitive(bool value) {
4712   sensitive = value;
4713   wxMenuItem* item = dynamic_cast<wxMenuItem*> (theWxWidget);
4714   if (item) item->Enable(value);
4715 }
4716 
SetButtonWidgetLabelText(const DString & value_)4717 void GDLWidgetMenuEntry::SetButtonWidgetLabelText( const DString& value_ ) {
4718   wxMenuItem* item = dynamic_cast<wxMenuItem*> (theWxWidget);
4719   if (item)  item->SetItemLabel(wxString( value_.c_str( ), wxConvUTF8 ));
4720 }
SetButtonWidgetBitmap(wxBitmap * bitmap_)4721 void GDLWidgetMenuEntry::SetButtonWidgetBitmap( wxBitmap* bitmap_ ) {
4722 wxMenuItem* item = dynamic_cast<wxMenuItem*> (theWxWidget);
4723   if (item) {
4724     item->SetBitmap( *bitmap_); //probably only on MSW
4725   }
4726 }
4727 
~GDLWidgetMenuEntry()4728 GDLWidgetMenuEntry::~GDLWidgetMenuEntry() {
4729 #ifdef GDL_DEBUG_WIDGETS
4730   std::cout << "~GDLWidgetMenuEntry(" << widgetID << ")" << std::endl;
4731 #endif
4732    GDLWidgetMenu* gdlParent = dynamic_cast<GDLWidgetMenu*>(GetWidget(parentID));
4733    if (gdlParent) gdlParent->RemoveChild(widgetID);
4734   if (menuItem) {
4735 #ifdef GDL_DEBUG_WIDGETS
4736     std::cout << "~GDLWidgetMenuEntry(" << widgetID << "): attempting to remove menuitem #" << menuItem->GetId() << " of menu " << parentID << std::endl;
4737 #endif
4738     wxMenu* menu = dynamic_cast<wxMenu*> (theWxContainer);
4739     menu->Remove(menuItem);
4740     if (addSeparatorAbove) menu->Remove(the_sep);
4741   }
4742 }
4743 
4744 //Mbar buttons are pulldown MENUS, so container
4745 
4746 #ifdef PREFERS_MENUBAR
GDLWidgetMenuBarButton(WidgetIDT p,EnvT * e,DStringGDL * value,DULong eventflags,DStringGDL * buttonToolTip)4747 GDLWidgetMenuBarButton::GDLWidgetMenuBarButton(WidgetIDT p, EnvT* e,
4748   DStringGDL* value, DULong eventflags, DStringGDL* buttonToolTip)
4749 : GDLWidgetMenu(p, e, value, eventflags, NULL)
4750 , entry(-1) {
4751   GDLWidgetMenuBar* gdlParent = dynamic_cast<GDLWidgetMenuBar*> (GetWidget(parentID));
4752   if (gdlParent) {
4753     wxMenuBar *menuBar = dynamic_cast<wxMenuBar*> (gdlParent->GetWxWidget());
4754     assert(menuBar != NULL);
4755     wxMenu* menu = new wxMenu();
4756     theWxContainer = menuBar; //not a WwxWindow
4757     theWxWidget = menu;
4758     entry = menuBar->GetMenuCount();
4759     menuBar->Insert(entry, menu, valueWxString);
4760     menuBar->EnableTop(entry, sensitive);
4761     buttonType = MENU;
4762 
4763     //MBAR menus cannot have a tooltip due to
4764 
4765 //    UPDATE_WINDOW; REALIZE_IF_NEEDED; //made on the fly, non need.
4766   }
4767 }
4768 
4769 #else
GDLWidgetMenuBarButton(WidgetIDT p,EnvT * e,DStringGDL * value,DULong eventflags,wxBitmap * bitmap_,DStringGDL * buttonToolTip)4770 GDLWidgetMenuBarButton::GDLWidgetMenuBarButton(WidgetIDT p, EnvT* e,
4771   DStringGDL* value, DULong eventflags, wxBitmap* bitmap_,  DStringGDL* buttonToolTip)
4772 : GDLWidgetMenu(p, e, value, eventflags, NULL)
4773 , entry(NULL) {
4774 
4775 
4776   GDLWidgetMenuBar* gdlParent = dynamic_cast<GDLWidgetMenuBar*> (GetWidget(parentID));
4777   assert(gdlParent->IsMenuBar());
4778 
4779   wxToolBar *toolBar = dynamic_cast<wxToolBar*> (gdlParent->GetWxWidget());
4780     assert(toolBar != NULL);
4781     if (bitmap_ == NULL) {
4782     wSize=computeWidgetSize();
4783     wxButtonGDL *button = new wxButtonGDL(font, toolBar, widgetID, valueWxString,
4784       wOffset, wSize,  wxBORDER_NONE);
4785     buttonType = POPUP_NORMAL; //gdlMenuButton is a wxButton --> normal. Bitmaps will be supported starting from 2.9.1
4786     theWxContainer = button;
4787     theWxWidget = button->GetPopupMenu(); //a menu
4788     button->Enable(sensitive);
4789     entry=toolBar->AddControl(button);
4790     wxSize tbSize=toolBar->GetSize();
4791     if (tbSize.y < wSize.y) toolBar->SetSize(wxSize(-1,wSize.y));
4792     toolBar->Realize();
4793     } else {
4794     wxBitmapButtonGDL *button = new wxBitmapButtonGDL(toolBar, widgetID, *bitmap_,
4795       wOffset, wSize,  wxBU_EXACTFIT|wxBORDER_NONE);
4796     buttonType = POPUP_BITMAP; //
4797     theWxContainer = button;
4798     theWxWidget = button->GetPopupMenu(); //a menu
4799     button->Enable(sensitive);
4800     entry=toolBar->AddControl(button);
4801     wxSize tbSize=toolBar->GetSize();
4802     if (tbSize.y < wSize.y) toolBar->SetSize(wxSize(-1,wSize.y));
4803     toolBar->Realize();
4804     }
4805 
4806   wxWindow *win = dynamic_cast<wxWindow*> (theWxContainer);
4807   if (win) {
4808     if (buttonToolTip) win->SetToolTip(wxString((*buttonToolTip)[0].c_str(), wxConvUTF8));
4809     if (widgetSizer) widgetSizer->Add(win, DONOTALLOWSTRETCH, widgetStyle|wxALL, gdlSPACE); //|wxALL, gdlSPACE_BUTTON);
4810   } else cerr << "Warning GDLWidgetMenuButton::GDLWidgetMenuButton(): widget type confusion.\n";
4811 
4812 //    UPDATE_WINDOW; REALIZE_IF_NEEDED;
4813 }
4814 #endif
4815 
SetSensitive(bool value)4816 void GDLWidgetMenuBarButton::SetSensitive(bool value) {
4817 #ifdef PREFERS_MENUBAR
4818   sensitive = value;
4819   wxMenuBar *menuBar = dynamic_cast<wxMenuBar*> (theWxContainer);
4820   menuBar->EnableTop(entry, value);
4821 #else
4822   GDLWidget::SetSensitive(value)  ;
4823 #endif
4824 }
4825 
SetButtonWidgetLabelText(const DString & value_)4826 void GDLWidgetMenuBarButton::SetButtonWidgetLabelText( const DString& value_ ) {
4827 #ifdef PREFERS_MENUBAR
4828   wxMenuBar *menuBar = dynamic_cast<wxMenuBar*> (theWxContainer);
4829   menuBar->SetMenuLabel(entry, wxString( value_.c_str( ), wxConvUTF8 ));
4830 #else
4831   wxButton* m=dynamic_cast<wxButton*>(theWxWidget);
4832   if (m) m->SetLabelText(wxString( value_.c_str( ), wxConvUTF8 ));
4833   this->RefreshDynamicWidget();
4834 #endif
4835 }
4836 
~GDLWidgetMenuBarButton()4837 GDLWidgetMenuBarButton::~GDLWidgetMenuBarButton() {
4838 #ifdef GDL_DEBUG_WIDGETS
4839   std::cout << "~GDLWidgetMenuBarButton(" << widgetID << ")" << std::endl;
4840 #endif
4841 #ifdef PREFERS_MENUBAR
4842   GDLWidgetMenuBar* gdlParent = dynamic_cast<GDLWidgetMenuBar*>(GetWidget(parentID));
4843   //which pos?
4844   if (gdlParent) {
4845     int pos=gdlParent->GetChildrenPos(widgetID);
4846     gdlParent->RemoveChild(widgetID);
4847     if (pos >= 0) {
4848       wxMenuBar *menuBar = dynamic_cast<wxMenuBar*> (theWxContainer);
4849       menuBar->Remove(pos);
4850     }
4851   }
4852 #else
4853  GDLWidgetMenuBar* gdlParent = dynamic_cast<GDLWidgetMenuBar*> (GetWidget(parentID));
4854   assert(gdlParent->IsMenuBar());
4855   wxToolBar *toolBar = dynamic_cast<wxToolBar*> (gdlParent->GetWxWidget());
4856   assert(toolBar != NULL);
4857   toolBar->RemoveTool(widgetID);
4858 #endif
4859 }
4860 
4861 //a MenuButton Widget is an otherwise normal button in a Base that activates a pulldown menu and is a container
GDLWidgetMenuButton(WidgetIDT p,EnvT * e,DStringGDL * value,DULong eventflags,wxBitmap * bitmap_,DStringGDL * buttonToolTip)4862 GDLWidgetMenuButton::GDLWidgetMenuButton(WidgetIDT p, EnvT* e,
4863   DStringGDL* value, DULong eventflags, wxBitmap* bitmap_, DStringGDL* buttonToolTip)
4864 : GDLWidgetMenu(p, e, value, eventflags, bitmap_) {
4865   GDLWidget* gdlParent = GetWidget(parentID);
4866   widgetPanel = GetParentPanel();
4867   widgetSizer = GetParentSizer();
4868   widgetStyle = widgetAlignment();
4869   wSize = computeWidgetSize();
4870 
4871   assert(gdlParent->IsBase());
4872 
4873   //A menu button in a base is a button starting a popup menu. it is a container also.
4874   //2 different buttons, if bitmap or not, waiting for version > 2.9.1 to have bitmaps handled for ALL buttontypes:
4875   if (bitmap_ == NULL) {
4876     wxButtonGDL *button = new wxButtonGDL(font, widgetPanel, widgetID, valueWxString,
4877       wOffset, wxDefaultSize, buttonTextAlignment());
4878     button->SetSize(wSize);
4879     button->SetMinSize(wSize);
4880     buttonType = POPUP_NORMAL; //gdlMenuButton is a wxButton --> normal. Bitmaps will be supported starting from 2.9.1
4881     theWxContainer = button;
4882     theWxWidget = button->GetPopupMenu(); //a menu
4883     button->Enable(sensitive);
4884   } else {
4885     wxBitmapButtonGDL *button = new wxBitmapButtonGDL(widgetPanel, widgetID, *bitmap_,
4886       wOffset, wxDefaultSize, buttonTextAlignment());
4887     button->SetSize(wSize);
4888     button->SetMinSize(wSize);
4889     buttonType = POPUP_BITMAP; //
4890     theWxContainer = button;
4891     theWxWidget = button->GetPopupMenu(); //a menu
4892     button->Enable(sensitive);
4893   }
4894   wxWindow *win = dynamic_cast<wxWindow*> (theWxContainer);
4895   if (win) {
4896     if (buttonToolTip) win->SetToolTip(wxString((*buttonToolTip)[0].c_str(), wxConvUTF8));
4897     if (widgetSizer) widgetSizer->Add(win, DONOTALLOWSTRETCH, widgetStyle|wxALL, gdlSPACE); //|wxALL, gdlSPACE_BUTTON);
4898   } else cerr << "Warning GDLWidgetMenuButton::GDLWidgetMenuButton(): widget type confusion.\n";
4899 
4900 //  UPDATE_WINDOW
4901   REALIZE_IF_NEEDED
4902 }
4903 
SetSensitive(bool value)4904 void GDLWidgetMenuButton::SetSensitive(bool value) {
4905   sensitive = value;
4906   wxButton* m = dynamic_cast<wxButton*> (theWxContainer);
4907   if (m) m->Enable(value);
4908 }
4909 
SetButtonWidgetLabelText(const DString & value_)4910 void GDLWidgetMenuButton::SetButtonWidgetLabelText( const DString& value_ ) {
4911   wxButton* m=dynamic_cast<wxButton*>(theWxContainer);
4912   if (m) m->SetLabelText(wxString( value_.c_str( ), wxConvUTF8 ));
4913   this->RefreshDynamicWidget();
4914 }
4915 
~GDLWidgetMenuButton()4916 GDLWidgetMenuButton::~GDLWidgetMenuButton() {
4917 #ifdef GDL_DEBUG_WIDGETS
4918   std::cout << "~GDLWidgetMenuButton(" << widgetID << ")" << std::endl;
4919 #endif
4920     GDLWidgetBase* b=dynamic_cast<GDLWidgetBase*>(GetWidget(parentID));
4921     if (b && !b->IsContextBase()) if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
4922   }
4923 
SetButtonWidgetBitmap(wxBitmap * bitmap_)4924 void GDLWidgetButton::SetButtonWidgetBitmap( wxBitmap* bitmap_ ) {
4925   if ( buttonType == BITMAP) {
4926     wxBitmapButton *b = dynamic_cast<wxBitmapButton*> (theWxWidget);
4927     if ( b ) {
4928       b->SetBitmapLabel( *bitmap_ );
4929       b->SetLabelText(wxEmptyString);
4930       }
4931   } else if ( buttonType == POPUP_BITMAP ) {
4932     wxBitmapButton *b = dynamic_cast<wxBitmapButton*> (theWxContainer); //not the wxWidget since the widget is the popup menu itself.
4933     if ( b ) {
4934       b->SetBitmapLabel( *bitmap_ );
4935       b->SetLabelText(wxEmptyString);
4936       }
4937   }  else if ( buttonType == MENU || buttonType ==ENTRY) {
4938     if ( menuItem != NULL ) {
4939       menuItem->SetBitmap( *bitmap_ );
4940       menuItem->SetItemLabel(wxT(" ")); //setting null strings to menus is not permitted !!!!
4941     }
4942   }
4943 // Should switch to version > 2.9 now!
4944 #if wxCHECK_VERSION(2,9,1)
4945   else if ( buttonType == NORMAL || buttonType == POPUP_NORMAL) {
4946       wxButton *b = dynamic_cast<wxButton*> (theWxWidget);
4947       if ( b ) {
4948         b->SetBitmapLabel( *bitmap_ );
4949         b->SetLabelText(wxEmptyString);
4950       }
4951      }
4952 #endif
4953   this->RefreshDynamicWidget();
4954 }
4955 
GDLWidgetList(WidgetIDT p,EnvT * e,BaseGDL * value,DLong style,DULong eventflags)4956 GDLWidgetList::GDLWidgetList( WidgetIDT p, EnvT* e, BaseGDL *value, DLong style, DULong eventflags )
4957     : GDLWidget( p, e, value, eventflags)
4958 , maxlinelength(0)
4959 , nlines(0)
4960 {
4961   GDLWidget* gdlParent = GetWidget( parentID );
4962   widgetPanel = GetParentPanel( );
4963   widgetSizer = GetParentSizer( );
4964 
4965   START_ADD_EVENTUAL_FRAME
4966 
4967   widgetStyle = widgetAlignment();
4968   if( vValue->Type() != GDL_STRING)
4969   {
4970     vValue = static_cast<DStringGDL*> (vValue->Convert2( GDL_STRING, BaseGDL::CONVERT ));
4971   }
4972   DStringGDL* val = static_cast<DStringGDL*> (vValue);
4973 
4974   nlines = val->N_Elements( );
4975   wxArrayString choices; // = new wxString[n];
4976   for ( SizeT i = 0; i < nlines; ++i ){
4977     int length=(*val)[i].length();
4978     if (length>maxlinelength){
4979       maxlinelength=length;
4980     }
4981     choices.Add( wxString( (*val)[i].c_str( ), wxConvUTF8 ) );
4982   }
4983   wxListBox * list=new wxListBox();
4984   theWxContainer = theWxWidget = list;
4985   //ok now size can be computed
4986   list->Create(widgetPanel, widgetID, wxDefaultPosition, wxDefaultSize , choices, style|wxLB_NEEDED_SB|wxLB_SINGLE); //|wxLB_MULTIPLE );
4987   this->setFont(); //set fancy font before computing sizes!
4988   wSize=computeWidgetSize();
4989   list->SetClientSize(wSize);
4990   list->SetMinClientSize(wSize);
4991   list->SetSelection(wxNOT_FOUND);//necessary to avoid spurious event on first click.
4992   this->AddToDesiredEvents( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED,wxCommandEventHandler(gdlwxFrame::OnListBoxDoubleClicked),list);
4993   this->AddToDesiredEvents( wxEVT_COMMAND_LISTBOX_SELECTED,wxCommandEventHandler(gdlwxFrame::OnListBox),list);
4994 
4995   END_ADD_EVENTUAL_FRAME
4996   TIDY_WIDGET(gdlBORDER_SPACE)
4997 
4998 //  UPDATE_WINDOW
4999   REALIZE_IF_NEEDED
5000 }
SetWidgetSize(DLong sizex,DLong sizey)5001 void GDLWidgetList::SetWidgetSize(DLong sizex, DLong sizey)
5002 {
5003 
5004   START_CHANGESIZE_NOEVENT
5005 
5006   wxWindow* me = dynamic_cast<wxWindow*> (this->GetWxWidget());
5007   if (me == NULL) {
5008 #ifdef GDL_DEBUG_WIDGETS
5009     wxMessageOutputStderr().Printf(_T("GDLWidgetList::SetSize of non wxWindow %s\n"), this->GetWidgetName().c_str());
5010 #endif
5011     return;
5012   }
5013   //a graphic window cannot be larger than the base widget it is in, if the base widget size has been fixed
5014   wxSize currentSize=me->GetSize();
5015   wxSize currentBestSize=me->GetBestSize();
5016 #ifdef GDL_DEBUG_WIDGETS
5017   wxMessageOutputStderr( ).Printf( _T( "GDLWidgetList::SetSize currentSize=%d,%d \n"),currentSize.x,currentSize.y);
5018 #endif
5019 
5020   //widget text size is in LINES in Y and CHARACTERS in X.
5021   wxRealPoint widgetSize = wxRealPoint(-1,-1);
5022   wxSize fontSize = getFontSize();
5023   //based on experience, actual line height is 1.2 times font y size for fonts > 20 but 1.5 for smaller fonts
5024   int lineHeight=(fontSize.y<20)?fontSize.y*1.5:fontSize.y*1.2;
5025   if (sizex > 0) {
5026     widgetSize.x = (sizex+0.5) * fontSize.x;
5027   } else {
5028     widgetSize.x = currentSize.x;
5029   }
5030 
5031   if (sizey > 0) {
5032     widgetSize.y =sizey * lineHeight;
5033   } else {
5034     widgetSize.y = currentSize.y;
5035   }
5036 
5037   if (sizex > 0 && maxlinelength > sizex) widgetSize.y += gdlSCROLL_HEIGHT_X;
5038   if (nlines > sizey) widgetSize.x += gdlSCROLL_WIDTH_Y;
5039   widgetSize.y += 10;
5040 
5041   sizex=ceil(widgetSize.x);
5042   sizey=ceil(widgetSize.y);
5043   wSize.x = sizex;
5044   wSize.y = sizey;
5045   me->SetSize(wSize);
5046   me->SetMinSize(wSize);
5047 
5048   if (!widgetSizer) { if (framePanel) framePanel->Fit();}
5049 
5050   UPDATE_WINDOW
5051 
5052   END_CHANGESIZE_NOEVENT
5053 
5054 #ifdef GDL_DEBUG_WIDGETS
5055     wxMessageOutputStderr().Printf(_T("GDLWidgetList::SetSize %d,%d (%s)\n"), sizex, sizey, this->GetWidgetName().c_str());
5056 #endif
5057 }
5058 
SetValue(BaseGDL * value)5059 void GDLWidgetList::SetValue(BaseGDL *value){
5060   GDLDelete(vValue);
5061   vValue=value;
5062  if( vValue->Type() != GDL_STRING)
5063   {
5064     vValue = static_cast<DStringGDL*> (vValue->Convert2( GDL_STRING, BaseGDL::CONVERT ));
5065   }
5066   DStringGDL* val = static_cast<DStringGDL*> (vValue);
5067 
5068   wxArrayString newchoices; // = new wxString[n];
5069   nlines = val->N_Elements( );
5070   for ( SizeT i = 0; i < nlines; ++i ){
5071     int length=(*val)[i].length();
5072     if (length>maxlinelength){
5073       maxlinelength=length;
5074     }
5075    newchoices.Add( wxString( (*val)[i].c_str( ), wxConvUTF8 ) );
5076   }
5077 
5078   wxListBox * list = dynamic_cast<wxListBox*>(theWxWidget);
5079   assert( list != NULL);
5080 
5081   list->Clear();
5082   list->InsertItems(newchoices,0);
5083   list->SetSelection(wxNOT_FOUND);
5084 }
5085 
SelectEntry(DLong entry_number)5086 void GDLWidgetList::SelectEntry(DLong entry_number){
5087   if (entry_number < 0 ) return;
5088  wxListBox * list=dynamic_cast<wxListBox*>(theWxWidget);
5089   assert( list != NULL);
5090   if (entry_number > list->GetCount()-1) return;
5091  list->Select(entry_number);
5092 }
5093 
GetSelectedEntries()5094 BaseGDL* GDLWidgetList::GetSelectedEntries(){
5095  wxListBox * list=dynamic_cast<wxListBox*>(theWxWidget);
5096   assert( list != NULL);
5097  wxArrayInt selections;
5098  list->GetSelections(selections);
5099  DIntGDL* liste;
5100  if  (selections.Count()<1) {
5101    liste=new DIntGDL(-1);
5102    return liste;
5103  }
5104  liste=new DIntGDL(dimension(selections.Count()));
5105  for (SizeT i=0; i< selections.Count(); ++i) (*liste)[i]=selections[i];
5106  return liste;
5107 }
5108 
~GDLWidgetList()5109 GDLWidgetList::~GDLWidgetList(){
5110 #ifdef GDL_DEBUG_WIDGETS
5111   std::cout << "~GDLWidgetList(" << widgetID << ")" << std::endl;
5112 #endif
5113   if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
5114 }
5115 
GDLWidgetDropList(WidgetIDT p,EnvT * e,BaseGDL * value,DULong eventflags,const DString & title_,DLong style_)5116 GDLWidgetDropList::GDLWidgetDropList( WidgetIDT p, EnvT* e, BaseGDL *value, DULong eventflags ,
5117 const DString& title_, DLong style_ )
5118 : GDLWidget( p, e, static_cast<DStringGDL*> (value->Convert2( GDL_STRING, BaseGDL::CONVERT )), eventflags)
5119 , title( title_ )
5120 , style( style_)
5121 {
5122   GDLWidget* gdlParent = GetWidget(parentID);
5123   widgetPanel = GetParentPanel();
5124   widgetSizer = GetParentSizer();
5125 
5126   DStringGDL* val = static_cast<DStringGDL*> (vValue);
5127   DLong n = val->N_Elements();
5128   wxArrayString choices; // = new wxString[n];
5129   for (SizeT i = 0; i < n; ++i) {
5130     choices.Add(wxString((*val)[i].c_str(), wxConvUTF8));
5131   }
5132 
5133 ///  static int flatIx=e->KeywordIx("FLAT"); ignored.
5134    widgetStyle=widgetAlignment();
5135   bool hastitle=(title.size()>0);
5136 
5137   //get defined sizes if any
5138   wSize=computeWidgetSize( );
5139 
5140   wxChoice * droplist;
5141   theWxContainer=NULL;
5142   wxSizer* theSizer=NULL;
5143   wxWindow* theWindow = widgetPanel;
5144   if (frameWidth > 0) {
5145     framePanel=new wxPanel(theWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, gdlBORDER_EXT);
5146  #ifdef GDL_DEBUG_WIDGETS_COLORIZE
5147     framePanel->SetBackgroundColour(wxColour(0x3a, 0x82, 0x56)); //vert fonce
5148 #endif
5149     wxSizer* frameSizer=new wxBoxSizer(wxVERTICAL);
5150     framePanel->SetSizer(frameSizer);
5151     theWxContainer=framePanel;
5152     theWindow=framePanel;
5153     wxPanel* intFramePanel=new wxPanel(framePanel);
5154     theWindow=intFramePanel;
5155     frameSizer->Add(intFramePanel, DONOTALLOWSTRETCH, wxALL, frameWidth);
5156   }
5157   if (hastitle) {
5158     wxPanel* comboPanel=new wxPanel(theWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
5159     wxSizer* combosz = new wxBoxSizer(wxHORIZONTAL);
5160     comboPanel->SetSizer(combosz);
5161     if (!theWxContainer) theWxContainer = comboPanel; //else stays as panel_if_framed.
5162     this->setFont(comboPanel); //enable fancy font
5163     wxStaticText *theTitle=new wxStaticText(comboPanel,wxID_ANY,wxString(title.c_str(), wxConvUTF8));
5164     combosz->Add(theTitle,DONOTALLOWSTRETCH, wxALIGN_CENTER|wxALL,gdlSPACE);
5165     combosz->AddSpacer(5);
5166     droplist = new wxChoice( comboPanel, widgetID, wxDefaultPosition, wxDefaultSize, choices, style );
5167     droplist->SetSize(wSize);
5168     droplist->SetMinSize(wSize);
5169     theWxWidget = droplist;
5170     combosz->Add(droplist,DONOTALLOWSTRETCH,wxALIGN_CENTER|wxALL,gdlSPACE);
5171     combosz->Fit(droplist);
5172     comboPanel->Fit();
5173     } else {
5174     droplist = new wxChoice( theWindow, widgetID, wxDefaultPosition, wxDefaultSize, choices, style );
5175     droplist->SetSize(wSize);
5176     droplist->SetMinSize(wSize);
5177     theWxWidget = droplist;
5178     if (!theWxContainer) theWxContainer = droplist;
5179   }
5180   if (framePanel) framePanel->Fit();
5181   if (widgetSizer) {
5182     widgetSizer->Add(dynamic_cast<wxWindow*>(theWxContainer), DONOTALLOWSTRETCH, widgetStyle|wxALL, gdlTEXT_SPACE);
5183     widgetSizer->Fit(dynamic_cast<wxWindow*>(theWxContainer));
5184   } else {
5185     widgetPanel->Fit();
5186     dynamic_cast<wxWindow*>(theWxContainer)->SetPosition(wOffset);
5187   }
5188 
5189 
5190   droplist->SetSelection(0);
5191   this->AddToDesiredEvents(  wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler(gdlwxFrame::OnDropList),droplist);
5192 
5193 //  UPDATE_WINDOW
5194   REALIZE_IF_NEEDED
5195 }
5196 
SetValue(BaseGDL * value)5197 void GDLWidgetDropList::SetValue(BaseGDL *value){
5198    GDLDelete(vValue);
5199   vValue=value;
5200  if( vValue->Type() != GDL_STRING)
5201   {
5202     vValue = static_cast<DStringGDL*> (vValue->Convert2( GDL_STRING, BaseGDL::CONVERT ));
5203   }
5204   DStringGDL* val = static_cast<DStringGDL*> (vValue);
5205   wxArrayString newchoices; // = new wxString[n];
5206   for ( SizeT i = 0; i < val->N_Elements( ); ++i )  newchoices.Add( wxString( (*val)[i].c_str( ), wxConvUTF8 ) );
5207 
5208   wxChoice* droplist=dynamic_cast<wxChoice*>(theWxWidget);
5209   assert( droplist != NULL);
5210   droplist->Clear();
5211   droplist->Append(newchoices);
5212   droplist->SetSelection(0);
5213   //IDL behaviour  with DynamicResize is identical
5214   if (this->IsDynamicResize()) {
5215     wSize=droplist->GetSizeFromTextSize(droplist->GetTextExtent(newchoices[0]).GetWidth());
5216     droplist->SetMinSize(wSize);
5217     droplist->SetSize(wSize);
5218    }
5219   RefreshDynamicWidget();
5220 }
5221 
SelectEntry(DLong entry_number)5222 void GDLWidgetDropList::SelectEntry(DLong entry_number){
5223  wxChoice * droplist=dynamic_cast<wxChoice*>(theWxWidget);
5224  assert( droplist != NULL);
5225  droplist->Select(entry_number);
5226 }
5227 
GetSelectedEntry()5228 BaseGDL* GDLWidgetDropList::GetSelectedEntry(){
5229   wxChoice * droplist=dynamic_cast<wxChoice*>(theWxWidget);
5230   assert( droplist != NULL);
5231   return new DIntGDL(droplist->GetSelection());
5232 }
5233 
~GDLWidgetDropList()5234 GDLWidgetDropList::~GDLWidgetDropList(){
5235 #ifdef GDL_DEBUG_WIDGETS
5236   std::cout << "~GDLWidgetDropList(" << widgetID << ")" << std::endl;
5237 #endif
5238     if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
5239 }
5240 
GDLWidgetComboBox(WidgetIDT p,EnvT * e,BaseGDL * value,DULong eventflags,DLong style_)5241 GDLWidgetComboBox::GDLWidgetComboBox( WidgetIDT p, EnvT* e, BaseGDL *value, DULong eventflags, DLong style_ )
5242 : GDLWidget( p, e, static_cast<DStringGDL*> (value->Convert2( GDL_STRING, BaseGDL::CONVERT )) , eventflags)
5243 , style( style_)
5244 {
5245   GDLWidget* gdlParent = GetWidget( parentID );
5246   widgetPanel = GetParentPanel( );
5247   widgetSizer = GetParentSizer( );
5248 
5249  START_ADD_EVENTUAL_FRAME
5250 
5251   widgetStyle=widgetAlignment();
5252 //  wxSize size = computeWidgetSize();
5253 
5254   DStringGDL* val = static_cast<DStringGDL*> (vValue);
5255   DLong n = val->N_Elements( );
5256   wxArrayString choices; // = new wxString[n];
5257   for ( SizeT i = 0; i < n; ++i )
5258   choices.Add( wxString( (*val)[i].c_str( ), wxConvUTF8 ) );
5259 
5260   wxString val0WxString = wxString( (*val)[0].c_str( ), wxConvUTF8 );
5261 
5262   wxComboBox * combobox = new wxComboBox();
5263   combobox->Create(widgetPanel, widgetID, val0WxString, wxDefaultPosition, wxDefaultSize, choices, style );
5264 
5265 
5266   theWxContainer = theWxWidget = combobox;
5267   this->AddToDesiredEvents( wxEVT_COMMAND_COMBOBOX_SELECTED,wxCommandEventHandler(gdlwxFrame::OnComboBox),combobox);
5268   if (style & wxTE_PROCESS_ENTER) this->AddToDesiredEvents( wxEVT_COMMAND_TEXT_ENTER,wxCommandEventHandler(gdlwxFrame::OnComboBoxTextEnter),combobox);
5269   wSize=computeWidgetSize();
5270   if (widgetSizer==NULL) {
5271     if (wSize.x < 1) wSize.x=gdlDEFAULT_XSIZE+gdlCOMBOBOX_ARROW_WIDTH;
5272   }
5273   combobox->SetSize(wSize);
5274   combobox->SetMinSize(wSize);
5275 
5276   END_ADD_EVENTUAL_FRAME
5277   TIDY_WIDGET(gdlBORDER_SPACE)
5278 //  UPDATE_WINDOW
5279   REALIZE_IF_NEEDED
5280 }
5281 
SetValue(BaseGDL * value)5282 void GDLWidgetComboBox::SetValue(BaseGDL *value){
5283   GDLDelete(vValue);
5284   vValue=value;
5285  if( vValue->Type() != GDL_STRING)
5286   {
5287     vValue = static_cast<DStringGDL*> (vValue->Convert2( GDL_STRING, BaseGDL::CONVERT ));
5288   }
5289   DStringGDL* val = static_cast<DStringGDL*> (vValue);
5290   wxArrayString newchoices; // = new wxString[n];
5291   for ( SizeT i = 0; i < val->N_Elements( ); ++i )  newchoices.Add( wxString( (*val)[i].c_str( ), wxConvUTF8 ) );
5292 
5293   wxComboBox * combo = dynamic_cast<wxComboBox*>(theWxWidget);
5294   assert( combo != NULL);
5295   combo->Clear();
5296   combo->Append(newchoices);
5297   combo->SetSelection(0,0);
5298   combo->SetValue(newchoices[0]);
5299   //IDL behaviour  with DynamicResize is different as Combobox's size never decreases with this method, it cannot be smaller than the initial size.
5300   //this would plead to have a new wInitialSize for which wSize cannot be smaller her, but is reset to new values with SetSize. Oh well.
5301   if (this->IsDynamicResize()) {
5302     wSize=combo->GetSizeFromTextSize(combo->GetTextExtent(newchoices[0]).GetWidth());
5303     combo->SetMinSize(wSize);
5304     combo->SetSize(wSize);
5305   }
5306   RefreshDynamicWidget();
5307   }
5308 
AddItem(DString value,DLong pos)5309 void GDLWidgetComboBox::AddItem(DString value, DLong pos) {
5310   wxComboBox * combo = dynamic_cast<wxComboBox*>(theWxWidget);
5311   assert( combo != NULL);
5312   int nvalues=combo->GetCount();
5313   if (pos == -1) combo->Append( wxString( value.c_str( ), wxConvUTF8 ) );
5314   else if (pos > -1  && pos < nvalues) combo->Insert( wxString( value.c_str( ), wxConvUTF8 ), pos);
5315 }
5316 
DeleteItem(DLong pos)5317 void GDLWidgetComboBox::DeleteItem(DLong pos) {
5318   wxComboBox * combo = dynamic_cast<wxComboBox*>(theWxWidget);
5319   assert( combo != NULL);
5320   int nvalues=combo->GetCount();
5321   int selected=combo->GetSelection();
5322   if (pos > -1  && pos < nvalues) combo->Delete( pos );
5323   if (pos==selected && (nvalues-1) > 0 ) combo->Select((pos+1)%(nvalues-1)); else if (selected==-1 && pos==0) combo->Select(0);
5324 }
5325 
SelectEntry(DLong entry_number)5326 void GDLWidgetComboBox::SelectEntry(DLong entry_number){
5327  wxComboBox * combo=dynamic_cast<wxComboBox*>(theWxWidget);
5328   assert( combo != NULL);
5329  combo->Select(entry_number);
5330 }
5331 
GetSelectedEntry()5332 BaseGDL* GDLWidgetComboBox::GetSelectedEntry(){
5333   wxComboBox * combo=dynamic_cast<wxComboBox*>(theWxWidget);
5334   assert( combo != NULL);
5335   DStringGDL* stringres=new DStringGDL(dimension(1));
5336   (*stringres)[0]=combo->GetStringSelection().mb_str(wxConvUTF8); //return null string if no selection
5337   return stringres;
5338 }
5339 
~GDLWidgetComboBox()5340 GDLWidgetComboBox::~GDLWidgetComboBox(){
5341 #ifdef GDL_DEBUG_WIDGETS
5342   std::cout << "~GDLWidgetComboBox(" << widgetID <<")"<< std::endl;
5343 #endif
5344   if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
5345 }
5346 
GDLWidgetText(WidgetIDT p,EnvT * e,DStringGDL * valueStr,DULong eventflags,bool noNewLine_,bool editable_)5347 GDLWidgetText::GDLWidgetText( WidgetIDT p, EnvT* e, DStringGDL* valueStr, DULong eventflags, bool noNewLine_,
5348 bool editable_ )
5349 : GDLWidget( p, e, valueStr, eventflags )
5350 , noNewLine( noNewLine_ )
5351 , editable(editable_)
5352 , multiline(false)
5353 , maxlinelength(0)
5354 {
5355   static int wrapIx=e->KeywordIx("WRAP");
5356   wrapped=(e->KeywordSet(wrapIx));
5357   DString value = "";
5358   nlines=1;
5359   //textSize is the current size (fixed or computed) in characters.
5360   textSize=wSize;
5361   if (textSize.y > 1) multiline=true; //multiline is a property implied by the widget Ysize, nothing else
5362   //reform entries into one string, with eventual \n . If noNewLines, do not insert a \n . If ysize=1 and no scroll, idem.
5363   bool doNotAddNl=(noNewLine || (!multiline) );
5364 
5365   if( vValue != NULL)
5366   {
5367       for( int i=0; i<vValue->N_Elements(); ++i)
5368       {
5369         int length=((*static_cast<DStringGDL*> (vValue))[i]).length();
5370         value += (*static_cast<DStringGDL*> (vValue))[i];
5371         if ( !doNotAddNl) maxlinelength=(length>maxlinelength)?length:maxlinelength; else maxlinelength+=length;
5372         if ( !doNotAddNl )
5373 #ifdef _WIN32
5374         {value += "\r\n"; nlines++;}
5375 #else
5376         {value += '\n'; nlines++;}
5377 #endif
5378       }
5379   }
5380 
5381   lastValue = value;
5382 
5383   //now the string is formatted as the widget will see it. If the string contains \n  the widget will be multiline anyway.
5384   //recompute number of \n as some could have been embedded in each of the strings
5385   //recompute nlines, maxlinelength from start to be sure
5386   nlines=1;
5387   maxlinelength=0;
5388   const char* s=lastValue.c_str();
5389   int length=0;
5390   for (int i=0; i<lastValue.length(); ++i, ++length)
5391   {
5392     if (s[i]==10) {
5393       maxlinelength=(length>maxlinelength)?length:maxlinelength;
5394       nlines++;
5395       length=0;
5396     }
5397   }
5398   if (length>maxlinelength) maxlinelength=length; //if no last return.
5399 
5400   GDLWidget* gdlParent = GetWidget( parentID );
5401   widgetPanel = GetParentPanel( );
5402   widgetSizer = GetParentSizer( );
5403 
5404   START_ADD_EVENTUAL_FRAME
5405 
5406   widgetStyle = widgetAlignment();
5407   bool report=((eventFlags & GDLWidget::EV_ALL)==1);
5408 
5409  //for text, apparently, if   wxTE_MULTILINE is in effect, the font handler is probably RichText
5410  //and the text SIZE is OK only if imposed by a wxTextAttr. (go figure).
5411  //note that computeWidgetSize() above returns sizes "compatible" with the font size, without any trouble.
5412   wxTextAttr attr= wxTextAttr ();
5413   attr.SetFont(font, 	wxTEXT_ATTR_FONT);
5414   wxString valueWxString = wxString( lastValue.c_str( ), wxConvUTF8 );
5415   long textStyle = wxTE_RICH2|wxTE_NOHIDESEL;
5416 
5417   if (multiline) textStyle |= wxTE_MULTILINE;
5418   if (!scrolled) {textStyle |= wxTE_NO_VSCROLL;} else {textStyle |= wxHSCROLL;}
5419   if (wrapped) textStyle |= wxTE_WORDWRAP; else textStyle |= wxTE_DONTWRAP;
5420   if (!editable && !report ) textStyle |= wxTE_READONLY;
5421 
5422   wxTextCtrlGDL* text = new wxTextCtrlGDL(widgetPanel, widgetID, wxEmptyString/*valueWxString*/, wxDefaultPosition, wxDefaultSize, textStyle);
5423   // above, permits to a procedure (cw_field.pro for example) to filter the editing of text fields.
5424   // so wxTextCtrl::OnChar is overwritten in gdlwidgeteventhandler.cpp just for this reason.
5425   theWxContainer = theWxWidget = text;
5426   this->setFont();
5427   if ((textStyle & wxTE_MULTILINE)==0) text->SetMargins(wxPoint(gdlTEXT_XMARGIN,gdlTEXT_YMARGIN)); //without the if clause, provokes: GLib-GObject-WARNING **: 23:04:21.080: invalid cast from 'GtkTextView' to 'GtkEntry' (and does not work)
5428   text->SetDefaultStyle(attr);
5429   text->SetValue(valueWxString);
5430 
5431   wSize = computeWidgetSize(); //updates textSize.
5432   text->SetClientSize(wSize);
5433   text->SetMinClientSize(wSize);
5434 
5435   text->SetSelection(0,0);
5436   text->SetInsertionPoint(0);
5437   text->ShowPosition(0);
5438 
5439   END_ADD_EVENTUAL_FRAME
5440   TIDY_WIDGET(gdlBORDER_SPACE)
5441 
5442 //  this->AddToDesiredEvents( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(GDLFrame::OnTextEnter),text); //NOT USED
5443   if( editable || report) this->AddToDesiredEvents(wxEVT_CHAR, wxKeyEventHandler(wxTextCtrlGDL::OnChar),text);
5444   //add scrolling even if text is not scrollable since scroll is not permitted (IDL widgets are not at all the same as GTK...)
5445   if (!scrolled) this->AddToDesiredEvents(wxEVT_MOUSEWHEEL, wxMouseEventHandler(wxTextCtrlGDL::OnMouseEvents),text);
5446   this->AddToDesiredEvents( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(gdlwxFrame::OnText),text);
5447   if (report) this->AddToDesiredEvents( wxEVT_COMMAND_TEXT_PASTE, wxClipboardTextEventHandler(gdlwxFrame::OnTextPaste),text);
5448   if (report) this->AddToDesiredEvents( wxEVT_COMMAND_TEXT_CUT, wxClipboardTextEventHandler(gdlwxFrame::OnTextCut),text);
5449   if (report) this->AddToDesiredEvents( wxEVT_LEFT_DOWN, wxMouseEventHandler(gdlwxFrame::OnTextMouseEvents),text);
5450   if (report) this->AddToDesiredEvents( wxEVT_LEFT_UP, wxMouseEventHandler(gdlwxFrame::OnTextMouseEvents),text);
5451   if (report) this->AddToDesiredEvents( wxEVT_MIDDLE_DOWN, wxMouseEventHandler(gdlwxFrame::OnTextMouseEvents),text);
5452 
5453 //  UPDATE_WINDOW
5454   REALIZE_IF_NEEDED
5455 }
SetWidgetSize(DLong sizex,DLong sizey)5456 void GDLWidgetText::SetWidgetSize(DLong sizex, DLong sizey)
5457 {
5458 
5459   START_CHANGESIZE_NOEVENT
5460 
5461   wxWindow* me = dynamic_cast<wxWindow*> (this->GetWxWidget());
5462   if (me == NULL) {
5463 #ifdef GDL_DEBUG_WIDGETS
5464     wxMessageOutputStderr().Printf(_T("GDLWidgetText::SetSize of non wxWindow %s\n"), this->GetWidgetName().c_str());
5465 #endif
5466     return;
5467   }
5468   //widget text size is in LINES in Y and CHARACTERS in X. But overridden by scr_xsize et if present
5469   wxRealPoint widgetSize = wxRealPoint(-1,-1);
5470   static std::string testExtent("M");
5471   wxSize fontSize=calculateTextScreenSize(testExtent); //use text extent of an EM for realistic fontSize.
5472   int lineHeight=fontSize.y;
5473   wxSize currentSize=me->GetClientSize();
5474 
5475   //for each x or y, if >0 take the new value in textSize, and correct wSize to take into account possible wxWidgets-induced scrollbars.
5476   // if ==0 take the initial textSize value
5477   // if < 0 use current textSize.
5478   // all pixels values are recomputed as we need to take care of spurious scrollbars.
5479   if (sizex > 0) textSize.x=sizex; else if (sizex == 0) textSize.x=initialSize.x;
5480 
5481   if (sizey > 0) textSize.y=sizey; else if (sizey == 0) textSize.y=initialSize.y;
5482 
5483   //proceed as in computeWidgetSize() , same code, except that textSize is never -1.
5484   widgetSize.x = (textSize.x) * fontSize.x;
5485   if (textSize.y > 1)  widgetSize.y = textSize.y * lineHeight; else widgetSize.y = lineHeight;
5486 
5487   if (textSize.y == 1) widgetSize.y+=2*gdlTEXT_SPACE; //for margin
5488   if (scrolled && textSize.y > 1) widgetSize.x+=gdlSCROLL_WIDTH_Y;
5489 
5490   //if multiline and no hscroll, a x-axis scrollbar will be added by wxWidgets if longestLineSize cannot be shown, and we cannot do anything about it.
5491   //multiline here is "if (multiline) textStyle |= wxTE_MULTILINE;"
5492   if (!scrolled) {if (textSize.y > 1 && (textSize.x < maxlinelength) )  widgetSize.y += gdlSCROLL_HEIGHT_X; }
5493   else if (textSize.y > 1 && widgetSize.x < (maxlinelength*fontSize.x+gdlSCROLL_WIDTH_Y) ) {
5494     widgetSize.y += gdlSCROLL_HEIGHT_X;
5495   }
5496   widgetSize.x+=2*gdlTEXT_SPACE; //for margin
5497 
5498   int x = ceil(widgetSize.x);
5499   int y = ceil(widgetSize.y);
5500   wSize = wxSize(x,y); //update current widgetSize.
5501   me->SetClientSize(wSize);
5502   me->SetMinClientSize(wSize);
5503   if (!widgetSizer) if (framePanel) framePanel->Fit();
5504 
5505   UPDATE_WINDOW
5506 
5507   END_CHANGESIZE_NOEVENT
5508 
5509 #ifdef GDL_DEBUG_WIDGETS
5510     wxMessageOutputStderr().Printf(_T("GDLWidgetList::SetSize %d,%d (%s)\n"), sizex, sizey, this->GetWidgetName().c_str());
5511 #endif
5512 }
5513 
~GDLWidgetText()5514 GDLWidgetText::~GDLWidgetText(){
5515 #ifdef GDL_DEBUG_WIDGETS
5516   std::cout << "~GDLWidgetText(" << widgetID <<")"<< std::endl;
5517 #endif
5518   if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
5519 }
5520 
ChangeText(DStringGDL * valueStr,bool noNewLine_)5521 void GDLWidgetText::ChangeText( DStringGDL* valueStr, bool noNewLine_)
5522 {
5523   delete vValue;
5524   vValue = valueStr;
5525   DString value = "";
5526 
5527   bool doNotAddNl=(noNewLine_ || (!multiline) );
5528 
5529   nlines=0;
5530     for( int i=0; i<valueStr->N_Elements(); ++i)
5531     {
5532     value += (*valueStr)[ i];
5533     if ( !doNotAddNl )
5534 #ifdef _WIN32
5535     {value += "\r\n"; nlines++;}
5536 #else
5537     {value += '\n'; nlines++;}
5538 #endif
5539     }
5540   lastValue = value;
5541   //recompute nlines, maxlinelength from start to be sure
5542   nlines=1;
5543   maxlinelength=0;
5544   const char* s=lastValue.c_str();
5545   int length=0;
5546   for (int i=0; i<lastValue.length(); ++i, ++length)
5547   {
5548     if (s[i]==10) {
5549       maxlinelength=(length>maxlinelength)?length:maxlinelength;
5550       nlines++;
5551       length=0;
5552     }
5553   }
5554   if (length>maxlinelength) maxlinelength=length; //if no last return.
5555 
5556   wxString valueWxString = wxString( lastValue.c_str( ), wxConvUTF8 );
5557   if ( theWxWidget != NULL ) {
5558     wxTextCtrl* txt=dynamic_cast<wxTextCtrl*> (theWxWidget);
5559     assert( txt != NULL);
5560     txt->ChangeValue( valueWxString ); //by contrast with SetValue, does not generate an EVENT -- IDL does not either.
5561   }  else std::cerr << "Null widget in GDLWidgetText::SetTextValue(), please report!" << std::endl;
5562 //update widgetSize. Important to deal with 'added' scrollbars.
5563   this->SetWidgetSize(-1,-1);
5564 }
5565 
InsertText(DStringGDL * valueStr,bool noNewLine_,bool append)5566 void GDLWidgetText::InsertText( DStringGDL* valueStr, bool noNewLine_, bool append) {
5567   wxTextCtrl* txt = dynamic_cast<wxTextCtrl*> (theWxWidget);
5568   assert(txt != NULL);
5569   long from, to;
5570 
5571   //wxWidgets bug?
5572   wxTextPos pos=txt->GetLastPosition();
5573   if (pos<=1) {
5574     GDLWidgetText::ChangeText(valueStr,noNewLine_);
5575     return;
5576   }
5577 
5578   //really append/replace
5579   if (append) { //see discussion wxTextEntry::GetInsertionPoint() at https://docs.wxwidgets.org/trunk/classwx_text_entry.html
5580     if (multiline) {
5581       txt->SetSelection(pos-1,pos);
5582     } else {
5583       txt->SetSelection(pos,pos);
5584     }
5585   }
5586   txt->GetSelection(&from, &to);
5587   bool doNotAddNl=(noNewLine_ || (!multiline) );
5588 
5589   DString value = (doNotAddNl)?"":(!append)?"":"\n";
5590   for ( int i = 0; i < valueStr->N_Elements( ); ++i ) {
5591     int length=(*valueStr)[ i].length();
5592     value += (*valueStr)[ i];
5593     if ( !doNotAddNl ) {
5594 #ifdef _WIN32
5595       value += "\r\n"; nlines++;
5596 #else
5597       value += '\n'; nlines++;
5598 #endif
5599     }
5600   }
5601   //note value.size it will be used
5602   int insertedLength=value.size();
5603   lastValue.replace(from,to-from,value);
5604   //recompute nlines, maxlinelength from start to be sure
5605   nlines=1;
5606   maxlinelength=0;
5607   const char* s=lastValue.c_str();
5608   int length=0;
5609   for (int i=0; i<lastValue.length(); ++i, ++length)
5610   {
5611     if (s[i]==10) {
5612       maxlinelength=(length>maxlinelength)?length:maxlinelength;
5613       nlines++;
5614       length=0;
5615     }
5616   }
5617   if (length>maxlinelength) maxlinelength=length; //if no last return.
5618   delete vValue;
5619   vValue = new DStringGDL(lastValue);
5620   wxString valueWxString = wxString( lastValue.c_str( ), wxConvUTF8 );
5621   if ( theWxWidget != NULL ) {
5622     txt->ChangeValue( valueWxString ); //by contrast with SetValue, does not generate an EVENT (neither does *DL).
5623     txt->SetSelection(from+insertedLength,from+insertedLength);
5624     txt->ShowPosition(from+insertedLength);
5625   }  else std::cerr << "Null widget in GDLWidgetText::SetTextValue(), please report!" << std::endl;
5626 //update widgetSize
5627   this->SetWidgetSize(-1,-1);
5628 }
5629 
SetTextSelection(DLongGDL * pos)5630 void GDLWidgetText::SetTextSelection(DLongGDL* pos)
5631 { //*DL selection are [start,length] [3,20] -> pos (3,23)
5632   //numerous cases to handle with invalid values (negative, too large).
5633   //Hope it works for all cases:
5634   long from,to,len;
5635   long oldSelStart, oldSelEnd;
5636   wxTextCtrl* txt=dynamic_cast<wxTextCtrl*> (theWxWidget);
5637   assert( txt != NULL);
5638 
5639   txt->GetSelection(&oldSelStart,&oldSelEnd);
5640   len = txt->GetLastPosition()+1;
5641 
5642   if ((*pos)[0] < 0 ) from=0;
5643   else if ((*pos)[0] > len ) from=len;
5644   else from=(*pos)[0];
5645 
5646 
5647   if (pos->N_Elements()<2) {
5648     //selection = insertion
5649     txt->SetSelection(from,from);
5650     return;
5651   }
5652   //2 elements, define selection
5653   to=(*pos)[1];
5654 
5655   if ( from+to >= len ) {
5656     //set insertion position at end of last selection (?)
5657     txt->SetSelection(oldSelEnd,oldSelEnd);
5658     return;
5659   }
5660   if ( to < 0 ) {
5661     //set insertion position at from
5662     txt->SetSelection(from,from);
5663     return;
5664   }
5665   txt->SetSelection(from,from+to);
5666 }
5667 
GetTextSelection()5668 DLongGDL* GDLWidgetText::GetTextSelection()
5669 {
5670   DLongGDL* pos=new DLongGDL(dimension(2),BaseGDL::ZERO);
5671   long from,to;
5672   wxTextCtrl* txt=dynamic_cast<wxTextCtrl*> (theWxWidget);
5673   assert( txt != NULL);
5674 
5675   txt->GetSelection(&from,&to);
5676   (*pos)[0]=from; (*pos)[1]=to-from;
5677   return pos;
5678 }
5679 
GetSelectedText()5680 DStringGDL* GDLWidgetText::GetSelectedText()
5681 {
5682   wxTextCtrl* txt=dynamic_cast<wxTextCtrl*>(theWxWidget);
5683   assert( txt != NULL);
5684 
5685 return new DStringGDL(txt->GetStringSelection().mb_str(wxConvUTF8).data());
5686 }
5687 
GDLWidgetLabel(WidgetIDT p,EnvT * e,const DString & value_,DULong eventflags,bool sunken_)5688 GDLWidgetLabel::GDLWidgetLabel( WidgetIDT p, EnvT* e, const DString& value_ , DULong eventflags, bool sunken_)
5689 : GDLWidget( p, e , NULL, eventflags )
5690 , value(value_)
5691 , sunken(sunken_)
5692 {
5693   GDLWidget* gdlParent = GetWidget( parentID );
5694   widgetPanel = GetParentPanel( );
5695   widgetSizer = GetParentSizer( );
5696 
5697   if (sunken) frameWidth=0;
5698 
5699   widgetStyle=widgetAlignment();
5700   const wxString valueWxString = wxString( value.c_str( ), wxConvUTF8 );
5701 
5702   bool simplelabel=(wSize.x < 0 && frameWidth <1 && !sunken); //before recomputing wSize!
5703   wSize=computeWidgetSize();
5704   //to comply with the positioning observed with IDL, a label with a defined size is in fact a label inside a (possibly invisible) frame of such size.
5705   //the centering of the label is 'center' by default and does not inherit from the parent base default centering (it is the frame that inherits), but if
5706   //a centering is required, it is done.
5707   //labels with no particular size and frames are made idem.
5708   //label with no particular size and no frame are aligned normally, i.e., they inherit if the alignment is not precised.
5709   // the simple case is
5710   if (simplelabel) {
5711     wxStaticText* label = new wxStaticText( widgetPanel, widgetID, wxT(""), wOffset, wxDefaultSize, wxST_NO_AUTORESIZE|widgetStyle);
5712     label->SetLabelText(valueWxString);
5713     label->SetSize(wSize);
5714     label->SetMinSize(wSize);
5715     label->Wrap(-1);
5716     theWxContainer = theWxWidget = label;
5717     if (widgetSizer) widgetSizer->Add(label, DONOTALLOWSTRETCH, widgetStyle|wxALL, gdlSPACE);
5718     if (widgetSizer) widgetSizer->Fit(label); else widgetPanel->Fit();
5719 //    UPDATE_WINDOW
5720     REALIZE_IF_NEEDED
5721     return;
5722   }
5723   //Now more complicated. Framed is not Sunken. Framed implies adding 2 panels, one 'extruded'.
5724   //the inside panel is of (eventually fixed) size wSize. It contains the text, aligned.
5725   //sizers should link all those sizes
5726   framePanel = new wxPanel(widgetPanel, wxID_ANY, wOffset, wxDefaultSize, sunken?wxBORDER_SUNKEN:(frameWidth >0 )?gdlBORDER_EXT:wxBORDER_NONE);
5727 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
5728   framePanel->SetBackgroundColour(wxColour(0x3a, 0x82, 0x56)); //vert fonce
5729 #endif
5730   wxSizer* frameSizer = new wxBoxSizer(wxVERTICAL);
5731   framePanel->SetSizer(frameSizer);
5732   wxStaticText* label;
5733   if (frameWidth >0) {
5734     //the inside panel, framed
5735     wxPanel* hiddenPanel = new wxPanel(framePanel);
5736     frameSizer->Add(hiddenPanel, DONOTALLOWSTRETCH, wxALL | wxEXPAND, frameWidth);
5737     hiddenPanel->SetSize(wSize);
5738     hiddenPanel->SetMinSize(wSize);
5739     wxSizer* sz = new wxBoxSizer(wxVERTICAL);
5740     hiddenPanel->SetSizer(sz);
5741     //the label, with special style inside
5742     int style = labelTextAlignment();
5743     //create and position label in panel
5744     label = new wxStaticText(hiddenPanel, widgetID, valueWxString);
5745     label->Wrap(-1);
5746     sz->Add(label, DONOTALLOWSTRETCH, style | wxALL, 0);
5747     sz->Fit(label);
5748     frameSizer->Fit(hiddenPanel);
5749     framePanel->Fit();
5750   } else {
5751     framePanel->SetSize(wSize);
5752     framePanel->SetMinSize(wSize);
5753     //the label, with special style inside
5754     int style= labelTextAlignment();
5755   //create and position label in panel
5756     label = new wxStaticText( framePanel, widgetID, valueWxString);
5757     label->Wrap(-1);
5758     frameSizer->Add(label,DONOTALLOWSTRETCH,style|wxALL,0);
5759     frameSizer->Fit(label); //sz exist always
5760   }
5761   theWxContainer=framePanel;
5762   theWxWidget=label;
5763   if (widgetSizer) widgetSizer->Add(framePanel, DONOTALLOWSTRETCH, widgetStyle|wxALL, 0);
5764   if (widgetSizer) widgetSizer->Fit(framePanel); else widgetPanel->Fit();
5765 //  UPDATE_WINDOW
5766   REALIZE_IF_NEEDED
5767 }
5768 
~GDLWidgetLabel()5769 GDLWidgetLabel::~GDLWidgetLabel(){
5770 #ifdef GDL_DEBUG_WIDGETS
5771     std::cout << "~GDLWidgetLabel(" << widgetID << ")" << std::endl;
5772 #endif
5773     if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
5774 }
SetWidgetSize(DLong sizex,DLong sizey)5775 void GDLWidgetLabel::SetWidgetSize(DLong sizex, DLong sizey) //in pixels. Always.
5776 {
5777   START_CHANGESIZE_NOEVENT
5778   //Sizes are in pixels. Units must be converted before calling this function.
5779   wxWindow* me=static_cast<wxWindow*>(theWxContainer);
5780   //a graphic window cannot be larger than the base widget it is in, if the base widget size has been fixed
5781   wxSize currentSize=me->GetSize();
5782   wxSize currentBestSize=me->GetBestSize();
5783 #ifdef GDL_DEBUG_WIDGETS
5784   wxMessageOutputStderr( ).Printf( _T( "GDLWidgetLabel::SetSize currentSize=%d,%d\n"),currentSize.x,currentSize.y);
5785 #endif
5786   //unprecised sizes do not change
5787   if (sizex == -1) sizex = currentSize.x;
5788   if (sizey == -1) sizey = currentSize.y;
5789 
5790   if (widgetSizer) {
5791     //passed zeroes = mr sizer, do your best..
5792     if (sizex == 0) sizex = -1;
5793     if (sizey == 0) sizey = -1;
5794   } else {
5795     //passed zeroes = your best is to keep best size (in cache, value defined at creation)
5796     if (sizex == 0) sizex = currentBestSize.x;
5797     if (sizey == 0) sizey = currentBestSize.y;
5798   }
5799   wSize.x = sizex;
5800   wSize.y = sizey;
5801   me->SetSize(wSize);
5802   //the sizer takes care of the eventual frame
5803   me->SetMinSize(wSize);
5804 
5805   UPDATE_WINDOW
5806 
5807   END_CHANGESIZE_NOEVENT
5808 
5809 
5810 #ifdef GDL_DEBUG_WIDGETS
5811   wxMessageOutputStderr( ).Printf( _T( "GDLWidget::SetSize %d,%d (%s)\n"),sizex,sizey,this->GetWidgetName().c_str());
5812 #endif
5813 }
5814 
SetLabelValue(const DString & value_)5815 void GDLWidgetLabel::SetLabelValue(const DString& value_) {
5816   value = value_;
5817   //update vValue
5818   delete(vValue);
5819   vValue = new DStringGDL(value);
5820 
5821   wxString valueWxString = wxString(value_.c_str(), wxConvUTF8);
5822   if (theWxWidget != NULL) {
5823     wxStaticText *label = dynamic_cast<wxStaticText*> (theWxWidget);
5824     if (label) {
5825       label->SetLabelText(valueWxString);
5826       if (this->IsDynamicResize()) {
5827         wSize = wxSize(-1, -1);
5828         wSize = computeWidgetSize();
5829         label->SetMinSize(wSize);
5830         label->SetSize(wSize);
5831         //special for labels:
5832         if (theWxContainer && theWxContainer != theWxWidget) {
5833           wxPanel* p = static_cast<wxPanel*> (theWxContainer);
5834           if (p) {
5835             // this looks complicated but how to do otherwise?
5836             p->SetMinSize(label->GetBestSize()+wxSize(2*frameWidth,2*frameWidth));
5837           }
5838         }
5839       }
5840     }
5841     else cerr << "Warning GDLWidgetLabel::SetLabelValue(): widget type confusion\n";
5842     //SetLabel, unless SetLabelText, interprets markup (<b></b> etc)
5843   } else std::cerr << "Null widget in GDLWidgetLabel::SetLabelValue(), please report!" << std::endl;
5844 }
5845 
5846 //propertysheet. Unsupported as need to be completely rewritten as the other widgets are (new code) and not able to test.
5847 #ifdef HAVE_WXWIDGETS_PROPERTYGRID
5848 //
5849 // GDLWidgetPropertySheet::GDLWidgetPropertySheet( WidgetIDT parentID, EnvT* e)
5850 // : GDLWidget( p, e , value, eventflag)
5851 //{
5852 //  GDLWidget* gdlParent = GetWidget( parentID );
5853 //  widgetPanel = GetParentPanel( );
5854 //  widgetSizer = GetParentSizer( );
5855 //  topWidgetSizer = this->GetTopLevelBaseWidget(parentID)->GetSizer();
5856 // // Construct wxPropertyGrid control
5857 //  wxPropertyGrid* pg = new wxPropertyGrid(gdlParent,widgetID,wxDefaultPosition,wxDefaultSize,
5858 //  // Here are just some of the supported window styles
5859 //  wxPG_AUTO_SORT | // Automatic sorting after items added
5860 //  wxPG_SPLITTER_AUTO_CENTER | // Automatically center splitter until user manually adjusts it
5861 //  // Default style
5862 //  wxPG_DEFAULT_STYLE );
5863 //// Window style flags are at premium, so some less often needed ones are
5864 //// available as extra window styles (wxPG_EX_xxx) which must be set using
5865 //// SetExtraStyle member function. wxPG_EX_HELP_AS_TOOLTIPS, for instance,
5866 //// allows displaying help strings as tool tips.
5867 //  pg->SetExtraStyle( wxPG_EX_HELP_AS_TOOLTIPS );
5868 //
5869 //  theWxWidget=pg;
5870 //
5871 //  // Add int property
5872 //pg->Append( new wxIntProperty("IntProperty", wxPG_LABEL, 12345678) );
5873 //// Add float property (value type is actually double)
5874 //pg->Append( new wxFloatProperty("FloatProperty", wxPG_LABEL, 12345.678) );
5875 //// Add a bool property
5876 //pg->Append( new wxBoolProperty("BoolProperty", wxPG_LABEL, false) );
5877 //// A string property that can be edited in a separate editor dialog.
5878 //pg->Append( new wxLongStringProperty("LongStringProperty",
5879 //wxPG_LABEL,
5880 //"This is much longer string than the "
5881 //"first one. Edit it by clicking the button."));
5882 //// String editor with dir selector button.
5883 //pg->Append( new wxDirProperty("DirProperty", wxPG_LABEL, ::wxGetUserHome()) );
5884 //// wxArrayStringProperty embeds a wxArrayString.
5885 //pg->Append( new wxArrayStringProperty("Label of ArrayStringProperty",
5886 //"NameOfArrayStringProp"));
5887 //// A file selector property.
5888 //pg->Append( new wxFileProperty("FileProperty", wxPG_LABEL, wxEmptyString) );
5889 //
5890 //UPDATE_WINDOW; REALIZE_IF_NEEDED;
5891 //}
5892 #endif
5893 // GDL widgets =====================================================
5894 // GDLFrame ========================================================
gdlwxFrame(wxWindow * parent,GDLWidgetTopBase * gdlOwner_,wxWindowID id,const wxString & title,const wxPoint & pos,const wxSize & size,long style)5895 gdlwxFrame::gdlwxFrame( wxWindow* parent, GDLWidgetTopBase* gdlOwner_, wxWindowID id, const wxString& title , const wxPoint& pos, const wxSize& size, long style)
5896 : wxFrame()
5897 , mapped( false )
5898 , frameSize(size)
5899 , gdlOwner( gdlOwner_)
5900 {
5901   Create ( parent, id, title, pos, size, style );
5902   m_resizeTimer = new wxTimer(this,RESIZE_TIMER);
5903 }
5904 
~gdlwxFrame()5905 gdlwxFrame::~gdlwxFrame()
5906 {
5907     if (m_resizeTimer->IsRunning()) m_resizeTimer->Stop();
5908 #ifdef GDL_DEBUG_WIDGETS
5909     std::cout << "~GDLFrame: " << this << std::endl;
5910 #endif
5911  //frame is part of a TLB. if frame is destroyed, destroy TLB if still existing.
5912  if( gdlOwner != NULL)
5913   {
5914 #ifdef GDL_DEBUG_WIDGETS
5915     std::cout << "~GDLFrame: Destroying Base Container" << gdlOwner->GetWidgetID() << std::endl;
5916 #endif
5917 //    gdlOwner->NullWxWidget( ); //remove one's reference from container
5918 //    gdlOwner->SelfDestroy( ); // send delete request to GDL owner = container.
5919   }
5920  }
5921 // Phantom frame
gdlwxPhantomFrame()5922 gdlwxPhantomFrame::gdlwxPhantomFrame()
5923 : wxFrame(NULL,wxID_ANY,wxString("phantom"),wxDefaultPosition,wxDefaultSize,wxFRAME_TOOL_WINDOW)
5924 {
5925   wxScrolled<wxPanel>* test = new wxScrolled<wxPanel>(this); //to measure scrollbars
5926   test->ShowScrollbars(wxSHOW_SB_ALWAYS, wxSHOW_SB_ALWAYS);
5927 }
5928 
Realize()5929 void gdlwxPhantomFrame::Realize() {
5930   wxWindow* c=this->GetChildren()[0];
5931   //retrieve toolkit's width and height of scrollbars (useful to calculate sizes for widgets)
5932   wxSize s=c->GetSize();
5933   wxSize e=c->GetClientSize();
5934   wxSize w=s-e;
5935 //  std::cerr<<w.x<<","<<w.y<<std::endl;
5936   if (w.x <= 0) w.x=gdlABSENT_SIZE_VALUE;
5937   if (w.y <= 0) w.y=gdlABSENT_SIZE_VALUE;
5938   sysScrollHeight=w.y;
5939   sysScrollWidth=w.x;
5940 }
5941 
5942 // Frame for Plots ========================================================
gdlwxPlotFrame(const wxString & title,const wxPoint & pos,const wxSize & size,long style,bool scrolled_)5943 gdlwxPlotFrame::gdlwxPlotFrame( const wxString& title , const wxPoint& pos, const wxSize& size, long style, bool scrolled_)
5944 : wxFrame( NULL, wxID_ANY, title, pos, size, style )
5945 , frameSize(size)
5946 , scrolled(scrolled_)
5947 {
5948   m_resizeTimer = new wxTimer(this,RESIZE_PLOT_TIMER);
5949 }
5950 
~gdlwxPlotFrame()5951 gdlwxPlotFrame::~gdlwxPlotFrame() {
5952   //We are here outside gdl widget hierarchy. If we Destroy the frame, everything goes.
5953   // However, we MUST insure this is equivalent to "WDELETE" because the complicated interplay of multidevices, plplot streams, and widgets.
5954   // So it is better to pass and wait for the deletion of the contained window id (by marking it unValid) and let TidyWindowsList clear everything.
5955   // this widget will be actually destroyed when the inside GraphicsPanel will be destroyed.
5956   if (m_resizeTimer->IsRunning()) m_resizeTimer->Stop();
5957 #ifdef GDL_DEBUG_WIDGETS
5958   std::cout << "~gdlwxPlotFrame: " << this << std::endl;
5959 #endif
5960 }
5961 
Realize()5962 void gdlwxPlotFrame::Realize() {
5963 #ifdef GDL_DEBUG_WIDGETS
5964     wxMessageOutputStderr().Printf(_T("gdlwxPlotFrame:Realize\n"));
5965 #endif
5966 }
5967 
5968 //version using wxBG_STYLE_PAINT and blit to an AutoBufferedPaintDC, will this improve speed?
gdlwxGraphicsPanel(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)5969 gdlwxGraphicsPanel::gdlwxGraphicsPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
5970 : wxScrolled<wxPanel>() // Use default ctor here!
5971 , pstreamIx( -1 )
5972 , pstreamP( NULL )
5973 , wx_dc( NULL)
5974 , drawSize(size)
5975 {
5976         // Do this first:
5977         SetBackgroundStyle(wxBG_STYLE_PAINT);
5978   Create( parent, id, pos, size, style, name );
5979 }
5980 //gdlwxGraphicsPanel::gdlwxGraphicsPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
5981 //: wxScrolled<wxPanel>( parent, id, pos, size, style, name )
5982 //, pstreamIx( -1 )
5983 //, pstreamP( NULL )
5984 //, m_dc( NULL)
5985 //, drawSize(size)
5986 //{ }
GetStream()5987 GDLWXStream* gdlwxGraphicsPanel::GetStream(){return pstreamP;};
DeleteUsingWindowNumber()5988 void gdlwxGraphicsPanel::DeleteUsingWindowNumber(){
5989   pstreamP->SetValid(false);
5990   GraphicsDevice::GetGUIDevice()->TidyWindowsList(); //tidy Window List will delete widget by itself
5991 }
SetStream(GDLWXStream * s)5992 void gdlwxGraphicsPanel::SetStream(GDLWXStream* s) {
5993   pstreamP = s;
5994   wx_dc = pstreamP->GetStreamDC();
5995 }
gdlwxPlotPanel(gdlwxPlotFrame * parent)5996 gdlwxPlotPanel::gdlwxPlotPanel( gdlwxPlotFrame* parent) //, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
5997 : gdlwxGraphicsPanel::gdlwxGraphicsPanel(parent)
5998 , myFrame(parent)
5999 {
6000 #ifdef GDL_DEBUG_WIDGETS
6001     std::cout << "gdlwxPlotPanel::gdlwxPlotPanel(" << this << ") called."<< std::endl;
6002 #endif
6003     this->SetBackgroundColour(*wxBLACK);
6004 }
6005 
RepaintGraphics(bool doClear)6006 void gdlwxGraphicsPanel::RepaintGraphics(bool doClear) {
6007   wxClientDC dc(this); //is a scrolled window: needed
6008   DoPrepareDC(dc); //you probably do not want to call wxScrolled::PrepareDC() on wxAutoBufferedPaintDC as it already does this internally for the real underlying wxPaintDC.
6009 //  dc.SetDeviceClippingRegion(GetUpdateRegion());
6010   if (doClear) dc.Clear();
6011   dc.Blit(0, 0, drawSize.x, drawSize.y, wx_dc, 0, 0);
6012 }
6013 
gdlwxDrawPanel(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)6014 gdlwxDrawPanel::gdlwxDrawPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
6015 : gdlwxGraphicsPanel::gdlwxGraphicsPanel(parent, id, pos, size, style, name )
6016 , myWidgetDraw(static_cast<GDLWidgetDraw*>(GDLWidget::GetWidget(id)))
6017 {
6018 #ifdef GDL_DEBUG_WIDGETS
6019     std::cout << "gdlwxDrawPanel::gdlwxDrawPanel(" << this << ") called."<< std::endl;
6020 #endif
6021 }
6022 
InitStream(int wIx)6023 void gdlwxDrawPanel::InitStream(int wIx)
6024 {
6025   if (wIx < 0)  pstreamIx = GraphicsDevice::GetGUIDevice( )->WAddFree( );
6026   else  pstreamIx = wIx;
6027   if ( pstreamIx == -1 ) throw GDLException( "Failed to allocate GUI stream." );
6028   pstreamP = static_cast<GDLWXStream*>(GraphicsDevice::GetGUIDevice( )->GUIOpen( pstreamIx, drawSize.x, drawSize.y, this ));
6029   if( pstreamP == NULL)
6030   {
6031     throw GDLException( "Failed to open GUI stream: " + i2s( pstreamIx ) );
6032   }
6033   wx_dc = pstreamP->GetStreamDC( );
6034 }
6035 
ResizeDrawArea(wxSize s)6036 void gdlwxGraphicsPanel::ResizeDrawArea(wxSize s)
6037 {
6038   bool doClear=false;
6039   if (drawSize.x > s.x || drawSize.y > s.y ) doClear=true;
6040   drawSize=s;
6041   this->SetVirtualSize(drawSize);
6042   pstreamP->SetSize(drawSize);
6043   RepaintGraphics(doClear);
6044 }
6045 
~gdlwxPlotPanel()6046 gdlwxPlotPanel::~gdlwxPlotPanel()
6047 {
6048 #ifdef GDL_DEBUG_WIDGETS
6049     std::cout << "~gdlwxPlotPanel() :" << this << "pstreamP="<<GetStream()<< " is now invalid."<<std::endl;
6050 #endif
6051     this->GetMyFrame()->Show(false);
6052     this->GetMyFrame()->Destroy(); //will be really destroyed after next call to wxApp (remember, wxApp is not running, only GDL is running).
6053 }
6054 
~gdlwxDrawPanel()6055 gdlwxDrawPanel::~gdlwxDrawPanel()
6056 {
6057  //widget_control,this,/dest actually calls wdelete. So the only case where we are not 'deleted' with a wdelete or widget_control command is during the detetion of a container.
6058  // in which case, we avoid reentrance because on the first pass the stream has been invalidated.
6059  // if associated stream is invalid, do nothing : 'this' has already been called. Normally, should not happen...
6060  if (pstreamP->GetValid()) return;
6061 
6062   //invalidate stream in any case, but do not have TidyWindowsList() re-deleting it, as whatever call us, gdlwxDrawPanel is going to die.
6063   pstreamP->SetValid(false);
6064 #ifdef GDL_DEBUG_WIDGETS
6065     std::cout << "~gdlwxDrawPanel() :" << this << "pstreamP="<<GetStream()<< " is now invalid."<<std::endl;
6066 #endif
6067 
6068     GraphicsDevice::GetGUIDevice()->TidyWindowsList(false);
6069   // get WIDGET_DRAW
6070   GDLWidgetDraw* d = GetMyWidget();
6071   // at exit from here, widget_draw is either destroyed because I ask for it or because it was already being destroyed. To prevent reentrance, NULL the reference to it.
6072   myWidgetDraw = NULL;
6073   //either widget_draw is valid and we must destroy it properly. Else it is not anymore (see ~GDLWidgetDraw() ) so we have nothing to do.
6074   if (d && d->IsValid()) { //we come from wdelete
6075     //this=thewxWidget will be destroyed no matter what, since this is part of its destruction process. To destroy the gdlwidget, it would need to remove 'this' from the
6076     //gdlWidget structure and the underlying wxwidgets parent-child lists. Difficult. Simpler at the moment:
6077     // unref the container (so destruction call of the wxcontainer will not be effected at widget destruction)
6078     // delete the wigdet to remove it from widget hierarchy.
6079     wxWindow* delayed_destroy_frame = static_cast<wxWindow*>(d->GetWxContainer()); //container can be theWxWidget=this
6080     d->UnrefTheWxContainer(); //in any cases
6081     //remove the container from its parent (panel)
6082     delayed_destroy_frame->GetParent()->RemoveChild(delayed_destroy_frame); //should hide the wxContainer.
6083     delayed_destroy_frame->Hide();
6084     //no link anymore to 'this' in gdlwidget destruction
6085     delete d;
6086   }
6087 }
GDLWidgetDraw(WidgetIDT p,EnvT * e,int windowIndex,DLong x_scroll_size,DLong y_scroll_size,bool app_scroll,DULong eventFlags_,DStringGDL * drawToolTip)6088 GDLWidgetDraw::GDLWidgetDraw( WidgetIDT p, EnvT* e, int windowIndex,
6089                   DLong x_scroll_size, DLong y_scroll_size, bool app_scroll, DULong eventFlags_, DStringGDL* drawToolTip)
6090   : GDLWidget( p, e, NULL, eventFlags_)
6091   , pstreamIx(windowIndex)
6092 {
6093   // xsize,ysize (or, scr_xsize, scr_ysize) define the plot size.
6094   assert( parentID != GDLWidget::NullID);
6095   wSize = computeWidgetSize();
6096   if (widgetSizer==NULL) {
6097     if (wSize.x < 1) wSize.x=gdlDEFAULT_XSIZE;
6098     if (wSize.y < 1) wSize.y=gdlDEFAULT_YSIZE;
6099   }
6100   //get immediately rid of scroll sizes in case of scroll or not... Here is the logic:
6101   // Note that IDL reports wrong dimensions when size and scr_xsize are used simultaneously for at least widget_draw.
6102 
6103   if (x_scroll_size > 0) {scrolled=true;x_scroll_size*=unitConversionFactor.x;x_scroll_size+=gdlSCROLL_WIDTH_Y;}
6104   if (y_scroll_size > 0) {scrolled=true;y_scroll_size*=unitConversionFactor.y;y_scroll_size+=gdlSCROLL_HEIGHT_X;}
6105   if (scrolled) {
6106     if (x_scroll_size < 1) x_scroll_size = gdlDEFAULT_XSIZE+gdlSCROLL_WIDTH_Y;
6107     if (y_scroll_size < 1) y_scroll_size = gdlDEFAULT_YSIZE+gdlSCROLL_HEIGHT_X;
6108   }
6109   wScrollSize = scrolled ? wxSize(x_scroll_size , y_scroll_size ) : wSize;
6110 
6111   GDLWidget* gdlParent = GetWidget( parentID);
6112   widgetPanel = GetParentPanel( );
6113   widgetSizer = GetParentSizer( );
6114 
6115   START_ADD_EVENTUAL_FRAME
6116 
6117   widgetStyle = widgetAlignment();
6118   long style = 0;
6119 
6120   gdlwxDrawPanel* draw = new gdlwxDrawPanel( widgetPanel, widgetID, wxDefaultPosition, wxDefaultSize, style);
6121 #ifdef GDL_DEBUG_WIDGETS_COLORIZE
6122   draw->SetBackgroundColour(wxColour(0,255,255));
6123 #endif
6124   draw->SetMinClientSize(wScrollSize);
6125   draw->SetClientSize(wScrollSize);
6126   draw->SetVirtualSize(wSize);
6127   draw->InitDrawSize(wSize);
6128 
6129   if (scrolled) {
6130     draw->SetScrollbars(gdlSCROLL_RATE, gdlSCROLL_RATE, wSize.x / gdlSCROLL_RATE, wSize.y / gdlSCROLL_RATE);
6131     draw->ShowScrollbars(wxSHOW_SB_ALWAYS, wxSHOW_SB_ALWAYS);
6132   }
6133 
6134 
6135   draw->SetCursor(wxCURSOR_CROSS);
6136   if (drawToolTip) dynamic_cast<wxWindow*>(draw)->SetToolTip( wxString((*drawToolTip)[0].c_str(),wxConvUTF8));
6137   theWxContainer = theWxWidget = draw;
6138 
6139   END_ADD_EVENTUAL_FRAME
6140   TIDY_WIDGET(gdlBORDER_SPACE)
6141 
6142   draw->InitStream(windowIndex);
6143 
6144   pstreamIx = draw->PStreamIx();
6145   GDLDelete( vValue);
6146   vValue = new DLongGDL(pstreamIx);
6147 
6148   //these widget specific events are always set:
6149    this->AddToDesiredEvents( wxEVT_PAINT, wxPaintEventHandler(gdlwxDrawPanel::OnPaint),draw);
6150 //   this->AddToDesiredEvents( wxEVT_SIZE,  wxSizeEventHandler(gdlwxDrawPanel::OnSize),draw);
6151    //disable flicker see https://wiki.wxwidgets.org/Flicker-Free_Drawing
6152    this->AddToDesiredEvents( wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(gdlwxDrawPanel::OnErase),draw);
6153 
6154   //other set event handling according to flags
6155   if (eventFlags & GDLWidget::EV_MOTION) this->AddToDesiredEvents( wxEVT_MOTION, wxMouseEventHandler(gdlwxDrawPanel::OnMouseMove),draw);
6156 //  if ( eventFlags & GDLWidget::EV_DROP) nothing to do yet, fixme!;
6157   if ( eventFlags & GDLWidget::EV_EXPOSE) this->AddToDesiredEvents(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(gdlwxDrawPanel::OnErase),draw);
6158 //  if ( eventFlags &  GDLWidget::EV_VIEWPORT) idem;
6159   if ( eventFlags &  GDLWidget::EV_WHEEL) this->AddToDesiredEvents( wxEVT_MOUSEWHEEL, wxMouseEventHandler(gdlwxDrawPanel::OnMouseWheel),draw);
6160   if ( eventFlags &  GDLWidget::EV_BUTTON) {
6161       this->AddToDesiredEvents(wxEVT_LEFT_DOWN, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown),draw);
6162       this->AddToDesiredEvents(wxEVT_LEFT_UP, wxMouseEventHandler(gdlwxDrawPanel::OnMouseUp),draw);
6163       this->AddToDesiredEvents(wxEVT_LEFT_DCLICK, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown),draw);
6164       this->AddToDesiredEvents(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown),draw);
6165       this->AddToDesiredEvents(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown),draw);
6166       this->AddToDesiredEvents(wxEVT_MIDDLE_UP, wxMouseEventHandler(gdlwxDrawPanel::OnMouseUp),draw);
6167       this->AddToDesiredEvents(wxEVT_RIGHT_DOWN, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown),draw);
6168       this->AddToDesiredEvents(wxEVT_RIGHT_DCLICK, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown),draw);
6169       this->AddToDesiredEvents(wxEVT_RIGHT_UP, wxMouseEventHandler(gdlwxDrawPanel::OnMouseUp),draw);
6170   }
6171   if (eventFlags &  GDLWidget::EV_KEYBOARD2 || eventFlags & GDLWidget::EV_KEYBOARD){
6172        this->AddToDesiredEvents(wxEVT_KEY_DOWN, wxKeyEventHandler(gdlwxDrawPanel::OnKey),draw);
6173        this->AddToDesiredEvents(wxEVT_KEY_UP, wxKeyEventHandler(gdlwxDrawPanel::OnKey),draw);
6174   }
6175 
6176 //   UPDATE_WINDOW
6177    REALIZE_IF_NEEDED
6178 }
6179 
~GDLWidgetDraw()6180 GDLWidgetDraw::~GDLWidgetDraw() {
6181 #ifdef GDL_DEBUG_WIDGETS
6182   std::cout << "~GDLWidgetDraw(" << widgetID << ")" << std::endl;
6183 #endif
6184  if (theWxContainer) static_cast<wxWindow*>(theWxContainer)->Destroy();
6185 }
6186 
AddEventType(DULong evType)6187 void GDLWidgetDraw::AddEventType( DULong evType){
6188   eventFlags |= evType;
6189   gdlwxDrawPanel* draw=(gdlwxDrawPanel*)theWxWidget;
6190 //this one is for the moment defined globally:
6191 //   if ( evType == GDLWidget::EV_TRACKING) {
6192 //    draw->Connect(widgetID, wxEVT_ENTER_WINDOW, wxMouseEventHandler(GDLFrame::OnEnterWindow));
6193 //    draw->Connect(widgetID, wxEVT_LEAVE_WINDOW, wxMouseEventHandler(GDLFrame::OnLeaveWindow));
6194 //  } else
6195   if ( evType == GDLWidget::EV_MOTION) draw->Connect(widgetID, wxEVT_MOTION, wxMouseEventHandler(gdlwxDrawPanel::OnMouseMove));
6196 //else  if ( evType == GDLWidget::EV_DROP) nothing to do yet, fixme!;
6197 //else  if ( evType == GDLWidget::EV_EXPOSE) nothing to do yet, fixme!;
6198 //else  if ( evType == GDLWidget::EV_VIEWPORT) idem;
6199   else if ( evType == GDLWidget::EV_WHEEL) draw->Connect(widgetID, wxEVT_MOUSEWHEEL, wxMouseEventHandler(gdlwxDrawPanel::OnMouseWheel));
6200   else if ( evType == GDLWidget::EV_BUTTON) {
6201       draw->Connect(widgetID, wxEVT_LEFT_DOWN, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6202       draw->Connect(widgetID, wxEVT_LEFT_UP, wxMouseEventHandler(gdlwxDrawPanel::OnMouseUp));
6203       draw->Connect(widgetID, wxEVT_LEFT_DCLICK, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6204       draw->Connect(widgetID, wxEVT_MIDDLE_DOWN, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6205       draw->Connect(widgetID, wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6206       draw->Connect(widgetID, wxEVT_MIDDLE_UP, wxMouseEventHandler(gdlwxDrawPanel::OnMouseUp));
6207       draw->Connect(widgetID, wxEVT_RIGHT_DOWN, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6208       draw->Connect(widgetID, wxEVT_RIGHT_DCLICK, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6209       draw->Connect(widgetID, wxEVT_RIGHT_UP, wxMouseEventHandler(gdlwxDrawPanel::OnMouseUp));
6210   }
6211   else if (evType == GDLWidget::EV_KEYBOARD2 || evType == GDLWidget::EV_KEYBOARD){
6212        draw->Connect(widgetID, wxEVT_KEY_DOWN, wxKeyEventHandler(gdlwxDrawPanel::OnKey));
6213        draw->Connect(widgetID, wxEVT_KEY_UP, wxKeyEventHandler(gdlwxDrawPanel::OnKey));
6214   }
6215 }
6216 
RemoveEventType(DULong evType)6217 void GDLWidgetDraw::RemoveEventType( DULong evType){
6218   gdlwxDrawPanel* draw=(gdlwxDrawPanel*)theWxWidget;
6219 //this one is for the moment defined globally:
6220 //   if ( evType == GDLWidget::EV_TRACKING) {
6221 //    draw->Disconnect(widgetID, wxEVT_ENTER_WINDOW, wxMouseEventHandler(GDLFrame::OnEnterWindow));
6222 //    draw->Disconnect(widgetID, wxEVT_LEAVE_WINDOW, wxMouseEventHandler(GDLFrame::OnLeaveWindow));
6223 //  } else
6224   if ( evType == GDLWidget::EV_MOTION) draw->Disconnect(widgetID, wxEVT_MOTION, wxMouseEventHandler(gdlwxDrawPanel::OnMouseMove));
6225 //else  if ( evType == GDLWidget::EV_DROP) nothing to do yet, fixme!;
6226 //else  if ( evType == GDLWidget::EV_EXPOSE) nothing to do yet, fixme!;
6227 //else  if ( evType == GDLWidget::EV_VIEWPORT) idem;
6228   else if ( evType == GDLWidget::EV_WHEEL) draw->Disconnect(widgetID, wxEVT_MOUSEWHEEL, wxMouseEventHandler(gdlwxDrawPanel::OnMouseWheel));
6229   else if ( evType == GDLWidget::EV_BUTTON) {
6230       draw->Disconnect(widgetID, wxEVT_LEFT_DOWN, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6231       draw->Disconnect(widgetID, wxEVT_LEFT_UP, wxMouseEventHandler(gdlwxDrawPanel::OnMouseUp));
6232       draw->Disconnect(widgetID, wxEVT_LEFT_DCLICK, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6233       draw->Disconnect(widgetID, wxEVT_MIDDLE_DOWN, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6234       draw->Disconnect(widgetID, wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6235       draw->Disconnect(widgetID, wxEVT_MIDDLE_UP, wxMouseEventHandler(gdlwxDrawPanel::OnMouseUp));
6236       draw->Disconnect(widgetID, wxEVT_RIGHT_DOWN, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6237       draw->Disconnect(widgetID, wxEVT_RIGHT_DCLICK, wxMouseEventHandler(gdlwxDrawPanel::OnMouseDown));
6238       draw->Disconnect(widgetID, wxEVT_RIGHT_UP, wxMouseEventHandler(gdlwxDrawPanel::OnMouseUp));
6239   }
6240   else if (evType == GDLWidget::EV_KEYBOARD2 || evType == GDLWidget::EV_KEYBOARD){
6241        draw->Disconnect(widgetID, wxEVT_KEY_DOWN, wxKeyEventHandler(gdlwxDrawPanel::OnKey));
6242        draw->Disconnect(widgetID, wxEVT_KEY_UP, wxKeyEventHandler(gdlwxDrawPanel::OnKey));
6243   }
6244   eventFlags &= ~evType;
6245 }
6246 
SetWidgetVirtualSize(DLong sizex,DLong sizey)6247  void GDLWidgetDraw::SetWidgetVirtualSize(DLong sizex, DLong sizey) {
6248   START_CHANGESIZE_NOEVENT
6249     gdlwxDrawPanel* me = dynamic_cast<gdlwxDrawPanel*> (theWxWidget);
6250     wxSize drawSize=me->GetDrawSize();
6251     if (sizex < 1) sizex=drawSize.x;
6252     if (sizey < 1) sizey=drawSize.y;
6253 #ifdef GDL_DEBUG_WIDGETS
6254     wxMessageOutputStderr().Printf(_T("GDLWidgetDraw::SetWidgetVirtualSize %d,%d\n"), sizex, sizey);
6255 #endif
6256      me->ResizeDrawArea(wxSize(sizex, sizey)); //changes draw area
6257     if (!scrolled) {
6258       wSize=wxSize(sizex, sizey);
6259       me->SetMinClientSize(wSize);
6260       me->SetClientSize(wSize);
6261     }
6262      UpdateGui();
6263   END_CHANGESIZE_NOEVENT
6264 }
6265 
6266  //Draw widgets as Base Widgets have a Size that can be SIZE(without scrollbars) or SCR_SIZE(with scrollbars)
SetWidgetSize(DLong sizex,DLong sizey)6267 void GDLWidgetDraw::SetWidgetSize(DLong sizex, DLong sizey) {
6268   START_CHANGESIZE_NOEVENT
6269   gdlwxDrawPanel* me = dynamic_cast<gdlwxDrawPanel*> (theWxWidget);
6270   if (!scrolled) { //size is same as clientSize
6271     if (sizex < 1) sizex = wSize.x;
6272     if (sizey < 1) sizey = wSize.y;
6273     wSize=wxSize(sizex,sizey);
6274     me->SetSize(wSize);
6275     me->SetMinSize(wSize);
6276     me->ResizeDrawArea(wSize); //changes draw area
6277   } else { //value asked is for CLIENT size
6278     if (sizex < 1) sizex = wScrollSize.x;
6279     if (sizey < 1) sizey = wScrollSize.y;
6280     wScrollSize=wxSize(sizex,sizey);
6281     me->SetClientSize(wScrollSize);
6282     me->SetMinClientSize(wScrollSize);
6283   }
6284 
6285 #ifdef GDL_DEBUG_WIDGETS
6286   wxMessageOutputStderr().Printf(_T("GDLWidgetDraw::SetWidgetSize %d,%d\n"), sizex, sizey);
6287 #endif
6288   UpdateGui();
6289   END_CHANGESIZE_NOEVENT
6290 }
6291 
6292 //Draw widgets as Base Widgets have a Size that can be SIZE(without scrollbars) or SCR_SIZE(with scrollbars)
SetWidgetScreenSize(DLong sizex,DLong sizey)6293 void GDLWidgetDraw::SetWidgetScreenSize(DLong sizex, DLong sizey) {
6294   START_CHANGESIZE_NOEVENT
6295   gdlwxDrawPanel* me = dynamic_cast<gdlwxDrawPanel*> (theWxWidget);
6296   if (!scrolled) { //size is same as clientSize
6297     if (sizex < 1) sizex = wSize.x;
6298     if (sizey < 1) sizey = wSize.y;
6299     wSize=wxSize(sizex,sizey);
6300     me->SetClientSize(wSize);
6301     me->SetMinClientSize(wSize);
6302     me->ResizeDrawArea(wSize); //changes draw area
6303   } else { //value asked is for SIZE
6304     if (sizex < 1) sizex = wScrollSize.x;
6305     if (sizey < 1) sizey = wScrollSize.y;
6306     wScrollSize=wxSize(sizex,sizey);
6307     me->SetSize(wScrollSize);
6308     me->SetMinSize(wScrollSize);
6309   }
6310 
6311 #ifdef GDL_DEBUG_WIDGETS
6312   wxMessageOutputStderr().Printf(_T("GDLWidgetDraw::SetWidgetSize %d,%d\n"), sizex, sizey);
6313 #endif
6314   UpdateGui();
6315   END_CHANGESIZE_NOEVENT
6316 }
6317 
6318 //for windows, it seems necessary to define our own wxApp and run it manually
6319 // for linux, it is NOT necessary, but thos works OK
6320 // for MacOS /COCOA port, the following code does not work and the widgets are not created.
6321 // (tied_scoped_ptr problem?)
6322 #ifndef __WXMAC__
6323 
6324 #include "wx/evtloop.h"
6325 #include "wx/ptr_scpd.h"
6326 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoop);
6327 
OnInit()6328 bool wxAppGDL::OnInit()
6329 {
6330     return true;
6331 }
6332 
MainLoop()6333 int wxAppGDL::MainLoop() {
6334   wxEventLoopTiedPtr mainLoop((wxEventLoop **) & m_mainLoop, new wxEventLoop);
6335   m_mainLoop->SetActive(m_mainLoop);
6336   loop = this->GetMainLoop();
6337   if (loop) {
6338     if (loop->IsRunning()) {
6339       while (loop->Pending()) // Unprocessed events in queue
6340       {
6341         loop->Dispatch(); // Dispatch next event in queue
6342       }
6343     }
6344   }
6345   return 0;
6346 }
6347 
OnExit()6348 int wxAppGDL::OnExit()
6349 {
6350   std::cout << " In GDLApp::OnExit()" << std::endl;
6351   // Defined in guiThread::OnExit() in gdlwidget.cpp
6352   //  std::cout << "Exiting thread (GDLApp::OnExit): " << thread << std::endl;
6353   return 0;
6354 }
6355 #endif
6356 
6357 #endif
6358