rev |
line source |
nuclear@6
|
1 /*
|
nuclear@6
|
2 GoatKit - a themable/animated widget toolkit for games
|
nuclear@6
|
3 Copyright (C) 2014 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@6
|
4
|
nuclear@6
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@6
|
6 it under the terms of the GNU Lesser General Public License as published by
|
nuclear@6
|
7 the Free Software Foundation, either version 3 of the License, or
|
nuclear@6
|
8 (at your option) any later version.
|
nuclear@6
|
9
|
nuclear@6
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@6
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@6
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@6
|
13 GNU Lesser General Public License for more details.
|
nuclear@6
|
14
|
nuclear@6
|
15 You should have received a copy of the GNU Lesser General Public License
|
nuclear@6
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@6
|
17 */
|
nuclear@6
|
18 #include <stdio.h>
|
nuclear@6
|
19 #include <string.h>
|
nuclear@6
|
20 #include <math.h>
|
nuclear@6
|
21 #include <string>
|
nuclear@6
|
22 #include <sstream>
|
nuclear@6
|
23 #include "widget.h"
|
nuclear@6
|
24 #include "boolanm.h"
|
nuclear@6
|
25 #include "theme.h"
|
nuclear@6
|
26 #include "screen.h"
|
nuclear@6
|
27
|
nuclear@6
|
28 namespace goatkit {
|
nuclear@6
|
29
|
nuclear@6
|
30 struct WidgetImpl {
|
nuclear@6
|
31 Screen *scr;
|
nuclear@6
|
32 std::string name, text;
|
nuclear@6
|
33 BBox box;
|
nuclear@6
|
34
|
nuclear@6
|
35 BoolAnim visible, active, press, hover, focus;
|
nuclear@6
|
36
|
nuclear@6
|
37 struct {
|
nuclear@6
|
38 EventCallback func;
|
nuclear@6
|
39 void *cls;
|
nuclear@6
|
40 } cb[NUM_EVENTS];
|
nuclear@6
|
41 };
|
nuclear@6
|
42
|
nuclear@6
|
43
|
nuclear@6
|
44 Widget::Widget()
|
nuclear@6
|
45 {
|
nuclear@6
|
46 static int widget_count;
|
nuclear@6
|
47
|
nuclear@6
|
48 widget = new WidgetImpl;
|
nuclear@6
|
49 widget->scr = 0;
|
nuclear@6
|
50
|
nuclear@6
|
51 std::stringstream sstr;
|
nuclear@6
|
52 sstr << get_type_name() << widget_count++;
|
nuclear@6
|
53 widget->name = sstr.str();
|
nuclear@6
|
54
|
nuclear@6
|
55 widget->box.bmin = Vec2(0, 0);
|
nuclear@6
|
56 widget->box.bmax = Vec2(1, 1);
|
nuclear@6
|
57
|
nuclear@6
|
58 widget->visible.set(true);
|
nuclear@6
|
59 widget->active.set(true);
|
nuclear@6
|
60
|
nuclear@6
|
61 widget->hover.set_transition_duration(250);
|
nuclear@6
|
62 widget->press.set_transition_duration(50);
|
nuclear@6
|
63
|
nuclear@6
|
64 memset(widget->cb, 0, sizeof widget->cb);
|
nuclear@6
|
65 }
|
nuclear@6
|
66
|
nuclear@6
|
67 Widget::~Widget()
|
nuclear@6
|
68 {
|
nuclear@6
|
69 delete widget;
|
nuclear@6
|
70 }
|
nuclear@6
|
71
|
nuclear@6
|
72 void Widget::set_screen(Screen *scr)
|
nuclear@6
|
73 {
|
nuclear@6
|
74 widget->scr = scr;
|
nuclear@6
|
75 }
|
nuclear@6
|
76
|
nuclear@6
|
77 Screen *Widget::get_screen() const
|
nuclear@6
|
78 {
|
nuclear@6
|
79 return widget->scr;
|
nuclear@6
|
80 }
|
nuclear@6
|
81
|
nuclear@6
|
82 const char *Widget::get_type_name() const
|
nuclear@6
|
83 {
|
nuclear@6
|
84 return "widget";
|
nuclear@6
|
85 }
|
nuclear@6
|
86
|
nuclear@6
|
87 void Widget::set_name(const char *name)
|
nuclear@6
|
88 {
|
nuclear@6
|
89 widget->name = std::string(name);
|
nuclear@6
|
90 }
|
nuclear@6
|
91
|
nuclear@6
|
92 const char *Widget::get_name() const
|
nuclear@6
|
93 {
|
nuclear@6
|
94 return widget->name.c_str();
|
nuclear@6
|
95 }
|
nuclear@6
|
96
|
nuclear@6
|
97 void Widget::set_text(const char *text)
|
nuclear@6
|
98 {
|
nuclear@6
|
99 widget->text = std::string(text);
|
nuclear@6
|
100 }
|
nuclear@6
|
101
|
nuclear@6
|
102 const char *Widget::get_text() const
|
nuclear@6
|
103 {
|
nuclear@6
|
104 return widget->text.c_str();
|
nuclear@6
|
105 }
|
nuclear@6
|
106
|
nuclear@6
|
107 void Widget::show()
|
nuclear@6
|
108 {
|
nuclear@6
|
109 widget->visible.change(true);
|
nuclear@6
|
110 }
|
nuclear@6
|
111
|
nuclear@6
|
112 void Widget::hide()
|
nuclear@6
|
113 {
|
nuclear@6
|
114 widget->visible.change(false);
|
nuclear@6
|
115 }
|
nuclear@6
|
116
|
nuclear@6
|
117 float Widget::get_visibility() const
|
nuclear@6
|
118 {
|
nuclear@6
|
119 return widget->visible.get_value();
|
nuclear@6
|
120 }
|
nuclear@6
|
121
|
nuclear@6
|
122 bool Widget::is_visible() const
|
nuclear@6
|
123 {
|
nuclear@6
|
124 return widget->visible.get_state();
|
nuclear@6
|
125 }
|
nuclear@6
|
126
|
nuclear@6
|
127 void Widget::activate()
|
nuclear@6
|
128 {
|
nuclear@6
|
129 widget->active.change(true);
|
nuclear@6
|
130 }
|
nuclear@6
|
131
|
nuclear@6
|
132 void Widget::deactivate()
|
nuclear@6
|
133 {
|
nuclear@6
|
134 widget->active.change(false);
|
nuclear@6
|
135 }
|
nuclear@6
|
136
|
nuclear@6
|
137 float Widget::get_active() const
|
nuclear@6
|
138 {
|
nuclear@6
|
139 return widget->active.get_value();
|
nuclear@6
|
140 }
|
nuclear@6
|
141
|
nuclear@6
|
142 bool Widget::is_active() const
|
nuclear@6
|
143 {
|
nuclear@6
|
144 return widget->active.get_state();
|
nuclear@6
|
145 }
|
nuclear@6
|
146
|
nuclear@6
|
147 void Widget::press()
|
nuclear@6
|
148 {
|
nuclear@6
|
149 widget->press.change(true);
|
nuclear@6
|
150 }
|
nuclear@6
|
151
|
nuclear@6
|
152 void Widget::release()
|
nuclear@6
|
153 {
|
nuclear@6
|
154 widget->press.change(false);
|
nuclear@6
|
155 }
|
nuclear@6
|
156
|
nuclear@6
|
157 float Widget::get_pressed() const
|
nuclear@6
|
158 {
|
nuclear@6
|
159 return widget->press.get_value();
|
nuclear@6
|
160 }
|
nuclear@6
|
161
|
nuclear@6
|
162 bool Widget::is_pressed() const
|
nuclear@6
|
163 {
|
nuclear@6
|
164 return widget->press.get_state();
|
nuclear@6
|
165 }
|
nuclear@6
|
166
|
nuclear@6
|
167 void Widget::mousein()
|
nuclear@6
|
168 {
|
nuclear@6
|
169 widget->hover.change(true);
|
nuclear@6
|
170 }
|
nuclear@6
|
171
|
nuclear@6
|
172 void Widget::mouseout()
|
nuclear@6
|
173 {
|
nuclear@6
|
174 widget->hover.change(false);
|
nuclear@6
|
175 if(widget->press) {
|
nuclear@6
|
176 widget->press.change(false);
|
nuclear@6
|
177 }
|
nuclear@6
|
178 }
|
nuclear@6
|
179
|
nuclear@6
|
180 float Widget::get_under_mouse() const
|
nuclear@6
|
181 {
|
nuclear@6
|
182 return widget->hover.get_value();
|
nuclear@6
|
183 }
|
nuclear@6
|
184
|
nuclear@6
|
185 bool Widget::is_under_mouse() const
|
nuclear@6
|
186 {
|
nuclear@6
|
187 return widget->hover.get_state();
|
nuclear@6
|
188 }
|
nuclear@6
|
189
|
nuclear@6
|
190 bool Widget::can_focus() const
|
nuclear@6
|
191 {
|
nuclear@6
|
192 return false;
|
nuclear@6
|
193 }
|
nuclear@6
|
194
|
nuclear@6
|
195 void Widget::focusin()
|
nuclear@6
|
196 {
|
nuclear@6
|
197 widget->focus.change(true);
|
nuclear@6
|
198 }
|
nuclear@6
|
199
|
nuclear@6
|
200 void Widget::focusout()
|
nuclear@6
|
201 {
|
nuclear@6
|
202 widget->focus.change(false);
|
nuclear@6
|
203 }
|
nuclear@6
|
204
|
nuclear@6
|
205 float Widget::get_focus() const
|
nuclear@6
|
206 {
|
nuclear@6
|
207 return widget->focus.get_value();
|
nuclear@6
|
208 }
|
nuclear@6
|
209
|
nuclear@6
|
210 bool Widget::is_focused() const
|
nuclear@6
|
211 {
|
nuclear@6
|
212 return widget->focus.get_state();
|
nuclear@6
|
213 }
|
nuclear@6
|
214
|
nuclear@6
|
215 void Widget::set_position(float x, float y)
|
nuclear@6
|
216 {
|
nuclear@6
|
217 set_position(Vec2(x, y));
|
nuclear@6
|
218 }
|
nuclear@6
|
219
|
nuclear@6
|
220 void Widget::set_position(const Vec2 &pos)
|
nuclear@6
|
221 {
|
nuclear@6
|
222 Vec2 sz = get_size();
|
nuclear@6
|
223
|
nuclear@6
|
224 widget->box.bmin = pos;
|
nuclear@6
|
225 widget->box.bmax.x = pos.x + sz.x;
|
nuclear@6
|
226 widget->box.bmax.y = pos.y + sz.y;
|
nuclear@6
|
227 }
|
nuclear@6
|
228
|
nuclear@6
|
229 const Vec2 &Widget::get_position() const
|
nuclear@6
|
230 {
|
nuclear@6
|
231 return widget->box.bmin;
|
nuclear@6
|
232 }
|
nuclear@6
|
233
|
nuclear@6
|
234 void Widget::set_size(float x, float y)
|
nuclear@6
|
235 {
|
nuclear@6
|
236 set_size(Vec2(x, y));
|
nuclear@6
|
237 }
|
nuclear@6
|
238
|
nuclear@6
|
239 void Widget::set_size(const Vec2 &sz)
|
nuclear@6
|
240 {
|
nuclear@6
|
241 widget->box.bmax.x = widget->box.bmin.x + sz.x;
|
nuclear@6
|
242 widget->box.bmax.y = widget->box.bmin.y + sz.y;
|
nuclear@6
|
243 }
|
nuclear@6
|
244
|
nuclear@6
|
245 const Vec2 Widget::get_size() const
|
nuclear@6
|
246 {
|
nuclear@6
|
247 return Vec2(widget->box.bmax.x - widget->box.bmin.x,
|
nuclear@6
|
248 widget->box.bmax.y - widget->box.bmin.y);
|
nuclear@6
|
249 }
|
nuclear@6
|
250
|
nuclear@6
|
251
|
nuclear@6
|
252 const BBox &Widget::get_box() const
|
nuclear@6
|
253 {
|
nuclear@6
|
254 return widget->box;
|
nuclear@6
|
255 }
|
nuclear@6
|
256
|
nuclear@6
|
257 bool Widget::hit_test(const Vec2 &pt) const
|
nuclear@6
|
258 {
|
nuclear@6
|
259 return pt.x >= widget->box.bmin.x && pt.x < widget->box.bmax.x &&
|
nuclear@6
|
260 pt.y >= widget->box.bmin.y && pt.y < widget->box.bmax.y;
|
nuclear@6
|
261 }
|
nuclear@6
|
262
|
nuclear@6
|
263 void Widget::draw() const
|
nuclear@6
|
264 {
|
nuclear@6
|
265 WidgetDrawFunc draw_func = default_draw_func;
|
nuclear@6
|
266
|
nuclear@6
|
267 if(theme) {
|
nuclear@6
|
268 draw_func = theme->get_draw_func(get_type_name());
|
nuclear@6
|
269 }
|
nuclear@6
|
270
|
nuclear@6
|
271 draw_func(this);
|
nuclear@6
|
272 }
|
nuclear@6
|
273
|
nuclear@6
|
274 // dummy event handlers
|
nuclear@6
|
275 void Widget::on_mouse_button(const ButtonEvent &ev)
|
nuclear@6
|
276 {
|
nuclear@6
|
277 }
|
nuclear@6
|
278
|
nuclear@6
|
279 void Widget::on_mouse_motion(const MotionEvent &ev)
|
nuclear@6
|
280 {
|
nuclear@6
|
281 }
|
nuclear@6
|
282
|
nuclear@6
|
283 void Widget::on_mouse_focus(const FocusEvent &ev)
|
nuclear@6
|
284 {
|
nuclear@6
|
285 }
|
nuclear@6
|
286
|
nuclear@6
|
287 void Widget::on_key(const KeyEvent &ev)
|
nuclear@6
|
288 {
|
nuclear@6
|
289 }
|
nuclear@6
|
290
|
nuclear@6
|
291 void Widget::on_click()
|
nuclear@6
|
292 {
|
nuclear@6
|
293 }
|
nuclear@6
|
294
|
nuclear@6
|
295 void Widget::on_double_click()
|
nuclear@6
|
296 {
|
nuclear@6
|
297 }
|
nuclear@6
|
298
|
nuclear@6
|
299 void Widget::on_change()
|
nuclear@6
|
300 {
|
nuclear@6
|
301 }
|
nuclear@6
|
302
|
nuclear@6
|
303
|
nuclear@6
|
304 #define CALL_CB(w, ev) \
|
nuclear@6
|
305 do { \
|
nuclear@6
|
306 if((w)->widget->cb[ev.type].func) { \
|
nuclear@6
|
307 (w)->widget->cb[ev.type].func((w), ev, (w)->widget->cb[ev.type].cls); \
|
nuclear@6
|
308 } \
|
nuclear@6
|
309 } while(0)
|
nuclear@6
|
310
|
nuclear@6
|
311 #define CALL_CB_TYPE(w, t) \
|
nuclear@6
|
312 do { \
|
nuclear@6
|
313 Event ev; \
|
nuclear@6
|
314 ev.type = (t); \
|
nuclear@6
|
315 CALL_CB(w, ev); \
|
nuclear@6
|
316 } while(0)
|
nuclear@6
|
317
|
nuclear@6
|
318 /* the event dispatcher generates high-level events (click, etc)
|
nuclear@6
|
319 * and calls the on_whatever() functions for both low and high-level
|
nuclear@6
|
320 * events.
|
nuclear@6
|
321 * The on_whatever functions are called *after* any other actions performed
|
nuclear@6
|
322 * here, to give subclasses the opportunity to override them easily, by
|
nuclear@6
|
323 * overriding the on_ functions, without having to override handle_event itself
|
nuclear@6
|
324 */
|
nuclear@6
|
325 // TODO also call callbacks here I guess...
|
nuclear@6
|
326 void Widget::handle_event(const Event &ev)
|
nuclear@6
|
327 {
|
nuclear@6
|
328 switch(ev.type) {
|
nuclear@6
|
329 case EV_MOUSE_BUTTON:
|
nuclear@6
|
330 if(ev.button.press) {
|
nuclear@6
|
331 press();
|
nuclear@6
|
332 } else {
|
nuclear@6
|
333 if(is_pressed()) {
|
nuclear@6
|
334 CALL_CB_TYPE(this, EV_CLICK);
|
nuclear@6
|
335 on_click();
|
nuclear@6
|
336 }
|
nuclear@6
|
337 release();
|
nuclear@6
|
338 }
|
nuclear@6
|
339
|
nuclear@6
|
340 on_mouse_button(ev.button);
|
nuclear@6
|
341 break;
|
nuclear@6
|
342
|
nuclear@6
|
343 case EV_MOUSE_MOTION:
|
nuclear@6
|
344 on_mouse_motion(ev.motion);
|
nuclear@6
|
345 break;
|
nuclear@6
|
346
|
nuclear@6
|
347 case EV_MOUSE_FOCUS:
|
nuclear@6
|
348 if(ev.focus.enter) {
|
nuclear@6
|
349 mousein();
|
nuclear@6
|
350 } else {
|
nuclear@6
|
351 mouseout();
|
nuclear@6
|
352 }
|
nuclear@6
|
353 on_mouse_focus(ev.focus);
|
nuclear@6
|
354 break;
|
nuclear@6
|
355
|
nuclear@6
|
356 case EV_KEY:
|
nuclear@6
|
357 on_key(ev.key);
|
nuclear@6
|
358 break;
|
nuclear@6
|
359
|
nuclear@6
|
360 case EV_CHANGE:
|
nuclear@6
|
361 on_change();
|
nuclear@6
|
362 break;
|
nuclear@6
|
363
|
nuclear@6
|
364 default:
|
nuclear@6
|
365 break;
|
nuclear@6
|
366 }
|
nuclear@6
|
367
|
nuclear@6
|
368 CALL_CB(this, ev);
|
nuclear@6
|
369 }
|
nuclear@6
|
370
|
nuclear@6
|
371
|
nuclear@6
|
372 void Widget::set_callback(EventType evtype, EventCallback func, void *cls)
|
nuclear@6
|
373 {
|
nuclear@6
|
374 widget->cb[evtype].func = func;
|
nuclear@6
|
375 widget->cb[evtype].cls = cls;
|
nuclear@6
|
376 }
|
nuclear@6
|
377
|
nuclear@6
|
378
|
nuclear@6
|
379 } // namespace goatkit
|