Simplify UI events even more

This commit is contained in:
2025-06-15 17:59:11 +02:00
parent bae2e8cde4
commit 50efa5085c
2 changed files with 293 additions and 308 deletions
+259 -281
View File
@@ -2,17 +2,26 @@
static SimpleMesh quad;
static const Widget DEFAULT_WIDGET =
{
.kind = WIDGET_PLAIN,
.do_layout = NULL,
.do_render = Widget_render_base,
.visible = true,
.children = NULL,
.icon = ICON_NONE,
.background_color = { 0.0, 0.0, 0.0, 0.0 }
};
static inline Widget *
ui_el_new_internal (WidgetKind kind)
{
/* new0 instead of new is important, otherwise there's trash memory
in the function pointers */
Widget *e = g_new0 (Widget, 1);
*e = DEFAULT_WIDGET;
e->kind = kind;
e->visible = true;
e->children = g_array_new (false, false, sizeof (Widget *));
e->icon = ICON_NONE;
glm_vec4_zero (e->background_color);
return e;
}
@@ -26,6 +35,7 @@ Widget *
Widget_container_new (gboolean horizontal, float padding, float child_spacing)
{
Widget *e = ui_el_new_internal (WIDGET_CONTAINER);
e->do_layout = Widget_layout_container;
e->container.horizontal = horizontal;
e->container.padding = padding;
e->container.child_spacing = child_spacing;
@@ -36,6 +46,7 @@ Widget *
Widget_label_new (const char *text, TextAlignment alignment)
{
Widget *e = ui_el_new_internal (WIDGET_LABEL);
e->do_render = Widget_render_label;
e->label.text = g_string_new (text);
e->label.text_alignment = alignment;
glm_vec4_one (e->label.color);
@@ -46,6 +57,7 @@ Widget *
Widget_scrollable_new ()
{
Widget *e = ui_el_new_internal (WIDGET_SCROLLABLE);
e->do_layout = Widget_layout_scrollable;
e->scrollable.scroll_amount = 10.0;
return e;
}
@@ -54,20 +66,12 @@ Widget *
Widget_scrollbar_new (Widget *target, gboolean horizontal)
{
Widget *e = ui_el_new_internal (WIDGET_SCROLLBAR);
e->do_render = Widget_render_scrollbar;
e->scrollbar.target = target;
e->scrollbar.horizontal = horizontal;
return e;
}
Widget *
Widget_multiline_new (const char *text, TextAlignment alignment)
{
Widget *e = ui_el_new_internal (WIDGET_MULTILINE);
e->multiline.text = g_string_new (text);
e->multiline.alignment = alignment;
return e;
}
void
Widget_add_child (Widget *parent, Widget *child)
{
@@ -166,127 +170,26 @@ Widget_find_xy (Widget *widget, vec2 pos)
}
void
ui_widget_mesh_init ()
{
quad = SimpleMesh_make_quad1_ui ();
}
void
Widget_tick (Widget *widget)
{
if (widget->on_tick)
{
widget->on_tick (widget, widget->tick_data);
}
for (unsigned int i = 0; i < widget->children->len; ++i)
{
Widget *child = g_array_index (widget->children, Widget *, i);
Widget_tick (child);
}
}
void
Widget_label_render_text (Widget *widget, mat4 projection)
{
program_use (RESPRG ("uitext"));
program_set_mat4 (RESPRG ("uitext"), "projection", projection);
texture_use (RESTEX ("font0"), 0);
float char_width = widget->size[1] * 0.5;
float total_width = g_utf8_strlen (widget->label.text->str, -1) * char_width;
float offset = 0.0;
switch (widget->label.text_alignment)
{
case TEXT_ALIGN_LEFT:
offset = -char_width;
break;
case TEXT_ALIGN_CENTER:
offset = (widget->size[0] / 2) - (total_width / 2.0) -char_width;
break;
case TEXT_ALIGN_RIGHT:
offset = widget->size[0] - total_width - char_width;
break;
}
const char *p = widget->label.text->str;
while (*p)
{
gunichar ch = g_utf8_get_char (p);
program_set_float (RESPRG ("uitext"), "character", ch);
program_set_vec4 (RESPRG ("uitext"), "color", widget->label.color);
mat3 model;
glm_translate2d_make (model, (vec2) { widget->position[0] + offset + char_width, widget->position[1] });
glm_scale2d (model, (vec2) { char_width, widget->size[1] });
offset += char_width;
program_set_mat3 (RESPRG ("uitext"), "model", model);
SimpleMesh_render (&quad, FALSE);
p = g_utf8_next_char (p);
}
}
void
Widget_scrollable_layout (Widget *parent)
{
vec2 content_size = { 0.0 };
Widget *child;
WIDGET_FOREACH_CHILD (parent, i, child)
{
float logical_x = 0.0f;
float logical_y = 0.0f;
child->position[0] = parent->position[0] + logical_x - parent->scrollable.scroll_position[0];
child->position[1] = parent->position[1] + logical_y - parent->scrollable.scroll_position[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];
}
float right = logical_x + child->size[0];
float bottom = logical_y + child->size[1];
if (right > content_size[0])
{
content_size[0] = right;
}
if (bottom > content_size[1])
{
content_size[1] = bottom;
}
}
glm_vec2_copy (content_size, parent->scrollable.content_size);
}
void
Widget_container_layout (Widget *parent, gboolean horizontal)
Widget_layout_container (Widget *self)
{
float total_weights = 0.0;
float total_fixed = 0.0;
gboolean horizontal = self->container.horizontal;
Widget *child;
WIDGET_FOREACH_CHILD (parent, i, child)
WIDGET_FOREACH_CHILD (self, i, child)
{
if (child->layout_weight == 0.0 || child->aspect_ratio > 0.0)
{
if (horizontal)
{
float h = parent->size[1] - 2 * parent->container.padding;
float h = self->size[1] - 2 * self->container.padding;
child->size[1] = h;
child->size[0] = h * child->aspect_ratio;
}
else
{
float w = parent->size[0] - 2 * parent->container.padding;
float w = self->size[0] - 2 * self->container.padding;
child->size[0] = w;
child->size[1] = w / child->aspect_ratio;
}
@@ -299,13 +202,13 @@ Widget_container_layout (Widget *parent, gboolean horizontal)
}
}
float spacing_total = glm_max (0, parent->children->len - 1) * parent->container.child_spacing;
float total_size = (horizontal ? parent->size[0] : parent->size[1])
- 2.0 * parent->container.padding - spacing_total;
float spacing_total = glm_max (0, self->children->len - 1) * self->container.child_spacing;
float total_size = (horizontal ? self->size[0] : self->size[1])
- 2.0 * self->container.padding - spacing_total;
float weights_size = total_weights > 0.0 ? (total_size - total_fixed) / total_weights : 0;
float offset = parent->container.padding;
float offset = self->container.padding;
WIDGET_FOREACH_CHILD (parent, i, child)
WIDGET_FOREACH_CHILD (self, i, child)
{
float size;
@@ -335,98 +238,97 @@ Widget_container_layout (Widget *parent, gboolean horizontal)
if (horizontal)
{
child->size[0] = size;
child->size[1] = parent->size[1] - 2 * parent->container.padding;
child->size[1] = self->size[1] - 2 * self->container.padding;
}
else
{
child->size[1] = size;
child->size[0] = parent->size[0] - 2 * parent->container.padding;
child->size[0] = self->size[0] - 2 * self->container.padding;
}
}
}
if (horizontal)
{
VEC2_SETI (child->position, parent->position[0] + offset,
parent->position[1] + parent->container.padding);
VEC2_SETI (child->position, self->position[0] + offset,
self->position[1] + self->container.padding);
}
else
{
VEC2_SETI (child->position, parent->position[0] + parent->container.padding,
parent->position[1] + offset);
VEC2_SETI (child->position, self->position[0] + self->container.padding,
self->position[1] + offset);
}
offset += size + parent->container.child_spacing;
offset += size + self->container.child_spacing;
}
}
void
Widget_render (Widget *widget, mat4 projection, int window_height)
Widget_layout_scrollable (Widget *self)
{
if (!widget->visible)
vec2 content_size = { 0.0 };
Widget *child;
WIDGET_FOREACH_CHILD (self, i, child)
{
float logical_x = 0.0f;
float logical_y = 0.0f;
child->position[0] = self->position[0] + logical_x - self->scrollable.scroll_position[0];
child->position[1] = self->position[1] + logical_y - self->scrollable.scroll_position[1];
if (child->layout_weight > 0.0)
{
child->size[0] = child->layout_weight * self->size[0];
child->size[1] = child->layout_weight * self->size[1];
}
float right = logical_x + child->size[0];
float bottom = logical_y + child->size[1];
if (right > content_size[0])
{
content_size[0] = right;
}
if (bottom > content_size[1])
{
content_size[1] = bottom;
}
}
glm_vec2_copy (content_size, self->scrollable.content_size);
}
void
Widget_render_base (Widget *self, mat4 projection, int window_height)
{
if (!self->visible)
{
return;
}
if (widget->parent == NULL)
if (self->parent == NULL)
{
SimpleMesh_bind (&quad);
}
if (widget->kind == WIDGET_CONTAINER)
{
Widget_container_layout (widget, widget->container.horizontal);
}
if (widget->kind == WIDGET_SCROLLABLE)
{
Widget_scrollable_layout (widget);
}
program_use (RESPRG ("uiwidget"));
program_set_float (RESPRG ("uiwidget"), "border_width", widget->border_width);
program_set_vec4 (RESPRG ("uiwidget"), "border_color", widget->border_color);
program_set_vec2 (RESPRG ("uiwidget"), "widget_size", widget->size);
program_set_float (RESPRG ("uiwidget"), "border_width", self->border_width);
program_set_vec4 (RESPRG ("uiwidget"), "border_color", self->border_color);
program_set_vec2 (RESPRG ("uiwidget"), "widget_size", self->size);
program_set_int (RESPRG ("uiwidget"), "has_background_image", widget->background_image != 0);
texture_use (widget->background_image, 0); /* If it doesn't have a texture, it'll be 0 anyway. */
program_set_int (RESPRG ("uiwidget"), "has_background_image", self->background_image != 0);
texture_use (self->background_image, 0); /* If it doesn't have a texture, it'll be 0 anyway. */
program_set_vec4 (RESPRG ("uiwidget"), "background_color", widget->background_color);
program_set_vec4 (RESPRG ("uiwidget"), "background_color", self->background_color);
program_set_int (RESPRG ("uiwidget"), "has_icon", widget->icon != -1);
program_set_float (RESPRG ("uiwidget"), "icon_index", widget->icon);
program_set_int (RESPRG ("uiwidget"), "has_icon", self->icon != -1);
program_set_float (RESPRG ("uiwidget"), "icon_index", self->icon);
texture_use (RESTEX ("icons"), 1);
if (widget->kind == WIDGET_SCROLLBAR)
{
program_set_int (RESPRG ("uiwidget"), "has_scrollbar", TRUE);
/* Calculate the scrollbar size. */
unsigned int idx = widget->scrollbar.horizontal ? 0 : 1;
Widget *scr = widget->scrollbar.target;
float content_size = scr->scrollable.content_size[idx];
float scroll_pos = scr->scrollable.scroll_position[idx];
float view_size = scr->size[idx];
float thumb_size_norm = view_size / content_size;
float thumb_pos_norm = scroll_pos / content_size;
program_set_vec2 (RESPRG ("uiwidget"), "scrollbar_position", widget->scrollbar.horizontal
? (vec2) { thumb_pos_norm, 0.0f }
: (vec2) { 0.0f, thumb_pos_norm });
program_set_vec2 (RESPRG ("uiwidget"), "scrollbar_size", widget->scrollbar.horizontal
? (vec2) { thumb_size_norm, 1.0f }
: (vec2) { 1.0f, thumb_size_norm });
}
else
{
program_set_int (RESPRG ("uiwidget"), "has_scrollbar", FALSE);
}
mat3 model;
glm_translate2d_make (model, widget->position);
glm_scale2d (model, widget->size);
glm_translate2d_make (model, self->position);
glm_scale2d (model, self->size);
program_set_mat3 (RESPRG ("uiwidget"), "model", model);
program_set_mat4 (RESPRG ("uiwidget"), "projection", projection);
@@ -434,24 +336,24 @@ Widget_render (Widget *widget, mat4 projection, int window_height)
/* Before we render, we calculate the scissor box based on the
parents. */
vec2 widget_aabb[2] = {
{ widget->position[0], widget->position[1] },
{ widget->position[0] + widget->size[0], widget->position[1] + widget->size[1] }
vec2 self_aabb[2] = {
{ self->position[0], self->position[1] },
{ self->position[0] + self->size[0], self->position[1] + self->size[1] }
};
vec2 parent_aabb[2];
glm_vec2_copy (widget_aabb[0], parent_aabb[0]);
glm_vec2_copy (widget_aabb[1], parent_aabb[1]);
glm_vec2_copy (self_aabb[0], parent_aabb[0]);
glm_vec2_copy (self_aabb[1], parent_aabb[1]);
if (widget->parent != NULL)
if (self->parent != NULL)
{
glm_vec2_copy ((vec2) { widget->parent->position[0], widget->parent->position[1] }, parent_aabb[0]);
glm_vec2_copy ((vec2) { widget->parent->position[0] + widget->parent->size[0], widget->parent->position[1] + widget->parent->size[1] },
glm_vec2_copy ((vec2) { self->parent->position[0], self->parent->position[1] }, parent_aabb[0]);
glm_vec2_copy ((vec2) { self->parent->position[0] + self->parent->size[0], self->parent->position[1] + self->parent->size[1] },
parent_aabb[1]);
}
vec2 clipped_aabb[2];
glm_aabb2d_crop (widget_aabb, parent_aabb, clipped_aabb);
glm_aabb2d_crop (self_aabb, parent_aabb, clipped_aabb);
int x = roundf (clipped_aabb[0][0]);
int y = roundf (window_height - clipped_aabb[1][1]);
@@ -460,14 +362,117 @@ Widget_render (Widget *widget, mat4 projection, int window_height)
/* X, Y is the lower left corner of the box. */
glScissor (x, y, w, h);
SimpleMesh_render (&quad, FALSE);
}
if (widget->kind == WIDGET_LABEL)
void
Widget_render_label (Widget *self, mat4 projection, int window_height)
{
Widget_render_base (self, projection, window_height);
program_use (RESPRG ("uitext"));
program_set_mat4 (RESPRG ("uitext"), "projection", projection);
texture_use (RESTEX ("font0"), 0);
float char_width = self->size[1] * 0.5;
float total_width = g_utf8_strlen (self->label.text->str, -1) * char_width;
float offset = 0.0;
switch (self->label.text_alignment)
{
Widget_label_render_text (widget, projection);
case TEXT_ALIGN_LEFT:
offset = -char_width;
break;
case TEXT_ALIGN_CENTER:
offset = (self->size[0] / 2) - (total_width / 2.0) -char_width;
break;
case TEXT_ALIGN_RIGHT:
offset = self->size[0] - total_width - char_width;
break;
}
const char *p = self->label.text->str;
while (*p)
{
gunichar ch = g_utf8_get_char (p);
program_set_float (RESPRG ("uitext"), "character", ch);
program_set_vec4 (RESPRG ("uitext"), "color", self->label.color);
mat3 model;
glm_translate2d_make (model, (vec2) { self->position[0] + offset + char_width, self->position[1] });
glm_scale2d (model, (vec2) { char_width, self->size[1] });
offset += char_width;
program_set_mat3 (RESPRG ("uitext"), "model", model);
SimpleMesh_render (&quad, FALSE);
p = g_utf8_next_char (p);
}
}
void
Widget_render_scrollbar (Widget *self, mat4 projection, int window_height)
{
program_set_int (RESPRG ("uiwidget"), "has_scrollbar", TRUE);
/* Calculate the scrollbar size. */
unsigned int idx = self->scrollbar.horizontal ? 0 : 1;
Widget *scr = self->scrollbar.target;
float content_size = scr->scrollable.content_size[idx];
float scroll_pos = scr->scrollable.scroll_position[idx];
float view_size = scr->size[idx];
float thumb_size_norm = view_size / content_size;
float thumb_pos_norm = scroll_pos / content_size;
program_set_vec2 (RESPRG ("uiwidget"), "scrollbar_position", self->scrollbar.horizontal
? (vec2) { thumb_pos_norm, 0.0f }
: (vec2) { 0.0f, thumb_pos_norm });
program_set_vec2 (RESPRG ("uiwidget"), "scrollbar_size", self->scrollbar.horizontal
? (vec2) { thumb_size_norm, 1.0f }
: (vec2) { 1.0f, thumb_size_norm });
program_set_int (RESPRG ("uiwidget"), "has_scrollbar", FALSE);
Widget_render_base (self, projection, window_height);
}
void
ui_widget_mesh_init ()
{
quad = SimpleMesh_make_quad1_ui ();
}
void
Widget_tick (Widget *widget)
{
if (widget->on_tick)
{
widget->on_tick (widget, widget->tick_data);
}
for (unsigned int i = 0; i < widget->children->len; ++i)
{
Widget *child = g_array_index (widget->children, Widget *, i);
Widget_tick (child);
}
}
void
Widget_render (Widget *widget, mat4 projection, int window_height)
{
if (widget->do_layout)
{
widget->do_layout (widget);
}
if (widget->do_render)
{
widget->do_render (widget, projection, window_height);
}
Widget *child;
WIDGET_FOREACH_CHILD (widget, i, child)
{
@@ -504,91 +509,64 @@ Widget_scrollable_scroll (Widget *widget, vec2 direction)
/* --------- */
LabelFormatData *
LabelFormatData_new_int (const char *fmt, int *ptr)
WidgetOpData *
WidgetOpData_new (WidgetOp op, void *ptr, ...)
{
LabelFormatData *data = g_new (LabelFormatData, 1);
data->fmt = fmt;
data->ptr_int = ptr;
WidgetOpData *data = g_new0 (WidgetOpData, 1);
data->op = op;
data->ptr = ptr;
va_list ap;
va_start (ap, ptr);
switch (data->op)
{
case OP_LABEL_SHOW_INT:
case OP_LABEL_SHOW_FLOAT:
data->fmt = va_arg (ap, const char *);
break;
case OP_MODIFY_INT:
data->delta = (float) va_arg (ap, double);
break;
case OP_SCROLLABLE_SCROLL:
glm_vec2_copy (va_arg (ap, vec2), data->scroll_dir);
break;
default:
break;
}
va_end (ap);
return data;
}
LabelFormatData *
LabelFormatData_new_float (const char *fmt, float *ptr)
{
LabelFormatData *data = g_new (LabelFormatData, 1);
data->fmt = fmt;
data->ptr_float = ptr;
return data;
}
void
uicb_label_show_int (Widget *self, void *userdata)
uicb_widget_op (Widget *self, void *userdata)
{
LabelFormatData *format_data = userdata;
Widget_label_printf (self, format_data->fmt, *format_data->ptr_int);
}
WidgetOpData *data = userdata;
void
uicb_label_show_float (Widget *self, void *userdata)
{
LabelFormatData *format_data = userdata;
Widget_label_printf (self, format_data->fmt, *format_data->ptr_float);
}
void
uicb_switch_flag (Widget *self, void *userdata)
{
UNUSED (self);
char *flag = userdata;
flags_switch (flag);
}
void
uicb_checkbox_show_flag (Widget *self, void *userdata)
{
char *flag = userdata;
self->icon = flags_get (flag) ? ICON_CHECKBOX_CHECKED : ICON_CHECKBOX_UNCHECKED;
}
void
uicb_increment_int (Widget *self, void *userdata)
{
UNUSED (self);
int *val = userdata;
*val = *val + 1;
}
void
uicb_decrement_int (Widget *self, void *userdata)
{
UNUSED (self);
int *val = userdata;
*val = *val - 1;
}
void
uicb_set_background (Widget *self, void *userdata)
{
UNUSED (self);
vec4 *color = userdata;
glm_vec4_copy (*color, self->background_color);
}
void
uicb_scrollable_scroll_up (Widget *self, void *userdata)
{
UNUSED (self);
Widget *scrollable = userdata;
Widget_scrollable_scroll (scrollable, (vec2) { 0.0, -1.0 });
}
void
uicb_scrollable_scroll_down (Widget *self, void *userdata)
{
UNUSED (self);
Widget *scrollable = userdata;
Widget_scrollable_scroll (scrollable, (vec2) { 0.0, 1.0 });
switch (data->op)
{
case OP_SWITCH_FLAG:
flags_switch ((char *) data->ptr);
break;
case OP_LABEL_SHOW_INT:
Widget_label_printf (self, data->fmt, * (int *)data->ptr);
break;
case OP_LABEL_SHOW_FLOAT:
Widget_label_printf (self, data->fmt, * (float *)data->ptr);
break;
case OP_CHECKBOX_SHOW_FLAG:
self->icon = flags_get ((char *) data->ptr) ? ICON_CHECKBOX_CHECKED : ICON_CHECKBOX_UNCHECKED;
break;
case OP_MODIFY_INT:
*(int*) data->ptr += (int) data->delta;
break;
case OP_SCROLLABLE_SCROLL:
Widget_scrollable_scroll ((Widget *) data->ptr, data->scroll_dir);
break;
default:
break;
}
}
void
@@ -611,15 +589,15 @@ uicb_scrollbar_start_scroll (Widget *self, void *userdata)
float max_scroll = content_size - view_size;
float thumb_pos_norm = max_scroll > 0.0f
? scr->scrollable.scroll_position[idx] / max_scroll
: 0.0f;
? scr->scrollable.scroll_position[idx] / max_scroll
: 0.0f;
float thumb_start_px = thumb_pos_norm * (track_pixels - thumb_pixels);
float click_axis = self->scrollbar.horizontal ? mouse_pos[0] : mouse_pos[1];
float track_start = self->scrollbar.horizontal
? self->position[0]
: self->position[1];
? self->position[0]
: self->position[1];
self->scrollbar.drag_offset = click_axis - track_start - thumb_start_px;
self->scrollbar.dragging = TRUE;
@@ -648,7 +626,7 @@ uicb_scrollbar_scroll (Widget *self, void *userdata)
float track_start = self->scrollbar.horizontal ? self->position[0] : self->position[1];
float t = (click_axis - track_start - self->scrollbar.drag_offset)
/ track_pixels;
/ track_pixels;
t = glm_clamp (t, 0.0f, 1.0f);
float max_scroll = content_size - view_size;
@@ -667,7 +645,7 @@ Widget *
Widget_label_make_int (const char *fmt, int *ptr, TextAlignment alignment)
{
Widget *w = Widget_label_new (NULL, alignment);
Widget_set_on_tick (w, uicb_label_show_int, LabelFormatData_new_int (fmt, ptr));
Widget_set_on_tick (w, uicb_widget_op, WidgetOpData_new (OP_LABEL_SHOW_INT, ptr, fmt));
return w;
}
@@ -675,7 +653,7 @@ Widget *
Widget_label_make_float (const char *fmt, float *ptr, TextAlignment alignment)
{
Widget *w = Widget_label_new (NULL, alignment);
Widget_set_on_tick (w, uicb_label_show_float, LabelFormatData_new_float (fmt, ptr));
Widget_set_on_tick (w, uicb_widget_op, WidgetOpData_new (OP_LABEL_SHOW_FLOAT, ptr, fmt));
return w;
}
@@ -687,10 +665,10 @@ 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_decrement_int, ptr);
Widget_set_on_event (left, EVENT_LEFT_UP, 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_increment_int, ptr);
Widget_set_on_event (right, EVENT_LEFT_UP, uicb_widget_op, WidgetOpData_new (OP_MODIFY_INT, ptr, 1.0));
right->icon = ICON_SPINNER_RIGHT;
right->aspect_ratio = 1.0;
@@ -711,8 +689,8 @@ Widget_composite_checkbox_make (const char *label, char *flag)
box->icon = ICON_CHECKBOX_UNCHECKED;
box->aspect_ratio = 1.0;
Widget_set_on_tick (box, uicb_checkbox_show_flag, flag);
Widget_set_on_event (box, EVENT_LEFT_UP, uicb_switch_flag, flag);
Widget_set_on_tick (box, uicb_widget_op, WidgetOpData_new (OP_CHECKBOX_SHOW_FLAG, flag));
Widget_set_on_event (box, EVENT_LEFT_UP, uicb_widget_op, WidgetOpData_new (OP_SWITCH_FLAG, flag));
Widget_add_child_weighed (cont, box, 1);
Widget_add_child_weighed (cont, Widget_label_new (label, TEXT_ALIGN_LEFT), 1);
+34 -27
View File
@@ -19,8 +19,7 @@ typedef enum WidgetKind
WIDGET_CONTAINER,
WIDGET_LABEL,
WIDGET_SCROLLABLE,
WIDGET_SCROLLBAR,
WIDGET_MULTILINE
WIDGET_SCROLLBAR
} WidgetKind;
typedef enum WidgetIcon
@@ -87,12 +86,6 @@ typedef struct ScrollbarWidget
float drag_offset;
} ScrollbarWidget;
typedef struct MultilineWidget
{
GString *text;
TextAlignment alignment;
} MultilineWidget;
typedef struct Widget
{
struct Widget *parent;
@@ -104,7 +97,6 @@ typedef struct Widget
LabelWidget label;
ScrollableWidget scrollable;
ScrollbarWidget scrollbar;
MultilineWidget multiline;
};
gboolean visible;
@@ -121,6 +113,9 @@ typedef struct Widget
float border_width;
vec4 border_color;
void (*do_layout) (struct Widget *);
void (*do_render) (struct Widget *, mat4, int);
void (*on_tick) (struct Widget *, void *);
void *tick_data;
@@ -145,6 +140,13 @@ void Widget_set_on_event (Widget *widget, WidgetEvent event, void (*on_event) (W
Widget *Widget_find_xy_event (Widget *widget, vec2 pos, WidgetEvent event);
Widget *Widget_find_xy (Widget *widget, vec2 point);
void Widget_layout_container (Widget *self);
void Widget_layout_scrollable (Widget *self);
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 ui_widget_mesh_init ();
void Widget_tick (Widget *widget);
void Widget_render (Widget *widget, mat4 projection, int window_height);
@@ -155,28 +157,33 @@ void Widget_label_printf (Widget *widget, const char *format, ...);
void Widget_scrollable_scroll (Widget *widget, vec2 direction);
/* ---------------------------------------------- */
typedef struct LabelFormatData
typedef enum WidgetOp
{
OP_SWITCH_FLAG,
OP_MODIFY_INT,
OP_LABEL_SHOW_INT,
OP_LABEL_SHOW_FLOAT,
OP_CHECKBOX_SHOW_FLAG,
OP_SCROLLABLE_SCROLL,
OP_SCROLLBAR_START_SCROLL,
OP_SCROLLBAR_SCROLL,
OP_SCROLLBAR_STOP_SCROLL
} WidgetOp;
typedef struct WidgetOpData
{
WidgetOp op;
void *ptr;
/* These are used dependant on what you wanna do. */
const char *fmt;
union {
int *ptr_int;
float *ptr_float;
};
} LabelFormatData;
float delta;
vec2 scroll_dir;
} WidgetOpData;
LabelFormatData *LabelFormatData_new_int (const char *fmt, int *ptr);
LabelFormatData *LabelFormatData_new_float (const char *fmt, float *ptr);
WidgetOpData *WidgetOpData_new (WidgetOp op, void *ptr, ...);
void uicb_widget_op (Widget *self, void *userdata);
void uicb_label_show_int (Widget *self, void *userdata);
void uicb_label_show_float (Widget *self, void *userdata);
void uicb_checkbox_show_flag (Widget *self, void *userdata);
void uicb_switch_flag (Widget *self, void *userdata);
void uicb_increment_int (Widget *self, void *userdata);
void uicb_decrement_int (Widget *self, void *userdata);
void uicb_set_background (Widget *self, void *userdata);
void uicb_scrollable_scroll_up (Widget *self, void *userdata);
void uicb_scrollable_scroll_down (Widget *self, void *userdata);
void uicb_scrollbar_start_scroll (Widget *self, void *userdata);
void uicb_scrollbar_scroll (Widget *self, void *userdata);
void uicb_scrollbar_stop_scroll (Widget *self, void *userdata);