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