More scrollable improvements

This commit is contained in:
2025-06-14 19:00:22 +02:00
parent e64634c986
commit 3398eb1426
3 changed files with 120 additions and 78 deletions
+2 -2
View File
@@ -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);
+100 -64
View File
@@ -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;
}
+18 -12
View File
@@ -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);