gameui
changeset 3:f1014234dece
transitions in gui elements are awesome :)
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 21 Mar 2014 03:37:16 +0200 |
parents | e5b1525084f7 |
children | e0916bb20b7f |
files | .clang_complete .hgignore Makefile include/button.h include/widget.h src/boolanm.cc src/boolanm.h src/button.cc src/event.h src/theme.cc src/theme.h src/vec.h src/widget.cc test.cc |
diffstat | 14 files changed, 556 insertions(+), 96 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.clang_complete Fri Mar 21 03:37:16 2014 +0200 1.3 @@ -0,0 +1,2 @@ 1.4 +-Isrc 1.5 +-Iinclude
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/.hgignore Fri Mar 21 03:37:16 2014 +0200 2.3 @@ -0,0 +1,6 @@ 2.4 +\.o$ 2.5 +\.d$ 2.6 +\.swp$ 2.7 +\.a$ 2.8 +\.so$ 2.9 +^test$
3.1 --- a/Makefile Thu Mar 20 07:03:58 2014 +0200 3.2 +++ b/Makefile Fri Mar 21 03:37:16 2014 +0200 3.3 @@ -3,9 +3,9 @@ 3.4 3.5 bin = test 3.6 3.7 -CFLAGS = -pedantic -Wall -g -Iinclude 3.8 +CFLAGS = -pedantic -Wall -g -Iinclude -Isrc 3.9 CXXFLAGS = $(CFLAGS) 3.10 -LDFLAGS = -lGL -lGLU -lglut 3.11 +LDFLAGS = -lGL -lGLU -lglut -lpthread 3.12 3.13 $(bin): $(obj) 3.14 $(CXX) -o $@ $(obj) $(LDFLAGS)
4.1 --- a/include/button.h Thu Mar 20 07:03:58 2014 +0200 4.2 +++ b/include/button.h Fri Mar 21 03:37:16 2014 +0200 4.3 @@ -5,11 +5,11 @@ 4.4 4.5 namespace gameui { 4.6 4.7 -class ButtonImpl; 4.8 +struct ButtonImpl; 4.9 4.10 -class Button { 4.11 +class Button : public Widget { 4.12 private: 4.13 - ButtonImpl *impl; 4.14 + ButtonImpl *button; 4.15 4.16 public: 4.17 Button();
5.1 --- a/include/widget.h Thu Mar 20 07:03:58 2014 +0200 5.2 +++ b/include/widget.h Fri Mar 21 03:37:16 2014 +0200 5.3 @@ -1,18 +1,12 @@ 5.4 #ifndef GAMEUI_WIDGET_H_ 5.5 #define GAMEUI_WIDGET_H_ 5.6 5.7 +#include "vec.h" 5.8 +#include "event.h" 5.9 + 5.10 namespace gameui { 5.11 5.12 -class Vec2 { 5.13 -public: 5.14 - float x, y; 5.15 - 5.16 - Vec2() : x(0), y(0) {} 5.17 - Vec2(float xx, float yy) : x(xx), y(yy) {} 5.18 -}; 5.19 - 5.20 -class BBox { 5.21 -public: 5.22 +struct BBox { 5.23 Vec2 bmin, bmax; 5.24 }; 5.25 5.26 @@ -20,44 +14,65 @@ 5.27 5.28 class Widget { 5.29 private: 5.30 - WidgetImpl *impl; 5.31 + WidgetImpl *widget; 5.32 + 5.33 + void set_type_string(const char *type_str); 5.34 5.35 public: 5.36 - enum VisState { 5.37 - VST_HIDDEN, 5.38 - VST_EASEIN, 5.39 - VST_VISIBLE, 5.40 - VST_EASEOUT 5.41 - }; 5.42 - enum ActiveState { 5.43 - AST_INACTIVE, 5.44 - AST_EASEIN, 5.45 - AST_ACTIVE, 5.46 - AST_EASEOUT 5.47 - }; 5.48 - 5.49 Widget(); 5.50 virtual ~Widget(); 5.51 5.52 virtual void show(); 5.53 virtual void hide(); 5.54 virtual float get_visibility() const; 5.55 + virtual bool is_visible() const; 5.56 5.57 virtual void activate(); 5.58 virtual void deactivate(); 5.59 virtual float get_active() const; 5.60 + virtual bool is_active() const; 5.61 + 5.62 + virtual void press(); 5.63 + virtual void release(); 5.64 + virtual float get_pressed() const; 5.65 + virtual bool is_pressed() const; 5.66 + 5.67 + virtual void mousein(); 5.68 + virtual void mouseout(); 5.69 + virtual float get_under_mouse() const; 5.70 + virtual bool is_under_mouse() const; 5.71 + 5.72 + virtual void set_position(float x, float y); 5.73 + virtual void set_position(const Vec2 &pos); 5.74 + virtual const Vec2 &get_position() const; 5.75 + 5.76 + virtual void set_size(float x, float y); 5.77 + virtual void set_size(const Vec2 &size); 5.78 + virtual const Vec2 get_size() const; 5.79 5.80 virtual const BBox &get_box() const; 5.81 - virtual const Vec2 &get_position() const; 5.82 - virtual const Vec2 &get_size() const; 5.83 5.84 virtual bool hit_test(const Vec2 &pt) const; 5.85 5.86 - virtual void draw() const = 0; 5.87 + virtual void draw() const; 5.88 + 5.89 + // low level events 5.90 + virtual void on_mouse_button(const ButtonEvent &ev); 5.91 + virtual void on_mouse_motion(const MotionEvent &ev); 5.92 + virtual void on_mouse_focus(const FocusEvent &ev); 5.93 + virtual void on_key(const KeyEvent &ev); 5.94 + 5.95 + // high level events 5.96 + virtual void on_click(); 5.97 + virtual void on_double_click(); 5.98 + virtual void on_change(); 5.99 + //virtual void on_drag_move(int bn, const Vec2 &pt); 5.100 + //virtual void on_drag_release(int bn, const Vec2 &pt); 5.101 + 5.102 + // event dispatcher 5.103 + virtual void handle_event(const Event &ev); 5.104 }; 5.105 5.106 -long get_cur_time(); 5.107 - 5.108 } 5.109 5.110 #endif // GAMEUI_WIDGET_H_
6.1 --- a/src/boolanm.cc Thu Mar 20 07:03:58 2014 +0200 6.2 +++ b/src/boolanm.cc Fri Mar 21 03:37:16 2014 +0200 6.3 @@ -4,10 +4,9 @@ 6.4 6.5 BoolAnim::BoolAnim(bool st) 6.6 { 6.7 - value = st ? 1.0 : 0.0; 6.8 - trans_dir = 0.0; 6.9 + set(st); 6.10 trans_start = 0; 6.11 - trans_dur = 1000; 6.12 + trans_dur = 500; 6.13 get_msec = default_get_msec; 6.14 } 6.15 6.16 @@ -43,6 +42,12 @@ 6.17 get_msec = time_func; 6.18 } 6.19 6.20 +void BoolAnim::set(bool st) 6.21 +{ 6.22 + value = st ? 1.0 : 0.0; 6.23 + trans_dir = 0.0; 6.24 +} 6.25 + 6.26 void BoolAnim::change(bool st) 6.27 { 6.28 change(st, get_msec());
7.1 --- a/src/boolanm.h Thu Mar 20 07:03:58 2014 +0200 7.2 +++ b/src/boolanm.h Fri Mar 21 03:37:16 2014 +0200 7.3 @@ -18,6 +18,8 @@ 7.4 void set_transition_duration(long dur); 7.5 void set_time_callback(long (*time_func)()); 7.6 7.7 + void set(bool st); 7.8 + 7.9 void change(bool st); 7.10 void change(bool st, long trans_start); 7.11
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/button.cc Fri Mar 21 03:37:16 2014 +0200 8.3 @@ -0,0 +1,18 @@ 8.4 +#include "button.h" 8.5 + 8.6 +namespace gameui { 8.7 + 8.8 +struct ButtonImpl { 8.9 +}; 8.10 + 8.11 +Button::Button() 8.12 +{ 8.13 + button = new ButtonImpl; 8.14 +} 8.15 + 8.16 +Button::~Button() 8.17 +{ 8.18 + delete button; 8.19 +} 8.20 + 8.21 +} // namespace gameui
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/event.h Fri Mar 21 03:37:16 2014 +0200 9.3 @@ -0,0 +1,45 @@ 9.4 +#ifndef EVENT_H_ 9.5 +#define EVENT_H_ 9.6 + 9.7 +#include "vec.h" 9.8 + 9.9 +namespace gameui { 9.10 + 9.11 +enum EventType { 9.12 + EV_MOUSE_BUTTON, 9.13 + EV_MOUSE_MOTION, 9.14 + EV_MOUSE_FOCUS, 9.15 + EV_KEY 9.16 +}; 9.17 + 9.18 +struct ButtonEvent { 9.19 + Vec2 pos; 9.20 + int button; 9.21 + bool press; 9.22 +}; 9.23 + 9.24 +struct MotionEvent { 9.25 + Vec2 pos; 9.26 +}; 9.27 + 9.28 +struct FocusEvent { 9.29 + bool enter; 9.30 +}; 9.31 + 9.32 +struct KeyEvent { 9.33 + int key; 9.34 + bool press; 9.35 +}; 9.36 + 9.37 +struct Event { 9.38 + EventType type; 9.39 + 9.40 + ButtonEvent button; 9.41 + MotionEvent motion; 9.42 + FocusEvent focus; 9.43 + KeyEvent key; 9.44 +}; 9.45 + 9.46 +} // namespace gameui 9.47 + 9.48 +#endif // EVENT_H_
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/src/theme.cc Fri Mar 21 03:37:16 2014 +0200 10.3 @@ -0,0 +1,100 @@ 10.4 +#include <stdio.h> 10.5 +#include "theme.h" 10.6 +#include "widget.h" 10.7 + 10.8 +#ifdef WIN32 10.9 +#include <windows.h> 10.10 +#endif 10.11 +#ifdef __APPLE__ 10.12 +#include <OpenGL/gl.h> 10.13 +#else 10.14 +#include <GL/gl.h> 10.15 +#endif 10.16 + 10.17 + 10.18 +namespace gameui { 10.19 + 10.20 +Theme *theme; 10.21 + 10.22 +Theme::Theme() 10.23 +{ 10.24 + so = 0; 10.25 +} 10.26 + 10.27 +bool Theme::load(const char *name) 10.28 +{ 10.29 + fprintf(stderr, "theme loading not implemented yet!\n"); 10.30 + return false; 10.31 +} 10.32 + 10.33 +widget_draw_func Theme::get_draw_func(const char *type) const 10.34 +{ 10.35 + std::map<std::string, widget_draw_func>::const_iterator it = draw_func.find(type); 10.36 + if(it == draw_func.end()) { 10.37 + return default_draw_func; 10.38 + } 10.39 + return it->second; 10.40 +} 10.41 + 10.42 +#define LERP(a, b, t) ((a) + ((b) - (a)) * t) 10.43 +#define DEF_TEX_SZ 32 10.44 +void default_draw_func(const Widget *w) 10.45 +{ 10.46 + static unsigned int tex; 10.47 + 10.48 + if(!tex) { 10.49 + unsigned char *pixels = new unsigned char[DEF_TEX_SZ * DEF_TEX_SZ * 3]; 10.50 + unsigned char *ptr = pixels; 10.51 + for(int i=0; i<DEF_TEX_SZ; i++) { 10.52 + for(int j=0; j<DEF_TEX_SZ; j++) { 10.53 + bool stripe = (((j + i) / 8) & 1) == 1; 10.54 + ptr[0] = ptr[1] = ptr[2] = stripe ? 255 : 0; 10.55 + ptr += 3; 10.56 + } 10.57 + } 10.58 + 10.59 + glGenTextures(1, &tex); 10.60 + glBindTexture(GL_TEXTURE_2D, tex); 10.61 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 10.62 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 10.63 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, DEF_TEX_SZ, DEF_TEX_SZ, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); 10.64 + delete [] pixels; 10.65 + } 10.66 + 10.67 + Vec2 pos = w->get_position(); 10.68 + Vec2 sz = w->get_size(); 10.69 + float aspect = sz.x / sz.y; 10.70 + 10.71 + glPushAttrib(GL_ENABLE_BIT); 10.72 + glEnable(GL_TEXTURE_2D); 10.73 + glBindTexture(GL_TEXTURE_2D, tex); 10.74 + 10.75 + float offs = w->get_pressed() * 0.1 * sz.y; 10.76 + glMatrixMode(GL_MODELVIEW); 10.77 + glPushMatrix(); 10.78 + glTranslatef(offs, -offs, 0); 10.79 + 10.80 + float active = w->get_active(); 10.81 + float hover = w->get_under_mouse(); 10.82 + 10.83 + float rg = LERP(0.4, 1.0, hover); 10.84 + float b = LERP(rg, 0, active); 10.85 + glColor3f(rg, rg, b); 10.86 + 10.87 + glBegin(GL_QUADS); 10.88 + glTexCoord2f(0, 1); 10.89 + glVertex2f(pos.x, pos.y); 10.90 + glTexCoord2f(aspect, 1); 10.91 + glVertex2f(pos.x + sz.x, pos.y); 10.92 + glTexCoord2f(aspect, 0); 10.93 + glVertex2f(pos.x + sz.x, pos.y + sz.y); 10.94 + glTexCoord2f(0, 0); 10.95 + glVertex2f(pos.x, pos.y + sz.y); 10.96 + glEnd(); 10.97 + 10.98 + glPopMatrix(); 10.99 + 10.100 + glPopAttrib(); 10.101 +} 10.102 + 10.103 +} // namespace gameui
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/src/theme.h Fri Mar 21 03:37:16 2014 +0200 11.3 @@ -0,0 +1,33 @@ 11.4 +#ifndef THEME_H_ 11.5 +#define THEME_H_ 11.6 + 11.7 +#include <string> 11.8 +#include <map> 11.9 + 11.10 +namespace gameui { 11.11 + 11.12 +class Widget; 11.13 + 11.14 +typedef void (*widget_draw_func)(const Widget*); 11.15 + 11.16 +void default_draw_func(const Widget *w); 11.17 + 11.18 +class Theme { 11.19 +private: 11.20 + void *so; 11.21 + std::map<std::string, widget_draw_func> draw_func; 11.22 + 11.23 +public: 11.24 + Theme(); 11.25 + ~Theme(); 11.26 + 11.27 + bool load(const char *name); 11.28 + 11.29 + widget_draw_func get_draw_func(const char *type) const; 11.30 +}; 11.31 + 11.32 +extern Theme *theme; // the current theme 11.33 + 11.34 +} // namespace gameui 11.35 + 11.36 +#endif // THEME_H_
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/src/vec.h Fri Mar 21 03:37:16 2014 +0200 12.3 @@ -0,0 +1,16 @@ 12.4 +#ifndef VEC_H_ 12.5 +#define VEC_H_ 12.6 + 12.7 +namespace gameui { 12.8 + 12.9 +class Vec2 { 12.10 +public: 12.11 + float x, y; 12.12 + 12.13 + Vec2() : x(0), y(0) {} 12.14 + Vec2(float xx, float yy) : x(xx), y(yy) {} 12.15 +}; 12.16 + 12.17 +} // namespace gameui 12.18 + 12.19 +#endif // VEC_H_
13.1 --- a/src/widget.cc Thu Mar 20 07:03:58 2014 +0200 13.2 +++ b/src/widget.cc Fri Mar 21 03:37:16 2014 +0200 13.3 @@ -1,12 +1,15 @@ 13.4 +#include <stdio.h> 13.5 +#include <math.h> 13.6 #include <string> 13.7 #include <sstream> 13.8 #include "widget.h" 13.9 #include "boolanm.h" 13.10 +#include "theme.h" 13.11 13.12 -using namespace gameui; 13.13 +namespace gameui { 13.14 13.15 struct WidgetImpl { 13.16 - std::string name_prefix; 13.17 + std::string type_str; 13.18 std::string name; 13.19 BBox box; 13.20 13.21 @@ -15,96 +18,249 @@ 13.22 13.23 13.24 Widget::Widget() 13.25 - : name_prefix("widget") 13.26 { 13.27 static int widget_count; 13.28 13.29 + widget = new WidgetImpl; 13.30 + set_type_string("widget"); 13.31 + 13.32 std::stringstream sstr; 13.33 - sstr << name_prefix << widget_count++; 13.34 - name = sstr.str(); 13.35 + sstr << widget->type_str << widget_count++; 13.36 + widget->name = sstr.str(); 13.37 13.38 - box.bmin = Vec2(0, 0); 13.39 - box.bmax = Vec2(1, 1); 13.40 + widget->box.bmin = Vec2(0, 0); 13.41 + widget->box.bmax = Vec2(1, 1); 13.42 13.43 - vis_st = VST_VISIBLE; 13.44 - act_st = AST_ACTIVE; 13.45 + widget->visible.set(true); 13.46 + widget->active.set(true); 13.47 13.48 - vis = act = 1.0; 13.49 + widget->hover.set_transition_duration(250); 13.50 + widget->press.set_transition_duration(50); 13.51 } 13.52 13.53 Widget::~Widget() 13.54 { 13.55 + delete widget; 13.56 } 13.57 13.58 void Widget::show() 13.59 { 13.60 - if(vis_st == VST_EASEVISIBLE || vis_st == VST_EASEIN) { 13.61 - return; 13.62 - } 13.63 - 13.64 - vis_st = VST_EASEIN; 13.65 - vis_start_time = get_cur_time(); 13.66 + widget->visible.change(true); 13.67 } 13.68 13.69 void Widget::hide() 13.70 { 13.71 - if(vis_st == VST_EASEHIDDEN || vis_st == VST_EASEOUT) { 13.72 - return; 13.73 - } 13.74 - 13.75 - vis_st = VST_EASEOUT; 13.76 - vis_start_time = get_cur_time(); 13.77 + widget->visible.change(false); 13.78 } 13.79 13.80 float Widget::get_visibility() const 13.81 { 13.82 - switch(vis_st) { 13.83 - case VST_EASEIN: 13.84 - vis = (get_cur_time() - vis_start_time) / gameui::ease_time; 13.85 - if(vis < 0.0) vis = 0.0; 13.86 - if(vis > 1.0) vis = 1.0; 13.87 - break; 13.88 + return widget->visible.get_value(); 13.89 +} 13.90 13.91 - case VST_EASEOUT: 13.92 - vis = 1.0 - (get_cur_time() - vis_start_time) / gameui::ease_time; 13.93 - if(vis < 0.0) vis = 0.0; 13.94 - if(vis > 1.0) vis = 1.0; 13.95 - break; 13.96 - 13.97 - case VST_HIDDEN: 13.98 - vis = 0.0; 13.99 - break; 13.100 - 13.101 - case VST_VISIBLE: 13.102 - vis = 1.0; 13.103 - break; 13.104 - } 13.105 - 13.106 - return vis; 13.107 +bool Widget::is_visible() const 13.108 +{ 13.109 + return widget->visible.get_state(); 13.110 } 13.111 13.112 void Widget::activate() 13.113 { 13.114 + widget->active.change(true); 13.115 } 13.116 13.117 -#ifdef WIN32 13.118 -long gameui::get_cur_time() 13.119 +void Widget::deactivate() 13.120 { 13.121 - return GetTickCount(); 13.122 + widget->active.change(false); 13.123 } 13.124 -#endif 13.125 13.126 -#if defined(__unix__) || defined(__APPLE__) 13.127 -long gameui::get_cur_time() 13.128 +float Widget::get_active() const 13.129 { 13.130 - struct timeval tv; 13.131 - static struct timeval tv0; 13.132 + return widget->active.get_value(); 13.133 +} 13.134 13.135 - gettimeofday(&tv, 0); 13.136 - if(tv0.tv_sec == 0 && tv0.tv_msec == 0) { 13.137 - tv0 = tv; 13.138 - return 0; 13.139 +bool Widget::is_active() const 13.140 +{ 13.141 + return widget->active.get_state(); 13.142 +} 13.143 + 13.144 +void Widget::press() 13.145 +{ 13.146 + widget->press.change(true); 13.147 +} 13.148 + 13.149 +void Widget::release() 13.150 +{ 13.151 + widget->press.change(false); 13.152 +} 13.153 + 13.154 +float Widget::get_pressed() const 13.155 +{ 13.156 + return widget->press.get_value(); 13.157 +} 13.158 + 13.159 +bool Widget::is_pressed() const 13.160 +{ 13.161 + return widget->press.get_state(); 13.162 +} 13.163 + 13.164 +void Widget::mousein() 13.165 +{ 13.166 + widget->hover.change(true); 13.167 +} 13.168 + 13.169 +void Widget::mouseout() 13.170 +{ 13.171 + widget->hover.change(false); 13.172 +} 13.173 + 13.174 +float Widget::get_under_mouse() const 13.175 +{ 13.176 + return widget->hover.get_value(); 13.177 +} 13.178 + 13.179 +bool Widget::is_under_mouse() const 13.180 +{ 13.181 + return widget->hover.get_state(); 13.182 +} 13.183 + 13.184 +void Widget::set_position(float x, float y) 13.185 +{ 13.186 + set_position(Vec2(x, y)); 13.187 +} 13.188 + 13.189 +void Widget::set_position(const Vec2 &pos) 13.190 +{ 13.191 + Vec2 sz = get_size(); 13.192 + 13.193 + widget->box.bmin = pos; 13.194 + widget->box.bmax.x = pos.x + sz.x; 13.195 + widget->box.bmax.y = pos.y + sz.y; 13.196 +} 13.197 + 13.198 +const Vec2 &Widget::get_position() const 13.199 +{ 13.200 + return widget->box.bmin; 13.201 +} 13.202 + 13.203 +void Widget::set_size(float x, float y) 13.204 +{ 13.205 + set_size(Vec2(x, y)); 13.206 +} 13.207 + 13.208 +void Widget::set_size(const Vec2 &sz) 13.209 +{ 13.210 + widget->box.bmax.x = widget->box.bmin.x + sz.x; 13.211 + widget->box.bmax.y = widget->box.bmin.y + sz.y; 13.212 +} 13.213 + 13.214 +const Vec2 Widget::get_size() const 13.215 +{ 13.216 + return Vec2(widget->box.bmax.x - widget->box.bmin.x, 13.217 + widget->box.bmax.y - widget->box.bmin.y); 13.218 +} 13.219 + 13.220 + 13.221 +const BBox &Widget::get_box() const 13.222 +{ 13.223 + return widget->box; 13.224 +} 13.225 + 13.226 +bool Widget::hit_test(const Vec2 &pt) const 13.227 +{ 13.228 + return pt.x >= widget->box.bmin.x && pt.x < widget->box.bmax.x && 13.229 + pt.y >= widget->box.bmin.y && pt.y < widget->box.bmax.y; 13.230 +} 13.231 + 13.232 +void Widget::draw() const 13.233 +{ 13.234 + widget_draw_func draw_func = default_draw_func; 13.235 + 13.236 + if(theme) { 13.237 + draw_func = theme->get_draw_func(widget->type_str.c_str()); 13.238 } 13.239 - return (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000; 13.240 + 13.241 + draw_func(this); 13.242 } 13.243 -#endif 13.244 + 13.245 +// dummy event handlers 13.246 +void Widget::on_mouse_button(const ButtonEvent &ev) 13.247 +{ 13.248 +} 13.249 + 13.250 +void Widget::on_mouse_motion(const MotionEvent &ev) 13.251 +{ 13.252 +} 13.253 + 13.254 +void Widget::on_mouse_focus(const FocusEvent &ev) 13.255 +{ 13.256 +} 13.257 + 13.258 +void Widget::on_key(const KeyEvent &ev) 13.259 +{ 13.260 +} 13.261 + 13.262 +void Widget::on_click() 13.263 +{ 13.264 +} 13.265 + 13.266 +void Widget::on_double_click() 13.267 +{ 13.268 +} 13.269 + 13.270 +void Widget::on_change() 13.271 +{ 13.272 +} 13.273 + 13.274 + 13.275 +void Widget::set_type_string(const char *type_str) 13.276 +{ 13.277 + widget->type_str = type_str; 13.278 +} 13.279 + 13.280 +/* the event dispatcher generates high-level events (click, etc) 13.281 + * and calls the on_whatever() functions for both low and high-level 13.282 + * events. 13.283 + * The on_whatever functions are called *after* any other actions performed 13.284 + * here, to give subclasses the opportunity to override them easily, by 13.285 + * overriding the on_ functions, without having to override handle_event itself 13.286 + */ 13.287 +// TODO also call callbacks here I guess... 13.288 +void Widget::handle_event(const Event &ev) 13.289 +{ 13.290 + switch(ev.type) { 13.291 + case EV_MOUSE_BUTTON: 13.292 + if(ev.button.press) { 13.293 + press(); 13.294 + } else { 13.295 + if(is_pressed()) { 13.296 + on_click(); 13.297 + } 13.298 + release(); 13.299 + } 13.300 + on_mouse_button(ev.button); 13.301 + break; 13.302 + 13.303 + case EV_MOUSE_MOTION: 13.304 + on_mouse_motion(ev.motion); 13.305 + break; 13.306 + 13.307 + case EV_MOUSE_FOCUS: 13.308 + if(ev.focus.enter) { 13.309 + mousein(); 13.310 + } else { 13.311 + mouseout(); 13.312 + } 13.313 + on_mouse_focus(ev.focus); 13.314 + break; 13.315 + 13.316 + case EV_KEY: 13.317 + on_key(ev.key); 13.318 + break; 13.319 + 13.320 + default: 13.321 + fprintf(stderr, "%s: unknown event id: %d\n", __func__, ev.type); 13.322 + } 13.323 +} 13.324 + 13.325 + 13.326 +} // namespace gameui
14.1 --- a/test.cc Thu Mar 20 07:03:58 2014 +0200 14.2 +++ b/test.cc Fri Mar 21 03:37:16 2014 +0200 14.3 @@ -1,11 +1,14 @@ 14.4 #include <stdio.h> 14.5 #include <stdlib.h> 14.6 #include <assert.h> 14.7 +#include <vector> 14.8 #include <GL/glut.h> 14.9 +#include "gameui.h" 14.10 14.11 static bool init(); 14.12 static void cleanup(); 14.13 static void disp(); 14.14 +static void idle(); 14.15 static void reshape(int x, int y); 14.16 static void keypress(unsigned char key, int x, int y); 14.17 static void keyrelease(unsigned char key, int x, int y); 14.18 @@ -14,6 +17,8 @@ 14.19 static void mouse(int bn, int st, int x, int y); 14.20 static void motion(int x, int y); 14.21 14.22 +static std::vector<gameui::Widget*> widgets; 14.23 + 14.24 int main(int argc, char **argv) 14.25 { 14.26 glutInitWindowSize(800, 600); 14.27 @@ -22,6 +27,7 @@ 14.28 glutCreateWindow("gameui test"); 14.29 14.30 glutDisplayFunc(disp); 14.31 + glutIdleFunc(idle); 14.32 glutReshapeFunc(reshape); 14.33 glutKeyboardFunc(keypress); 14.34 glutKeyboardUpFunc(keyrelease); 14.35 @@ -43,27 +49,45 @@ 14.36 14.37 static bool init() 14.38 { 14.39 + gameui::Button *button = new gameui::Button; 14.40 + button->set_position(350, 280); 14.41 + button->set_size(100, 40); 14.42 + widgets.push_back(button); 14.43 + 14.44 return true; 14.45 } 14.46 14.47 static void cleanup() 14.48 { 14.49 + for(size_t i=0; i<widgets.size(); i++) { 14.50 + delete widgets[i]; 14.51 + } 14.52 } 14.53 14.54 static void disp() 14.55 { 14.56 + glClearColor(0.2, 0.2, 0.2, 1.0); 14.57 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 14.58 14.59 + for(size_t i=0; i<widgets.size(); i++) { 14.60 + widgets[i]->draw(); 14.61 + } 14.62 + 14.63 glutSwapBuffers(); 14.64 assert(glGetError() == GL_NO_ERROR); 14.65 } 14.66 14.67 +static void idle() 14.68 +{ 14.69 + glutPostRedisplay(); 14.70 +} 14.71 + 14.72 static void reshape(int x, int y) 14.73 { 14.74 glViewport(0, 0, x, y); 14.75 glMatrixMode(GL_PROJECTION); 14.76 glLoadIdentity(); 14.77 - glOrtho(0, x, y, 0, -1, 1); 14.78 + glOrtho(0, x, 0, y, -1, 1); 14.79 } 14.80 14.81 static void keypress(unsigned char key, int x, int y) 14.82 @@ -87,8 +111,46 @@ 14.83 14.84 static void mouse(int bn, int st, int x, int y) 14.85 { 14.86 + int bidx = bn - GLUT_LEFT_BUTTON; 14.87 + bool down = st == GLUT_DOWN; 14.88 + 14.89 + for(size_t i=0; i<widgets.size(); i++) { 14.90 + gameui::Widget *w = widgets[i]; 14.91 + 14.92 + if(w->hit_test(gameui::Vec2(x, y))) { 14.93 + gameui::Event ev; 14.94 + ev.type = gameui::EV_MOUSE_BUTTON; 14.95 + ev.button.button = bidx; 14.96 + ev.button.press = down; 14.97 + ev.button.pos = gameui::Vec2(x, y); 14.98 + w->handle_event(ev); 14.99 + } 14.100 + } 14.101 } 14.102 14.103 static void motion(int x, int y) 14.104 { 14.105 + static gameui::Widget *active; 14.106 + 14.107 + if(active && !active->hit_test(gameui::Vec2(x, y))) { 14.108 + gameui::Event ev; 14.109 + ev.type = gameui::EV_MOUSE_FOCUS; 14.110 + ev.focus.enter = false; 14.111 + active->handle_event(ev); 14.112 + active = 0; 14.113 + } 14.114 + 14.115 + for(size_t i=0; i<widgets.size(); i++) { 14.116 + gameui::Widget *w = widgets[i]; 14.117 + 14.118 + if(w->hit_test(gameui::Vec2(x, y))) { 14.119 + if(active != w) { 14.120 + gameui::Event ev; 14.121 + ev.type = gameui::EV_MOUSE_FOCUS; 14.122 + ev.focus.enter = true; 14.123 + w->handle_event(ev); 14.124 + active = w; 14.125 + } 14.126 + } 14.127 + } 14.128 }