aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO3
m---------depends/mgl0
-rw-r--r--include/mgui/button.h5
-rw-r--r--include/mgui/image.h5
-rw-r--r--include/mgui/label.h7
-rw-r--r--include/mgui/list.h14
-rw-r--r--include/mgui/mgui.h2
-rw-r--r--include/mgui/richtext.h5
-rw-r--r--include/mgui/scrollview.h7
-rw-r--r--include/mgui/widget.h42
-rw-r--r--src/mgui/button.c17
-rw-r--r--src/mgui/image.c61
-rw-r--r--src/mgui/label.c29
-rw-r--r--src/mgui/list.c130
-rw-r--r--src/mgui/mgui.c9
-rw-r--r--src/mgui/richtext.c58
-rw-r--r--src/mgui/scrollview.c81
-rw-r--r--src/mgui/widget.c91
-rw-r--r--tests/main.c19
19 files changed, 393 insertions, 192 deletions
diff --git a/TODO b/TODO
index 866aa89..a898137 100644
--- a/TODO
+++ b/TODO
@@ -2,4 +2,5 @@ Widget alignment.
Widget horizontal/vertical expand.
Homogeneous sizing for list items.
Allow setting list direction. This is more efficient than prepending widgets to a list.
-Stop rendering scroll view when reaching outside the scissor view. \ No newline at end of file
+Stop rendering scroll view when reaching outside the scissor view.
+Widgets such as richtext and label should unload their text when updated but not rendered, this allows the widget to save its render size without saving the render data. \ No newline at end of file
diff --git a/depends/mgl b/depends/mgl
-Subproject e52886f8bea55fb3c9ff973b16ed812549cd1f2
+Subproject 08b27c7854cf38d3f03b0607f06c0140d6dc795
diff --git a/include/mgui/button.h b/include/mgui/button.h
index 986cb9c..f8e223c 100644
--- a/include/mgui/button.h
+++ b/include/mgui/button.h
@@ -20,9 +20,8 @@ mgui_widget* mgui_button_to_widget(mgui_button *list);
mgui_button* mgui_widget_to_button(mgui_widget *widget);
void mgui_button_set_position(mgui_button *self, mgl_vec2i position);
-void mgui_button_set_width(mgui_button *self, int width);
+void mgui_button_calculate_size(mgui_button *self, mgl_vec2i max_size);
void mgui_button_on_event(mgui_button *self, mgl_window *window, mgl_event *event);
-/* Returns the size of the widget */
-mgl_vec2i mgui_button_draw(mgui_button *self, mgl_window *window);
+void mgui_button_draw(mgui_button *self, mgl_window *window);
#endif /* MGUI_BUTTON_H */
diff --git a/include/mgui/image.h b/include/mgui/image.h
index 8d34a7a..e6787f2 100644
--- a/include/mgui/image.h
+++ b/include/mgui/image.h
@@ -15,9 +15,8 @@ mgui_widget* mgui_image_to_widget(mgui_image *list);
mgui_image* mgui_widget_to_image(mgui_widget *widget);
void mgui_image_set_position(mgui_image *self, mgl_vec2i position);
-void mgui_image_set_width(mgui_image *self, int width);
+void mgui_image_calculate_size(mgui_image *self, mgl_vec2i max_size);
void mgui_image_on_event(mgui_image *self, mgl_window *window, mgl_event *event);
-/* Returns the size of the widget */
-mgl_vec2i mgui_image_draw(mgui_image *self, mgl_window *window);
+void mgui_image_draw(mgui_image *self, mgl_window *window);
#endif /* MGUI_IMAGE_H */
diff --git a/include/mgui/label.h b/include/mgui/label.h
index 4b66ef8..ef1369b 100644
--- a/include/mgui/label.h
+++ b/include/mgui/label.h
@@ -10,8 +10,6 @@ typedef struct {
char *str;
size_t str_size;
mgl_text text;
- mgl_vec2i position;
- int width;
} mgui_label;
mgui_label* mgui_label_create(const char *str, size_t size, unsigned char character_size);
@@ -20,9 +18,8 @@ mgui_widget* mgui_label_to_widget(mgui_label *list);
mgui_label* mgui_widget_to_label(mgui_widget *widget);
void mgui_label_set_position(mgui_label *self, mgl_vec2i position);
-void mgui_label_set_width(mgui_label *self, int width);
+void mgui_label_calculate_size(mgui_label *self, mgl_vec2i max_size);
void mgui_label_on_event(mgui_label *self, mgl_window *window, mgl_event *event);
-/* Returns the size of the widget */
-mgl_vec2i mgui_label_draw(mgui_label *self, mgl_window *window);
+void mgui_label_draw(mgui_label *self, mgl_window *window);
#endif /* MGUI_LABEL_H */
diff --git a/include/mgui/list.h b/include/mgui/list.h
index af1ceae..7769ab6 100644
--- a/include/mgui/list.h
+++ b/include/mgui/list.h
@@ -3,6 +3,7 @@
#include "widget.h"
#include <stddef.h>
+#include <stdint.h>
#include <mgl/graphics/color.h>
typedef struct mgl_window mgl_window;
@@ -14,11 +15,14 @@ typedef enum {
} mgui_list_direction;
typedef struct {
+ mgui_widget *widget;
+} mgui_list_item;
+
+typedef struct {
mgui_widget widget;
mgui_list_direction direction;
mgl_vec2i position;
- mgl_color background_color;
- mgui_widget **items;
+ mgui_list_item *items;
size_t items_capacity;
size_t num_items;
} mgui_list;
@@ -29,11 +33,9 @@ mgui_widget* mgui_list_to_widget(mgui_list *list);
mgui_list* mgui_widget_to_list(mgui_widget *widget);
void mgui_list_set_position(mgui_list *self, mgl_vec2i position);
-void mgui_list_set_width(mgui_list *self, int width);
-void mgui_list_set_background_color(mgui_list *self, mgl_color color);
+void mgui_list_calculate_size(mgui_list *self, mgl_vec2i max_size);
void mgui_list_append(mgui_list *self, mgui_widget *widget);
void mgui_list_on_event(mgui_list *self, mgl_window *window, mgl_event *event);
-/* Returns the size of the widget */
-mgl_vec2i mgui_list_draw(mgui_list *self, mgl_window *window);
+void mgui_list_draw(mgui_list *self, mgl_window *window);
#endif /* MGUI_LIST_H */
diff --git a/include/mgui/mgui.h b/include/mgui/mgui.h
index d76226f..15a2f73 100644
--- a/include/mgui/mgui.h
+++ b/include/mgui/mgui.h
@@ -2,9 +2,11 @@
#define MGUI_H
typedef struct mgui_widget mgui_widget;
+typedef struct mgl_event mgl_event;
typedef struct mgl_window mgl_window;
void mgui_init();
+void mgui_on_event(mgui_widget *root_widget, mgl_window *window, mgl_event *event);
void mgui_draw(mgui_widget *root_widget, mgl_window *window);
/* Clamped to 1.0 second */
double mgui_get_seconds_since_last_update();
diff --git a/include/mgui/richtext.h b/include/mgui/richtext.h
index c0604c9..ff57271 100644
--- a/include/mgui/richtext.h
+++ b/include/mgui/richtext.h
@@ -31,9 +31,8 @@ mgui_widget* mgui_richtext_to_widget(mgui_richtext *list);
mgui_richtext* mgui_widget_to_richtext(mgui_widget *widget);
void mgui_richtext_set_position(mgui_richtext *self, mgl_vec2i position);
-void mgui_richtext_set_width(mgui_richtext *self, int width);
+void mgui_richtext_calculate_size(mgui_richtext *self, mgl_vec2i max_size);
void mgui_richtext_on_event(mgui_richtext *self, mgl_window *window, mgl_event *event);
-/* Returns the size of the widget */
-mgl_vec2i mgui_richtext_draw(mgui_richtext *self, mgl_window *window);
+void mgui_richtext_draw(mgui_richtext *self, mgl_window *window);
#endif /* MGUI_RICHTEXT_H */
diff --git a/include/mgui/scrollview.h b/include/mgui/scrollview.h
index 1b3d109..dded990 100644
--- a/include/mgui/scrollview.h
+++ b/include/mgui/scrollview.h
@@ -6,9 +6,7 @@
typedef struct {
mgui_widget widget;
mgui_widget *child;
- mgl_vec2i child_size;
mgl_vec2i position;
- mgl_vec2i size;
mgl_vec2i scroll;
mgl_vec2f mouse_scroll;
} mgui_scrollview;
@@ -20,10 +18,9 @@ mgui_scrollview* mgui_widget_to_scrollview(mgui_widget *widget);
void mgui_scrollview_set_child(mgui_scrollview *self, mgui_widget *child);
void mgui_scrollview_set_position(mgui_scrollview *self, mgl_vec2i position);
+void mgui_scrollview_calculate_size(mgui_scrollview *self, mgl_vec2i max_size);
void mgui_scrollview_set_size(mgui_scrollview *self, mgl_vec2i size);
-void mgui_scrollview_set_width(mgui_scrollview *self, int width);
void mgui_scrollview_on_event(mgui_scrollview *self, mgl_window *window, mgl_event *event);
-/* Returns the size of the widget */
-mgl_vec2i mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window);
+void mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window);
#endif /* MGUI_SCROLLVIEW_H */
diff --git a/include/mgui/widget.h b/include/mgui/widget.h
index 679e4ad..d425c11 100644
--- a/include/mgui/widget.h
+++ b/include/mgui/widget.h
@@ -2,6 +2,8 @@
#define MGUI_WIDGET_H
#include <mgl/system/vec.h>
+#include <stdint.h>
+#include <stdbool.h>
typedef struct mgl_window mgl_window;
typedef struct mgl_event mgl_event;
@@ -16,27 +18,55 @@ typedef enum {
MGUI_WIDGET_IMAGE
} mgui_widget_type;
+typedef enum {
+ MGUI_WIDGET_ALIGN_TOP_LEFT,
+ MGUI_WIDGET_ALIGN_TOP_CENTER,
+ MGUI_WIDGET_ALIGN_TOP_RIGHT,
+
+ MGUI_WIDGET_ALIGN_CENTER_LEFT,
+ MGUI_WIDGET_ALIGN_CENTER_CENTER,
+ MGUI_WIDGET_ALIGN_CENTER_RIGHT,
+
+ MGUI_WIDGET_ALIGN_BOTTOM_LEFT,
+ MGUI_WIDGET_ALIGN_BOTTOM_CENTER,
+ MGUI_WIDGET_ALIGN_BOTTOM_RIGHT,
+} mgui_alignment;
+
+typedef enum {
+ MGUI_WIDGET_VISIBLE = 1 << 0,
+ MGUI_WIDGET_EXPAND_HORIZONTAL = 1 << 1,
+ MGUI_WIDGET_EXPAND_VERTICAL = 1 << 2,
+ MGUI_WIDGET_DEBUG_HAS_PARENT = 1 << 3
+} mgui_widget_flags;
+
typedef struct {
int left;
- int top;
int right;
+ int top;
int bottom;
} mgui_margin;
struct mgui_widget {
- mgui_widget_type type;
+ uint8_t type; /* mgui_widget_type */
+ uint8_t flags; /* mgui_widget_flags */
+ uint8_t alignment; /* mgui_alignment, MGUI_WIDGET_ALIGN_TOP_LEFT by default */
mgui_margin margin;
+ mgl_vec2i size;
};
void mgui_widget_init(mgui_widget *self, mgui_widget_type type);
void mgui_widget_destroy(mgui_widget *widget);
-void mgui_widget_set_margin(mgui_widget *self, int left, int top, int right, int bottom);
+void mgui_widget_set_visible(mgui_widget *self, bool visible);
+void mgui_widget_set_expand(mgui_widget *self, bool horizontal, bool vertical);
+void mgui_widget_set_alignment(mgui_widget *self, mgui_alignment alignment);
+void mgui_widget_set_margin(mgui_widget *self, mgui_margin margin);
+void mgui_widget_set_size(mgui_widget *self, mgl_vec2i size);
void mgui_widget_set_position(mgui_widget *self, mgl_vec2i position);
-void mgui_widget_set_width(mgui_widget *self, int width);
+void mgui_widget_calculate_size(mgui_widget *self, mgl_vec2i max_size);
+void mgui_widget_set_has_parent(mgui_widget *self);
void mgui_widget_on_event(mgui_widget *self, mgl_window *window, mgl_event *event);
-/* Returns the size of the widget */
-mgl_vec2i mgui_widget_draw(mgui_widget *self, mgl_window *window);
+void mgui_widget_draw(mgui_widget *self, mgl_window *window);
#endif /* MGUI_WIDGET_H */
diff --git a/src/mgui/button.c b/src/mgui/button.c
index 02070c3..00db361 100644
--- a/src/mgui/button.c
+++ b/src/mgui/button.c
@@ -7,6 +7,10 @@
#include <string.h>
#include <assert.h>
+static int min_int(int a, int b) {
+ return a <= b ? a : b;
+}
+
mgui_button* mgui_button_create(const char *str, size_t size, unsigned char character_size) {
mgui_button *button = mgui_alloc(sizeof(mgui_button));
mgui_widget_init(&button->widget, MGUI_WIDGET_BUTTON);
@@ -45,14 +49,12 @@ void mgui_button_set_position(mgui_button *self, mgl_vec2i position) {
});
}
-static int max_int(int a, int b) {
- return a >= b ? a : b;
-}
-
-void mgui_button_set_width(mgui_button *self, int width) {
+void mgui_button_calculate_size(mgui_button *self, mgl_vec2i max_size) {
const mgl_vec2f text_bounds = mgl_text_get_bounds(&self->text);
- self->background.size.x = max_int(text_bounds.x, width);
+ const mgl_vec2i text_bounds_int = (mgl_vec2i){ text_bounds.x, text_bounds.y };
+ self->background.size = (mgl_vec2f){ min_int(text_bounds_int.x, max_size.x), min_int(text_bounds_int.y, max_size.y) };
mgui_button_set_position(self, (mgl_vec2i){ self->background.position.x, self->background.position.y });
+ self->widget.size = (mgl_vec2i){ self->background.size.x, self->background.size.y };
}
void mgui_button_on_event(mgui_button *self, mgl_window *window, mgl_event *event) {
@@ -70,12 +72,11 @@ void mgui_button_on_event(mgui_button *self, mgl_window *window, mgl_event *even
}
}
-mgl_vec2i mgui_button_draw(mgui_button *self, mgl_window *window) {
+void mgui_button_draw(mgui_button *self, mgl_window *window) {
const mgl_vec2i position = (mgl_vec2i){ self->background.position.x, self->background.position.y };
const mgl_vec2i size = (mgl_vec2i){ self->background.size.x, self->background.size.y };
if(mgui_rectangle_intersects_with_scissor(position, size, window)) {
mgl_rectangle_draw(mgl_get_context(), &self->background);
mgl_text_draw(mgl_get_context(), &self->text);
}
- return size;
}
diff --git a/src/mgui/image.c b/src/mgui/image.c
index c2ff12f..1a0871f 100644
--- a/src/mgui/image.c
+++ b/src/mgui/image.c
@@ -9,6 +9,46 @@
/* TODO: Load image asynchronously and support network files */
+static mgl_vec2i wrap_to_size_x(mgl_vec2i size, int clamp_size) {
+ mgl_vec2i new_size;
+ if(size.x == 0) {
+ new_size.x = 0;
+ new_size.y = 0;
+ return new_size;
+ }
+ float size_ratio = (float)size.y / (float)size.x;
+ new_size.x = clamp_size;
+ new_size.y = new_size.x * size_ratio;
+ return new_size;
+}
+
+static mgl_vec2i wrap_to_size_y(mgl_vec2i size, int clamp_size) {
+ mgl_vec2i new_size;
+ if(size.y == 0) {
+ new_size.x = 0;
+ new_size.y = 0;
+ return new_size;
+ }
+ float size_ratio = (float)size.x / (float)size.y;
+ new_size.y = clamp_size;
+ new_size.x = new_size.y * size_ratio;
+ return new_size;
+}
+
+static mgl_vec2i wrap_to_size(const mgl_vec2i size, const mgl_vec2i clamp_size) {
+ mgl_vec2i new_size = wrap_to_size_x(size, clamp_size.x);
+ if(new_size.y > clamp_size.y)
+ new_size = wrap_to_size_y(size, clamp_size.y);
+ return new_size;
+}
+
+static mgl_vec2i clamp_to_size(mgl_vec2i size, mgl_vec2i clamp_size) {
+ mgl_vec2i new_size = size;
+ if(size.x > clamp_size.x || size.y > clamp_size.y)
+ new_size = wrap_to_size(new_size, clamp_size);
+ return new_size;
+}
+
mgui_image* mgui_image_create(const char *filepath) {
mgui_image *image = mgui_alloc(sizeof(mgui_image));
mgui_widget_init(&image->widget, MGUI_WIDGET_IMAGE);
@@ -35,10 +75,18 @@ void mgui_image_set_position(mgui_image *self, mgl_vec2i position) {
mgl_sprite_set_position(&self->sprite, (mgl_vec2f){ position.x, position.y });
}
-void mgui_image_set_width(mgui_image *self, int width) {
- /* TODO: Implement */
- (void)self;
- (void)width;
+void mgui_image_calculate_size(mgui_image *self, mgl_vec2i max_size) {
+ if(self->sprite.texture) {
+ const mgl_vec2i texture_size = (mgl_vec2i){ self->sprite.texture->width, self->sprite.texture->height };
+ const mgl_vec2i new_size = clamp_to_size(texture_size, max_size);
+
+ self->sprite.scale.x = (float)new_size.x / (float)texture_size.x;
+ self->sprite.scale.y = (float)new_size.y / (float)texture_size.y;
+
+ self->widget.size = new_size;
+ } else {
+ self->widget.size = (mgl_vec2i){ 0, 0 };
+ }
}
void mgui_image_on_event(mgui_image *self, mgl_window *window, mgl_event *event) {
@@ -48,13 +96,10 @@ void mgui_image_on_event(mgui_image *self, mgl_window *window, mgl_event *event)
/* TODO: Implement */
}
-mgl_vec2i mgui_image_draw(mgui_image *self, mgl_window *window) {
+void mgui_image_draw(mgui_image *self, mgl_window *window) {
if(self->sprite.texture) {
const mgl_vec2i texture_size = (mgl_vec2i){ self->sprite.texture->width, self->sprite.texture->height };
if(mgui_rectangle_intersects_with_scissor((mgl_vec2i){ self->sprite.position.x, self->sprite.position.y }, texture_size, window))
mgl_sprite_draw(mgl_get_context(), &self->sprite);
- return texture_size;
- } else {
- return (mgl_vec2i){ 0, 0 };
}
}
diff --git a/src/mgui/label.c b/src/mgui/label.c
index 767297c..e380aac 100644
--- a/src/mgui/label.c
+++ b/src/mgui/label.c
@@ -9,6 +9,10 @@
/* TODO: Scale label by scale setting */
+static int min_int(int a, int b) {
+ return a <= b ? a : b;
+}
+
mgui_label* mgui_label_create(const char *str, size_t size, unsigned char character_size) {
mgui_label *label = mgui_alloc(sizeof(mgui_label));
mgui_widget_init(&label->widget, MGUI_WIDGET_LABEL);
@@ -16,8 +20,6 @@ mgui_label* mgui_label_create(const char *str, size_t size, unsigned char charac
label->str_size = size;
memcpy(label->str, str, size);
mgl_text_init(&label->text, mgui_get_font(MGUI_FONT_LATIN, character_size), label->str, label->str_size);
- label->position = (mgl_vec2i){ 0, 0 };
- label->width = mgl_text_get_bounds(&label->text).x;
return label;
}
@@ -37,22 +39,14 @@ mgui_label* mgui_widget_to_label(mgui_widget *widget) {
}
void mgui_label_set_position(mgui_label *self, mgl_vec2i position) {
- const mgl_vec2f text_bounds = mgl_text_get_bounds(&self->text);
- self->position = position;
- mgl_text_set_position(&self->text, (mgl_vec2f){
- (int)(position.x + self->width * 0.5f - text_bounds.x * 0.5f),
- position.y
- });
+ mgl_text_set_position(&self->text, (mgl_vec2f){ position.x, position.y });
}
-static int max_int(int a, int b) {
- return a >= b ? a : b;
-}
-
-void mgui_label_set_width(mgui_label *self, int width) {
+void mgui_label_calculate_size(mgui_label *self, mgl_vec2i max_size) {
const mgl_vec2f text_bounds = mgl_text_get_bounds(&self->text);
- self->width = max_int(text_bounds.x, width);
- mgui_label_set_position(self, self->position);
+ const mgl_vec2i text_bounds_int = (mgl_vec2i){ text_bounds.x, text_bounds.y };
+ self->widget.size.x = min_int(text_bounds_int.x, max_size.x);
+ self->widget.size.y = min_int(text_bounds_int.y, max_size.y);
}
void mgui_label_on_event(mgui_label *self, mgl_window *window, mgl_event *event) {
@@ -62,10 +56,9 @@ void mgui_label_on_event(mgui_label *self, mgl_window *window, mgl_event *event)
(void)event;
}
-mgl_vec2i mgui_label_draw(mgui_label *self, mgl_window *window) {
+void mgui_label_draw(mgui_label *self, mgl_window *window) {
const mgl_vec2f text_bounds = mgl_text_get_bounds(&self->text);
const mgl_vec2i text_bounds_int = (mgl_vec2i){ text_bounds.x, text_bounds.y };
- if(mgui_rectangle_intersects_with_scissor(self->position, text_bounds_int, window))
+ if(mgui_rectangle_intersects_with_scissor((mgl_vec2i){ self->text.position.x, self->text.position.y }, text_bounds_int, window))
mgl_text_draw(mgl_get_context(), &self->text);
- return text_bounds_int;
}
diff --git a/src/mgui/list.c b/src/mgui/list.c
index 58fc964..687906d 100644
--- a/src/mgui/list.c
+++ b/src/mgui/list.c
@@ -8,12 +8,15 @@
if num_items <= 2.
*/
+static int max_int(int a, int b) {
+ return a >= b ? a : b;
+}
+
mgui_list* mgui_list_create(mgui_list_direction direction) {
mgui_list *list = mgui_alloc(sizeof(mgui_list));
mgui_widget_init(&list->widget, MGUI_WIDGET_LIST);
list->direction = direction;
list->position = (mgl_vec2i){ 0, 0 };
- list->background_color = (mgl_color){ 0, 0, 0, 0 };
list->items = NULL;
list->items_capacity = 0;
list->num_items = 0;
@@ -22,7 +25,7 @@ mgui_list* mgui_list_create(mgui_list_direction direction) {
void mgui_list_destroy(mgui_list *list) {
for(size_t i = 0; i < list->num_items; ++i) {
- mgui_widget_destroy(list->items[i]);
+ mgui_widget_destroy(list->items[i].widget);
}
mgui_free(list->items);
mgui_free(list);
@@ -41,19 +44,71 @@ void mgui_list_set_position(mgui_list *self, mgl_vec2i position) {
self->position = position;
}
-void mgui_list_set_width(mgui_list *self, int width) {
- /* TODO: if direction is horizontal then put the widget in the center of its area */
- /* TODO: put the widget in the center for vertical as well, for items with a max size */
- /* TODO: support max size for widgets */
- if(self->direction == MGUI_LIST_VERTICAL) {
- for(size_t i = 0; i < self->num_items; ++i) {
- mgui_widget_set_width(self->items[i], width);
+void mgui_list_calculate_size(mgui_list *self, mgl_vec2i max_size) {
+ mgl_vec2i size = (mgl_vec2i){ 0, 0 };
+ switch(self->direction) {
+ case MGUI_LIST_HORIZONITAL: {
+ int num_expanded_widgets = 0;
+ for(size_t i = 0; i < self->num_items; ++i) {
+ mgui_widget *widget = self->items[i].widget;
+ if(widget->flags & MGUI_WIDGET_EXPAND_HORIZONTAL) {
+ ++num_expanded_widgets;
+ } else {
+ mgui_widget_calculate_size(widget, max_size);
+ size.x += widget->size.x;
+ size.y = max_int(size.y, widget->size.y);
+ max_size.x -= widget->size.x;
+ }
+ }
+
+ if(num_expanded_widgets == 0)
+ break;
+
+ max_size.x = max_size.x / num_expanded_widgets;
+
+ for(size_t i = 0; i < self->num_items; ++i) {
+ mgui_widget *widget = self->items[i].widget;
+ if(widget->flags & MGUI_WIDGET_EXPAND_HORIZONTAL) {
+ mgui_widget_calculate_size(widget, max_size);
+ widget->size = max_size;
+ size.x += widget->size.x;
+ size.y = max_int(size.y, widget->size.y);
+ }
+ }
+ break;
}
- }
-}
+ case MGUI_LIST_VERTICAL: {
+ int num_expanded_widgets = 0;
+ for(size_t i = 0; i < self->num_items; ++i) {
+ mgui_widget *widget = self->items[i].widget;
+ if(widget->flags & MGUI_WIDGET_EXPAND_VERTICAL) {
+ ++num_expanded_widgets;
+ } else {
+ mgui_widget_calculate_size(widget, max_size);
+ size.x = max_int(size.x, widget->size.x);
+ size.y += widget->size.y;
+ max_size.y -= widget->size.y;
+ }
+ }
+
+ if(num_expanded_widgets == 0)
+ break;
-void mgui_list_set_background_color(mgui_list *self, mgl_color color) {
- self->background_color = color;
+ max_size.y = max_size.y / num_expanded_widgets;
+
+ for(size_t i = 0; i < self->num_items; ++i) {
+ mgui_widget *widget = self->items[i].widget;
+ if(widget->flags & MGUI_WIDGET_EXPAND_VERTICAL) {
+ mgui_widget_calculate_size(widget, max_size);
+ widget->size = max_size;
+ size.x = max_int(size.x, widget->size.x);
+ size.y += widget->size.y;
+ }
+ }
+ break;
+ }
+ }
+ self->widget.size = size;
}
static void mgui_list_ensure_capacity(mgui_list *self, size_t new_capacity) {
@@ -73,63 +128,46 @@ static void mgui_list_ensure_capacity(mgui_list *self, size_t new_capacity) {
}
void mgui_list_append(mgui_list *self, mgui_widget *widget) {
- mgui_list_ensure_capacity(self, (self->num_items + 1) * sizeof(mgui_widget*));
- self->items[self->num_items] = widget;
+ mgui_widget_set_has_parent(widget);
+ mgui_list_ensure_capacity(self, (self->num_items + 1) * sizeof(mgui_list_item));
+ self->items[self->num_items].widget = widget;
++self->num_items;
}
void mgui_list_on_event(mgui_list *self, mgl_window *window, mgl_event *event) {
for(size_t i = 0; i < self->num_items; ++i) {
- mgui_widget_on_event(self->items[i], window, event);
+ mgui_widget_on_event(self->items[i].widget, window, event);
}
}
-static int max_int(int a, int b) {
- return a >= b ? a : b;
-}
-
/* TODO: Check if visible in scissor */
-mgl_vec2i mgui_list_draw(mgui_list *self, mgl_window *window) {
+void mgui_list_draw(mgui_list *self, mgl_window *window) {
mgl_vec2i position = self->position;
- /* TODO: */
- mgl_vec2i size = (mgl_vec2i){ 0, 0 };
-
- /* TODO:
- if(self->background_color.a > 0) {
- mgl_rectangle rect = {
- .position = { self->position.x, self->position.y },
- .size = { self->size.x, self->size.y },
- .color = self->background_color
- };
- mgl_rectangle_draw(mgl_get_context(), &rect);
- }
- */
/* TODO: Set scissor for each draw widget */
+ /* TODO: Only do this when a direct child widget is dirty */
+ //mgui_list_calculate_size(self);
+
switch(self->direction) {
case MGUI_LIST_HORIZONITAL: {
for(size_t i = 0; i < self->num_items; ++i) {
- mgui_widget_set_position(self->items[i], position);
- const mgl_vec2i widget_size = mgui_widget_draw(self->items[i], window);
- size.x += widget_size.x;
- size.y = max_int(size.y, widget_size.y);
- position.x += widget_size.x;
+ mgui_widget *widget = self->items[i].widget;
+ mgui_widget_set_position(widget, position);
+ mgui_widget_draw(widget, window);
+ position.x += widget->size.x;
}
break;
}
case MGUI_LIST_VERTICAL: {
for(size_t i = 0; i < self->num_items; ++i) {
- mgui_widget_set_position(self->items[i], position);
- const mgl_vec2i widget_size = mgui_widget_draw(self->items[i], window);
- size.x = max_int(size.x, widget_size.x);
- size.y += widget_size.y;
- position.y += widget_size.y;
+ mgui_widget *widget = self->items[i].widget;
+ mgui_widget_set_position(widget, position);
+ mgui_widget_draw(widget, window);
+ position.y += widget->size.y;
}
break;
}
}
-
- return size;
}
diff --git a/src/mgui/mgui.c b/src/mgui/mgui.c
index e2fa0be..3c1d955 100644
--- a/src/mgui/mgui.c
+++ b/src/mgui/mgui.c
@@ -1,5 +1,6 @@
#include "../../include/mgui/mgui.h"
#include "../../include/mgui/widget.h"
+#include <mgl/window/event.h>
#include <mgl/system/clock.h>
static mgl_clock global_timer;
@@ -8,7 +9,15 @@ void mgui_init() {
mgl_clock_init(&global_timer);
}
+void mgui_on_event(mgui_widget *root_widget, mgl_window *window, mgl_event *event) {
+ if(event->type == MGL_EVENT_RESIZED)
+ mgui_widget_set_size(root_widget, (mgl_vec2i){ event->size.width, event->size.height });
+ mgui_widget_on_event(root_widget, window, event);
+}
+
void mgui_draw(mgui_widget *root_widget, mgl_window *window) {
+ /* TODO: Only do this if widget is dirty */
+ mgui_widget_calculate_size(root_widget, root_widget->size);
mgui_widget_draw(root_widget, window);
}
diff --git a/src/mgui/richtext.c b/src/mgui/richtext.c
index c70967f..9b1acfc 100644
--- a/src/mgui/richtext.c
+++ b/src/mgui/richtext.c
@@ -28,6 +28,10 @@ static int max_int(int a, int b) {
return a >= b ? a : b;
}
+static int min_int(int a, int b) {
+ return a <= b ? a : b;
+}
+
/* TODO: Is there a more efficient way to do this? maybe japanese characters have a specific bit-pattern? */
static bool is_japanese_codepoint(uint32_t codepoint) {
return (codepoint >= 0x2E80 && codepoint <= 0x2FD5) /* Kanji radicals */
@@ -93,6 +97,13 @@ static void mgui_richtext_vertices_clear(mgui_richtext *self, size_t vertex_inde
self->vertex_data[vertex_index].vertex_count = 0;
}
+static void mgui_richtext_vertices_free(mgui_richtext *self, size_t vertex_index) {
+ mgui_free(self->vertex_data[vertex_index].vertices);
+ self->vertex_data[vertex_index].vertices = NULL;
+ self->vertex_data[vertex_index].vertices_capacity = 0;
+ self->vertex_data[vertex_index].vertex_count = 0;
+}
+
mgui_richtext* mgui_richtext_create(const char *str, size_t size, unsigned char character_size) {
mgui_richtext *richtext = mgui_alloc(sizeof(mgui_richtext));
mgui_widget_init(&richtext->widget, MGUI_WIDGET_RICHTEXT);
@@ -133,17 +144,6 @@ void mgui_richtext_set_position(mgui_richtext *self, mgl_vec2i position) {
self->position = position;
}
-void mgui_richtext_set_width(mgui_richtext *self, int width) {
- self->width = width;
-}
-
-void mgui_richtext_on_event(mgui_richtext *self, mgl_window *window, mgl_event *event) {
- /* TODO: Implement */
- (void)self;
- (void)window;
- (void)event;
-}
-
static void mgui_richtext_append_glyph(mgui_richtext *self, size_t vertex_index, mgl_vec2f position, mgl_color color, mgl_font_glyph *glyph) {
const mgl_vertex top_left_vertex = {
.position = (mgl_vec2f){ round_float(position.x + glyph->position.x), round_float(position.y + glyph->position.y) },
@@ -229,8 +229,8 @@ static void mgui_richtext_update(mgui_richtext *self) {
} else {
if(mgl_font_get_glyph(font, codepoint, &glyph) == 0) {
if(position.x + glyph.size.x > self->width) {
- //position.x = 0;
- //position.y += self->character_size;
+ position.x = 0;
+ position.y += self->character_size;
}
mgui_richtext_append_glyph(self, vertex_index, position, color, &glyph);
@@ -245,14 +245,37 @@ static void mgui_richtext_update(mgui_richtext *self) {
}
}
-mgl_vec2i mgui_richtext_draw(mgui_richtext *self, mgl_window *window) {
+void mgui_richtext_calculate_size(mgui_richtext *self, mgl_vec2i max_size) {
/* TODO: Do not update if not visible on screen? */
+ if(max_size.x != self->width) {
+ self->width = max_size.x;
+ self->dirty = true;
+ }
+
+ /* TODO: Instead of updating richtext vertices, calculcate the richtext bounds only and update the vertices in the draw function if dirty */
if(self->dirty) {
self->dirty = false;
mgui_richtext_update(self);
+ self->widget.size.x = self->render_size.x;
+ self->widget.size.y = min_int(self->render_size.y, max_size.y);
}
+}
+
+void mgui_richtext_on_event(mgui_richtext *self, mgl_window *window, mgl_event *event) {
+ /* TODO: Implement */
+ (void)self;
+ (void)window;
+ (void)event;
+}
+void mgui_richtext_draw(mgui_richtext *self, mgl_window *window) {
if(mgui_rectangle_intersects_with_scissor(self->position, self->render_size, window)) {
+ /* This can happen when the item is first not visible in its scissor and then becomes visible */
+ if(self->dirty) {
+ self->dirty = false;
+ mgui_richtext_update(self);
+ }
+
const mgui_font_type font_types[NUM_VERTEX_DATA] = {
MGUI_FONT_LATIN,
MGUI_FONT_CJK
@@ -268,7 +291,10 @@ mgl_vec2i mgui_richtext_draw(mgui_richtext *self, mgl_window *window) {
}
mgl_texture_use(NULL);
+ } else {
+ for(size_t i = 0; i < NUM_VERTEX_DATA; ++i) {
+ mgui_richtext_vertices_free(self, i);
+ }
+ self->dirty = true;
}
-
- return self->render_size;
}
diff --git a/src/mgui/scrollview.c b/src/mgui/scrollview.c
index 3c5850c..c7a4075 100644
--- a/src/mgui/scrollview.c
+++ b/src/mgui/scrollview.c
@@ -4,18 +4,35 @@
#include <mgl/mgl.h>
#include <mgl/window/window.h>
#include <mgl/window/event.h>
+#include <limits.h>
#include <assert.h>
#define SCROLL_ACCEL 20.0f
#define SCROLL_DEACCEL 10.0f
+#define WIDGET_NATURAL_SIZE INT_MAX
+
+static float max_float(float a, float b) {
+ return a >= b ? a : b;
+}
+
+static int max_int(int a, int b) {
+ return a >= b ? a : b;
+}
+
+static int min_int(int a, int b) {
+ return a <= b ? a : b;
+}
+
+static float abs_float(float value) {
+ return value >= 0.0f ? value : -value;
+}
+
mgui_scrollview* mgui_scrollview_create() {
mgui_scrollview *scrollview = mgui_alloc(sizeof(mgui_scrollview));
mgui_widget_init(&scrollview->widget, MGUI_WIDGET_SCROLLVIEW);
scrollview->child = NULL;
- scrollview->child_size = (mgl_vec2i){ 0, 0 };
scrollview->position = (mgl_vec2i){ 0, 0 };
- scrollview->size = (mgl_vec2i){ 0, 0 };
scrollview->scroll = (mgl_vec2i){ 0, 0 };
scrollview->mouse_scroll = (mgl_vec2f){ 0.0f, 0.0f };
return scrollview;
@@ -39,22 +56,26 @@ mgui_scrollview* mgui_widget_to_scrollview(mgui_widget *widget) {
void mgui_scrollview_set_child(mgui_scrollview *self, mgui_widget *child) {
assert(child != mgui_scrollview_to_widget(self));
self->child = child;
- mgui_scrollview_set_width(self, self->size.x);
+ if(self->child) {
+ mgui_widget_set_has_parent(self->child);
+ mgui_widget_calculate_size(self->child, self->widget.size);
+ }
}
void mgui_scrollview_set_position(mgui_scrollview *self, mgl_vec2i position) {
self->position = position;
}
-void mgui_scrollview_set_size(mgui_scrollview *self, mgl_vec2i size) {
- self->size = size;
- mgui_scrollview_set_width(self, self->size.x);
-}
+void mgui_scrollview_calculate_size(mgui_scrollview *self, mgl_vec2i max_size) {
+ self->widget.size = max_size;
+ if(self->widget.size.x == WIDGET_NATURAL_SIZE)
+ self->widget.size.x = 500;
+
+ if(self->widget.size.y == WIDGET_NATURAL_SIZE)
+ self->widget.size.y = 600;
-void mgui_scrollview_set_width(mgui_scrollview *self, int width) {
- /* TODO: Call for child so text can wordwrap? but only if wordwrap is enabled in this scrollview */
if(self->child)
- mgui_widget_set_width(self->child, width);
+ mgui_widget_calculate_size(self->child, (mgl_vec2i){ WIDGET_NATURAL_SIZE, WIDGET_NATURAL_SIZE });
}
void mgui_scrollview_on_event(mgui_scrollview *self, mgl_window *window, mgl_event *event) {
@@ -66,25 +87,9 @@ void mgui_scrollview_on_event(mgui_scrollview *self, mgl_window *window, mgl_eve
mgui_widget_on_event(self->child, window, event);
}
-static float max_float(float a, float b) {
- return a >= b ? a : b;
-}
-
-static int max_int(int a, int b) {
- return a >= b ? a : b;
-}
-
-static int min_int(int a, int b) {
- return a <= b ? a : b;
-}
-
-static float abs_float(float value) {
- return value >= 0.0f ? value : -value;
-}
-
/* TODO: Check if visible in scissor */
-mgl_vec2i mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window) {
+void mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window) {
const double frame_time = mgui_get_seconds_since_last_update();
self->mouse_scroll.x *= max_float(0.0f, (1.0f - frame_time * SCROLL_DEACCEL));
self->mouse_scroll.y *= max_float(0.0f, (1.0f - frame_time * SCROLL_DEACCEL));
@@ -98,16 +103,22 @@ mgl_vec2i mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window) {
self->scroll.x += (int)self->mouse_scroll.x;
self->scroll.y += (int)self->mouse_scroll.y;
- if(self->child_size.x > self->size.x) {
+ mgl_vec2i child_size;
+ if(self->child)
+ child_size = self->child->size;
+ else
+ child_size = (mgl_vec2i){ 0, 0 };
+
+ if(child_size.x > self->widget.size.x) {
self->scroll.x = min_int(self->scroll.x, 0);
- self->scroll.x = max_int(self->scroll.x, -self->child_size.x + self->size.x);
+ self->scroll.x = max_int(self->scroll.x, -child_size.x + self->widget.size.x);
} else {
self->scroll.x = 0;
}
- if(self->child_size.y > self->size.y) {
+ if(child_size.y > self->widget.size.y) {
self->scroll.y = min_int(self->scroll.y, 0);
- self->scroll.y = max_int(self->scroll.y, -self->child_size.y + self->size.y);
+ self->scroll.y = max_int(self->scroll.y, -child_size.y + self->widget.size.y);
} else {
self->scroll.y = 0;
}
@@ -118,17 +129,13 @@ mgl_vec2i mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window) {
mgl_scissor new_scissor = {
.position = self->position,
- .size = self->size
+ .size = self->widget.size
};
mgl_window_set_scissor(window, &new_scissor);
mgui_widget_set_position(self->child, (mgl_vec2i){ self->position.x + self->scroll.x, self->position.y + self->scroll.y });
- self->child_size = mgui_widget_draw(self->child, window);
+ mgui_widget_draw(self->child, window);
mgl_window_set_scissor(window, &prev_scissor);
- } else {
- self->child_size = (mgl_vec2i){ 0, 0 };
}
-
- return self->child_size;
}
diff --git a/src/mgui/widget.c b/src/mgui/widget.c
index b9865ca..ed50154 100644
--- a/src/mgui/widget.c
+++ b/src/mgui/widget.c
@@ -6,12 +6,34 @@
#include "../../include/mgui/richtext.h"
#include "../../include/mgui/image.h"
#include "../../include/alloc.h"
+#include <stdio.h>
+#include <stdlib.h>
/* TODO: Use margin */
+/* TODO: Use alignment */
+/* TODO: Use visible flag */
+
+static void mgui_widget_set_flag(mgui_widget *self, uint8_t flag) {
+ self->flags |= flag;
+}
+
+static void mgui_widget_unset_flag(mgui_widget *self, uint8_t flag) {
+ self->flags &= ~flag;
+}
+
+static void mgui_widget_set_flag_state(mgui_widget *self, uint8_t flag, bool set) {
+ if(set)
+ mgui_widget_set_flag(self, flag);
+ else
+ mgui_widget_unset_flag(self, flag);
+}
void mgui_widget_init(mgui_widget *self, mgui_widget_type type) {
self->type = type;
- mgui_widget_set_margin(self, 0, 0, 0, 0);
+ self->flags = MGUI_WIDGET_VISIBLE;
+ self->alignment = MGUI_WIDGET_ALIGN_TOP_LEFT;
+ mgui_widget_set_margin(self, (mgui_margin){ 0, 0, 0, 0 });
+ self->size = (mgl_vec2i){ 0, 0 };
}
void mgui_widget_destroy(mgui_widget *widget) {
@@ -37,11 +59,25 @@ void mgui_widget_destroy(mgui_widget *widget) {
}
}
-void mgui_widget_set_margin(mgui_widget *self, int left, int top, int right, int bottom) {
- self->margin.left = left;
- self->margin.top = top;
- self->margin.right = right;
- self->margin.bottom = bottom;
+void mgui_widget_set_visible(mgui_widget *self, bool visible) {
+ mgui_widget_set_flag_state(self, MGUI_WIDGET_VISIBLE, visible);
+}
+
+void mgui_widget_set_expand(mgui_widget *self, bool horizontal, bool vertical) {
+ mgui_widget_set_flag_state(self, MGUI_WIDGET_EXPAND_HORIZONTAL, horizontal);
+ mgui_widget_set_flag_state(self, MGUI_WIDGET_EXPAND_VERTICAL, vertical);
+}
+
+void mgui_widget_set_alignment(mgui_widget *self, mgui_alignment alignment) {
+ self->alignment = alignment;
+}
+
+void mgui_widget_set_margin(mgui_widget *self, mgui_margin margin) {
+ self->margin = margin;
+}
+
+void mgui_widget_set_size(mgui_widget *self, mgl_vec2i size) {
+ self->size = size;
}
void mgui_widget_set_position(mgui_widget *self, mgl_vec2i position) {
@@ -67,29 +103,37 @@ void mgui_widget_set_position(mgui_widget *self, mgl_vec2i position) {
}
}
-void mgui_widget_set_width(mgui_widget *self, int width) {
+void mgui_widget_calculate_size(mgui_widget *self, mgl_vec2i max_size) {
switch(self->type) {
case MGUI_WIDGET_LIST:
- mgui_list_set_width(mgui_widget_to_list(self), width);
+ mgui_list_calculate_size(mgui_widget_to_list(self), max_size);
break;
case MGUI_WIDGET_SCROLLVIEW:
- mgui_scrollview_set_width(mgui_widget_to_scrollview(self), width);
+ mgui_scrollview_calculate_size(mgui_widget_to_scrollview(self), max_size);
break;
case MGUI_WIDGET_BUTTON:
- mgui_button_set_width(mgui_widget_to_button(self), width);
+ mgui_button_calculate_size(mgui_widget_to_button(self), max_size);
break;
case MGUI_WIDGET_LABEL:
- mgui_label_set_width(mgui_widget_to_label(self), width);
+ mgui_label_calculate_size(mgui_widget_to_label(self), max_size);
break;
case MGUI_WIDGET_RICHTEXT:
- mgui_richtext_set_width(mgui_widget_to_richtext(self), width);
+ mgui_richtext_calculate_size(mgui_widget_to_richtext(self), max_size);
break;
case MGUI_WIDGET_IMAGE:
- mgui_image_set_width(mgui_widget_to_image(self), width);
+ mgui_image_calculate_size(mgui_widget_to_image(self), max_size);
break;
}
}
+void mgui_widget_set_has_parent(mgui_widget *self) {
+ if(self->flags & MGUI_WIDGET_DEBUG_HAS_PARENT) {
+ fprintf(stderr, "mglgui error: widget %p was added to a list/scrollview twice. One widget can only belong to one list/scrollview.\n", (void*)self);
+ abort();
+ }
+ self->flags |= MGUI_WIDGET_DEBUG_HAS_PARENT;
+}
+
void mgui_widget_on_event(mgui_widget *self, mgl_window *window, mgl_event *event) {
switch(self->type) {
case MGUI_WIDGET_LIST:
@@ -113,20 +157,25 @@ void mgui_widget_on_event(mgui_widget *self, mgl_window *window, mgl_event *even
}
}
-mgl_vec2i mgui_widget_draw(mgui_widget *self, mgl_window *window) {
+void mgui_widget_draw(mgui_widget *self, mgl_window *window) {
switch(self->type) {
case MGUI_WIDGET_LIST:
- return mgui_list_draw(mgui_widget_to_list(self), window);
+ mgui_list_draw(mgui_widget_to_list(self), window);
+ break;
case MGUI_WIDGET_SCROLLVIEW:
- return mgui_scrollview_draw(mgui_widget_to_scrollview(self), window);
+ mgui_scrollview_draw(mgui_widget_to_scrollview(self), window);
+ break;
case MGUI_WIDGET_BUTTON:
- return mgui_button_draw(mgui_widget_to_button(self), window);
+ mgui_button_draw(mgui_widget_to_button(self), window);
+ break;
case MGUI_WIDGET_LABEL:
- return mgui_label_draw(mgui_widget_to_label(self), window);
+ mgui_label_draw(mgui_widget_to_label(self), window);
+ break;
case MGUI_WIDGET_RICHTEXT:
- return mgui_richtext_draw(mgui_widget_to_richtext(self), window);
+ mgui_richtext_draw(mgui_widget_to_richtext(self), window);
+ break;
case MGUI_WIDGET_IMAGE:
- return mgui_image_draw(mgui_widget_to_image(self), window);
+ mgui_image_draw(mgui_widget_to_image(self), window);
+ break;
}
- return (mgl_vec2i){ 0, 0 };
}
diff --git a/tests/main.c b/tests/main.c
index e02d4bb..6261bcd 100644
--- a/tests/main.c
+++ b/tests/main.c
@@ -12,7 +12,6 @@
static mgui_list* create_list_item(const char *title, const char *description) {
mgui_list *container = mgui_list_create(MGUI_LIST_HORIZONITAL);
- mgui_list_set_background_color(container, (mgl_color){ 255, 0, 0, 255 });
mgui_list_append(container, mgui_button_to_widget(mgui_button_create("button", 6, 30)));
mgui_list *list = mgui_list_create(MGUI_LIST_VERTICAL);
@@ -32,7 +31,14 @@ int main() {
if(mgl_window_create(&window, "mgl", &(mgl_window_create_params){ .size = { 1280, 720 } }) != 0)
return 1;
+ mgui_list *root = mgui_list_create(MGUI_LIST_VERTICAL);
+ mgui_widget *root_widget = mgui_list_to_widget(root);
+ mgui_list_append(root, mgui_list_to_widget(create_list_item("Title", "Description")));
+
mgui_scrollview *scrollview = mgui_scrollview_create();
+ mgui_widget_set_expand(mgui_scrollview_to_widget(scrollview), false, true);
+ mgui_list_append(root, mgui_scrollview_to_widget(scrollview));
+
mgui_list *list = mgui_list_create(MGUI_LIST_VERTICAL);
mgui_scrollview_set_child(scrollview, mgui_list_to_widget(list));
for(int i = 0; i < 30; ++i) {
@@ -41,20 +47,21 @@ int main() {
mgui_list_append(list, mgui_list_to_widget(create_list_item("User", text)));
}
+ mgui_list_append(root, mgui_list_to_widget(create_list_item("Bottom", "bottom")));
+
mgl_event event;
while(mgl_window_is_open(&window)) {
while(mgl_window_poll_event(&window, &event)) {
- if(event.type == MGL_EVENT_RESIZED)
- mgui_scrollview_set_size(scrollview, (mgl_vec2i){ event.size.width, event.size.height });
- mgui_scrollview_on_event(scrollview, &window, &event);
+ mgui_on_event(root_widget, &window, &event);
}
mgl_window_clear(&window, (mgl_color){ 0, 0, 0, 0 });
- mgui_draw(mgui_scrollview_to_widget(scrollview), &window);
+ mgui_draw(root_widget, &window);
mgl_window_display(&window);
}
- mgui_widget_destroy(mgui_scrollview_to_widget(scrollview));
+ mgui_widget_destroy(root_widget);
+ mgl_window_deinit(&window);
mgl_deinit();
return 0;
}