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@14
|
127 void Widget::set_visibility_transition(long msec)
|
nuclear@14
|
128 {
|
nuclear@14
|
129 widget->visible.set_transition_duration(msec);
|
nuclear@14
|
130 }
|
nuclear@14
|
131
|
nuclear@14
|
132 long Widget::get_visibility_transition() const
|
nuclear@14
|
133 {
|
nuclear@14
|
134 return widget->visible.get_transition_duration();
|
nuclear@14
|
135 }
|
nuclear@14
|
136
|
nuclear@6
|
137 void Widget::activate()
|
nuclear@6
|
138 {
|
nuclear@6
|
139 widget->active.change(true);
|
nuclear@6
|
140 }
|
nuclear@6
|
141
|
nuclear@6
|
142 void Widget::deactivate()
|
nuclear@6
|
143 {
|
nuclear@6
|
144 widget->active.change(false);
|
nuclear@6
|
145 }
|
nuclear@6
|
146
|
nuclear@6
|
147 float Widget::get_active() const
|
nuclear@6
|
148 {
|
nuclear@6
|
149 return widget->active.get_value();
|
nuclear@6
|
150 }
|
nuclear@6
|
151
|
nuclear@6
|
152 bool Widget::is_active() const
|
nuclear@6
|
153 {
|
nuclear@6
|
154 return widget->active.get_state();
|
nuclear@6
|
155 }
|
nuclear@6
|
156
|
nuclear@14
|
157 void Widget::set_active_transition(long msec)
|
nuclear@14
|
158 {
|
nuclear@14
|
159 widget->active.set_transition_duration(msec);
|
nuclear@14
|
160 }
|
nuclear@14
|
161
|
nuclear@14
|
162 long Widget::get_active_transition() const
|
nuclear@14
|
163 {
|
nuclear@15
|
164 return widget->active.get_transition_duration();
|
nuclear@14
|
165 }
|
nuclear@14
|
166
|
nuclear@6
|
167 void Widget::press()
|
nuclear@6
|
168 {
|
nuclear@6
|
169 widget->press.change(true);
|
nuclear@6
|
170 }
|
nuclear@6
|
171
|
nuclear@6
|
172 void Widget::release()
|
nuclear@6
|
173 {
|
nuclear@6
|
174 widget->press.change(false);
|
nuclear@6
|
175 }
|
nuclear@6
|
176
|
nuclear@6
|
177 float Widget::get_pressed() const
|
nuclear@6
|
178 {
|
nuclear@6
|
179 return widget->press.get_value();
|
nuclear@6
|
180 }
|
nuclear@6
|
181
|
nuclear@6
|
182 bool Widget::is_pressed() const
|
nuclear@6
|
183 {
|
nuclear@6
|
184 return widget->press.get_state();
|
nuclear@6
|
185 }
|
nuclear@6
|
186
|
nuclear@14
|
187 void Widget::set_press_transition(long msec)
|
nuclear@14
|
188 {
|
nuclear@14
|
189 widget->press.set_transition_duration(msec);
|
nuclear@14
|
190 }
|
nuclear@14
|
191
|
nuclear@14
|
192 long Widget::get_press_transition() const
|
nuclear@14
|
193 {
|
nuclear@14
|
194 return widget->press.get_transition_duration();
|
nuclear@14
|
195 }
|
nuclear@14
|
196
|
nuclear@6
|
197 void Widget::mousein()
|
nuclear@6
|
198 {
|
nuclear@6
|
199 widget->hover.change(true);
|
nuclear@6
|
200 }
|
nuclear@6
|
201
|
nuclear@6
|
202 void Widget::mouseout()
|
nuclear@6
|
203 {
|
nuclear@6
|
204 widget->hover.change(false);
|
nuclear@6
|
205 if(widget->press) {
|
nuclear@6
|
206 widget->press.change(false);
|
nuclear@6
|
207 }
|
nuclear@6
|
208 }
|
nuclear@6
|
209
|
nuclear@6
|
210 float Widget::get_under_mouse() const
|
nuclear@6
|
211 {
|
nuclear@6
|
212 return widget->hover.get_value();
|
nuclear@6
|
213 }
|
nuclear@6
|
214
|
nuclear@6
|
215 bool Widget::is_under_mouse() const
|
nuclear@6
|
216 {
|
nuclear@6
|
217 return widget->hover.get_state();
|
nuclear@6
|
218 }
|
nuclear@6
|
219
|
nuclear@14
|
220 void Widget::set_hover_transition(long msec)
|
nuclear@14
|
221 {
|
nuclear@14
|
222 widget->hover.set_transition_duration(msec);
|
nuclear@14
|
223 }
|
nuclear@14
|
224
|
nuclear@14
|
225 long Widget::get_hover_transition() const
|
nuclear@14
|
226 {
|
nuclear@14
|
227 return widget->hover.get_transition_duration();
|
nuclear@14
|
228 }
|
nuclear@14
|
229
|
nuclear@6
|
230 bool Widget::can_focus() const
|
nuclear@6
|
231 {
|
nuclear@6
|
232 return false;
|
nuclear@6
|
233 }
|
nuclear@6
|
234
|
nuclear@6
|
235 void Widget::focusin()
|
nuclear@6
|
236 {
|
nuclear@6
|
237 widget->focus.change(true);
|
nuclear@6
|
238 }
|
nuclear@6
|
239
|
nuclear@6
|
240 void Widget::focusout()
|
nuclear@6
|
241 {
|
nuclear@6
|
242 widget->focus.change(false);
|
nuclear@6
|
243 }
|
nuclear@6
|
244
|
nuclear@6
|
245 float Widget::get_focus() const
|
nuclear@6
|
246 {
|
nuclear@6
|
247 return widget->focus.get_value();
|
nuclear@6
|
248 }
|
nuclear@6
|
249
|
nuclear@6
|
250 bool Widget::is_focused() const
|
nuclear@6
|
251 {
|
nuclear@6
|
252 return widget->focus.get_state();
|
nuclear@6
|
253 }
|
nuclear@6
|
254
|
nuclear@14
|
255 void Widget::set_focus_transition(long msec)
|
nuclear@14
|
256 {
|
nuclear@14
|
257 widget->focus.set_transition_duration(msec);
|
nuclear@14
|
258 }
|
nuclear@14
|
259
|
nuclear@14
|
260 long Widget::get_focus_transition() const
|
nuclear@14
|
261 {
|
nuclear@14
|
262 return widget->focus.get_transition_duration();
|
nuclear@14
|
263 }
|
nuclear@14
|
264
|
nuclear@6
|
265 void Widget::set_position(float x, float y)
|
nuclear@6
|
266 {
|
nuclear@6
|
267 set_position(Vec2(x, y));
|
nuclear@6
|
268 }
|
nuclear@6
|
269
|
nuclear@6
|
270 void Widget::set_position(const Vec2 &pos)
|
nuclear@6
|
271 {
|
nuclear@6
|
272 Vec2 sz = get_size();
|
nuclear@6
|
273
|
nuclear@6
|
274 widget->box.bmin = pos;
|
nuclear@6
|
275 widget->box.bmax.x = pos.x + sz.x;
|
nuclear@6
|
276 widget->box.bmax.y = pos.y + sz.y;
|
nuclear@6
|
277 }
|
nuclear@6
|
278
|
nuclear@6
|
279 const Vec2 &Widget::get_position() const
|
nuclear@6
|
280 {
|
nuclear@6
|
281 return widget->box.bmin;
|
nuclear@6
|
282 }
|
nuclear@6
|
283
|
nuclear@6
|
284 void Widget::set_size(float x, float y)
|
nuclear@6
|
285 {
|
nuclear@6
|
286 set_size(Vec2(x, y));
|
nuclear@6
|
287 }
|
nuclear@6
|
288
|
nuclear@6
|
289 void Widget::set_size(const Vec2 &sz)
|
nuclear@6
|
290 {
|
nuclear@6
|
291 widget->box.bmax.x = widget->box.bmin.x + sz.x;
|
nuclear@6
|
292 widget->box.bmax.y = widget->box.bmin.y + sz.y;
|
nuclear@6
|
293 }
|
nuclear@6
|
294
|
nuclear@6
|
295 const Vec2 Widget::get_size() const
|
nuclear@6
|
296 {
|
nuclear@6
|
297 return Vec2(widget->box.bmax.x - widget->box.bmin.x,
|
nuclear@6
|
298 widget->box.bmax.y - widget->box.bmin.y);
|
nuclear@6
|
299 }
|
nuclear@6
|
300
|
nuclear@6
|
301
|
nuclear@6
|
302 const BBox &Widget::get_box() const
|
nuclear@6
|
303 {
|
nuclear@6
|
304 return widget->box;
|
nuclear@6
|
305 }
|
nuclear@6
|
306
|
nuclear@6
|
307 bool Widget::hit_test(const Vec2 &pt) const
|
nuclear@6
|
308 {
|
nuclear@6
|
309 return pt.x >= widget->box.bmin.x && pt.x < widget->box.bmax.x &&
|
nuclear@6
|
310 pt.y >= widget->box.bmin.y && pt.y < widget->box.bmax.y;
|
nuclear@6
|
311 }
|
nuclear@6
|
312
|
nuclear@6
|
313 void Widget::draw() const
|
nuclear@6
|
314 {
|
nuclear@6
|
315 WidgetDrawFunc draw_func = default_draw_func;
|
nuclear@6
|
316
|
nuclear@6
|
317 if(theme) {
|
nuclear@6
|
318 draw_func = theme->get_draw_func(get_type_name());
|
nuclear@6
|
319 }
|
nuclear@6
|
320
|
nuclear@6
|
321 draw_func(this);
|
nuclear@6
|
322 }
|
nuclear@6
|
323
|
nuclear@6
|
324 // dummy event handlers
|
nuclear@6
|
325 void Widget::on_mouse_button(const ButtonEvent &ev)
|
nuclear@6
|
326 {
|
nuclear@6
|
327 }
|
nuclear@6
|
328
|
nuclear@6
|
329 void Widget::on_mouse_motion(const MotionEvent &ev)
|
nuclear@6
|
330 {
|
nuclear@6
|
331 }
|
nuclear@6
|
332
|
nuclear@6
|
333 void Widget::on_mouse_focus(const FocusEvent &ev)
|
nuclear@6
|
334 {
|
nuclear@6
|
335 }
|
nuclear@6
|
336
|
nuclear@6
|
337 void Widget::on_key(const KeyEvent &ev)
|
nuclear@6
|
338 {
|
nuclear@6
|
339 }
|
nuclear@6
|
340
|
nuclear@6
|
341 void Widget::on_click()
|
nuclear@6
|
342 {
|
nuclear@6
|
343 }
|
nuclear@6
|
344
|
nuclear@6
|
345 void Widget::on_double_click()
|
nuclear@6
|
346 {
|
nuclear@6
|
347 }
|
nuclear@6
|
348
|
nuclear@6
|
349 void Widget::on_change()
|
nuclear@6
|
350 {
|
nuclear@6
|
351 }
|
nuclear@6
|
352
|
nuclear@6
|
353
|
nuclear@6
|
354 #define CALL_CB(w, ev) \
|
nuclear@6
|
355 do { \
|
nuclear@6
|
356 if((w)->widget->cb[ev.type].func) { \
|
nuclear@6
|
357 (w)->widget->cb[ev.type].func((w), ev, (w)->widget->cb[ev.type].cls); \
|
nuclear@6
|
358 } \
|
nuclear@6
|
359 } while(0)
|
nuclear@6
|
360
|
nuclear@6
|
361 #define CALL_CB_TYPE(w, t) \
|
nuclear@6
|
362 do { \
|
nuclear@6
|
363 Event ev; \
|
nuclear@6
|
364 ev.type = (t); \
|
nuclear@6
|
365 CALL_CB(w, ev); \
|
nuclear@6
|
366 } while(0)
|
nuclear@6
|
367
|
nuclear@6
|
368 /* the event dispatcher generates high-level events (click, etc)
|
nuclear@6
|
369 * and calls the on_whatever() functions for both low and high-level
|
nuclear@6
|
370 * events.
|
nuclear@6
|
371 * The on_whatever functions are called *after* any other actions performed
|
nuclear@6
|
372 * here, to give subclasses the opportunity to override them easily, by
|
nuclear@6
|
373 * overriding the on_ functions, without having to override handle_event itself
|
nuclear@6
|
374 */
|
nuclear@6
|
375 // TODO also call callbacks here I guess...
|
nuclear@6
|
376 void Widget::handle_event(const Event &ev)
|
nuclear@6
|
377 {
|
nuclear@6
|
378 switch(ev.type) {
|
nuclear@6
|
379 case EV_MOUSE_BUTTON:
|
nuclear@6
|
380 if(ev.button.press) {
|
nuclear@6
|
381 press();
|
nuclear@6
|
382 } else {
|
nuclear@6
|
383 if(is_pressed()) {
|
nuclear@6
|
384 CALL_CB_TYPE(this, EV_CLICK);
|
nuclear@6
|
385 on_click();
|
nuclear@6
|
386 }
|
nuclear@6
|
387 release();
|
nuclear@6
|
388 }
|
nuclear@6
|
389
|
nuclear@6
|
390 on_mouse_button(ev.button);
|
nuclear@6
|
391 break;
|
nuclear@6
|
392
|
nuclear@6
|
393 case EV_MOUSE_MOTION:
|
nuclear@6
|
394 on_mouse_motion(ev.motion);
|
nuclear@6
|
395 break;
|
nuclear@6
|
396
|
nuclear@6
|
397 case EV_MOUSE_FOCUS:
|
nuclear@6
|
398 if(ev.focus.enter) {
|
nuclear@6
|
399 mousein();
|
nuclear@6
|
400 } else {
|
nuclear@6
|
401 mouseout();
|
nuclear@6
|
402 }
|
nuclear@6
|
403 on_mouse_focus(ev.focus);
|
nuclear@6
|
404 break;
|
nuclear@6
|
405
|
nuclear@6
|
406 case EV_KEY:
|
nuclear@6
|
407 on_key(ev.key);
|
nuclear@6
|
408 break;
|
nuclear@6
|
409
|
nuclear@6
|
410 case EV_CHANGE:
|
nuclear@6
|
411 on_change();
|
nuclear@6
|
412 break;
|
nuclear@6
|
413
|
nuclear@6
|
414 default:
|
nuclear@6
|
415 break;
|
nuclear@6
|
416 }
|
nuclear@6
|
417
|
nuclear@6
|
418 CALL_CB(this, ev);
|
nuclear@6
|
419 }
|
nuclear@6
|
420
|
nuclear@6
|
421
|
nuclear@6
|
422 void Widget::set_callback(EventType evtype, EventCallback func, void *cls)
|
nuclear@6
|
423 {
|
nuclear@6
|
424 widget->cb[evtype].func = func;
|
nuclear@6
|
425 widget->cb[evtype].cls = cls;
|
nuclear@6
|
426 }
|
nuclear@6
|
427
|
nuclear@6
|
428
|
nuclear@6
|
429 } // namespace goatkit
|