- did some C++ifying. let's try to follow suit :)
[supertux.git] / src / 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 "setup.h"
25 #include "screen/screen.h"
26 #include "screen/drawing_context.h"
27 #include "globals.h"
28 #include "button.h"
29 #include "camera.h"
30
31 Timer Button::popup_timer;
32
33 Button::Button(Surface* button_image, const std::string& ninfo,
34     SDLKey nshortcut, int x, int y, int mw, int mh)
35 {
36   popup_timer.init(false);
37
38   if(button_image)
39     icon.push_back(button_image);
40
41   info = ninfo;
42
43   shortcut = nshortcut;
44
45   rect.x = x;
46   rect.y = y;
47   rect.w = icon[0]->w;
48   rect.h = icon[0]->h;
49   tag = -1;
50   state = BUTTON_NONE;
51   show_info = false;
52 }
53
54 Button::Button(const std::string& imagefilename, const std::string& ninfo,
55     SDLKey nshortcut, int x, int y, int mw, int mh)
56 {
57   popup_timer.init(false);
58
59   add_icon(imagefilename, mw, mh);
60   
61   info = ninfo;
62
63   shortcut = nshortcut;
64
65   rect.x = x;
66   rect.y = y;
67   rect.w = icon[0]->w;
68   rect.h = icon[0]->h;
69   tag = -1;
70   state = BUTTON_NONE;
71   show_info = false;
72 }
73
74 void Button::add_icon(const std::string& icon_file, int mw, int mh)
75 {
76   char filename[1024];
77
78   if(!icon_file.empty())
79   {
80     snprintf(filename, 1024, "%s/%s", datadir.c_str(), icon_file.c_str());
81     if(!faccessible(filename))
82       snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
83   }
84   else
85   {
86     snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
87   }
88
89   if(mw != -1 || mh != -1)
90   {
91     icon.push_back(new Surface(filename,USE_ALPHA));
92     icon.back()->resize(mw,mh);
93   }
94   else
95     icon.push_back(new Surface(filename,USE_ALPHA));
96
97 }
98
99 void Button::draw(DrawingContext& context)
100 {
101   if(state == BUTTON_HOVER)
102     if(!popup_timer.check())
103       show_info = true;
104
105   fillrect(rect.x,rect.y,rect.w,rect.h,75,75,75,200);
106   fillrect(rect.x+1,rect.y+1,rect.w-2,rect.h-2,175,175,175,200);
107
108   for(std::vector<Surface*>::iterator it = icon.begin(); it != icon.end(); ++it)
109     context.draw_surface(*it, Vector(rect.x,rect.y), LAYER_GUI);
110
111 /*  if(drawable)
112   {
113     Camera viewport;
114     viewport.set_translation(Vector(rect.x, rect.y));
115     drawable->draw(viewport, 0);
116   }*/
117
118   if(show_info)
119   {
120     char str[80];
121     int i = -32;
122
123     if(0 > rect.x - white_small_text->get_text_width(info))
124       i = rect.w + (int)white_small_text->get_text_width(info);
125
126     if(!info.empty())
127       context.draw_text(white_small_text, info, Vector(i + rect.x - white_small_text->get_text_width(info), rect.y), LAYER_GUI);
128     sprintf(str,"(%s)", SDL_GetKeyName(shortcut));
129     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);
130   }
131   if(state == BUTTON_PRESSED || state == BUTTON_DEACTIVE)
132     fillrect(rect.x,rect.y,rect.w,rect.h,75,75,75,200);
133   else if(state == BUTTON_HOVER)
134     fillrect(rect.x,rect.y,rect.w,rect.h,150,150,150,128);
135 }
136
137 Button::~Button()
138 {
139   for(std::vector<Surface*>::iterator it = icon.begin(); it != icon.end(); ++it)
140     delete (*it);
141   icon.clear();
142   // FIXME TODO XXX: commenting this out fixes the leveleditor quit crash
143   //   probably should be deleted somehow, though
144   //delete drawable;
145 }
146
147 void Button::event(SDL_Event &event)
148 {
149   if(state == BUTTON_DEACTIVE)
150     return;
151
152   SDLKey key = event.key.keysym.sym;
153
154   if(event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP)
155   {
156     if(event.button.x < rect.x || event.button.x >= rect.x + rect.w ||
157         event.button.y < rect.y || event.button.y >= rect.y + rect.h)
158       return;
159
160     if(event.button.button == SDL_BUTTON_RIGHT)
161     {
162       show_info = true;
163       return;
164     }
165     else if(event.type == SDL_MOUSEBUTTONUP && event.button.button == 4) /* Mouse wheel up. */
166     {
167       state = BUTTON_WHEELUP;
168       return;
169     }
170     else if(event.type == SDL_MOUSEBUTTONUP && event.button.button == 5) /* Mouse wheel down. */
171     {
172       state = BUTTON_WHEELDOWN;
173       return;
174     }
175
176     if(event.button.button == SDL_BUTTON_LEFT)
177       if(event.type == SDL_MOUSEBUTTONDOWN)
178         state = BUTTON_PRESSED;
179       else
180         state = BUTTON_CLICKED;
181   }
182   else if(event.type == SDL_MOUSEMOTION)
183   {
184     if(event.motion.x < rect.x || event.motion.x >= rect.x + rect.w ||
185         event.motion.y < rect.y || event.motion.y >= rect.y + rect.h)
186     {
187       state = BUTTON_NONE;
188     }
189     else
190     {
191       state = BUTTON_HOVER;
192       popup_timer.start(1500);
193     }
194
195     if(show_info)
196     {
197       show_info = false;
198     }
199   }
200   else if(event.type == SDL_KEYDOWN)
201   {
202     if(key == shortcut)
203       state = BUTTON_PRESSED;
204   }
205   else if(event.type == SDL_KEYUP)
206   {
207     if(state == BUTTON_PRESSED && key == shortcut)
208       state = BUTTON_CLICKED;
209   }
210 }
211
212 int Button::get_state()
213 {
214   int rstate;
215   switch(state)
216   {
217   case BUTTON_CLICKED:
218   case BUTTON_WHEELUP:
219   case BUTTON_WHEELDOWN:
220     rstate = state;
221     state = BUTTON_NONE;
222     return rstate;
223   default:
224     return state;
225   }
226 }
227
228 ButtonPanel::ButtonPanel(int x, int y, int w, int h)
229 {
230   bw = 32;
231   bh = 32;
232   rect.x = x;
233   rect.y = y;
234   rect.w = w;
235   rect.h = h;
236   hidden = false;
237   hlast = false;
238 }
239
240 Button* ButtonPanel::event(SDL_Event& event)
241 {
242   if(!hidden)
243   {
244   Button* ret = NULL;
245     for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
246     {
247       (*it)->event(event);
248       if((*it)->state != BUTTON_NONE)
249       {
250         if(hlast && (*it)->state == BUTTON_CLICKED)
251           last_clicked = it;
252         ret = (*it);
253       }
254     }
255     return ret;
256   }
257   else
258   {
259     return NULL;
260   }
261 }
262
263 ButtonPanel::~ButtonPanel()
264 {
265   for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
266   {
267     delete (*it);
268   }
269   item.clear();
270 }
271
272 void ButtonPanel::draw(DrawingContext& context)
273 {
274
275   if(hidden == false)
276   {
277     fillrect(rect.x,rect.y,rect.w,rect.h,100,100,100,200);
278     for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
279     {
280       (*it)->draw(context);
281       if(hlast && it == last_clicked)
282       {
283         fillrect((*it)->get_pos().x,(*it)->get_pos().y,(*it)->get_pos().w,(*it)->get_pos().h,100,100,100,128);
284       }
285     }
286   }
287 }
288
289 void ButtonPanel::additem(Button* pbutton, int tag)
290 {
291   int max_cols, row, col;
292
293   item.push_back(pbutton);
294
295   /* A button_panel takes control of the buttons it contains and arranges them */
296
297   max_cols = rect.w / bw;
298
299   row = (item.size()-1) / max_cols;
300   col = (item.size()-1) % max_cols;
301
302   item[item.size()-1]->rect.x = rect.x + col * bw;
303   item[item.size()-1]->rect.y = rect.y + row * bh;
304   item[item.size()-1]->tag = tag;
305
306 }
307
308 void ButtonPanel::set_button_size(int w, int h)
309 {
310   bw = w;
311   bh = h;
312 }
313
314 Button* ButtonPanel::manipulate_button(int i)
315 {
316   if(int(item.size())-1 < i)
317     return item[item.size()-1];
318   else
319     return item[i];
320 }
321
322 void ButtonPanel::highlight_last(bool b)
323 {
324   hlast = b;
325 }