# HG changeset patch
# User John Tsiombikas <nuclear@member.fsf.org>
# Date 1395365836 -7200
# Node ID f1014234dece536c15a614c0f73ca749bda0371d
# Parent  e5b1525084f73ab8cb4cf1d77b99f2ab4eb08c6b
transitions in gui elements are awesome :)

diff -r e5b1525084f7 -r f1014234dece .clang_complete
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.clang_complete	Fri Mar 21 03:37:16 2014 +0200
@@ -0,0 +1,2 @@
+-Isrc
+-Iinclude
diff -r e5b1525084f7 -r f1014234dece .hgignore
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Fri Mar 21 03:37:16 2014 +0200
@@ -0,0 +1,6 @@
+\.o$
+\.d$
+\.swp$
+\.a$
+\.so$
+^test$
diff -r e5b1525084f7 -r f1014234dece Makefile
--- a/Makefile	Thu Mar 20 07:03:58 2014 +0200
+++ b/Makefile	Fri Mar 21 03:37:16 2014 +0200
@@ -3,9 +3,9 @@
 
 bin = test
 
-CFLAGS = -pedantic -Wall -g -Iinclude
+CFLAGS = -pedantic -Wall -g -Iinclude -Isrc
 CXXFLAGS = $(CFLAGS)
-LDFLAGS = -lGL -lGLU -lglut
+LDFLAGS = -lGL -lGLU -lglut -lpthread
 
 $(bin): $(obj)
 	$(CXX) -o $@ $(obj) $(LDFLAGS)
