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