diff --git a/game/src/ui/widget.c b/game/src/ui/widget.c index c0df479..9505a90 100644 --- a/game/src/ui/widget.c +++ b/game/src/ui/widget.c @@ -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); diff --git a/game/src/ui/widget.h b/game/src/ui/widget.h index 28963fc..a2880ab 100644 --- a/game/src/ui/widget.h +++ b/game/src/ui/widget.h @@ -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);