PEBL 2.2
Psychology Experiment Building Language - Cross-platform psychological experiment development system
sdl/PlatformWidget.cpp
Go to the documentation of this file.
1//* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
3// Name: src/platforms/sdl/PlatformWidget.cpp
4// Purpose: Contains SDL-specific interface GUI objects
5// Author: Shane T. Mueller, Ph.D.
6// Copyright: (c) 2003-2026 Shane T. Mueller <smueller@obereed.net>
7// License: GPL 2
8//
9//
10//
11// This file is part of the PEBL project.
12//
13// PEBL is free software; you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation; either version 2 of the License, or
16// (at your option) any later version.
17//
18// PEBL is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with PEBL; if not, write to the Free Software
25// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27#include "PlatformWidget.h"
28
29#ifdef PEBL_OSX
30#include "SDL.h"
31#else
32#include "SDL.h"
33#endif
34
35#include "SDLUtility.h"
36#include "../../utility/PError.h"
37#include "../../base/PComplexData.h"
38#include <iostream>
39#include <cstring>
40#include <cmath>
41
42// cout removed - use cerr for debug output
43using std::cerr;
44using std::endl;
45
46//Standard constructor
48 mNeedsTexture(true)
49{
51 mSurface = NULL;
52 mTexture = NULL;
53
54 //cout << "Creating null platformwidget\n";
55}
56
58{
59
60
61 //Remove this from its parent (if one exists)
62 if(mParent)
63 {
65 }
66
68
69
70 if(mSurface)
71 {
72
73 SDL_FreeSurface(mSurface);
74 mSurface = NULL;
75 }
76
77 //Don't destroy the 'borrowed' texture of drawobjects.
79 {
80
81 if(mTexture)
82 {
83
84 SDL_DestroyTexture(mTexture);
85 }
86 }
87
88}
89
90
91
92std::ostream & PlatformWidget::SendToStream(std::ostream& out) const
93{
94 out << "<SDL PlatformWidget> " << std::flush;
95 return out;
96}
97
98
99
100
101//
102//
103//
105{
106
107 if(mRenderer)
108 {
109 long unsigned int newWidth = mWidth;
110 long unsigned int newHeight = mHeight;
111
112 if(IsVisible())
113 {
114 //To draw a widget, draw each of the window's subwidgets
115 //(using PlatformWidget::Draw(SDLSurface)
116 //This should be done backwards, so that the last item added
117 //(which is on the front) will be the last item drawn.
118
119
120 std::list<PWidget *>::iterator p = mSubWidgets.end();
121 while(p != mSubWidgets.begin())
122 {
123
124 //decrement iterator--moving backward so we draw things in
125 //reverse order.
126 p--;
127 //Draw the subwidget
128 if((*p)->IsVisible())
129 {
130
131 (*p)->Draw();
132
133 }
134 }
135
136 //Once the widget sub-items are drawn,
137 //draw the widget to its parent.
138
139 if (mParent)
140 {
141 long unsigned int w = mWidth;
142 long unsigned int h = mHeight;
143
144 if(mNeedsTexture)
145 {
146 //SDL_QueryTexture(mTexture,NULL,NULL,&w,&h);
147 w = mTextureWidth;
148 h = mTextureHeight;
149 }
150
151 SDL_Rect fromRect = {0,0,(int)w,(int)h};
152
153 //Check to see if any roto-zooming is needed
154 if(std::abs(mZoomX-1.0)>.001 || std::abs(mZoomY-1.0)>.001 )
155 {
156
157 //We need to reset the sizes.
158 //Calculate the new size.
159
160 newWidth = w * mZoomX;
161 newHeight = h * mZoomY;
162
163 PWidget::SetProperty("WIDTH",newWidth);
164 PWidget::SetProperty("HEIGHT",newHeight);
165 //zoomx and zoomy should take care of setting widths correctly.
166
167
168
169 //these call PWidget::SetZoom
170 SetProperty("ZOOMX",mZoomX);
171 SetProperty("ZOOMY",mZoomY);
172
173 SetPosition(mX,mY); //Reset position so
174 //objects get centered properly
175
176 }
177 else
178 {
179
181 PWidget::SetProperty("HEIGHT", mHeight);
182 PWidget::SetProperty("ZOOMX",1);
183 PWidget::SetProperty("ZOOMY",1);
184 }
185
186
187
188 //The to rect depends on the type of object...
189 //textboxes don't change their to x value;
190 //all others will adjust to self-center.
191
192 SDL_Rect toRect = {static_cast<int>(mDrawX),
193 static_cast<int>(mDrawY),
194 (int)newWidth,
195 (int) newHeight};
196
197
198 //This renders from the texture onto the base window.
199 //we sort of want to render to parent instead.
200 int result;
201 SDL_Texture * parenttexture = dynamic_cast<PlatformWidget*>(mParent)->GetSDL_Texture();
202
203 if(parenttexture)
204 {
205 result = SDL_SetRenderTarget(mRenderer,parenttexture);
206
207 if(result<0)
208 {
209 cerr << " SetRenderTarget failed with error code: " << result << endl;
210
211 cerr << "SDL message: " << SDL_GetError() << endl;
212 cerr << *this << endl;
213 cerr << "Parent:" << parenttexture << endl;
214
215 }
216
217 result = -1;
218 int count = 0;
219 while(result<0 & count++<10)
220 {
221
222 result = SDL_RenderCopyEx(mRenderer, mTexture,
223 &fromRect, &toRect,
224 -mRotation,NULL,SDL_FLIP_NONE);
225
226 if(result<0)
227 {
228 cerr << "SDL_RenderCopyEx failed with error code: " << result << "|" << count<< endl;
229 cerr << "SDL message: " << SDL_GetError() << endl;
230 cerr << *this << endl;
231 cerr << "Texture:" << mTexture << endl;
232
233 }
234 }
235
236 result =SDL_SetRenderTarget(mRenderer,NULL);
237
238 if(result<0)
239 {
240 cerr << "Resetting SDL_SetRenderTarget failed with error code: " << result << endl;
241 cerr << "SDL message: " << SDL_GetError() << endl;
242 cerr << *this << endl;
243 cerr << "Texture:" << mTexture << endl;
244
245 }
246 } else{
247
248
249
250 SDL_SetTextureBlendMode(mTexture, SDL_BLENDMODE_BLEND);
251 result = SDL_RenderCopyEx(mRenderer, mTexture,
252 &fromRect, &toRect,
253 -mRotation,NULL,SDL_FLIP_NONE);
254
255 if(result<0)
256 {
257 cerr << "Rendering failed to NULL texture using SDL_RenderCopyEx with error code: " << result << endl;
258 cerr << "SDL message: " << SDL_GetError() << endl;
259 cerr << *this << endl;
260 cerr << "Texture:" << mTexture << endl;
261
262 }
263
264 }
265 }
266 else
267 {
268
269 // IF there is no parent, this is probably a window or an
270 //unassigned widget
271
272 }
273 }
274 }else{
275
276 //We will sometimes call a Draw() on an object that is not yet assigned
277 //a renderer--not attached to a window, etc.
278 //cout << "Trying to render widget with no renderer" << *this << endl;
279 }
280 return true;
281}
282
283
284//Sets a pixel to be a certain color. This requires the object to have
285//an active renderer. Otherwise...toobad.
286
287bool PlatformWidget::SetPoint(int x, int y, PColor col)
288{
289
290 SDLUtility::DrawPixel(mRenderer,this,x,y,col);
291 return true;
292}
293
294
296{
297 if(mSurface)
298 {
300 }else{
301
302 return PColor(0,0,0,0);
303 }
304
305}
306
307
308
309bool PlatformWidget::RotoZoom(double angle, double zoomx, double zoomy, int smooth)
310
311{
312
313#ifdef SDL2_DELETE
314 //This is probably handled directly by SDL2
315 SDL_Surface * tmp = rotozoomSurfaceXY(mSurface, angle,zoomx, zoomy, smooth);
316 SDL_FreeSurface(mSurface);
317 mSurface = tmp;
318
319
320 //We need to reset the sizes.
321
322 mWidth = mSurface->w;
323 mHeight = mSurface->h;
324 PWidget::SetProperty("WIDTH", mSurface->w);
325 PWidget::SetProperty("HEIGHT", mSurface->h);
326 if(mSurface)return true;
327 else return false;
328#endif
329 return false;
330}
331
332
333#ifdef SDL2_DELETE
334SDL_Surface * PlatformWidget::GetSDL_Surface()
335{
336 return mSurface;
337}
338#endif
339
340
341
342
343
345{
346 return mTexture;
347}
348
349
351{
352
353
354 SetParent(parent);
355
356
357 //Child widgets currently are of one of three types:
358 // * images/canvases have internal mSurfaces that may contain
359 // data but don't have a texture yet
360 // * text objects (labels, textboxes) don't have an msurface,
361 // but when it is first draw()ed/render()ed, a temp surface
362 // will get created and transferred to mTexture, which will
363 //then be used; tmpSurface will be destroyed, and mSurface
364 //not used
365 // * DrawObjects(), which draw directly to the parent texture.
366 // so that no rendercopy'ing is needed. Here, no mSurface and no // mTexture is used.
367
368
369
370
371 //Assign us the parent's renderer. There is only one renderer
372 //per window, and so we can't creat the texture until it gets
373 //added to the window.
374
375 int out = SetRenderer(parent->GetRenderer());
376 return out == 0;
377}
378
379
380
381bool PlatformWidget::SetRenderer(SDL_Renderer * renderer)
382{
383
384 // cout<<"****************" << *this << "Setting renderer--" << renderer << endl;
385 mRenderer = renderer;
386
387 //Be sure renderer is set for all children, recursively
388 std::list<PWidget*>::iterator i = mSubWidgets.begin();
389 while(i != mSubWidgets.end())
390 {
391
392 PlatformWidget* p = dynamic_cast<PlatformWidget*>(*i);
393 //cout << "setting child renderer:" << **i <<"|" << mRenderer << endl;
394 p->SetRenderer(renderer);
395
396 i++;
397 }
398
399
400 return true;
401}
402
403
405{
406 // cout << "Adding subwidget " << *child<<endl;
407
408
409 if(strcmp(child->ObjectName().c_str(),"PlatformMovie")==0)
410 {
411 PError::SignalFatalError("Cannot add movie to another widget\n");
412 } else {
413
414
415 //if(! mRenderer)
416 // {
417 // PError::SignalFatalError("To add a child widget to a parent, renderer must exist.");
418 // exit(0);
419 // }
420
421
422 //This manages the renderer and does a setparent()
423
424
425 //This resets zorder:
427 // child->AddToParentWidget(this);
428 child->SetParent(this);
430
431 }
432
433 return true;
434}
435
436
437
439{
440
441
442
444
445 mSubWidgets.remove(dynamic_cast<PWidget*>(child));
446 mSubWidgets.remove(child);
447 //child->SetParent(NULL); //handled in pwidget::remove
448 child->SetRenderer(NULL);
449
450 return true;
451}
452
453
454
455
457{
458
459 if(mSubWidgets.size()>0)
460 {
461
462 std::list<PWidget*>::iterator i = mSubWidgets.begin();
463 while(i != mSubWidgets.end())
464 {
465 //(*i)->SetParent(NULL);
466 //mSubWidgets.pop_front();
467 //This might not be the right thing to do:
468 //see removesubwidget above.
469 mSubWidgets.remove(*i);
470 //(*i)->SetParent(NULL);
471
472 //RemoveSubWidget(dynamic_cast<PlatformWidget*>(*i));
473 i=mSubWidgets.begin(); //readjust so it points to the start of the list.
474 }
475
476 mSubWidgets.clear();
477 }
478
479 return true;
480}
481
483{
484
485 PWidget::SetParent(parent);
486}
487
488#ifdef SDL2_DELETE
489void PlatformWidget::SetParentSurface(SDL_Surface* surface)
490{
491 mParentSurface = surface;
492}
493
494
495void PlatformWidget::SetParentTexture(SDL_Texture* texture)
496{
497 mParentTexture = texture;
498}
499#endif
500
501
502void PlatformWidget::PrintSubWidgets(std::ostream & out)const
503{
504
505 if(mSubWidgets.size()>0)
506 {
507
508 std::list<PWidget*>::const_iterator i = mSubWidgets.begin();
509 while(i != mSubWidgets.end())
510 {
511
512 i++;
513 }
514
515 }else{
516
517 }
518
519}
520
521
522
523
524
525
528{
529#ifdef SDL2_DELETE
530 if(SDL_MUSTLOCK(mSurface))
531 {
532
533 //cout << "Locking-------->" << endl;
534 //The below returns 0 on success, -1 otherwise,
535 //so reverse it for t/f
536 if(SDL_LockSurface(mSurface)<0)
537 {
538 cerr << "Need to lock surface but can't\n";
539 return false;
540 }
541 return true;
542 }
543
544#endif
545 return false;
546
547}
548
551{
552#ifdef SDL2_DELETE
553 if(SDL_MUSTLOCK(mSurface))
554 {
555 // cout << "------->Unlocking" << endl;
556 SDL_UnlockSurface(mSurface);
557 }
558#endif
559 return true;
560}
#define NULL
Definition BinReloc.cpp:317
pInt mDrawX
Definition PWidget.h:129
virtual void SetPosition(pInt x, pInt y)
This sets the widget's position on its parent widget.
Definition PWidget.cpp:220
pDouble mZoomX
Definition PWidget.h:139
virtual bool SetProperty(std::string, Variant v)
Definition PWidget.cpp:142
pInt mWidth
Definition PWidget.h:136
virtual std::string ObjectName() const
Definition PWidget.h:115
std::list< PWidget * > mSubWidgets
Definition PWidget.h:147
pInt mX
Definition PWidget.h:125
virtual bool AddSubWidget(PWidget *widget)
Definition PWidget.cpp:330
pInt mHeight
Definition PWidget.h:136
pInt mY
Definition PWidget.h:125
pDouble mZoomY
Definition PWidget.h:140
PWidget * mParent
Definition PWidget.h:154
virtual bool RemoveSubWidget(PWidget *widget)
Definition PWidget.cpp:375
virtual bool IsVisible() const
Definition PWidget.h:113
pInt mDrawY
Definition PWidget.h:130
pDouble mRotation
Definition PWidget.h:141
virtual void SetParent(PWidget *widget)
This unconditionally sets the parent widget.
Definition PWidget.cpp:315
virtual bool AddSubWidget(PlatformWidget *widget)
bool SetPoint(int x, int y, PColor col)
SDL_Surface * mSurface
virtual void PrintSubWidgets(std::ostream &out) const
virtual std::ostream & SendToStream(std::ostream &out) const
An inheritable printing class used by PEBLObjectBase::operator<<.
virtual bool LockSurface()
This needs to be used on some platforms/video cards.
void SetParent(PlatformWidget *parent)
SDL_Texture * mTexture
SDL_Renderer * GetRenderer()
virtual bool Draw()
This method initiates everything needed to display the main window
virtual bool RemoveSubWidget(PlatformWidget *widget)
virtual bool RotoZoom(double angle, double zoomx, double zoomy, int smooth)
This uses the SDL_gfx package to 'rotozoom'.
virtual bool UnlockSurface()
This needs to be used on some platforms/video cards.
SDL_Renderer * mRenderer
virtual bool SetRenderer(SDL_Renderer *renderer)
PColor GetPixel(int x, int y)
virtual SDL_Texture * GetSDL_Texture()
Used to extract an SDL surface from the widget. Used by children drawing themselves on their parent.
virtual bool AddToParentWidget(PlatformWidget *parent)
virtual bool RemoveSubWidgets()
void SignalFatalError(const std::string &message)
void DrawPixel(SDL_Renderer *renderer, PlatformWidget *pwidget, int x, int y, PColor color)
This sets a pixel to be a certain color.
PColor GetPixelColor(SDL_Surface *surface, int x, int y)
This extracts the color of a pixel.
int count
Definition test.cpp:12