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  }