Revamp the UI event system a bit

This commit is contained in:
2025-06-15 16:46:51 +02:00
parent d72fb81ebf
commit bae2e8cde4
3 changed files with 87 additions and 169 deletions
+24 -74
View File
@@ -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
View File
@@ -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
View File
@@ -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
{