1 /***************************************************************************
2   gdlwxstream.cpp  - adapted from plplot wxWidgets driver documentation
3                              -------------------
4     begin                : Wed Oct 16 2013
5     copyright            : (C) 2013 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 "gdlwxstream.hpp"
23 
24 
25 
GDLWXStream(int width,int height)26 GDLWXStream::GDLWXStream( int width, int height )
27 : GDLGStream( width, height, "wxwidgets")
28   , streamDC(NULL)
29   , streamBitmap(NULL)
30   , m_width(width), m_height(height)
31   , container(NULL)
32 {
33   streamDC = new wxMemoryDC();
34   streamBitmap = new wxBitmap( width, height, 32);
35   streamDC->SelectObject( *streamBitmap);
36   if( !streamDC->IsOk())
37   {
38     streamDC->SelectObject( wxNullBitmap );
39     delete streamBitmap;
40     delete streamDC;
41     throw GDLException("GDLWXStream: Failed to create DC.");
42   }
43   setopt("drvopt", "hrshsym=0,text=1" ); //no hershey; WE USE TT fonts (antialiasing very nice and readable. Moreover, big bug somewhere with hershey fonts).
44 
45   PLFLT XDPI=(*static_cast<DFloatGDL*>( SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("X_PX_CM"))))[0]*2.5;
46   PLFLT YDPI=(*static_cast<DFloatGDL*>( SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("Y_PX_CM"))))[0]*2.5;
47   spage( XDPI, YDPI, width, height, 0, 0 ); //width and height have importance. 90 dpi is what is in the driver code.
48 
49   //plplot switched from PLESC_DEVINIT to dev_data for wxwidgets around version 5.11
50 #define PLPLOT_TEST_VERSION_NUMBER PLPLOT_VERSION_MAJOR*1000+PLPLOT_VERSION_MINOR
51 #if (PLPLOT_TEST_VERSION_NUMBER > 5010)
52   this->pls->dev_data=(void*)streamDC;
53 #endif
54   init();
55   plstream::cmd(PLESC_DEVINIT, (void*)streamDC );
56 
57    // no pause on win destruction
58     spause( false);
59 
60     // extended fonts
61     fontld( 1);
62 
63     // we want color
64     scolor( 1);
65 
66     PLINT r[ctSize], g[ctSize], b[ctSize];
67     GDLCT* myCT=GraphicsDevice::GetGUIDevice( )->GetCT();
68     myCT->Get( r, g, b);
69     SetColorMap0( r, g, b, ctSize); //set colormap 0 to 256 values
70 
71     // need to be called initially. permit to fix things
72     ssub(1,1);
73     adv(0);
74     // load font
75     font( 1);
76     vpor(0,1,0,1);
77     wind(0,1,0,1);
78     DefaultCharSize();
79     clear();
80 }
81 
~GDLWXStream()82 GDLWXStream::~GDLWXStream()
83 {
84   //all WXStreams are in a wxWidget, either alone (plot window) or widget architecture (widget_draw)
85   // destroying the stream must destroy the widget or the plot window.
86   // we delete the bitmaps
87   streamDC->SelectObject( wxNullBitmap );
88   delete streamBitmap;
89   delete streamDC;
90   DestroyContainer();
91 }
92 
EventHandler()93 void GDLWXStream::EventHandler() {
94   if (!valid) return;
95 // GraphicsDevice::GetDevice()->TidyWindowsList(); //necessary since we removed TidyWindowList() from GraphicsMultiDevice::EventHandler()
96   // plplot event handler
97 //  plstream::cmd(PLESC_EH, NULL);
98 }
99 
SetGdlxwGraphicsPanel(gdlwxGraphicsPanel * w,bool isPlot)100 void GDLWXStream::SetGdlxwGraphicsPanel(gdlwxGraphicsPanel* w, bool isPlot)
101 {
102   container = w;
103   isplot=isPlot;
104 }
105 
Update()106 void GDLWXStream::Update()
107 {
108   if( this->valid && container != NULL) {
109     container->RepaintGraphics();
110     //will be updated by eventloop.
111 #ifdef __WXMAC__
112   wxTheApp->Yield();
113 #else
114   wxGetApp().MainLoop(); //central loop for wxEvents!
115 #endif
116   }
117 }
118 
119 ////should be used when one does not recreate a wxstream each time size changes...
SetSize(wxSize s)120 void GDLWXStream::SetSize( wxSize s )
121 {
122   if ( s.x<1 || s.y <1) return;
123   //Due to a 'bug' in PLPLOT, we need to resize streamDC by destroying it and getting a better one, instead of just using PLESC_RESIZE.
124   streamDC->SelectObject( wxNullBitmap );
125   delete streamBitmap;
126   delete streamDC; //only solution to have it work with plplot-5.15
127   streamDC = new wxMemoryDC;
128   container->SetStream(this); //act change of streamDC
129   streamBitmap = new wxBitmap( s.x, s.y, 32 );
130   streamDC->SelectObject( *streamBitmap );
131   if( !streamDC->IsOk())
132   {
133     streamDC->SelectObject( wxNullBitmap );
134     delete streamBitmap;
135     delete streamDC;
136     throw GDLException("GDLWXStream: Failed to resize DC.");
137   }
138   this->set_stream();
139   this->cmd( PLESC_DEVINIT, (void *) streamDC );
140   this->cmd(PLESC_RESIZE, (void*)&s );
141   m_width = s.x;
142   m_height = s.y;
143 }
144 
WarpPointer(DLong x,DLong y)145 void GDLWXStream::WarpPointer(DLong x, DLong y) {
146   if (container) {
147     int xx=x;
148     int yy=y;
149     wxPanel *p = static_cast<wxPanel*>(container);
150     p->WarpPointer(xx,container->GetSize().y-yy);
151   }
152 }
153 
Init()154 void GDLWXStream::Init()
155 {
156   this->plstream::init();
157 
158 //  set_stream(); // private
159 // test :  gdlFrame->Show();
160 }
161 
162 
RenewPlot()163 void GDLWXStream::RenewPlot()
164 {
165   plstream::cmd( PLESC_CLEAR, NULL );
166   replot();
167 }
168 
GetGeometry(long & xSize,long & ySize)169 void GDLWXStream::GetGeometry( long& xSize, long& ySize)
170 {
171   // plplot does not return the real size
172   xSize = m_width;
173   ySize = m_height;
174   if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"GDLWXStream::GetGeometry(%ld %ld)\n", xSize, ySize);
175 }
176 
GetWindowDepth()177 unsigned long GDLWXStream::GetWindowDepth() {
178   return wxDisplayDepth();
179 }
180 
Clear()181 void GDLWXStream::Clear() {
182       PLINT red,green,blue;
183       DByte r,g,b;
184       PLINT red0,green0,blue0;
185 
186       GraphicsDevice::GetCT()->Get(0,r,g,b);red=r;green=g;blue=b;
187 
188       red0=GraphicsDevice::GetDevice()->BackgroundR();
189       green0=GraphicsDevice::GetDevice()->BackgroundG();
190       blue0=GraphicsDevice::GetDevice()->BackgroundB();
191       plstream::scolbg(red0,green0,blue0); //overwrites col[0]
192       ::c_plbop();
193       ::c_plclear();
194       plstream::scolbg(red,green,blue); //resets col[0]
195 }
196 
197 //FALSE: REPLACE With Clear(DLong chan) as in X //TBD
Clear(DLong bColor)198 void GDLWXStream::Clear(DLong bColor) {
199   Clear();
200 }
201 
PaintImage(unsigned char * idata,PLINT nx,PLINT ny,DLong * pos,DLong trueColorOrder,DLong chan)202 bool GDLWXStream::PaintImage(unsigned char *idata, PLINT nx, PLINT ny, DLong *pos,
203         DLong trueColorOrder, DLong chan) {
204 //  plstream::cmd( PLESC_FLUSH, NULL );
205 //  Update();
206   DLong decomposed=GraphicsDevice::GetDevice()->GetDecomposed();
207   wxMemoryDC temp_dc;
208   temp_dc.SelectObject(*streamBitmap);
209   wxImage image=streamBitmap->ConvertToImage();
210   unsigned char* mem=image.GetData();
211   PLINT xoff = (PLINT) pos[0]; //(pls->wpxoff / 32767 * dev->width + 1);
212   PLINT yoff = (PLINT) pos[2]; //(pls->wpyoff / 24575 * dev->height + 1);
213 
214   PLINT xsize = m_width;
215   PLINT ysize = m_height;
216   PLINT kxLimit = xsize - xoff;
217   PLINT kyLimit = ysize - yoff;
218   if (nx < kxLimit) kxLimit = nx;
219   if (ny < kyLimit) kyLimit = ny;
220 
221   if (nx > 0 && ny > 0) {
222     SizeT p = (ysize - yoff - 1)*3 * xsize;
223     if (trueColorOrder == 0 && chan == 0) {
224       if (decomposed == 1) {
225         for (int iy = 0; iy < kyLimit; ++iy) {
226           SizeT rowStart = p;
227           p += xoff * 3;
228           for (int ix = 0; ix < kxLimit; ++ix) {
229             mem[p++] = idata[iy * nx + ix];
230             mem[p++] = idata[iy * nx + ix];
231             mem[p++] = idata[iy * nx + ix];
232           }
233           p = rowStart - (xsize * 3);
234         }
235       } else {
236         for (int iy = 0; iy < kyLimit; ++iy) {
237           SizeT rowStart = p;
238           p += xoff * 3;
239           for (int ix = 0; ix < kxLimit; ++ix) {
240             mem[p++] = pls->cmap0[idata[iy * nx + ix]].r;
241             mem[p++] = pls->cmap0[idata[iy * nx + ix]].g;
242             mem[p++] = pls->cmap0[idata[iy * nx + ix]].b;
243           }
244           p = rowStart - (xsize * 3);
245         }
246       }
247     } else {
248       if (chan == 0) {
249         if (trueColorOrder == 1) {
250           for (int iy = 0; iy < kyLimit; ++iy) {
251             SizeT rowStart = p;
252             p += xoff * 3;
253             for (int ix = 0; ix < kxLimit; ++ix) {
254               mem[p++] = idata[3 * (iy * nx + ix) + 0];
255               mem[p++] = idata[3 * (iy * nx + ix) + 1];
256               mem[p++] = idata[3 * (iy * nx + ix) + 2];
257             }
258             p = rowStart - (xsize * 3);
259           }
260         } else if (trueColorOrder == 2) {
261           for (int iy = 0; iy < kyLimit; ++iy) {
262             SizeT rowStart = p;
263             p += xoff * 3;
264             for (int ix = 0; ix < kxLimit; ++ix) {
265               mem[p++] = idata[nx * (iy * 3 + 0) + ix];
266               mem[p++] = idata[nx * (iy * 3 + 1) + ix];
267               mem[p++] = idata[nx * (iy * 3 + 2) + ix];
268             }
269             p = rowStart - (xsize * 3);
270           }
271         } else if (trueColorOrder == 3) {
272           for (int iy = 0; iy < kyLimit; ++iy) {
273             SizeT rowStart = p;
274             p += xoff * 3;
275             for (int ix = 0; ix < kxLimit; ++ix) {
276               mem[p++] = idata[nx * (0 * ny + iy) + ix];
277               mem[p++] = idata[nx * (1 * ny + iy) + ix];
278               mem[p++] = idata[nx * (2 * ny + iy) + ix];
279             }
280             p = rowStart - (xsize * 3);
281           }
282         }
283       } else { //1 byte bitmap passed.
284         if (chan == 1) {
285           for (int iy = 0; iy < kyLimit; ++iy) {
286             SizeT rowStart = p;
287             p += xoff * 3;
288             for (int ix = 0; ix < kxLimit; ++ix) {
289               mem[p++] = idata[1 * (iy * nx + ix) + 0];
290               p += 2;
291             }
292             p = rowStart - (xsize * 3);
293           }
294         } else if (chan == 2) {
295           for (int iy = 0; iy < kyLimit; ++iy) {
296             SizeT rowStart = p;
297             p += xoff * 3;
298             for (int ix = 0; ix < kxLimit; ++ix) {
299               p++;
300               mem[p++] = idata[1 * (iy * nx + ix) + 0];
301               p++;
302             }
303             p = rowStart - (xsize * 3);
304           }
305         } else if (chan == 3) {
306           for (int iy = 0; iy < kyLimit; ++iy) {
307             SizeT rowStart = p;
308             p += xoff * 3;
309             for (int ix = 0; ix < kxLimit; ++ix) {
310               p += 2;
311               mem[p++] = idata[1 * (iy * nx + ix) + 0];
312             }
313             p = rowStart - (xsize * 3);
314           }
315         }
316       }
317     }
318   }
319   streamDC->DrawBitmap(image,0,0);
320   image.Destroy();
321   temp_dc.SelectObject( wxNullBitmap);
322   *streamBitmap = streamDC->GetAsBitmap();
323 //  Update();
324   return true;
325 }
326 
SetGraphicsFunction(long value)327 bool GDLWXStream::SetGraphicsFunction( long value) {
328   //use switch since passing an enum to a function is problematic for some compilers, grrrrrrrrrrrr!
329   value=(value<0)?0:(value>15)?15:value;
330   switch ( value ) {
331     case 0: //wxCLEAR:
332       streamDC->SetLogicalFunction( wxCLEAR);
333       break;
334     case 1: //wxAND:
335       streamDC->SetLogicalFunction( wxAND);
336       break;
337     case 2: //wxAND_REVERSE:
338       streamDC->SetLogicalFunction( wxAND_REVERSE);
339       break;
340     default:
341     case 3: //wxCOPY:
342       streamDC->SetLogicalFunction( wxCOPY);
343       break;
344     case 4: //wxAND_INVERT:
345       streamDC->SetLogicalFunction( wxAND_INVERT);
346       break;
347     case 5: //wxNO_OP:
348       streamDC->SetLogicalFunction( wxNO_OP);
349       break;
350     case 6: //wxXOR:
351       streamDC->SetLogicalFunction( wxXOR);
352       break;
353     case 7: //wxNOR:
354       streamDC->SetLogicalFunction( wxNOR);
355       break;
356     case 8: //wxEQUIV:
357       streamDC->SetLogicalFunction( wxEQUIV);
358       break;
359     case 9: //wxINVERT:
360       streamDC->SetLogicalFunction( wxINVERT);
361       break;
362     case 10: //wxOR_REVERSE:
363       streamDC->SetLogicalFunction( wxOR_REVERSE);
364       break;
365     case 11: //wxSRC_INVERT:
366       streamDC->SetLogicalFunction( wxSRC_INVERT);
367       break;
368     case 12: //wxOR_INVERT:
369       streamDC->SetLogicalFunction( wxOR_INVERT);
370       break;
371     case 13: //wxNAND:
372       streamDC->SetLogicalFunction( wxNAND);
373       break;
374     case 14: //wxSET:
375       streamDC->SetLogicalFunction( wxSET);
376       break;
377   }
378  return true;
379 }
380 
GetWindowPosition(long & xpos,long & ypos)381 bool GDLWXStream::GetWindowPosition(long& xpos, long& ypos ) {
382   wxRect r=container->GetScreenRect();
383   xpos=r.x;
384   ypos=r.y;
385  return true;
386 }
387 
GetScreenResolution(double & resx,double & resy)388 bool GDLWXStream::GetScreenResolution(double& resx, double& resy) {
389   wxScreenDC *temp_dc=new wxScreenDC();
390   wxSize reso=temp_dc->GetPPI();
391   resx = reso.x/2.54;
392   resy = reso.y/2.54;
393   return true;
394 }
DefineSomeWxCursors()395 void GDLWXStream::DefineSomeWxCursors(){
396 
397 #include "otherdevices/gdlcursors.h"
398   for (int cnum=0; cnum<nglyphs; cnum++) {
399   char* glyph=(char*)&(glyphs[glyphs_offset[cnum]]);
400   char* glyph_mask=(char*)&(glyphs_mask[glyphs_mask_offset[cnum]]);
401   int nx=glyphs_dims[cnum*2];
402   int ny=glyphs_dims[cnum*2+1];
403   int hotspot_x=glyphs_hotspot[cnum*2];
404   int hotspot_y=glyphs_hotspot[cnum*2+1];
405 #ifdef __WXMSW__
406     for(int i=0; i< (nx/8+1)*ny; ++i) {glyph[i]=~glyph[i]; glyph_mask[i]=~glyph_mask[i];}
407     wxBitmap glyph_bitmap(glyph, nx,ny);
408     wxBitmap glyph_mask_bitmap(glyph_mask, nx,ny);
409     glyph_bitmap.SetMask(new wxMask(glyph_mask_bitmap));
410     wxImage glyph_image = glyph_bitmap.ConvertToImage();
411     glyph_image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, hotspot_x);
412     glyph_image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, hotspot_y);
413     wxCursor glyph_cursor = wxCursor(glyph_image);
414     gdlwxCursors.push_back(glyph_cursor);
415 #elif defined(__WXGTK__) or defined(__WXMOTIF__)
416     wxCursor glyph_cursor= wxCursor(glyph,nx,ny,hotspot_x,hotspot_y,glyph_mask); //, wxWHITE, wxBLACK);
417     gdlwxCursors.push_back(glyph_cursor);
418 #endif
419   }
420 }
CursorStandard(int cursorNumber)421 bool GDLWXStream::CursorStandard(int cursorNumber)
422 {
423   if (cursorNumber == -1) { //device,/CURSOR_ORIGINAL
424     container->SetCursor(wxNullCursor); //back to default
425     return true;
426   }
427   if (cursorNumber == -2) { //device,/CURSOR_CROSS
428     container->SetCursor(wxCursor(wxCURSOR_CROSS));
429     return true;
430   }
431   if (gdlwxCursors.size() < 1) DefineSomeWxCursors();
432   int cnum=cursorNumber/2;
433   if (cnum < 0) cnum=0;
434   if (cnum > (gdlwxCursors.size()-1) ) cnum=gdlwxCursors.size()-1;
435   container->SetCursor(gdlwxCursors[cnum]);
436  return true;
437 }
CursorImage(char * v,int x,int y,char * m)438 bool GDLWXStream::CursorImage(char* v, int x, int y, char* m)
439 {
440 #ifdef __WXMSW__
441   for(int i=0; i< 31; ++i) v[i]=~v[i];
442     wxBitmap bitmap(v, 16, 16);
443     if (m) {
444      for(int i=0; i< 31; ++i) m[i]=~m[i];
445       wxBitmap mask_bitmap(m, 16,16);
446       bitmap.SetMask(new wxMask(mask_bitmap));
447     }
448     wxImage image = bitmap.ConvertToImage();
449     image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, x);
450     image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, y);
451     wxCursor cursor = wxCursor(image);
452     container->SetCursor(cursor);
453 #elif defined(__WXGTK__) or defined(__WXMOTIF__)
454     wxCursor cursor= wxCursor(v,16,16,x,y,m); //, wxWHITE, wxBLACK);
455    container->SetCursor(cursor);
456 #endif
457  return true;
458 }
GetVisualDepth()459 DLong GDLWXStream::GetVisualDepth() {
460 return 24;
461 }
GetFontnames(DString pattern)462 BaseGDL* GDLWXStream::GetFontnames(DString pattern) {
463   if (pattern.length()<=0) return NULL;
464   wxFontEnumerator fontEnumerator;
465   fontEnumerator.EnumerateFacenames();
466   int nFacenames = fontEnumerator.GetFacenames().GetCount();
467   // we are supposed to select only entries lexically corresponding to 'pattern'.
468   //first check who passes (ugly)
469   wxString wxPattern(pattern);
470   wxPattern=wxPattern.Upper();
471   std::vector<int> good;
472   for (int i=0; i< nFacenames; ++i) if (fontEnumerator.GetFacenames().Item(i).Upper().Matches(wxPattern)) { good.push_back(i); }
473   if (good.size() == 0) return NULL;
474   //then get them
475   DStringGDL* myList=new DStringGDL(dimension(good.size()));
476   for (int i=0; i< good.size(); ++i) (*myList)[i].assign(fontEnumerator.GetFacenames().Item(good[i]).mb_str(wxConvUTF8));
477   return myList;
478 }
GetFontnum(DString pattern)479 DLong GDLWXStream::GetFontnum(DString pattern){
480   if (this->GetFontnames(pattern) == NULL) return 0;
481   if (pattern.length()==0) return 0;
482   return this->GetFontnames(pattern)->N_Elements();
483 }
SetCurrentFont(std::string fontname)484 void GDLWXStream::SetCurrentFont(std::string fontname){
485   if (fontname.size() > 0) {
486    wxFont font=wxFont(wxString(fontname.c_str( ), wxConvLibc));
487    if (!font.IsSameAs(wxNullFont)) streamDC->SetFont(font);
488   }
489 }
GetVisualName()490 DString GDLWXStream::GetVisualName() {
491 static const char* visual="TrueColor";
492 return visual;
493 }
494 
GetBitmapData()495 DByteGDL* GDLWXStream::GetBitmapData() {
496     wxImage image=streamBitmap->ConvertToImage();
497     unsigned char* mem=image.GetData();
498     if ( mem == NULL ) return NULL;
499 
500     unsigned int nx = streamBitmap->GetWidth();
501     unsigned int ny = streamBitmap->GetHeight();
502 
503     SizeT datadims[3];
504     datadims[0] = nx;
505     datadims[1] = ny;
506     datadims[2] = 3;
507     dimension datadim(datadims, (SizeT) 3);
508     DByteGDL *bitmap = new DByteGDL( datadim, BaseGDL::NOZERO);
509     //PADDING is 3BPP -- we revert Y to respect IDL default
510     SizeT kpad = 0;
511     for ( SizeT iy =0; iy < ny ; ++iy ) {
512       for ( SizeT ix = 0; ix < nx; ++ix ) {
513         (*bitmap)[3 * ((ny-1-iy) * nx + ix) + 0] =  mem[kpad++];
514         (*bitmap)[3 * ((ny-1-iy) * nx + ix) + 1] =  mem[kpad++];
515         (*bitmap)[3 * ((ny-1-iy) * nx + ix) + 2] =  mem[kpad++];
516       }
517     }
518     image.Destroy();
519     return bitmap;
520 }
521 
Raise()522 void GDLWXStream::Raise() {
523 this->GetMyContainer()->RaisePanel();
524 }
525 
Lower()526 void GDLWXStream::Lower() {
527 this->GetMyContainer()->LowerPanel();
528 }
529 
Iconic()530 void GDLWXStream::Iconic() {
531  this->GetMyContainer()->IconicPanel();
532 }
533 
DeIconic()534 void GDLWXStream::DeIconic() {
535  this->GetMyContainer()->DeIconicPanel();
536 }
537 
UnsetFocus()538 bool GDLWXStream::UnsetFocus(){
539  return false; //UnsetFocus is dangerous: it prevents using wxEvents correctly.
540 }
541 
GetGin(PLGraphicsIn * gin,int mode)542 bool GDLWXStream::GetGin(PLGraphicsIn *gin, int mode) {
543   if (container==NULL) return false;
544   enum CursorOpt {
545     NOWAIT = 0,
546     WAIT, //1
547     CHANGE, //2
548     DOWN, //3
549     UP //4
550   };
551   wxMouseState mouse=wxGetMouseState();
552   wxPoint mousePoint = wxGetMousePosition ();
553   unsigned int state=0, ostate=0; //start with null state
554   unsigned int button=0; //gets the button state 1,2,3
555   int x,y;
556   x = mouse.GetX();
557   y = mouse.GetY();
558   gin->pX = x;
559   gin->pY = y;
560 
561   //state is like the button state value, combination of all buttonstate masks of X11. It is merely to know what buttons are down
562   if (mouse.LeftIsDown())  {button = 1; ostate |= 1;}
563   if (mouse.MiddleIsDown()){button = 2; ostate |= 2;}
564   if (mouse.RightIsDown()) {button = 3; ostate |= 4;}
565 #if wxCHECK_VERSION(3,0,0)
566   if (mouse.Aux1IsDown())  {button = 4; ostate |= 8;}
567   if (mouse.Aux2IsDown())  {button = 5; ostate |= 16;}
568 #endif
569   //return if NOWAIT or WAIT and Button pressed
570   if ((mode == NOWAIT) || (mode == WAIT && button > 0)) {
571     state=ostate;
572     goto end; //else wait below for a down...
573   }
574   while (1) { //poll repeatedly -- waiting for event would be better but needs start locally the wx eventloop.
575      if (container->GetScreenRect().Contains(wxGetMousePosition())) { //if cursor is in the window...
576        mouse=wxGetMouseState();
577        x = mouse.GetX();
578        y = mouse.GetY();
579        if (mouse.LeftIsDown())   {button = 1; state |= 1;}
580        if (mouse.MiddleIsDown()) {button = 2; state |= 2;}
581        if (mouse.RightIsDown())  {button = 3; state |= 4;}
582 #if wxCHECK_VERSION(3,0,0)
583        if (mouse.Aux1IsDown())   {button = 4; state |= 8;}
584        if (mouse.Aux2IsDown())   {button = 5; state |= 16;}
585 #endif
586        int change=(state^ostate);
587        //is it a button up or down?
588        int diff=(state&change)-(ostate&change);
589        bool ButtonRelease=( diff < 0 ); //from 1 to 0: negative
590        if (change > 0) { //press or release
591          gin->pX = x;
592          gin->pY = y;
593          if (mode==CHANGE) goto end;
594          if (mode==UP && ButtonRelease) goto end;
595          if (!ButtonRelease && (mode==WAIT || mode==DOWN) ) goto end;
596        }
597        if ( (pow((float)x-gin->pX,2)+pow((float)y-gin->pY,2) > 0) && mode==CHANGE) {
598          gin->pX = x;
599          gin->pY = y;
600          goto end;
601        }
602        ostate=state; //update state
603        state=0;
604        gin->pX = x; //update new position
605        gin->pY = y;
606      }
607   //We must get out of this loop sometime!
608        wxMilliSleep( 50 );      // Sleep a bit to prevent CPU overuse
609 
610         if ( sigControlC )
611           return false;
612   }
613 end:
614   //convert screen to client coord
615   container->ScreenToClient(&x,&y); //now in coordinates
616   gin->pX = x;
617   gin->pY = container->GetSize().y - y;
618   gin->dX = (PLFLT) gin->pX / ( container->GetSize().x - 1);
619   gin->dY = (PLFLT) gin->pY / ( container->GetSize().y - 1);
620   gin->string[0] = '\0';
621   gin->keysym = 0x20;
622   gin->button = button;
623   return true;
624 }
625 
626 #endif
627