Had to change the #includes of dependend headers from "dir/header.h" to "../dir...
[supertux.git] / lib / gui / button.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 //  02111-1307, USA.
20
21 #include <cstring>
22 #include <cstdlib>
23
24 #include "../app/setup.h"
25 #include "../video/screen.h"
26 #include "../video/drawing_context.h"
27 #include "../app/globals.h"
28 #include "../gui/button.h"
29
30 using namespace SuperTux;
31
32 Timer Button::popup_timer;
33
34 Button::Button(Surface* button_image, const std::string& ninfo,
35                SDLKey nshortcut, int x, int y, int mw, int mh)
36 {
37   popup_timer.init(false);
38
39   if(button_image)
40     icon.push_back(button_image);
41
42   info = ninfo;
43
44   shortcut = nshortcut;
45
46   rect.x = x;
47   rect.y = y;
48   rect.w = icon[0]->w;
49   rect.h = icon[0]->h;
50   tag = -1;
51   state = BUTTON_NONE;
52   show_info = false;
53 }
54
55 Button::Button(const std::string& imagefilename, const std::string& ninfo,
56                SDLKey nshortcut, int x, int y, int mw, int mh)
57 {
58   popup_timer.init(false);
59
60   add_icon(imagefilename, mw, mh);
61
62   info = ninfo;
63
64   shortcut = nshortcut;
65
66   rect.x = x;
67   rect.y = y;
68   rect.w = icon[0]->w;
69   rect.h = icon[0]->h;
70   tag = -1;
71   state = BUTTON_NONE;
72   show_info = false;
73 }
74
75 void Button::add_icon(const std::string& icon_file, int mw, int mh)
76 {
77   char filename[1024];
78
79   if(!icon_file.empty())
80     {
81       snprintf(filename, 1024, "%s/%s", datadir.c_str(), icon_file.c_str());
82       if(!faccessible(filename))
83         snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
84     }
85   else
86     {
87       snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
88     }
89
90   if(mw != -1 || mh != -1)
91     {
92       icon.push_back(new Surface(filename,true));
93       icon.back()->resize(mw,mh);
94     }
95   else
96     icon.push_back(new Surface(filename,true));
97
98 }
99
100 void Button::draw(DrawingContext& context)
101 {
102   if(state == BUTTON_HOVER)
103     if(!popup_timer.check())
104       show_info = true;
105
106   fillrect(rect.x,rect.y,rect.w,rect.h,75,75,75,200);
107   fillrect(rect.x+1,rect.y+1,rect.w-2,rect.h-2,175,175,175,200);
108
109   for(std::vector<Surface*>::iterator it = icon.begin(); it != icon.end(); ++it)
110     context.draw_surface(*it, Vector(rect.x,rect.y), LAYER_GUI);
111
112   /*  if(drawable)
113     {
114       Camera viewport;
115       viewport.set_translation(Vector(rect.x, rect.y));
116       drawable->draw(viewport, 0);
117     }*/
118
119   if(show_info)
120     {
121       char str[80];
122       int i = -32;
123
124       if(0 > rect.x - white_small_text->get_text_width(info))
125         i = rect.w + (int)white_small_text->get_text_width(info);
126
127       if(!info.empty())
128         context.draw_text(white_small_text, info, Vector(i + rect.x - white_small_text->get_text_width(info), rect.y), LAYER_GUI);
129       sprintf(str,"(%s)", SDL_GetKeyName(shortcut));
130       context.draw_text(white_small_text, str, Vector(i + rect.x -  white_small_text->get_text_width(str), rect.y + white_small_text->get_height()+2), LAYER_GUI);
131     }
132   if(state == BUTTON_PRESSED || state == BUTTON_DEACTIVE)
133     fillrect(rect.x,rect.y,rect.w,rect.h,75,75,75,200);
134   else if(state == BUTTON_HOVER)
135     fillrect(rect.x,rect.y,rect.w,rect.h,150,150,150,128);
136 }
137
138 Button::~Button()
139 {
140   for(std::vector<Surface*>::iterator it = icon.begin(); it != icon.end(); ++it)
141     delete (*it);
142   icon.clear();
143   // FIXME TODO XXX: commenting this out fixes the leveleditor quit crash
144   //   probably should be deleted somehow, though
145   //delete drawable;
146 }
147
148 void Button::event(SDL_Event &event)
149 {
150   if(state == BUTTON_DEACTIVE)
151     return;
152
153   SDLKey key = event.key.keysym.sym;
154
155   if(event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP)
156     {
157       if(event.button.x < rect.x || event.button.x >= rect.x + rect.w ||
158           event.button.y < rect.y || event.button.y >= rect.y + rect.h)
159         return;
160
161       if(event.button.button == SDL_BUTTON_RIGHT)
162         {
163           show_info = true;
164           return;
165         }
166       else if(event.type == SDL_MOUSEBUTTONUP && event.button.button == 4) /* Mouse wheel up. */
167         {
168           state = BUTTON_WHEELUP;
169           return;
170         }
171       else if(event.type == SDL_MOUSEBUTTONUP && event.button.button == 5) /* Mouse wheel down. */
172         {
173           state = BUTTON_WHEELDOWN;
174           return;
175         }
176
177       if(event.button.button == SDL_BUTTON_LEFT)
178         if(event.type == SDL_MOUSEBUTTONDOWN)
179           state = BUTTON_PRESSED;
180         else
181           state = BUTTON_CLICKED;
182     }
183   else if(event.type == SDL_MOUSEMOTION)
184     {
185       if(event.motion.x < rect.x || event.motion.x >= rect.x + rect.w ||
186           event.motion.y < rect.y || event.motion.y >= rect.y + rect.h)
187         {
188           state = BUTTON_NONE;
189         }
190       else
191         {
192           state = BUTTON_HOVER;
193           popup_timer.start(1500);
194         }
195
196       if(show_info)
197         {
198           show_info = false;
199         }
200     }
201   else if(event.type == SDL_KEYDOWN)
202     {
203       if(key == shortcut)
204         state = BUTTON_PRESSED;
205     }
206   else if(event.type == SDL_KEYUP)
207     {
208       if(state == BUTTON_PRESSED && key == shortcut)
209         state = BUTTON_CLICKED;
210     }
211 }
212
213 int Button::get_state()
214 {
215   int rstate;
216   switch(state)
217     {
218     case BUTTON_CLICKED:
219     case BUTTON_WHEELUP:
220     case BUTTON_WHEELDOWN:
221       rstate = state;
222       state = BUTTON_NONE;
223       return rstate;
224     default:
225       return state;
226     }
227 }
228
229 ButtonPanel::ButtonPanel(const SDL_Rect& rect)
230 {
231   ButtonPanel(rect.x, rect.y, rect.w, rect.h);
232 }
233
234 ButtonPanel::ButtonPanel(int x, int y, int w, int h)
235 {
236   bw = 32;
237   bh = 32;
238   rect.x = x;
239   rect.y = y;
240   rect.w = w;
241   rect.h = h;
242   hidden = false;
243   hlast = false;
244 }
245
246 Button* ButtonPanel::event(SDL_Event& event)
247 {
248   if(!hidden)
249     {
250       Button* ret = NULL;
251       for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
252         {
253           (*it)->event(event);
254           if((*it)->state != BUTTON_NONE)
255             {
256               if(hlast && (*it)->state == BUTTON_CLICKED)
257                 last_clicked = it;
258               ret = (*it);
259             }
260         }
261       return ret;
262     }
263   else
264     {
265       return NULL;
266     }
267 }
268
269 ButtonPanel::~ButtonPanel()
270 {
271   for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
272     {
273       delete (*it);
274     }
275   item.clear();
276 }
277
278 void ButtonPanel::draw(DrawingContext& context)
279 {
280
281   if(hidden == false)
282     {
283       fillrect(rect.x,rect.y,rect.w,rect.h,100,100,100,200);
284       for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
285         {
286           (*it)->draw(context);
287           if(hlast && it == last_clicked)
288             {
289               fillrect((*it)->get_pos().x,(*it)->get_pos().y,(*it)->get_pos().w,(*it)->get_pos().h,100,100,100,128);
290             }
291         }
292     }
293 }
294
295 void ButtonPanel::additem(Button* pbutton, int tag)
296 {
297   int max_cols, row, col;
298
299   item.push_back(pbutton);
300
301   /* A button_panel takes control of the buttons it contains and arranges them */
302
303   max_cols = rect.w / bw;
304
305   row = (item.size()-1) / max_cols;
306   col = (item.size()-1) % max_cols;
307
308   item[item.size()-1]->rect.x = rect.x + col * bw;
309   item[item.size()-1]->rect.y = rect.y + row * bh;
310   item[item.size()-1]->tag = tag;
311
312 }
313
314 void ButtonPanel::set_button_size(int w, int h)
315 {
316   bw = w;
317   bh = h;
318 }
319
320 Button* ButtonPanel::manipulate_button(int i)
321 {
322   if(int(item.size())-1 < i)
323     return item[item.size()-1];
324   else
325     return item[i];
326 }
327
328 void ButtonPanel::highlight_last(bool b)
329 {
330   hlast = b;
331 }
332
333 void ButtonPanel::set_last_clicked(unsigned int last)
334 {
335   if(hlast)
336     {
337       if(item.size() >= last)
338         {
339           last_clicked = item.begin() + last;
340         }
341     }
342 }