diff -r e5b1525084f7 -r f1014234dece include/button.h
--- a/include/button.h	Thu Mar 20 07:03:58 2014 +0200
+++ b/include/button.h	Fri Mar 21 03:37:16 2014 +0200
@@ -5,11 +5,11 @@
 
 namespace gameui {
 
-class ButtonImpl;
+struct ButtonImpl;
 
-class Button {
+class Button : public Widget {
 private:
-	ButtonImpl *impl;
+	ButtonImpl *button;
 
 public:
 	Button();
diff -r e5b1525084f7 -r f1014234dece include/widget.h
--- a/include/widget.h	Thu Mar 20 07:03:58 2014 +0200
+++ b/include/widget.h	Fri Mar 21 03:37:16 2014 +0200
@@ -1,18 +1,12 @@
 #ifndef GAMEUI_WIDGET_H_
 #define GAMEUI_WIDGET_H_
 
+#include "vec.h"
+#include "event.h"
+
 namespace gameui {
 
-class Vec2 {
-public:
-	float x, y;
-
-	Vec2() : x(0), y(0) {}
-	Vec2(float xx, float yy) : x(xx), y(yy) {}
-};
-
-class BBox {
-public:
+struct BBox {
 	Vec2 bmin, bmax;
 };
 
@@ -20,44 +14,65 @@
 
 class Widget {
 private:
-	WidgetImpl *impl;
+	WidgetImpl *widget;
+
+	void set_type_string(const char *type_str);
 
 public:
-	enum VisState {
-		VST_HIDDEN,
-		VST_EASEIN,
-		VST_VISIBLE,
-		VST_EASEOUT
-	};
-	enum ActiveState {
-		AST_INACTIVE,
-		AST_EASEIN,
-		AST_ACTIVE,
-		AST_EASEOUT
-	};
-
 	Widget();
 	virtual ~Widget();
 
 	virtual void show();
 	virtual void hide();
 	virtual float get_visibility() const;
+	virtual bool is_visible() const;
 
 	virtual void activate();
 	virtual void deactivate();
 	virtual float get_active() const;
+	virtual bool is_active() const;
+
+	virtual void press();
+	virtual void release();
+	virtual float get_pressed() const;
+	virtual bool is_pressed() const;
+
+	virtual void mousein();
+	virtual void mouseout();
+	virtual float get_under_mouse() const;
+	virtual bool is_under_mouse() const;
+
+	virtual void set_position(float x, float y);
+	virtual void set_position(const Vec2 &pos);
+	virtual const Vec2 &get_position() const;
+
+	virtual void set_size(float x, float y);
+	virtual void set_size(const Vec2 &size);
+	virtual const Vec2 get_size() const;
 
 	virtual const BBox &get_box() const;
-	virtual const Vec2 &get_position() const;
-	virtual const Vec2 &get_size() const;
 
 	virtual bool hit_test(const Vec2 &pt) const;
 
-	virtual void draw() const = 0;
+	virtual void draw() const;
+
+	// low level events
+	virtual void on_mouse_button(const ButtonEvent &ev);
+	virtual void on_mouse_motion(const MotionEvent &ev);
+	virtual void on_mouse_focus(const FocusEvent &ev);
+	virtual void on_key(const KeyEvent &ev);
+
+	// high level events
+	virtual void on_click();
+	virtual void on_double_click();
+	virtual void on_change();
+	//virtual void on_drag_move(int bn, const Vec2 &pt);
+	//virtual void on_drag_release(int bn, const Vec2 &pt);
+
+	// event dispatcher
+	virtual void handle_event(const Event &ev);
 };
 
-long get_cur_time();
-
 }
 
 #endif	// GAMEUI_WIDGET_H_
diff -r e5b1525084f7 -r f1014234dece src/boolanm.cc
--- a/src/boolanm.cc	Thu Mar 20 07:03:58 2014 +0200
+++ b/src/boolanm.cc	Fri Mar 21 03:37:16 2014 +0200
@@ -4,10 +4,9 @@
 
 BoolAnim::BoolAnim(bool st)
 {
-	value = st ? 1.0 : 0.0;
-	trans_dir = 0.0;
+	set(st);
 	trans_start = 0;
-	trans_dur = 1000;
+	trans_dur = 500;
 	get_msec = default_get_msec;
 }
 
@@ -43,6 +42,12 @@
 	get_msec = time_func;
 }
 
+void BoolAnim::set(bool st)
+{
+	value = st ? 1.0 : 0.0;
+	trans_dir = 0.0;
+}
+
 void BoolAnim::change(bool st)
 {
 	change(st, get_msec());
diff -r e5b1525084f7 -r f1014234dece src/boolanm.h
--- a/src/boolanm.h	Thu Mar 20 07:03:58 2014 +0200
+++ b/src/boolanm.h	Fri Mar 21 03:37:16 2014 +0200
@@ -18,6 +18,8 @@
 	void set_transition_duration(long dur);
 	void set_time_callback(long (*time_func)());
 
+	void set(bool st);
+
 	void change(bool st);
 	void change(bool st, long trans_start);
 
diff -r e5b1525084f7 -r f1014234dece src/button.cc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/button.cc	Fri Mar 21 03:37:16 2014 +0200
@@ -0,0 +1,18 @@
+#include "button.h"
+
+namespace gameui {
+
+struct ButtonImpl {
+};
+
+Button::Button()
+{
+	button = new ButtonImpl;
+}
+
+Button::~Button()
+{
+	delete button;
+}
+
+}	// namespace gameui
diff -r e5b1525084f7 -r f1014234dece src/event.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/event.h	Fri Mar 21 03:37:16 2014 +0200
@@ -0,0 +1,45 @@
+#ifndef EVENT_H_
+#define EVENT_H_
+
+#include "vec.h"
+
+namespace gameui {
+
+enum EventType {
+	EV_MOUSE_BUTTON,
+	EV_MOUSE_MOTION,
+	EV_MOUSE_FOCUS,
+	EV_KEY
+};
+
+struct ButtonEvent {
+	Vec2 pos;
+	int button;
+	bool press;
+};
+
+struct MotionEvent {
+	Vec2 pos;
+};
+
+struct FocusEvent {
+	bool enter;
+};
+
+struct KeyEvent {
+	int key;
+	bool press;
+};
+
+struct Event {
+	EventType type;
+
+	ButtonEvent button;
+	MotionEvent motion;
+	FocusEvent focus;
+	KeyEvent key;
+};
+
+}	// namespace gameui
+
+#endif	// EVENT_H_
diff -r e5b1525084f7 -r f1014234dece src/theme.cc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/theme.cc	Fri Mar 21 03:37:16 2014 +0200
@@ -0,0 +1,100 @@
+#include <stdio.h>
+#include "theme.h"
+#include "widget.h"
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#else
+#include <GL/gl.h>
+#endif
+
+
+namespace gameui {
+
+Theme *theme;
+
+Theme::Theme()
+{
+	so = 0;
+}
+
+bool Theme::load(const char *name)
+{
+	fprintf(stderr, "theme loading not implemented yet!\n");
+	return false;
+}
+
+widget_draw_func Theme::get_draw_func(const char *type) const
+{
+	std::map<std::string, widget_draw_func>::const_iterator it = draw_func.find(type);
+	if(it == draw_func.end()) {
+		return default_draw_func;
+	}
+	return it->second;
+}
+
+#define LERP(a, b, t)	((a) + ((b) - (a)) * t)
+#define DEF_TEX_SZ	32
+void default_draw_func(const Widget *w)
+{
+	static unsigned int tex;
+
+	if(!tex) {
+		unsigned char *pixels = new unsigned char[DEF_TEX_SZ * DEF_TEX_SZ * 3];
+		unsigned char *ptr = pixels;
+		for(int i=0; i<DEF_TEX_SZ; i++) {
+			for(int j=0; j<DEF_TEX_SZ; j++) {
+				bool stripe = (((j + i) / 8) & 1) == 1;
+				ptr[0] = ptr[1] = ptr[2] = stripe ? 255 : 0;
+				ptr += 3;
+			}
+		}
+
+		glGenTextures(1, &tex);
+		glBindTexture(GL_TEXTURE_2D, tex);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, DEF_TEX_SZ, DEF_TEX_SZ, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
+		delete [] pixels;
+	}
+
+	Vec2 pos = w->get_position();
+	Vec2 sz = w->get_size();
+	float aspect = sz.x / sz.y;
+
+	glPushAttrib(GL_ENABLE_BIT);
+	glEnable(GL_TEXTURE_2D);
+	glBindTexture(GL_TEXTURE_2D, tex);
+
+	float offs = w->get_pressed() * 0.1 * sz.y;
+	glMatrixMode(GL_MODELVIEW);
+	glPushMatrix();
+	glTranslatef(offs, -offs, 0);
+
+	float active = w->get_active();
+	float hover = w->get_under_mouse();
+
+	float rg = LERP(0.4, 1.0, hover);
+	float b = LERP(rg, 0, active);
+	glColor3f(rg, rg, b);
+
+	glBegin(GL_QUADS);
+	glTexCoord2f(0, 1);
+	glVertex2f(pos.x, pos.y);
+	glTexCoord2f(aspect, 1);
+	glVertex2f(pos.x + sz.x, pos.y);
+	glTexCoord2f(aspect, 0);
+	glVertex2f(pos.x + sz.x, pos.y + sz.y);
+	glTexCoord2f(0, 0);
+	glVertex2f(pos.x, pos.y + sz.y);
+	glEnd();
+
+	glPopMatrix();
+
+	glPopAttrib();
+}
+
+}	// namespace gameui
diff -r e5b1525084f7 -r f1014234dece src/theme.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/theme.h	Fri Mar 21 03:37:16 2014 +0200
@@ -0,0 +1,33 @@
+#ifndef THEME_H_
+#define THEME_H_
+
+#include <string>
+#include <map>
+
+namespace gameui {
+
+class Widget;
+
+typedef void (*widget_draw_func)(const Widget*);
+
+void default_draw_func(const Widget *w);
+
+class Theme {
+private:
+	void *so;
+	std::map<std::string, widget_draw_func> draw_func;
+
+public:
+	Theme();
+	~Theme();
+
+	bool load(const char *name);
+
+	widget_draw_func get_draw_func(const char *type) const;
+};
+
+extern Theme *theme;	// the current theme
+
+}	// namespace gameui
+
+#endif	// THEME_H_
diff -r e5b1525084f7 -r f1014234dece src/vec.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vec.h	Fri Mar 21 03:37:16 2014 +0200
@@ -0,0 +1,16 @@
+#ifndef VEC_H_
+#define VEC_H_
+
+namespace gameui {
+
+class Vec2 {
+public:
+	float x, y;
+
+	Vec2() : x(0), y(0) {}
+	Vec2(float xx, float yy) : x(xx), y(yy) {}
+};
+
+}	// namespace gameui
+
+#endif	// VEC_H_
diff -r e5b1525084f7 -r f1014234dece src/widget.cc
--- a/src/widget.cc	Thu Mar 20 07:03:58 2014 +0200
+++ b/src/widget.cc	Fri Mar 21 03:37:16 2014 +0200
@@ -1,12 +1,15 @@
+#include <stdio.h>
+#include <math.h>
 #include <string>
 #include <sstream>
 #include "widget.h"
 #include "boolanm.h"
+#include "theme.h"
 
-using namespace gameui;
+namespace gameui {
 
 struct WidgetImpl {
-	std::string name_prefix;
+	std::string type_str;
 	std::string name;
 	BBox box;
 
@@ -15,96 +18,249 @@
 
 
 Widget::Widget()
-	: name_prefix("widget")
 {
 	static int widget_count;
 
+	widget = new WidgetImpl;
+	set_type_string("widget");
+
 	std::stringstream sstr;
-	sstr << name_prefix << widget_count++;
-	name = sstr.str();
+	sstr << widget->type_str << widget_count++;
+	widget->name = sstr.str();
 
-	box.bmin = Vec2(0, 0);
-	box.bmax = Vec2(1, 1);
+	widget->box.bmin = Vec2(0, 0);
+	widget->box.bmax = Vec2(1, 1);
 
-	vis_st = VST_VISIBLE;
-	act_st = AST_ACTIVE;
+	widget->visible.set(true);
+	widget->active.set(true);
 
-	vis = act = 1.0;
+	widget->hover.set_transition_duration(250);
+	widget->press.set_transition_duration(50);
 }
 
 Widget::~Widget()
 {
+	delete widget;
 }
 
 void Widget::show()
 {
-	if(vis_st == VST_EASEVISIBLE || vis_st == VST_EASEIN) {
-		return;
-	}
-
-	vis_st = VST_EASEIN;
-	vis_start_time = get_cur_time();
+	widget->visible.change(true);
 }
 
 void Widget::hide()
 {
-	if(vis_st == VST_EASEHIDDEN || vis_st == VST_EASEOUT) {
-		return;
-	}
-
-	vis_st = VST_EASEOUT;
-	vis_start_time = get_cur_time();
+	widget->visible.change(false);
 }
 
 float Widget::get_visibility() const
 {
-	switch(vis_st) {
-	case VST_EASEIN:
-		vis = (get_cur_time() - vis_start_time) / gameui::ease_time;
-		if(vis < 0.0) vis = 0.0;
-		if(vis > 1.0) vis = 1.0;
-		break;
+	return widget->visible.get_value();
+}
 
-	case VST_EASEOUT:
-		vis = 1.0 - (get_cur_time() - vis_start_time) / gameui::ease_time;
-		if(vis < 0.0) vis = 0.0;
-		if(vis > 1.0) vis = 1.0;
-		break;
-
-	case VST_HIDDEN:
-		vis = 0.0;
-		break;
-
-	case VST_VISIBLE:
-		vis = 1.0;
-		break;
-	}
-
-	return vis;
+bool Widget::is_visible() const
+{
+	return widget->visible.get_state();
 }
 
 void Widget::activate()
 {
+	widget->active.change(true);
 }
 
-#ifdef WIN32
-long gameui::get_cur_time()
+void Widget::deactivate()
 {
-	return GetTickCount();
+	widget->active.change(false);
 }
-#endif
 
-#if defined(__unix__) || defined(__APPLE__)
-long gameui::get_cur_time()
+float Widget::get_active() const
 {
-	struct timeval tv;
-	static struct timeval tv0;
+	return widget->active.get_value();
+}
 
-	gettimeofday(&tv, 0);
-	if(tv0.tv_sec == 0 && tv0.tv_msec == 0) {
-		tv0 = tv;
-		return 0;
+bool Widget::is_active() const
+{
+	return widget->active.get_state();
+}
+
+void Widget::press()
+{
+	widget->press.change(true);
+}
+
+void Widget::release()
+{
+	widget->press.change(false);
+}
+
+float Widget::get_pressed() const
+{
+	return widget->press.get_value();
+}
+
+bool Widget::is_pressed() const
+{
+	return widget->press.get_state();
+}
+
+void Widget::mousein()
+{
+	widget->hover.change(true);
+}
+
+void Widget::mouseout()
+{
+	widget->hover.change(false);
+}
+
+float Widget::get_under_mouse() const
+{
+	return widget->hover.get_value();
+}
+
+bool Widget::is_under_mouse() const
+{
+	return widget->hover.get_state();
+}
+
+void Widget::set_position(float x, float y)
+{
+	set_position(Vec2(x, y));
+}
+
+void Widget::set_position(const Vec2 &pos)
+{
+	Vec2 sz = get_size();
+
+	widget->box.bmin = pos;
+	widget->box.bmax.x = pos.x + sz.x;
+	widget->box.bmax.y = pos.y + sz.y;
+}
+
+const Vec2 &Widget::get_position() const
+{
+	return widget->box.bmin;
+}
+
+void Widget::set_size(float x, float y)
+{
+	set_size(Vec2(x, y));
+}
+
+void Widget::set_size(const Vec2 &sz)
+{
+	widget->box.bmax.x = widget->box.bmin.x + sz.x;
+	widget->box.bmax.y = widget->box.bmin.y + sz.y;
+}
+
+const Vec2 Widget::get_size() const
+{
+	return Vec2(widget->box.bmax.x - widget->box.bmin.x,
+			widget->box.bmax.y - widget->box.bmin.y);
+}
+
+
+const BBox &Widget::get_box() const
+{
+	return widget->box;
+}
+
+bool Widget::hit_test(const Vec2 &pt) const
+{
+	return pt.x >= widget->box.bmin.x && pt.x < widget->box.bmax.x &&
+		pt.y >= widget->box.bmin.y && pt.y < widget->box.bmax.y;
+}
+
+void Widget::draw() const
+{
+	widget_draw_func draw_func = default_draw_func;
+
+	if(theme) {
+		draw_func = theme->get_draw_func(widget->type_str.c_str());
 	}
-	return (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000;
+
+	draw_func(this);
 }
-#endif
+
+// dummy event handlers
+void Widget::on_mouse_button(const ButtonEvent &ev)
+{
+}
+
+void Widget::on_mouse_motion(const MotionEvent &ev)
+{
+}
+
+void Widget::on_mouse_focus(const FocusEvent &ev)
+{
+}
+
+void Widget::on_key(const KeyEvent &ev)
+{
+}
+
+void Widget::on_click()
+{
+}
+
+void Widget::on_double_click()
+{
+}
+
+void Widget::on_change()
+{
+}
+
+
+void Widget::set_type_string(const char *type_str)
+{
+	widget->type_str = type_str;
+}
+
+/* the event dispatcher generates high-level events (click, etc)
+ * and calls the on_whatever() functions for both low and high-level
+ * events.
+ * The on_whatever functions are called *after* any other actions performed
+ * here, to give subclasses the opportunity to override them easily, by
+ * overriding the on_ functions, without having to override handle_event itself
+ */
+// TODO also call callbacks here I guess...
+void Widget::handle_event(const Event &ev)
+{
+	switch(ev.type) {
+	case EV_MOUSE_BUTTON:
+		if(ev.button.press) {
+			press();
+		} else {
+			if(is_pressed()) {
+				on_click();
+			}
+			release();
+		}
+		on_mouse_button(ev.button);
+		break;
+
+	case EV_MOUSE_MOTION:
+		on_mouse_motion(ev.motion);
+		break;
+
+	case EV_MOUSE_FOCUS:
+		if(ev.focus.enter) {
+			mousein();
+		} else {
+			mouseout();
+		}
+		on_mouse_focus(ev.focus);
+		break;
+
+	case EV_KEY:
+		on_key(ev.key);
+		break;
+
+	default:
+		fprintf(stderr, "%s: unknown event id: %d\n", __func__, ev.type);
+	}
+}
+
+
+}	// namespace gameui
diff -r e5b1525084f7 -r f1014234dece test.cc
--- a/test.cc	Thu Mar 20 07:03:58 2014 +0200
+++ b/test.cc	Fri Mar 21 03:37:16 2014 +0200
@@ -1,11 +1,14 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
+#include <vector>
 #include <GL/glut.h>
+#include "gameui.h"
 
 static bool init();
 static void cleanup();
 static void disp();
+static void idle();
 static void reshape(int x, int y);
 static void keypress(unsigned char key, int x, int y);
 static void keyrelease(unsigned char key, int x, int y);
@@ -14,6 +17,8 @@
 static void mouse(int bn, int st, int x, int y);
 static void motion(int x, int y);
 
+static std::vector<gameui::Widget*> widgets;
+
 int main(int argc, char **argv)
 {
 	glutInitWindowSize(800, 600);
@@ -22,6 +27,7 @@
 	glutCreateWindow("gameui test");
 
 	glutDisplayFunc(disp);
+	glutIdleFunc(idle);
 	glutReshapeFunc(reshape);
 	glutKeyboardFunc(keypress);
 	glutKeyboardUpFunc(keyrelease);
@@ -43,27 +49,45 @@
 
 static bool init()
 {
+	gameui::Button *button = new gameui::Button;
+	button->set_position(350, 280);
+	button->set_size(100, 40);
+	widgets.push_back(button);
+
 	return true;
 }
 
 static void cleanup()
 {
+	for(size_t i=0; i<widgets.size(); i++) {
+		delete widgets[i];
+	}
 }
 
 static void disp()
 {
+	glClearColor(0.2, 0.2, 0.2, 1.0);
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
+	for(size_t i=0; i<widgets.size(); i++) {
+		widgets[i]->draw();
+	}
+
 	glutSwapBuffers();
 	assert(glGetError() == GL_NO_ERROR);
 }
 
+static void idle()
+{
+	glutPostRedisplay();
+}
+
 static void reshape(int x, int y)
 {
 	glViewport(0, 0, x, y);
 	glMatrixMode(GL_PROJECTION);
 	glLoadIdentity();
-	glOrtho(0, x, y, 0, -1, 1);
+	glOrtho(0, x, 0, y, -1, 1);
 }
 
 static void keypress(unsigned char key, int x, int y)
@@ -87,8 +111,46 @@
 
 static void mouse(int bn, int st, int x, int y)
 {
+	int bidx = bn - GLUT_LEFT_BUTTON;
+	bool down = st == GLUT_DOWN;
+
+	for(size_t i=0; i<widgets.size(); i++) {
+		gameui::Widget *w = widgets[i];
+
+		if(w->hit_test(gameui::Vec2(x, y))) {
+			gameui::Event ev;
+			ev.type = gameui::EV_MOUSE_BUTTON;
+			ev.button.button = bidx;
+			ev.button.press = down;
+			ev.button.pos = gameui::Vec2(x, y);
+			w->handle_event(ev);
+		}
+	}
 }
 
 static void motion(int x, int y)
 {
+	static gameui::Widget *active;
+
+	if(active && !active->hit_test(gameui::Vec2(x, y))) {
+		gameui::Event ev;
+		ev.type = gameui::EV_MOUSE_FOCUS;
+		ev.focus.enter = false;
+		active->handle_event(ev);
+		active = 0;
+	}
+
+	for(size_t i=0; i<widgets.size(); i++) {
+		gameui::Widget *w = widgets[i];
+
+		if(w->hit_test(gameui::Vec2(x, y))) {
+			if(active != w) {
+				gameui::Event ev;
+				ev.type = gameui::EV_MOUSE_FOCUS;
+				ev.focus.enter = true;
+				w->handle_event(ev);
+				active = w;
+			}
+		}
+	}
 }