istereo2

view libs/goatkit/widget.cc @ 11:03cc3b1884d1

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