Vibe coded multiline text
This commit is contained in:
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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 ();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
|
||||
void Widget_layout_container (Widget *self);
|
||||
void Widget_layout_scrollable (Widget *self);
|
||||
void Widget_layout_multiline_text (Widget *self);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user