4 // Graphical User Interface button class
7 // JLH = James L. Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 02/02/2006 Created this file
15 #include "guimisc.h" // Various support functions
17 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
18 #define MASK_R 0xFF000000
19 #define MASK_G 0x00FF0000
20 #define MASK_B 0x0000FF00
21 #define MASK_A 0x000000FF
23 #define MASK_R 0x000000FF
24 #define MASK_G 0x0000FF00
25 #define MASK_B 0x00FF0000
26 #define MASK_A 0xFF000000
30 //#define DEBUG_GUI_BUTTON
31 #ifdef DEBUG_GUI_BUTTON
36 // Button class implementation
40 Some notes about this class:
42 - Button colors are hardwired (for plain text buttons)
45 Button::Button(uint32_t x/*= 0*/, uint32_t y/*= 0*/, uint32_t w/*= 0*/, uint32_t h/*= 0*/,
46 Element * parent/*= NULL*/):
47 Element(x, y, w, h, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, parent),
48 activated(false), clicked(false), inside(false),
49 buttonUp(NULL), buttonDown(NULL), buttonHover(NULL), surfacesAreLocal(false),
50 activatedSave(false), clickedSave(false), insideSave(false)
52 // Should we make a local button bitmap here?
55 Button::Button(uint32_t x, uint32_t y, uint32_t w, uint32_t h, SDL_Surface * upImg, Element * parent/*= NULL*/):
56 Element(x, y, w, h, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, parent),
57 activated(false), clicked(false), inside(false),
58 buttonUp(upImg), buttonDown(NULL), buttonHover(NULL), surfacesAreLocal(false),
59 activatedSave(false), clickedSave(false), insideSave(false)
64 // uint32_t width = ((Bitmap *)upImg)->width, height = ((Bitmap *)upImg)->height;
66 // buttonUp = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
67 // 32, MASK_R, MASK_G, MASK_B, MASK_A);
68 // memcpy(buttonUp->pixels, ((Bitmap *)upImg)->pixelData, width * height * 4);
70 // Should we make a local button bitmap here? NO--it's passed in!
73 Button::Button(uint32_t x, uint32_t y, SDL_Surface * bU, SDL_Surface * bH/*= NULL*/,
74 SDL_Surface * bD/*= NULL*/, Element * parent/*= NULL*/):
75 Element(x, y, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, parent),
76 activated(false), clicked(false), inside(false),
77 buttonUp(bU), buttonDown(bD), buttonHover(bH), surfacesAreLocal(false),
78 activatedSave(false), clickedSave(false), insideSave(false)
81 extents.w = buttonUp->w,
82 extents.h = buttonUp->h;
85 Button::Button(uint32_t x, uint32_t y, uint32_t w, uint32_t h, std::string s, Element * parent/*= NULL*/):
86 Element(x, y, w, h, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, parent),
87 activated(false), clicked(false), inside(false),
88 buttonUp(NULL), buttonDown(NULL), buttonHover(NULL), surfacesAreLocal(true),
89 activatedSave(false), clickedSave(false), insideSave(false)
91 // Create the button surfaces here...
94 Button::Button(uint32_t x, uint32_t y, std::string s, Element * parent/*= NULL*/):
95 Element(x, y, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xCF, 0x00, 0xFF, parent),
96 activated(false), clicked(false), inside(false),
97 buttonUp(NULL), buttonDown(NULL), buttonHover(NULL), surfacesAreLocal(true),
98 activatedSave(false), clickedSave(false), insideSave(false)
100 extents.w = (s.length() + 2) * GetFontWidth();
101 extents.h = GetFontHeight();
103 // Create the button surfaces here...
105 buttonUp = SDL_CreateRGBSurface(SDL_SWSURFACE, extents.w, extents.h, 32,
106 MASK_R, MASK_G, MASK_B, MASK_A);
107 buttonDown = SDL_CreateRGBSurface(SDL_SWSURFACE, extents.w, extents.h, 32,
108 MASK_R, MASK_G, MASK_B, MASK_A);
109 buttonHover = SDL_CreateRGBSurface(SDL_SWSURFACE, extents.w, extents.h, 32,
110 MASK_R, MASK_G, MASK_B, MASK_A);
113 uint8_t r1, g1, b1, a1;
114 SDL_GetRGBA(fgColor, screen->format, &r1, &g1, &b1, &a1);
115 fgColor = SDL_MapRGBA(buttonUp->format, r1, g1, b1, a1);
116 SDL_GetRGBA(bgColor, screen->format, &r1, &g1, &b1, &a1);
117 bgColor = SDL_MapRGBA(buttonUp->format, r1, g1, b1, a1);
118 fgColorHL = SDL_MapRGBA(buttonUp->format, 0xFF, 0xFF, 0xFF, 0xFF);
119 bgColorHL = SDL_MapRGBA(buttonUp->format, 0x4F, 0xFF, 0x4F, 0xFF);
122 // Need to create backgrounds before we do this stuff...
123 SDL_FillRect(buttonUp, NULL, bgColor);
124 SDL_FillRect(buttonDown, NULL, fgColor);
125 SDL_FillRect(buttonHover, NULL, bgColorHL);
127 DrawStringTrans(buttonUp, GetFontWidth(), 0, fgColor, s.c_str());
128 DrawStringTrans(buttonDown, GetFontWidth(), 0, fgColor, s.c_str());
129 DrawStringTrans(buttonHover, GetFontWidth(), 0, fgColorHL, s.c_str());
131 #ifdef DEBUG_GUI_BUTTON
132 WriteLog("Button::Button()...\n");
133 WriteLog("\tbuttonUp w/h = %u/%u\n", buttonUp->w, buttonUp->h);
134 WriteLog("\tbuttonDown w/h = %u/%u\n", buttonDown->w, buttonDown->h);
135 WriteLog("\tbuttonHover w/h = %u/%u\n", buttonHover->w, buttonHover->h);
141 if (surfacesAreLocal)
144 SDL_FreeSurface(buttonUp);
147 SDL_FreeSurface(buttonDown);
150 SDL_FreeSurface(buttonHover);
154 void Button::HandleKey(SDL_Scancode key)
158 void Button::HandleMouseMove(uint32_t x, uint32_t y)
163 SaveStateVariables();
164 inside = Inside(x, y);
165 CheckStateAndRedrawIfNeeded();
168 void Button::HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown)
173 SaveStateVariables();
180 if (clicked && !mouseDown)
182 clicked = false, activated = true;
184 // Send a message to our parent widget (if any) that we're activated
186 parent->Notify(this);
190 clicked = activated = false;
192 CheckStateAndRedrawIfNeeded();
195 void Button::Draw(void)
197 #ifdef DEBUG_GUI_BUTTON
198 WriteLog("Button::Draw()...\n");
203 if (buttonUp == NULL)
204 return; // Bail out if no surface was created...
206 // Now, draw the appropriate button state!
208 SDL_Surface * picToShow = buttonUp;
210 if (buttonHover != NULL && inside && !clicked)
211 picToShow = buttonHover;
213 if (buttonDown != NULL && inside && clicked)
214 picToShow = buttonDown;
216 SDL_Rect rect = GetScreenCoords();
217 #ifdef DEBUG_GUI_BUTTON
218 WriteLog(" coords: x=%u, y=%u\n", rect.x, rect.y);
219 WriteLog(" picToShow=%08X\n", picToShow);
222 //Need to do coverage list blitting here, to avoid unnecessary drawing when doing mouseovers
223 //Also, need to add suport in Gui()...
224 SDL_BlitSurface(picToShow, NULL, screen, &rect); // This handles alpha blending too! :-D
225 #ifdef DEBUG_GUI_BUTTON
226 WriteLog(" width: w=%u, h=%u\n", rect.w, rect.h);
229 needToRefreshScreen = true;
231 #ifdef DEBUG_GUI_BUTTON
232 // SDL_FillRect(screen, &extents, fgColor);
236 void Button::Notify(Element *)
240 bool Button::ButtonClicked(void)
245 void Button::SaveStateVariables(void)
247 activatedSave = activated;
248 clickedSave = clicked;
252 void Button::CheckStateAndRedrawIfNeeded(void)
254 // Check to see if any of our state variables changed since we last saved them...
255 if (activated != activatedSave || clicked != clickedSave || inside != insideSave)
259 void Button::SetText(std::string s)
261 // Need to create backgrounds before we do this stuff...
262 SDL_FillRect(buttonUp, NULL, bgColor);
263 SDL_FillRect(buttonDown, NULL, fgColor);
264 SDL_FillRect(buttonHover, NULL, bgColorHL);
266 DrawStringTrans(buttonUp, GetFontWidth(), 0, fgColor, s.c_str());
267 DrawStringTrans(buttonDown, GetFontWidth(), 0, fgColor, s.c_str());
268 DrawStringTrans(buttonHover, GetFontWidth(), 0, fgColorHL, s.c_str());