Vibe coded multiline text

This commit is contained in:
2025-06-16 12:59:59 +02:00
parent d9877243e3
commit dd0eb68d46
11 changed files with 204 additions and 10 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.
+9 -6
View File
@@ -16,6 +16,13 @@ static mat4 projection;
static Widget *hovered_widget = NULL;
const char *lorem_ipsum =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut "
"labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris "
"nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit "
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in "
"culpa qui officia deserunt mollit anim id est laborum.";
void
uiman_init ()
{
@@ -52,17 +59,13 @@ uiman_init ()
window2->style->layout_padding = 8;
window2->style->background_image = RESTEX ("terrain0");
VEC2_SETI (window2->position, 414, 32);
VEC2_SETI (window2->size, 350, 200);
VEC2_SETI (window2->size, 400, 200);
Widget_add_child (ui_root, window2);
Widget *scrtest = Widget_scrollable_new ();
scrtest->scrollable.layout_horizontal = TRUE;
Widget *test1 = Widget_plain_new ();
test1->style->background_image = RESTEX ("terrain1");
test1->size[1] = 500;
Widget_add_child_weighed (scrtest, test1, 1);
Widget_add_child_weighed (scrtest, Widget_multiline_text_new (lorem_ipsum, 21, TEXT_ALIGN_LEFT), 1);
Widget_add_child_weighed (window2, scrtest, 0.95);
Widget_add_child_weighed (window2, Widget_scrollbar_new (scrtest, FALSE), 0.05);
}
+13
View File
@@ -100,6 +100,19 @@ Widget_progress_new (gboolean horizontal, float min, float max, float *ptr)
return e;
}
Widget *
Widget_multiline_text_new (const char *text, float line_height, TextAlignment alignment)
{
Widget *e = ui_el_new_internal (WIDGET_MULTILINE_TEXT);
e->do_layout = Widget_layout_multiline_text;
e->do_render = Widget_render_multiline_text;
e->multiline_text.text = g_string_new (text);
e->multiline_text.lines = g_array_new (FALSE, FALSE, sizeof (GString));
e->multiline_text.line_height = line_height;
e->multiline_text.text_alignment = alignment;
return e;
}
Widget *
Widget_container_new (gboolean horizontal)
{
+15 -2
View File
@@ -21,11 +21,14 @@
typedef enum WidgetKind
{
WIDGET_PLAIN,
WIDGET_CONTAINER,
WIDGET_LABEL,
WIDGET_SCROLLABLE,
WIDGET_SCROLLBAR,
WIDGET_PROGRESS,
WIDGET_MULTILINE_TEXT,
WIDGET_CONTAINER,
WIDGET_SCROLLABLE,
} WidgetKind;
typedef enum WidgetIcon
@@ -85,6 +88,14 @@ typedef struct ProgressWidget
float min, max, *ptr;
} ProgressWidget;
typedef struct MultilineTextWidget
{
GString *text;
GArray *lines;
float line_height;
TextAlignment text_alignment;
} MultilineTextWidget;
typedef struct ContainerWidget
{
gboolean horizontal;
@@ -110,6 +121,7 @@ typedef struct Widget
LabelWidget label;
ScrollbarWidget scrollbar;
ProgressWidget progress;
MultilineTextWidget multiline_text;
ContainerWidget container;
ScrollableWidget scrollable;
@@ -141,6 +153,7 @@ Widget *Widget_plain_new ();
Widget *Widget_label_new (const char *text, TextAlignment alignment);
Widget *Widget_scrollbar_new (Widget *target, gboolean horizontal);
Widget *Widget_progress_new (gboolean horizontal, float min, float max, float *ptr);
Widget *Widget_multiline_text_new (const char *text, float line_height, TextAlignment alignment);
Widget *Widget_container_new (gboolean horizontal);
Widget *Widget_scrollable_new ();
+95
View File
@@ -108,3 +108,98 @@ Widget_layout_scrollable (Widget *self)
glm_vec2_copy (content_size, self->scrollable.content_size);
self->layout_dirty = FALSE;
}
void
Widget_layout_multiline_text (Widget *self)
/* Vibe coded. Dunno what the fuck it does. */
{
if (self->multiline_text.lines)
{
for (guint i = 0; i < self->multiline_text.lines->len; ++i)
{
GString *old = g_array_index (self->multiline_text.lines, GString *, i);
g_string_free (old, TRUE);
}
g_array_free (self->multiline_text.lines, TRUE);
}
GArray *lines = g_array_new (FALSE, FALSE, sizeof (GString *));
self->multiline_text.lines = lines;
float pad = self->style->layout_padding;
float row_h = self->multiline_text.line_height;
float char_w = row_h * (9.0 / 20.0);
float usable = self->size[0] - 2 * pad;
const char *p = self->multiline_text.text->str;
GString *cur = g_string_new (NULL);
float cur_w = 0.0;
while (*p)
{
const char *end = p;
while (*end && *end != ' ' && *end != '\n')
{
end++;
}
size_t wb = end - p;
size_t wc = g_utf8_strlen (p, wb);
float w = wc * char_w;
if (*end == '\n' || (cur_w > 0 && cur_w + char_w + w > usable))
{
g_array_append_val (lines, cur);
cur = g_string_new (NULL);
cur_w = 0.0f;
}
if (cur->len > 0 && *p != '\n')
{
g_string_append_c (cur, ' ');
cur_w += char_w;
}
g_string_append_len (cur, p, wb);
cur_w += w;
if (*end == '\n')
{
g_array_append_val (lines, cur);
cur = g_string_new (NULL);
cur_w = 0.0;
p = end + 1;
}
else
{
p = end;
while (*p == ' ')
{
p++;
}
}
}
if (cur->len > 0)
{
g_array_append_val (lines, cur);
}
else
{
g_string_free (cur, TRUE);
}
self->size[1] = pad * 2 + lines->len * row_h;
self->layout_dirty = FALSE;
/* Just a hack. In case the multiline text is inside a scrollable
(which, most of the time, would be the case) we have to update
the scrollable, so it can set it's content_size properly and the
scrollbar can be the right size. */
if (self->parent)
{
self->parent->layout_dirty = TRUE;
}
}
+1
View File
@@ -5,3 +5,4 @@
void Widget_layout_container (Widget *self);
void Widget_layout_scrollable (Widget *self);
void Widget_layout_multiline_text (Widget *self);
+70 -2
View File
@@ -98,7 +98,7 @@ Widget_render_label (Widget *self, mat4 projection, int window_height)
program_use (RESPRG ("uitext"));
program_set_mat4 (RESPRG ("uitext"), "projection", projection);
texture_use (self->style->font_bitmap, 0);
texture_use (style->font_bitmap, 0);
program_set_vec4 (RESPRG ("uitext"), "color", style->text_color);
@@ -111,7 +111,7 @@ Widget_render_label (Widget *self, mat4 projection, int window_height)
program_set_vec4 (RESPRG ("uitext"), "color", style->text_color_hovered);
}
float char_width = self->size[1] * 0.5;
float char_width = self->size[1] * (9.0 / 20.0);
float total_width = g_utf8_strlen (self->label.text->str, -1) * char_width;
float offset = 0.0;
@@ -208,3 +208,71 @@ Widget_render_progress (Widget *self, mat4 projection, int window_height)
Widget_render_base (self, projection, window_height);
program_set_int (RESPRG ("uiwidget"), "has_progress", FALSE);
}
void
Widget_render_multiline_text (Widget *self, mat4 projection, int window_height)
{
Widget_render_base(self, projection, window_height);
WidgetStyle *style = self->style;
program_use (RESPRG ("uitext"));
program_set_mat4 (RESPRG ("uitext"), "projection", projection);
texture_use (style->font_bitmap, 0);
program_set_vec4 (RESPRG ("uitext"), "color", style->text_color);
float pad = style->layout_padding;
guint lines = self->multiline_text.lines->len;
if (lines == 0)
{
return;
}
float row_h = self->multiline_text.line_height;
float char_w = row_h * (9.0 / 20.0);
float x0 = self->position[0] + pad;
float y0 = self->position[1] + pad;
float usable = self->size[0] - 2 * pad;
for (guint i = 0; i < lines; ++i)
{
GString *line = g_array_index (self->multiline_text.lines, GString *, i);
guint nchars = g_utf8_strlen (line->str, -1);
float line_w = nchars * char_w;
float y = y0 + i * row_h;
float x;
switch (self->multiline_text.text_alignment)
{
case TEXT_ALIGN_CENTER:
x = x0 + (usable - line_w) * 0.5;
break;
case TEXT_ALIGN_RIGHT:
x = x0 + (usable - line_w);
break;
case TEXT_ALIGN_LEFT:
default:
x = x0;
break;
}
const char *p = line->str;
while (*p)
{
gunichar ch = g_utf8_get_char (p);
program_set_float (RESPRG ("uitext"), "character", ch);
mat3 model;
glm_translate2d_make (model, (vec2) { x, y });
glm_scale2d (model, (vec2) { char_w, row_h });
program_set_mat3 (RESPRG ("uitext"), "model", model);
SimpleMesh_render (&quad, FALSE);
x += char_w;
p = g_utf8_next_char (p);
}
}
}
+1
View File
@@ -11,3 +11,4 @@ void Widget_render_base (Widget *self, mat4 projection, int window_height);
void Widget_render_label (Widget *self, mat4 projection, int window_height);
void Widget_render_scrollbar (Widget *self, mat4 projection, int window_height);
void Widget_render_progress (Widget *self, mat4 projection, int window_height);
void Widget_render_multiline_text (Widget *self, mat4 projection, int window_height);