diff --git a/game/src/ui/uiman.c b/game/src/ui/uiman.c index 1c22a89..bfd043e 100644 --- a/game/src/ui/uiman.c +++ b/game/src/ui/uiman.c @@ -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 diff --git a/game/src/ui/widget.c b/game/src/ui/widget.c index 6210a89..c0df479 100644 --- a/game/src/ui/widget.c +++ b/game/src/ui/widget.c @@ -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,27 +687,12 @@ 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); @@ -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); diff --git a/game/src/ui/widget.h b/game/src/ui/widget.h index 34b713f..28963fc 100644 --- a/game/src/ui/widget.h +++ b/game/src/ui/widget.h @@ -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 {