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