Revamp the UI event system a bit
This commit is contained in:
+24
-74
@@ -62,6 +62,18 @@ uiman_render ()
|
||||
Widget_render (ui_root, projection, sdl_window_h);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
_uiman_call_on_event (Widget *widget, WidgetEvent event)
|
||||
{
|
||||
if (widget && widget->on_event[event])
|
||||
{
|
||||
widget->on_event[event] (widget, widget->event_data[event]);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
uiman_cb_switch_focus (SDL_Event *event, void *data)
|
||||
{
|
||||
@@ -103,108 +115,46 @@ uiman_cb_mouse_motion (SDL_Event *event, void *data)
|
||||
|
||||
if (new_hover != hovered_widget)
|
||||
{
|
||||
if (hovered_widget && hovered_widget->on_mouse_leave)
|
||||
{
|
||||
hovered_widget->on_mouse_leave (hovered_widget, hovered_widget->mouse_leave_data);
|
||||
}
|
||||
|
||||
if (new_hover && new_hover->on_mouse_enter)
|
||||
{
|
||||
new_hover->on_mouse_enter (new_hover, new_hover->mouse_enter_data);
|
||||
}
|
||||
|
||||
_uiman_call_on_event (hovered_widget, EVENT_MOUSE_LEAVE);
|
||||
_uiman_call_on_event (new_hover, EVENT_MOUSE_ENTER);
|
||||
hovered_widget = new_hover;
|
||||
}
|
||||
|
||||
if (hovered_widget && hovered_widget->on_mouse_move)
|
||||
{
|
||||
hovered_widget->on_mouse_move (hovered_widget, hovered_widget->mouse_move_data);
|
||||
}
|
||||
_uiman_call_on_event (hovered_widget, EVENT_MOUSE_MOVE);
|
||||
|
||||
/* This callback always eats the event, because why would the game
|
||||
need mouse motion if the UI has stolen the focus? */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean widget_match_bdown (Widget *self) { return self->on_left_down || self->on_right_down; };
|
||||
gboolean
|
||||
uiman_cb_button_down (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (data);
|
||||
|
||||
Widget *widget = Widget_find_xy_matching (ui_root, (vec2) { event->button.x, event->button.y }, widget_match_bdown);
|
||||
|
||||
if (widget)
|
||||
{
|
||||
if (event->button.button == SDL_BUTTON_LEFT && widget->on_left_down)
|
||||
{
|
||||
widget->on_left_down (widget, widget->left_down_data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (event->button.button == SDL_BUTTON_RIGHT && widget->on_right_down)
|
||||
{
|
||||
widget->on_right_down (widget, widget->right_down_data);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
WidgetEvent e = event->button.button == SDL_BUTTON_LEFT ? EVENT_LEFT_DOWN : EVENT_RIGHT_DOWN;
|
||||
Widget *widget = Widget_find_xy_event (ui_root, (vec2) { event->button.x, event->button.y }, e);
|
||||
return _uiman_call_on_event (widget, e);
|
||||
}
|
||||
|
||||
gboolean widget_match_bup (Widget *self) { return self->on_left_up || self->on_right_up; };
|
||||
gboolean
|
||||
uiman_cb_button_up (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (data);
|
||||
|
||||
Widget *widget = Widget_find_xy_matching (ui_root, (vec2) { event->button.x, event->button.y }, widget_match_bup);
|
||||
|
||||
if (widget)
|
||||
{
|
||||
if (event->button.button == SDL_BUTTON_LEFT && widget->on_left_up)
|
||||
{
|
||||
widget->on_left_up (widget, widget->left_up_data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (event->button.button == SDL_BUTTON_RIGHT && widget->on_right_up)
|
||||
{
|
||||
widget->on_right_up (widget, widget->right_up_data);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
WidgetEvent e = event->button.button == SDL_BUTTON_LEFT ? EVENT_LEFT_UP : EVENT_RIGHT_UP;
|
||||
Widget *widget = Widget_find_xy_event (ui_root, (vec2) { event->button.x, event->button.y }, e);
|
||||
return _uiman_call_on_event (widget, e);
|
||||
}
|
||||
|
||||
gboolean widget_match_scroll (Widget *self) { return self->on_scroll_down || self->on_scroll_up; };
|
||||
gboolean
|
||||
uiman_cb_mouse_wheel (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
|
||||
Widget *widget = Widget_find_xy_matching (ui_root, (vec2) { event->wheel.mouse_x, event->wheel.mouse_y }, widget_match_scroll);
|
||||
|
||||
if (widget)
|
||||
{
|
||||
if (event->wheel.y > 0)
|
||||
{
|
||||
if (widget->on_scroll_up)
|
||||
{
|
||||
widget->on_scroll_up (widget, widget->scroll_up_data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (widget->on_scroll_down)
|
||||
{
|
||||
widget->on_scroll_down (widget, widget->scroll_down_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
WidgetEvent e = event->wheel.y > 0 ? EVENT_SCROLL_UP : EVENT_SCROLL_DOWN;
|
||||
Widget *widget = Widget_find_xy_event (ui_root, (vec2) { event->wheel.mouse_x, event->wheel.mouse_y }, e);
|
||||
return _uiman_call_on_event (widget, e);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
||||
+39
-67
@@ -90,47 +90,18 @@ Widget_add_child_weighed (Widget *parent, Widget *child, float layout_weight)
|
||||
|
||||
void
|
||||
Widget_set_on_tick (Widget *widget,
|
||||
void (*on_tick) (Widget *, void *),
|
||||
void *userdata)
|
||||
void (*on_tick) (Widget *, void *), void *userdata)
|
||||
{
|
||||
widget->on_tick = on_tick;
|
||||
widget->tick_data = userdata;
|
||||
}
|
||||
|
||||
void
|
||||
Widget_set_on_left_up (Widget *widget,
|
||||
void (*on_left_up) (Widget *, void *),
|
||||
void *userdata)
|
||||
Widget_set_on_event (Widget *widget, WidgetEvent event,
|
||||
void (*on_event) (Widget *, void *), void *userdata)
|
||||
{
|
||||
widget->on_left_up = on_left_up;
|
||||
widget->left_up_data = userdata;
|
||||
}
|
||||
|
||||
void
|
||||
Widget_label_set_text (Widget *widget, const char *text)
|
||||
{
|
||||
g_string_overwrite (widget->label.text, 0, text);
|
||||
}
|
||||
|
||||
void
|
||||
Widget_label_printf (Widget *widget, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
g_string_vprintf (widget->label.text, format, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
void
|
||||
Widget_scrollable_scroll (Widget *widget, vec2 direction)
|
||||
{
|
||||
glm_vec2_muladds (direction, widget->scrollable.scroll_amount, widget->scrollable.scroll_position);
|
||||
widget->scrollable.scroll_position[0] =
|
||||
glm_clamp (widget->scrollable.scroll_position[0], 0.0f,
|
||||
glm_max (0.0f, widget->scrollable.content_size[0] - widget->size[0]));
|
||||
widget->scrollable.scroll_position[1] =
|
||||
glm_clamp (widget->scrollable.scroll_position[1], 0.0f,
|
||||
glm_max (0.0f, widget->scrollable.content_size[1] - widget->size[1]));
|
||||
widget->on_event[event] = on_event;
|
||||
widget->event_data[event] = userdata;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -149,7 +120,7 @@ Widget_hit_test (Widget *widget, vec2 point)
|
||||
}
|
||||
|
||||
Widget *
|
||||
Widget_find_xy_matching (Widget *widget, vec2 pos, gboolean (*match_fn) (Widget *widget))
|
||||
Widget_find_xy_event (Widget *widget, vec2 pos, WidgetEvent event)
|
||||
{
|
||||
if (!widget->visible)
|
||||
{
|
||||
@@ -172,7 +143,7 @@ Widget_find_xy_matching (Widget *widget, vec2 pos, gboolean (*match_fn) (Widget
|
||||
for (int i = widget->children->len - 1; i >= 0; --i)
|
||||
{
|
||||
Widget *child = g_array_index (widget->children, Widget *, i);
|
||||
Widget *found = Widget_find_xy_matching (child, pos_scrolled, match_fn);
|
||||
Widget *found = Widget_find_xy_event (child, pos_scrolled, event);
|
||||
|
||||
if (found != NULL)
|
||||
{
|
||||
@@ -180,7 +151,7 @@ Widget_find_xy_matching (Widget *widget, vec2 pos, gboolean (*match_fn) (Widget
|
||||
}
|
||||
}
|
||||
|
||||
if (!match_fn || match_fn (widget))
|
||||
if (event == EVENT_NONE || widget->on_event[event])
|
||||
{
|
||||
return widget;
|
||||
}
|
||||
@@ -191,7 +162,7 @@ Widget_find_xy_matching (Widget *widget, vec2 pos, gboolean (*match_fn) (Widget
|
||||
Widget *
|
||||
Widget_find_xy (Widget *widget, vec2 pos)
|
||||
{
|
||||
return Widget_find_xy_matching (widget, pos, NULL);
|
||||
return Widget_find_xy_event (widget, pos, EVENT_NONE);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -504,6 +475,33 @@ Widget_render (Widget *widget, mat4 projection, int window_height)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Widget_label_set_text (Widget *widget, const char *text)
|
||||
{
|
||||
g_string_overwrite (widget->label.text, 0, text);
|
||||
}
|
||||
|
||||
void
|
||||
Widget_label_printf (Widget *widget, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
g_string_vprintf (widget->label.text, format, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
void
|
||||
Widget_scrollable_scroll (Widget *widget, vec2 direction)
|
||||
{
|
||||
glm_vec2_muladds (direction, widget->scrollable.scroll_amount, widget->scrollable.scroll_position);
|
||||
widget->scrollable.scroll_position[0] =
|
||||
glm_clamp (widget->scrollable.scroll_position[0], 0.0f,
|
||||
glm_max (0.0f, widget->scrollable.content_size[0] - widget->size[0]));
|
||||
widget->scrollable.scroll_position[1] =
|
||||
glm_clamp (widget->scrollable.scroll_position[1], 0.0f,
|
||||
glm_max (0.0f, widget->scrollable.content_size[1] - widget->size[1]));
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
LabelFormatData *
|
||||
@@ -689,28 +687,13 @@ Widget_composite_spinner_make_int (const char *fmt, int *ptr)
|
||||
Widget *label = Widget_label_make_int (fmt, ptr, TEXT_ALIGN_CENTER);
|
||||
Widget *right = Widget_plain_new ();
|
||||
|
||||
Widget_set_on_left_up (left, uicb_decrement_int, ptr);
|
||||
Widget_set_on_event (left, EVENT_LEFT_UP, uicb_decrement_int, ptr);
|
||||
left->icon = ICON_SPINNER_LEFT;
|
||||
left->aspect_ratio = 1.0;
|
||||
Widget_set_on_left_up (right, uicb_increment_int, ptr);
|
||||
Widget_set_on_event (right, EVENT_LEFT_UP, uicb_increment_int, ptr);
|
||||
right->icon = ICON_SPINNER_RIGHT;
|
||||
right->aspect_ratio = 1.0;
|
||||
|
||||
vec4 *enter_color = g_new (vec4, 1);
|
||||
glm_vec4_copy ((vec4) { 1, 1, 1, 0.3 }, *enter_color);
|
||||
vec4 *leave_color = g_new (vec4, 1);
|
||||
glm_vec4_copy ((vec4) { 1, 1, 1, 0.0 }, *leave_color);
|
||||
|
||||
left->on_mouse_enter = uicb_set_background;
|
||||
left->on_mouse_leave = uicb_set_background;
|
||||
right->on_mouse_enter = uicb_set_background;
|
||||
right->on_mouse_leave = uicb_set_background;
|
||||
|
||||
left->mouse_enter_data = enter_color;
|
||||
left->mouse_leave_data = leave_color;
|
||||
right->mouse_enter_data = enter_color;
|
||||
right->mouse_leave_data = leave_color;
|
||||
|
||||
Widget_add_child_weighed (cont, left, 1);
|
||||
Widget_add_child_weighed (cont, label, 1);
|
||||
Widget_add_child_weighed (cont, right, 1);
|
||||
@@ -729,18 +712,7 @@ Widget_composite_checkbox_make (const char *label, char *flag)
|
||||
box->icon = ICON_CHECKBOX_UNCHECKED;
|
||||
box->aspect_ratio = 1.0;
|
||||
Widget_set_on_tick (box, uicb_checkbox_show_flag, flag);
|
||||
Widget_set_on_left_up (box, uicb_switch_flag, flag);
|
||||
|
||||
box->on_mouse_enter = uicb_set_background;
|
||||
box->on_mouse_leave = uicb_set_background;
|
||||
|
||||
vec4 *enter_color = g_new (vec4, 1);
|
||||
glm_vec4_copy ((vec4) { 1, 1, 1, 0.3 }, *enter_color);
|
||||
vec4 *leave_color = g_new (vec4, 1);
|
||||
glm_vec4_copy ((vec4) { 1, 1, 1, 0.0 }, *leave_color);
|
||||
|
||||
box->mouse_enter_data = enter_color;
|
||||
box->mouse_leave_data = leave_color;
|
||||
Widget_set_on_event (box, EVENT_LEFT_UP, uicb_switch_flag, flag);
|
||||
|
||||
Widget_add_child_weighed (cont, box, 1);
|
||||
Widget_add_child_weighed (cont, Widget_label_new (label, TEXT_ALIGN_LEFT), 1);
|
||||
|
||||
+24
-28
@@ -36,6 +36,20 @@ typedef enum WidgetIcon
|
||||
ICON_ARROW_DOWN
|
||||
} WidgetIcon;
|
||||
|
||||
typedef enum WidgetEvent
|
||||
{
|
||||
EVENT_NONE = -1, /* Don't use. */
|
||||
EVENT_LEFT_DOWN = 0,
|
||||
EVENT_LEFT_UP,
|
||||
EVENT_RIGHT_DOWN,
|
||||
EVENT_RIGHT_UP,
|
||||
EVENT_MOUSE_ENTER,
|
||||
EVENT_MOUSE_LEAVE,
|
||||
EVENT_MOUSE_MOVE,
|
||||
EVENT_SCROLL_UP,
|
||||
EVENT_SCROLL_DOWN
|
||||
} WidgetEvent;
|
||||
|
||||
typedef struct ContainerWidget
|
||||
{
|
||||
gboolean horizontal;
|
||||
@@ -107,29 +121,11 @@ typedef struct Widget
|
||||
float border_width;
|
||||
vec4 border_color;
|
||||
|
||||
void (*on_left_down) (struct Widget *, void *);
|
||||
void *left_down_data;
|
||||
void (*on_left_up) (struct Widget *, void *);
|
||||
void *left_up_data;
|
||||
void (*on_right_down) (struct Widget *, void *);
|
||||
void *right_down_data;
|
||||
void (*on_right_up) (struct Widget *, void *);
|
||||
void *right_up_data;
|
||||
|
||||
void (*on_mouse_enter) (struct Widget *, void *);
|
||||
void *mouse_enter_data;
|
||||
void (*on_mouse_leave) (struct Widget *, void *);
|
||||
void *mouse_leave_data;
|
||||
void (*on_mouse_move) (struct Widget *, void *);
|
||||
void *mouse_move_data;
|
||||
|
||||
void (*on_scroll_down) (struct Widget *, void *);
|
||||
void *scroll_down_data;
|
||||
void (*on_scroll_up) (struct Widget *, void *);
|
||||
void *scroll_up_data;
|
||||
|
||||
void (*on_tick) (struct Widget *, void *);
|
||||
void *tick_data;
|
||||
|
||||
void (*on_event[9]) (struct Widget *, void *);
|
||||
void *event_data[9];
|
||||
} Widget;
|
||||
|
||||
Widget *Widget_plain_new ();
|
||||
@@ -144,20 +140,20 @@ void Widget_add_child_weighed (Widget *parent, Widget *child,
|
||||
float layout_weight);
|
||||
|
||||
void Widget_set_on_tick (Widget *widget, void (*on_tick) (Widget *, void *), void *userdata);
|
||||
void Widget_set_on_left_up (Widget *widget, void (*on_left_up) (Widget *, void *), void *userdata);
|
||||
void Widget_set_on_event (Widget *widget, WidgetEvent event, void (*on_event) (Widget *, void *), void *userdata);
|
||||
|
||||
void Widget_label_set_text (Widget *widget, const char *text);
|
||||
void Widget_label_printf (Widget *widget, const char *format, ...);
|
||||
|
||||
void Widget_scrollable_scroll (Widget *widget, vec2 direction);
|
||||
|
||||
Widget *Widget_find_xy_matching (Widget *widget, vec2 pos, gboolean (*match_fn) (Widget *widget));
|
||||
Widget *Widget_find_xy_event (Widget *widget, vec2 pos, WidgetEvent event);
|
||||
Widget *Widget_find_xy (Widget *widget, vec2 point);
|
||||
|
||||
void ui_widget_mesh_init ();
|
||||
void Widget_tick (Widget *widget);
|
||||
void Widget_render (Widget *widget, mat4 projection, int window_height);
|
||||
|
||||
void Widget_label_set_text (Widget *widget, const char *text);
|
||||
void Widget_label_printf (Widget *widget, const char *format, ...);
|
||||
|
||||
void Widget_scrollable_scroll (Widget *widget, vec2 direction);
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
typedef struct LabelFormatData
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user