4 // Graphical User Interface base class
7 // JLH = James L. Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 02/02/2006 Created this file
12 // JLH 02/13/2006 Added backbuffer and rendering functions
13 // JLH 03/02/2006 Moved backbuffer destruction to destructor, added parent
18 #include "guimisc.h" // Various support functions
20 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
21 #define MASK_R 0xFF000000
22 #define MASK_G 0x00FF0000
23 #define MASK_B 0x0000FF00
24 #define MASK_A 0x000000FF
26 #define MASK_R 0x000000FF
27 #define MASK_G 0x0000FF00
28 #define MASK_B 0x00FF0000
29 #define MASK_A 0xFF000000
32 //#define DEBUG_ELEMENT
38 // Initialize class variables
40 SDL_Surface * Element::screen = NULL;
41 bool Element::needToRefreshScreen = false;
43 Element::Element(uint32_t x/*= 0*/, uint32_t y/*= 0*/, uint32_t w/*= 0*/, uint32_t h/*= 0*/,
44 Element * parentElement/*= NULL*/): parent(parentElement), backstore(NULL), visible(true)
50 coverList.push_back(extents);
53 Element::Element(uint32_t x, uint32_t y, uint32_t w, uint32_t h,
54 uint8_t fgR/*= 0xFF*/, uint8_t fgG/*= 0xFF*/, uint8_t fgB/*= 0xFF*/, uint8_t fgA/*= 0xFF*/,
55 uint8_t bgR/*= 0x00*/, uint8_t bgG/*= 0x00*/, uint8_t bgB/*= 0x00*/, uint8_t bgA/*= 0xFF*/,
56 Element * parentElement/*= NULL*/): parent(parentElement), backstore(NULL), visible(true)
62 coverList.push_back(extents);
65 // This *should* allow us to store our colors in an endian safe way... :-/
66 uint8_t * c = (uint8_t *)&fgColor;
67 c[0] = fgR, c[1] = fgG, c[2] = fgB, c[3] = fgA;
68 c = (uint8_t *)&bgColor;
69 c[0] = bgR, c[1] = bgG, c[2] = bgB, c[3] = bgA;
71 fgColor = SDL_MapRGBA(screen->format, fgR, fgG, fgB, fgA);
72 bgColor = SDL_MapRGBA(screen->format, bgR, bgG, bgB, bgA);
80 RestoreScreenFromBackstore();
81 SDL_FreeSurface(backstore);
82 needToRefreshScreen = true;
86 bool Element::Inside(uint32_t x, uint32_t y)
88 return (x >= (uint32_t)extents.x && x < (uint32_t)(extents.x + extents.w)
89 && y >= (uint32_t)extents.y && y < (uint32_t)(extents.y + extents.h) ? true : false);
92 //Badly named--!!! FIX !!! [DONE]
93 //SDL_Rect Element::GetParentCorner(void)
94 SDL_Rect Element::GetScreenCoords(void)
97 rect.x = extents.x, rect.y = extents.y;
99 // First, traverse the parent tree to get the absolute screen address...
101 Element * currentParent = parent;
103 while (currentParent)
105 rect.x += currentParent->extents.x;
106 rect.y += currentParent->extents.y;
107 currentParent = currentParent->parent;
114 //May use this in the future...
115 SDL_Rect Element::GetParentRect(void)
117 // If there is no parent, then return the entire screen as the parent's
121 rect.x = 0, rect.y = 0, rect.w = screen->w, rect.h = screen->h;
125 rect.x = parent->extents.x;
126 rect.y = parent->extents.y;
127 rect.w = parent->extents.w;
128 rect.h = parent->extents.h;
135 SDL_Rect Element::GetExtents(void)
141 #include "settings.h"
142 void Element::CreateBackstore(void)
144 backstore = SDL_CreateRGBSurface(SDL_SWSURFACE, extents.w, extents.h, 32,
145 MASK_R, MASK_G, MASK_B, 0x00);
148 printf("Element: About to do SDL_BlitSurface...\n");
151 if (settings.useOpenGL)
154 //Since screen is the main screen surface, OpenGL doesn't like it being touched.
156 SDL_BlitSurface(screen, &extents, backstore, NULL);
158 printf("Element: SDL_BlitSurface...Done.\n");
162 void Element::RestoreScreenFromBackstore(void)
168 SDL_BlitSurface(backstore, NULL, screen, &r);
171 void Element::SaveScreenToBackstore(void)
173 SDL_BlitSurface(screen, &extents, backstore, NULL);
176 void Element::ResetCoverageList(void)
178 // Setup our coverage list with the entire window area
180 coverList.push_back(extents);
183 void Element::AdjustCoverageList(SDL_Rect r)
185 //Prolly should have a bool here to set whether or not to do this crap, since it
186 //takes a little time...
188 // Here's where we do the coverage list voodoo... :-)
192 o Check for intersection. If no intersection, then no need to divide rects.
193 o Loop through current rects. If rect is completely inside passed in rect, remove from list.
194 o Loop through remaining rects. If rect intersects, decompose to four rects and
195 exclude degenerate rects, push rest into the coverage list.
198 // std::list<Element *>::reverse_iterator ri;
199 // std::list<SDL_Rect>::iterator i;
201 // Loop through rects and remove those completely covered by passed in rect.
202 /* for(i=coverList.begin(); i!=coverList.end(); i++)
204 // if (RectanglesIntersect(r, *i))
205 if (RectangleFirstInsideSecond(*i, r))
207 //This is not right--do a while loop instead of a for loop?
208 // Remove it from the list...
209 std::list<SDL_Rect>::iterator next = coverList.erase(i);
213 // Loop through rects and remove those completely covered by passed in rect.
214 std::list<SDL_Rect>::iterator i = coverList.begin();
216 while (i != coverList.end())
218 if (RectangleFirstInsideSecond(*i, r))
219 i = coverList.erase(i); // This will also advance i to the next item!
224 //This may not be needed if nothing follows the loop below...!
225 // if (coverList.empty())
228 // Check for intersection. If no intersection, then no need to divide rects.
229 i = coverList.begin();
231 while (i != coverList.end())
233 if (RectanglesIntersect(r, *i))
235 // Do the decomposition here. There will always be at least *one* rectangle
236 // generated by this algorithm, so we know we're OK in removing the original
237 // from the list. The general pattern looks like this:
242 // |2|//|3| <- Rectangle "r" is in the center
247 // Even if r extends beyond the bounds of the rectangle under consideration,
248 // that's OK because we test to see that the rectangle isn't degenerate
249 // before adding it to the list.
251 //Should probably use a separate list here and splice it in when we're done here...
252 //Or, could use push_front() to avoid the problem... Neat! Doesn't require a separate list!
253 //But, we need to remove the currently referenced rect... Another while loop!
255 //This approach won't work--if no rect1 then we're screwed! [FIXED]
256 //Now *that* will work...
257 SDL_Rect current = *i;
258 uint32_t bottomOfRect1 = current.y;
259 // uint32_t rightOfRect2 = current.x;
260 // uint32_t leftOfRect3 = current.x + current.w;
261 uint32_t topOfRect4 = current.y + current.h;
263 // Rectangle #1 (top)
264 if (r.y > current.y) // Simple rectangle degeneracy test...
267 SDL_Rect rect = current;
268 rect.h = r.y - current.y;
269 coverList.push_front(rect);
272 // Rectangle #4 (bottom)
273 if (r.y + r.h < current.y + current.h)
275 topOfRect4 = r.y + r.h;
276 SDL_Rect rect = current;
278 rect.h = (current.y + current.h) - (r.y + r.h);
279 coverList.push_front(rect);
282 // Rectangle #2 (left side)
285 SDL_Rect rect = current;
286 rect.w = r.x - current.x;
287 rect.y = bottomOfRect1;
288 rect.h = topOfRect4 - bottomOfRect1;
289 coverList.push_front(rect);
292 // Rectangle #3 (right side)
293 if (r.x + r.w < current.x + current.w)
297 rect.w = (current.x + current.w) - (r.x + r.w);
298 rect.y = bottomOfRect1;
299 rect.h = topOfRect4 - bottomOfRect1;
300 coverList.push_front(rect);
303 i = coverList.erase(i); // This will also advance i to the next item!
310 void Element::SetVisible(bool visibility)
312 visible = visibility;
319 void Element::SetScreen(SDL_Surface * s)
324 bool Element::ScreenNeedsRefreshing(void)
326 return needToRefreshScreen;
329 void Element::ScreenWasRefreshed(void)
331 needToRefreshScreen = false;