diff --git a/game/src/ui/uiman.c b/game/src/ui/uiman.c index 123f27e..2eef95d 100644 --- a/game/src/ui/uiman.c +++ b/game/src/ui/uiman.c @@ -50,9 +50,9 @@ uiman_init () Widget_add_child_weighed (debug_menu, chkboxes, 1); Widget *content = Widget_label_new ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", TEXT_ALIGN_LEFT); - VEC2_SETI (content->size, 3000, 100); + VEC2_SETI (content->size, 3000, 500); - Widget *scrollable_window = Widget_composite_scrollable_make (TRUE, content); + Widget *scrollable_window = Widget_composite_scrollable_make (content); Widget_set_background_image (scrollable_window, RESTEX ("terrain4")); VEC2_SETI (scrollable_window->position, 390, 32); VEC2_SETI (scrollable_window->size, 350, 350); diff --git a/game/src/ui/widget.c b/game/src/ui/widget.c index cecad74..7b96085 100644 --- a/game/src/ui/widget.c +++ b/game/src/ui/widget.c @@ -42,10 +42,9 @@ Widget_label_new (const char *text, TextAlignment alignment) } Widget * -Widget_scrollable_new (gboolean horizontal) +Widget_scrollable_new () { Widget *e = ui_el_new_internal (WIDGET_SCROLLABLE); - e->scrollable.horizontal = horizontal; e->scrollable.scroll_amount = 5.0; return e; } @@ -71,10 +70,10 @@ Widget_add_child_weighed (Widget *parent, Widget *child, float layout_weight) } void -Widget_set_icon (Widget *widget, unsigned int icon_index) +Widget_set_icon (Widget *widget, WidgetIcon icon) { widget->has_icon = TRUE; - widget->icon_index = icon_index; + widget->icon = icon; } void @@ -118,11 +117,15 @@ Widget_label_printf (Widget *widget, const char *format, ...) } void -Widget_scrollable_scroll (Widget *widget, bool up) +Widget_scrollable_scroll (Widget *widget, vec2 direction) { - widget->scrollable.scroll_position += up ? widget->scrollable.scroll_amount : -widget->scrollable.scroll_amount; - float max_scroll = glm_max (0.0f, widget->scrollable.content_size - (widget->scrollable.horizontal ? widget->size[0] : widget->size[1])); - widget->scrollable.scroll_position = glm_clamp (widget->scrollable.scroll_position, 0.0f, max_scroll); + 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])); } gboolean @@ -148,20 +151,15 @@ Widget_find_xy (Widget *widget, vec2 pos) return NULL; } - vec2 pos_scrolled = { pos[0], pos[1] }; + vec2 pos_scrolled; + glm_vec2_copy (pos, pos_scrolled); + if (widget->kind == WIDGET_SCROLLABLE) { - if (widget->scrollable.horizontal) - { - pos_scrolled[0] += widget->scrollable.scroll_position; - } - else - { - pos_scrolled[1] += widget->scrollable.scroll_position; - } + glm_vec2_add (pos_scrolled, widget->scrollable.scroll_position, pos_scrolled); } - if (!Widget_hit_test (widget, pos)) + if (!Widget_hit_test (widget, pos_scrolled)) { return NULL; } @@ -169,7 +167,7 @@ Widget_find_xy (Widget *widget, vec2 pos) for (int i = widget->children->len - 1; i >= 0; --i) { Widget *child = g_array_index (widget->children, Widget *, i); - Widget *found = Widget_find_xy (child, pos); + Widget *found = Widget_find_xy (child, pos_scrolled); if (found != NULL) { @@ -247,42 +245,36 @@ Widget_label_render_text (Widget *widget, mat4 projection) } void -Widget_scrollable_layout (Widget *parent, gboolean horizontal) +Widget_scrollable_layout (Widget *parent) { - float content_size = 0.0f; + vec2 content_size = { 0.0 }; Widget *child; WIDGET_FOREACH_CHILD (parent, i, child) { - if (horizontal) - { - child->position[1] = parent->position[1]; - child->size[1] = parent->size[1]; - - if (child->layout_weight > 0) - { - child->size[0] = child->layout_weight * parent->size[0]; - } - - child->position[0] = parent->position[0] + content_size - parent->scrollable.scroll_position; - content_size += child->size[0]; - } - else - { - child->position[0] = parent->position[0]; - child->size[0] = parent->size[0]; + child->position[0] = parent->position[0] - parent->scrollable.scroll_position[0]; + child->position[1] = parent->position[1] - parent->scrollable.scroll_position[1]; - if (child->layout_weight > 0) - { - child->size[1] = child->layout_weight * parent->size[1]; - } + if (child->layout_weight > 0.0) + { + child->size[0] = child->layout_weight * parent->size[0]; + child->size[1] = child->layout_weight * parent->size[1]; + } - child->position[1] = parent->position[1] + content_size - parent->scrollable.scroll_position; - content_size += child->size[1]; - } + float right = child->position[0] + child->size[0]; + float bottom = child->position[1] + child->size[1]; + + if (right > content_size[0]) + { + content_size[0] = right; + } + if (bottom > content_size[1]) + { + content_size[1] = bottom; + } } - parent->scrollable.content_size = content_size; + glm_vec2_copy (content_size, parent->scrollable.content_size); } void @@ -398,7 +390,7 @@ Widget_render (Widget *widget, mat4 projection, int window_height) if (widget->kind == WIDGET_SCROLLABLE) { - Widget_scrollable_layout (widget, widget->scrollable.horizontal); + Widget_scrollable_layout (widget); } program_use (RESPRG ("uiwidget")); @@ -421,7 +413,7 @@ Widget_render (Widget *widget, mat4 projection, int window_height) } program_set_int (RESPRG ("uiwidget"), "has_icon", widget->has_icon); - program_set_float (RESPRG ("uiwidget"), "icon_index", widget->icon_index); + program_set_float (RESPRG ("uiwidget"), "icon_index", widget->icon); texture_use (RESTEX ("icons"), 1); mat3 model; @@ -520,7 +512,7 @@ void uicb_checkbox_show_flag (Widget *self, void *userdata) { char *flag = userdata; - self->icon_index = flags_get (flag) ? ICON_CHECKBOX_CHECKED : ICON_CHECKBOX_UNCHECKED; + self->icon = flags_get (flag) ? ICON_CHECKBOX_CHECKED : ICON_CHECKBOX_UNCHECKED; } void @@ -544,7 +536,7 @@ uicb_scrollable_scroll_down (Widget *self, void *userdata) { UNUSED (self); Widget *scrollable = userdata; - Widget_scrollable_scroll (scrollable, FALSE); + Widget_scrollable_scroll (scrollable, (vec2) { 0.0, 1.0 }); } void @@ -552,7 +544,23 @@ uicb_scrollable_scroll_up (Widget *self, void *userdata) { UNUSED (self); Widget *scrollable = userdata; - Widget_scrollable_scroll (scrollable, TRUE); + Widget_scrollable_scroll (scrollable, (vec2) { 0.0, -1.0 }); +} + +void +uicb_scrollable_scroll_left (Widget *self, void *userdata) +{ + UNUSED (self); + Widget *scrollable = userdata; + Widget_scrollable_scroll (scrollable, (vec2) { -1.0, 0.0 }); +} + +void +uicb_scrollable_scroll_right (Widget *self, void *userdata) +{ + UNUSED (self); + Widget *scrollable = userdata; + Widget_scrollable_scroll (scrollable, (vec2) { 1.0, 0.0 }); } Widget * @@ -613,29 +621,57 @@ Widget_composite_checkbox_make (const char *label, char *flag) } Widget * -Widget_composite_scrollable_make (gboolean horizontal, Widget *content) +Widget_composite_scrollable_make (Widget *content) { - Widget *cont1 = Widget_container_new (!horizontal, 8, 4); - Widget *scrollable = Widget_scrollable_new (horizontal); + Widget *cont_main = Widget_container_new (FALSE, 8, 4); + Widget *scrollable = Widget_scrollable_new (); Widget_add_child (scrollable, content); - Widget *scrollbarcont = Widget_container_new (horizontal, 0, 0); - Widget *scroll_down = Widget_plain_new (); Widget *scroll_up = Widget_plain_new (); + Widget *scroll_down = Widget_plain_new (); - Widget_set_icon (scroll_up, ICON_SPINNER_RIGHT); + Widget_set_icon (scroll_up, ICON_SPINNER_LEFT); Widget_set_on_left_click (scroll_up, uicb_scrollable_scroll_up, scrollable); scroll_up->aspect_ratio = 1.0; - Widget_set_icon (scroll_down, ICON_SPINNER_LEFT); + + Widget_set_icon (scroll_down, ICON_SPINNER_RIGHT); Widget_set_on_left_click (scroll_down, uicb_scrollable_scroll_down, scrollable); scroll_down->aspect_ratio = 1.0; - Widget_add_child_weighed (scrollbarcont, scroll_down, 1.0); - Widget_add_child_weighed (scrollbarcont, Widget_plain_new (), 1.0); - Widget_add_child_weighed (scrollbarcont, scroll_up, 1.0); + Widget *cont_horiz = Widget_container_new (TRUE, 0, 4); + Widget *scrollbar_vertical = Widget_container_new (FALSE, 0, 0); - Widget_add_child_weighed (cont1, scrollable, 0.93); - Widget_add_child_weighed (cont1, scrollbarcont, 0.07); + Widget_add_child_weighed (scrollbar_vertical, scroll_up, 1); + Widget_add_child_weighed (scrollbar_vertical, Widget_plain_new (), 1); + Widget_add_child_weighed (scrollbar_vertical, scroll_down, 1); + + Widget_add_child_weighed (cont_horiz, scrollable, 0.93); + Widget_add_child_weighed (cont_horiz, scrollbar_vertical, 0.07); + + Widget_add_child_weighed (cont_main, cont_horiz, 0.93); + + Widget *scroll_left = Widget_plain_new (); + Widget *scroll_right = Widget_plain_new (); + + Widget_set_icon (scroll_left, ICON_SPINNER_LEFT); + Widget_set_on_left_click (scroll_left, uicb_scrollable_scroll_left, scrollable); + scroll_left->aspect_ratio = 1.0; + + Widget_set_icon (scroll_right, ICON_SPINNER_RIGHT); + Widget_set_on_left_click (scroll_right, uicb_scrollable_scroll_right, scrollable); + scroll_right->aspect_ratio = 1.0; + + Widget *scrollbar_horizontal = Widget_container_new (TRUE, 0, 0); + + Widget *padding = Widget_plain_new (); + padding->aspect_ratio = 1.0; - return cont1; + Widget_add_child_weighed (scrollbar_horizontal, scroll_left, 1); + Widget_add_child_weighed (scrollbar_horizontal, Widget_plain_new (), 1); + Widget_add_child_weighed (scrollbar_horizontal, scroll_right, 1); + Widget_add_child_weighed (scrollbar_horizontal, padding, 1); + + Widget_add_child_weighed (cont_main, scrollbar_horizontal, 0.07); + + return cont_main; } diff --git a/game/src/ui/widget.h b/game/src/ui/widget.h index 7a1e118..2a02a1d 100644 --- a/game/src/ui/widget.h +++ b/game/src/ui/widget.h @@ -13,10 +13,7 @@ for (unsigned int i = 0; i < widget->children->len && \ ((child = g_array_index(widget->children, Widget *, i)), 1); ++i) -#define ICON_CHECKBOX_UNCHECKED 0 -#define ICON_CHECKBOX_CHECKED 1 -#define ICON_SPINNER_LEFT 2 -#define ICON_SPINNER_RIGHT 3 + typedef enum WidgetKind { @@ -49,12 +46,19 @@ typedef struct LabelWidget typedef struct ScrollableWidget { - gboolean horizontal; - float scroll_position; float scroll_amount; - float content_size; + vec2 scroll_position; + vec2 content_size; } ScrollableWidget; +typedef enum WidgetIcon + { + ICON_CHECKBOX_UNCHECKED = 0, + ICON_CHECKBOX_CHECKED, + ICON_SPINNER_LEFT, + ICON_SPINNER_RIGHT + } WidgetIcon; + typedef struct Widget { struct Widget *parent; @@ -83,7 +87,7 @@ typedef struct Widget unsigned int background_image; gboolean has_icon; - unsigned int icon_index; + WidgetIcon icon; float border_width; vec4 border_color; @@ -99,21 +103,21 @@ typedef struct Widget Widget *Widget_plain_new (); Widget *Widget_container_new (gboolean horizontal, float padding, float child_spacing); Widget *Widget_label_new (const char *text, TextAlignment alignment); -Widget *Widget_scrollable_new (gboolean horizontal); +Widget *Widget_scrollable_new (); void Widget_add_child (Widget *parent, Widget *child); void Widget_add_child_weighed (Widget *parent, Widget *child, float layout_weight); void Widget_set_background_image (Widget *widget, unsigned int image); -void Widget_set_icon (Widget *widget, unsigned int icon_index); +void Widget_set_icon (Widget *widget, WidgetIcon icon); void Widget_set_on_tick (Widget *widget, void (*on_tick) (Widget *, void *), void *userdata); void Widget_set_on_left_click (Widget *widget, void (*on_left_click) (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, bool up); +void Widget_scrollable_scroll (Widget *widget, vec2 direction); Widget *Widget_find_xy (Widget *widget, vec2 point); @@ -143,10 +147,12 @@ void uicb_decrement_int (Widget *self, void *userdata); void uicb_scrollable_scroll_down (Widget *self, void *userdata); void uicb_scrollable_scroll_up (Widget *self, void *userdata); +void uicb_scrollable_scroll_left (Widget *self, void *userdata); +void uicb_scrollable_scroll_right (Widget *self, void *userdata); Widget *Widget_label_make_int (const char *fmt, int *ptr, TextAlignment alignment); Widget *Widget_label_make_float (const char *fmt, float *ptr, TextAlignment alignment); Widget *Widget_composite_spinner_make_int (const char *format, int *ptr); Widget *Widget_composite_checkbox_make (const char *label, char *flag); -Widget *Widget_composite_scrollable_make (gboolean horizontal, Widget *content); +Widget *Widget_composite_scrollable_make (Widget *content);