From 5320c69f7da6944d0471d94ce53ac588390946cf Mon Sep 17 00:00:00 2001 From: Emil Kosz Date: Mon, 16 Jun 2025 09:34:42 +0200 Subject: [PATCH] Misc --- game/src/ui/uiman.c | 29 +++++++++++-- game/src/ui/widget_composites.c | 34 ++++++++++++++- game/src/ui/widget_core.c | 73 ++++++++++++++++++++------------- game/src/ui/widget_core.h | 34 +++++++-------- game/src/ui/widget_render.c | 28 +++++++++++-- game/src/ui/widget_style.h | 10 +++++ 6 files changed, 154 insertions(+), 54 deletions(-) diff --git a/game/src/ui/uiman.c b/game/src/ui/uiman.c index 894f01f..df03e4a 100644 --- a/game/src/ui/uiman.c +++ b/game/src/ui/uiman.c @@ -47,8 +47,6 @@ uiman_init () Widget_add_child_weighed (chkboxes, Widget_composite_checkbox_make ("Wireframe", "wireframe_enabled"), 1); Widget_add_child_weighed (chkboxes, Widget_composite_checkbox_make ("Flight", "flight_enabled"), 1); Widget_add_child_weighed (debug_menu, chkboxes, 1); - - Widget_add_child_weighed (debug_menu, Widget_progress_new (TRUE, 0.0, 0.1, &delta_time), 1); } void @@ -81,6 +79,24 @@ _uiman_call_on_event (Widget *widget, WidgetEvent event) return FALSE; } +static inline void +_uiman_set_clicked (Widget *widget, gboolean state) +{ + if (widget) + { + widget->clicked = state; + } +} + +static inline void +_uiman_set_hovered (Widget *widget, gboolean state) +{ + if (widget) + { + widget->hovered = state; + } +} + gboolean uiman_cb_switch_focus (SDL_Event *event, void *data) { @@ -123,7 +139,10 @@ uiman_cb_mouse_motion (SDL_Event *event, void *data) if (new_hover != hovered_widget) { _uiman_call_on_event (hovered_widget, EVENT_MOUSE_LEAVE); + _uiman_set_hovered (hovered_widget, FALSE); + _uiman_set_clicked (hovered_widget, FALSE); _uiman_call_on_event (new_hover, EVENT_MOUSE_ENTER); + _uiman_set_hovered (new_hover, TRUE); hovered_widget = new_hover; } @@ -140,7 +159,8 @@ uiman_cb_button_down (SDL_Event *event, void *data) UNUSED (data); 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); + Widget *widget = Widget_find_xy (ui_root, (vec2) { event->button.x, event->button.y }); + _uiman_set_clicked (widget, TRUE); return _uiman_call_on_event (widget, e); } @@ -150,7 +170,8 @@ uiman_cb_button_up (SDL_Event *event, void *data) UNUSED (data); 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); + Widget *widget = Widget_find_xy (ui_root, (vec2) { event->button.x, event->button.y }); + _uiman_set_clicked (widget, FALSE); return _uiman_call_on_event (widget, e); } diff --git a/game/src/ui/widget_composites.c b/game/src/ui/widget_composites.c index 6c06736..378d15e 100644 --- a/game/src/ui/widget_composites.c +++ b/game/src/ui/widget_composites.c @@ -1,5 +1,30 @@ #include "widget_composites.h" +WidgetStyle widget_style_icon_button = + { + .background_color = { 0.0, 0.0, 0.0, 0.0 }, + .background_color_hovered = { 0.0, 0.0, 0.0, 0.0 }, + .background_color_clicked = { 0.0, 0.0, 0.0, 0.0 }, + + .text_color = { 1.0, 1.0, 1.0, 1.0 }, + .text_color_hovered = { 1.0, 1.0, 1.0, 1.0 }, + .text_color_clicked = { 1.0, 1.0, 1.0, 1.0 }, + + .icon_color = { 1.0, 1.0, 1.0, 1.0 }, + .icon_color_hovered = { 1.0, 1.0, 0.0, 1.0 }, + .icon_color_clicked = { 1.0, 0.0, 0.0, 1.0 }, + + .border_color = { 1.0, 1.0, 1.0, 1.0 }, + .progress_color = { 1.0, 1.0, 1.0, 1.0 }, + + .border_width = 0, + .layout_padding = 0, + .layout_child_spacing = 8, + + .background_image = 0, + .font_bitmap = 0 + }; + Widget * Widget_label_make_int (const char *fmt, int *ptr, TextAlignment alignment) { @@ -24,10 +49,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_event (left, EVENT_LEFT_UP, uicb_widget_op, WidgetOpData_new (OP_MODIFY_INT, ptr, -1.0)); + Widget_set_style (left, widget_style_icon_button); + Widget_set_style (right, widget_style_icon_button); + + Widget_set_on_event (left, EVENT_LEFT_DOWN, uicb_widget_op, WidgetOpData_new (OP_MODIFY_INT, ptr, -1.0)); left->icon = ICON_SPINNER_LEFT; left->aspect_ratio = 1.0; - Widget_set_on_event (right, EVENT_LEFT_UP, uicb_widget_op, WidgetOpData_new (OP_MODIFY_INT, ptr, 1.0)); + Widget_set_on_event (right, EVENT_LEFT_DOWN, uicb_widget_op, WidgetOpData_new (OP_MODIFY_INT, ptr, 1.0)); right->icon = ICON_SPINNER_RIGHT; right->aspect_ratio = 1.0; @@ -46,6 +74,8 @@ Widget_composite_checkbox_make (const char *label, char *flag) Widget *cont = Widget_container_new (TRUE); Widget *box = Widget_plain_new (); + Widget_set_style (box, widget_style_icon_button); + box->icon = ICON_CHECKBOX_UNCHECKED; box->aspect_ratio = 1.0; Widget_set_on_tick (box, uicb_widget_op, WidgetOpData_new (OP_CHECKBOX_SHOW_FLAG, flag)); diff --git a/game/src/ui/widget_core.c b/game/src/ui/widget_core.c index f62d427..d231822 100644 --- a/game/src/ui/widget_core.c +++ b/game/src/ui/widget_core.c @@ -11,11 +11,20 @@ static const Widget DEFAULT_WIDGET = .icon = ICON_NONE }; -WidgetStyle DEFAULT_STYLE = +WidgetStyle widget_style_default = { - .background_color = { 0.0, 0.0, 0.0, 0.0 }, - .text_color = { 1.0, 1.0, 1.0, 1.0 }, - .icon_color = { 1.0, 1.0, 1.0, 1.0 }, + .background_color = { 0.0, 0.0, 0.0, 0.0 }, + .background_color_hovered = { 0.0, 0.0, 0.0, 0.0 }, + .background_color_clicked = { 0.0, 0.0, 0.0, 0.0 }, + + .text_color = { 1.0, 1.0, 1.0, 1.0 }, + .text_color_hovered = { 1.0, 1.0, 1.0, 1.0 }, + .text_color_clicked = { 1.0, 1.0, 1.0, 1.0 }, + + .icon_color = { 1.0, 1.0, 1.0, 1.0 }, + .icon_color_hovered = { 1.0, 1.0, 1.0, 1.0 }, + .icon_color_clicked = { 1.0, 1.0, 1.0, 1.0 }, + .border_color = { 1.0, 1.0, 1.0, 1.0 }, .progress_color = { 1.0, 1.0, 1.0, 1.0 }, @@ -23,7 +32,8 @@ WidgetStyle DEFAULT_STYLE = .layout_padding = 0, .layout_child_spacing = 8, - .background_image = 0 + .background_image = 0, + .font_bitmap = 0 }; static inline Widget * @@ -35,7 +45,8 @@ ui_el_new_internal (WidgetKind kind) *e = DEFAULT_WIDGET; e->kind = kind; e->children = g_array_new (false, false, sizeof (Widget *)); - e->style = g_memdup2 (&DEFAULT_STYLE, sizeof (WidgetStyle)); + Widget_set_style (e, widget_style_default); + e->style->font_bitmap = RESTEX ("font0"); return e; } @@ -45,15 +56,6 @@ Widget_plain_new () return ui_el_new_internal (WIDGET_PLAIN); } -Widget * -Widget_container_new (gboolean horizontal) -{ - Widget *e = ui_el_new_internal (WIDGET_CONTAINER); - e->do_layout = Widget_layout_container; - e->container.horizontal = horizontal; - return e; -} - Widget * Widget_label_new (const char *text, TextAlignment alignment) { @@ -64,19 +66,6 @@ Widget_label_new (const char *text, TextAlignment alignment) return e; } -Widget * -Widget_scrollable_new () -{ - Widget *e = ui_el_new_internal (WIDGET_SCROLLABLE); - e->do_layout = Widget_layout_scrollable; - e->scrollable.scroll_amount = 10.0; - Widget_set_on_event (e, EVENT_SCROLL_UP, uicb_widget_op, - WidgetOpData_new (OP_SCROLLABLE_SCROLL, e, (vec2) { 0.0, -1.0 })); - Widget_set_on_event (e, EVENT_SCROLL_DOWN, uicb_widget_op, - WidgetOpData_new (OP_SCROLLABLE_SCROLL, e, (vec2) { 0.0, 1.0 })); - return e; -} - Widget * Widget_scrollbar_new (Widget *target, gboolean horizontal) { @@ -103,6 +92,28 @@ Widget_progress_new (gboolean horizontal, float min, float max, float *ptr) return e; } +Widget * +Widget_container_new (gboolean horizontal) +{ + Widget *e = ui_el_new_internal (WIDGET_CONTAINER); + e->do_layout = Widget_layout_container; + e->container.horizontal = horizontal; + return e; +} + +Widget * +Widget_scrollable_new () +{ + Widget *e = ui_el_new_internal (WIDGET_SCROLLABLE); + e->do_layout = Widget_layout_scrollable; + e->scrollable.scroll_amount = 10.0; + Widget_set_on_event (e, EVENT_SCROLL_UP, uicb_widget_op, + WidgetOpData_new (OP_SCROLLABLE_SCROLL, e, (vec2) { 0.0, -1.0 })); + Widget_set_on_event (e, EVENT_SCROLL_DOWN, uicb_widget_op, + WidgetOpData_new (OP_SCROLLABLE_SCROLL, e, (vec2) { 0.0, 1.0 })); + return e; +} + void Widget_add_child (Widget *parent, Widget *child) { @@ -139,6 +150,12 @@ Widget_set_on_event (Widget *widget, WidgetEvent event, widget->event_data[event] = userdata; } +void +Widget_set_style (Widget *widget, WidgetStyle style) +{ + widget->style = g_memdup2 (&style, sizeof (WidgetStyle)); +} + void Widget_label_set_text (Widget *widget, const char *text) { diff --git a/game/src/ui/widget_core.h b/game/src/ui/widget_core.h index 79be4b0..7eae149 100644 --- a/game/src/ui/widget_core.h +++ b/game/src/ui/widget_core.h @@ -64,24 +64,12 @@ typedef enum TextAlignment TEXT_ALIGN_RIGHT } TextAlignment; -typedef struct ContainerWidget -{ - gboolean horizontal; -} ContainerWidget; - typedef struct LabelWidget { GString *text; TextAlignment text_alignment; } LabelWidget; -typedef struct ScrollableWidget -{ - float scroll_amount; - vec2 scroll_position; - vec2 content_size; -} ScrollableWidget; - typedef struct ScrollbarWidget { struct Widget *target; @@ -97,6 +85,18 @@ typedef struct ProgressWidget float min, max, *ptr; } ProgressWidget; +typedef struct ContainerWidget +{ + gboolean horizontal; +} ContainerWidget; + +typedef struct ScrollableWidget +{ + float scroll_amount; + vec2 scroll_position; + vec2 content_size; +} ScrollableWidget; + typedef struct Widget { struct Widget *parent; @@ -104,11 +104,12 @@ typedef struct Widget WidgetKind kind; union { - ContainerWidget container; LabelWidget label; - ScrollableWidget scrollable; ScrollbarWidget scrollbar; ProgressWidget progress; + + ContainerWidget container; + ScrollableWidget scrollable; }; gboolean visible; @@ -134,11 +135,11 @@ typedef struct Widget } Widget; Widget *Widget_plain_new (); -Widget *Widget_container_new (gboolean horizontal); Widget *Widget_label_new (const char *text, TextAlignment alignment); -Widget *Widget_scrollable_new (); Widget *Widget_scrollbar_new (Widget *target, gboolean horizontal); Widget *Widget_progress_new (gboolean horizontal, float min, float max, float *ptr); +Widget *Widget_container_new (gboolean horizontal); +Widget *Widget_scrollable_new (); void Widget_add_child (Widget *parent, Widget *child); void Widget_add_child_weighed (Widget *parent, Widget *child, @@ -146,6 +147,7 @@ void Widget_add_child_weighed (Widget *parent, Widget *child, void Widget_set_on_tick (Widget *widget, void (*on_tick) (Widget *, void *), void *userdata); void Widget_set_on_event (Widget *widget, WidgetEvent event, void (*on_event) (Widget *, void *), void *userdata); +void Widget_set_style (Widget *widget, WidgetStyle style); void Widget_label_set_text (Widget *widget, const char *text); void Widget_label_printf (Widget *widget, const char *format, ...); diff --git a/game/src/ui/widget_render.c b/game/src/ui/widget_render.c index 23b287e..5819963 100644 --- a/game/src/ui/widget_render.c +++ b/game/src/ui/widget_render.c @@ -31,13 +31,24 @@ Widget_render_base (Widget *self, mat4 projection, int window_height) program_set_int (RESPRG ("uiwidget"), "has_background_image", style->background_image != 0); texture_use (style->background_image, 0); /* If it doesn't have a texture, it'll be 0 anyway. */ - program_set_vec4 (RESPRG ("uiwidget"), "background_color", style->background_color); - program_set_int (RESPRG ("uiwidget"), "has_icon", self->icon != -1); program_set_float (RESPRG ("uiwidget"), "icon_index", self->icon); - program_set_vec4 (RESPRG ("uiwidget"), "icon_color", style->icon_color); texture_use (RESTEX ("icons"), 1); + + program_set_vec4 (RESPRG ("uiwidget"), "background_color", style->background_color); + program_set_vec4 (RESPRG ("uiwidget"), "icon_color", style->icon_color); + if (self->clicked) + { + program_set_vec4 (RESPRG ("uiwidget"), "background_color", style->background_color_clicked); + program_set_vec4 (RESPRG ("uiwidget"), "icon_color", style->icon_color_clicked); + } + else if (self->hovered) + { + program_set_vec4 (RESPRG ("uiwidget"), "background_color", style->background_color_hovered); + program_set_vec4 (RESPRG ("uiwidget"), "icon_color", style->icon_color_hovered); + } + mat3 model; glm_translate2d_make (model, self->position); glm_scale2d (model, self->size); @@ -87,7 +98,16 @@ Widget_render_label (Widget *self, mat4 projection, int window_height) program_use (RESPRG ("uitext")); program_set_mat4 (RESPRG ("uitext"), "projection", projection); program_set_vec4 (RESPRG ("uitext"), "color", style->text_color); - texture_use (RESTEX ("font0"), 0); + texture_use (self->style->font_bitmap, 0); + + if (self->clicked) + { + program_set_vec4 (RESPRG ("uitext"), "color", style->text_color_clicked); + } + else if (self->hovered) + { + program_set_vec4 (RESPRG ("uitext"), "color", style->text_color_hovered); + } float char_width = self->size[1] * 0.5; float total_width = g_utf8_strlen (self->label.text->str, -1) * char_width; diff --git a/game/src/ui/widget_style.h b/game/src/ui/widget_style.h index 9022f53..c5567a3 100644 --- a/game/src/ui/widget_style.h +++ b/game/src/ui/widget_style.h @@ -6,8 +6,17 @@ typedef struct WidgetStyle { vec4 background_color; + vec4 background_color_hovered; + vec4 background_color_clicked; + vec4 text_color; + vec4 text_color_hovered; + vec4 text_color_clicked; + vec4 icon_color; + vec4 icon_color_hovered; + vec4 icon_color_clicked; + vec4 border_color; vec4 progress_color; @@ -17,5 +26,6 @@ typedef struct WidgetStyle float layout_child_spacing; unsigned int background_image; + unsigned int font_bitmap; } WidgetStyle;