diff options
Diffstat (limited to 'src/mgui')
-rw-r--r-- | src/mgui/button.c | 4 | ||||
-rw-r--r-- | src/mgui/image.c | 38 | ||||
-rw-r--r-- | src/mgui/label.c | 4 | ||||
-rw-r--r-- | src/mgui/list.c | 32 | ||||
-rw-r--r-- | src/mgui/mgui.c | 24 | ||||
-rw-r--r-- | src/mgui/richtext.c | 26 | ||||
-rw-r--r-- | src/mgui/scrollview.c | 42 | ||||
-rw-r--r-- | src/mgui/widget.c | 21 |
8 files changed, 153 insertions, 38 deletions
diff --git a/src/mgui/button.c b/src/mgui/button.c index 00db361..d77750d 100644 --- a/src/mgui/button.c +++ b/src/mgui/button.c @@ -12,6 +12,10 @@ static int min_int(int a, int b) { } mgui_button* mgui_button_create(const char *str, size_t size, unsigned char character_size) { + /* TODO: Make this work for character size >= 100 */ + if(character_size >= 100) + character_size = 99; + mgui_button *button = mgui_alloc(sizeof(mgui_button)); mgui_widget_init(&button->widget, MGUI_WIDGET_BUTTON); button->background.position = (mgl_vec2f){ 0.0f, 0.0f }; diff --git a/src/mgui/image.c b/src/mgui/image.c index 1a0871f..9f50b9c 100644 --- a/src/mgui/image.c +++ b/src/mgui/image.c @@ -2,12 +2,15 @@ #include "../../include/resource_loader.h" #include "../../include/common.h" #include "../../include/alloc.h" +#include "../../include/async_image.h" #include <mgl/mgl.h> #include <mgl/window/event.h> -#include <mgl/graphics/texture.h> +#include <stdio.h> +#include <stdlib.h> #include <assert.h> -/* TODO: Load image asynchronously and support network files */ +/* TODO: Support network files */ +/* TODO: Set a target size and use that for calculating size and resize image to that */ static mgl_vec2i wrap_to_size_x(mgl_vec2i size, int clamp_size) { mgl_vec2i new_size; @@ -52,13 +55,24 @@ static mgl_vec2i clamp_to_size(mgl_vec2i size, mgl_vec2i clamp_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); - (void)filepath; - /* TODO: Use |filepath| */ mgl_sprite_init(&image->sprite, NULL); + image->max_size = (mgl_vec2i){ 0, 0 }; + + if(filepath) { + image->async_image = mgui_async_image_get_by_path(filepath); + if(image->async_image->state == MGUI_ASYNC_IMAGE_APPLIED) + mgl_sprite_set_texture(&image->sprite, &image->async_image->texture); + } else { + image->async_image = NULL; + } + return image; } void mgui_image_destroy(mgui_image *image) { + if(image->async_image) + mgui_async_image_unref(image->async_image); + image->sprite.texture = NULL; mgui_free(image); } @@ -76,6 +90,7 @@ void mgui_image_set_position(mgui_image *self, mgl_vec2i position) { } void mgui_image_calculate_size(mgui_image *self, mgl_vec2i max_size) { + self->max_size = 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); @@ -85,7 +100,7 @@ void mgui_image_calculate_size(mgui_image *self, mgl_vec2i max_size) { self->widget.size = new_size; } else { - self->widget.size = (mgl_vec2i){ 0, 0 }; + self->widget.size = (mgl_vec2i){ 1, 1 }; } } @@ -97,9 +112,14 @@ void mgui_image_on_event(mgui_image *self, mgl_window *window, mgl_event *event) } 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); + if(self->async_image && mgui_rectangle_intersects_with_scissor((mgl_vec2i){ self->sprite.position.x, self->sprite.position.y }, self->widget.size, window)) { + mgui_async_image_update(self->async_image); + if(self->async_image->state == MGUI_ASYNC_IMAGE_APPLIED) { + mgl_sprite_set_texture(&self->sprite, &self->async_image->texture); + /* TODO: Check if this is correct when taking margin into consideration */ + mgui_image_calculate_size(self, self->max_size); + if(self->sprite.texture && self->sprite.texture->id) + mgl_sprite_draw(mgl_get_context(), &self->sprite); + } } } diff --git a/src/mgui/label.c b/src/mgui/label.c index e380aac..4f5b51f 100644 --- a/src/mgui/label.c +++ b/src/mgui/label.c @@ -14,6 +14,10 @@ static int min_int(int a, int b) { } mgui_label* mgui_label_create(const char *str, size_t size, unsigned char character_size) { + /* TODO: Make this work for character size >= 100 */ + if(character_size >= 100) + character_size = 99; + mgui_label *label = mgui_alloc(sizeof(mgui_label)); mgui_widget_init(&label->widget, MGUI_WIDGET_LABEL); label->str = mgui_alloc(size); diff --git a/src/mgui/list.c b/src/mgui/list.c index 687906d..ee58616 100644 --- a/src/mgui/list.c +++ b/src/mgui/list.c @@ -16,6 +16,7 @@ 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->spacing = 0; list->position = (mgl_vec2i){ 0, 0 }; list->items = NULL; list->items_capacity = 0; @@ -40,14 +41,25 @@ mgui_list* mgui_widget_to_list(mgui_widget *widget) { return (mgui_list*)widget; } +void mgui_list_set_spacing(mgui_list *self, int spacing) { + /* TODO: Multiply by scaling */ + self->spacing = spacing; + /* TODO: mgui_list_calculate_size */ +} + void mgui_list_set_position(mgui_list *self, mgl_vec2i position) { self->position = position; } void mgui_list_calculate_size(mgui_list *self, mgl_vec2i max_size) { + const int total_spacing = max_int(0, self->num_items - 1) * self->spacing; + mgl_vec2i size = (mgl_vec2i){ 0, 0 }; switch(self->direction) { case MGUI_LIST_HORIZONITAL: { + size.x = total_spacing; + max_size.x = max_int(0, max_size.x - total_spacing); + int num_expanded_widgets = 0; for(size_t i = 0; i < self->num_items; ++i) { mgui_widget *widget = self->items[i].widget; @@ -78,6 +90,9 @@ void mgui_list_calculate_size(mgui_list *self, mgl_vec2i max_size) { break; } case MGUI_LIST_VERTICAL: { + size.y = total_spacing; + max_size.y = max_int(0, max_size.y - total_spacing); + int num_expanded_widgets = 0; for(size_t i = 0; i < self->num_items; ++i) { mgui_widget *widget = self->items[i].widget; @@ -150,22 +165,31 @@ void mgui_list_draw(mgui_list *self, mgl_window *window) { /* TODO: Only do this when a direct child widget is dirty */ //mgui_list_calculate_size(self); + mgl_scissor scissor; + mgl_window_get_scissor(window, &scissor); + switch(self->direction) { case MGUI_LIST_HORIZONITAL: { for(size_t i = 0; i < self->num_items; ++i) { mgui_widget *widget = self->items[i].widget; - mgui_widget_set_position(widget, position); + mgui_widget_set_position(widget, (mgl_vec2i){ position.x + widget->margin.left, position.y + widget->margin.top }); mgui_widget_draw(widget, window); - position.x += widget->size.x; + position.x += widget->size.x + self->spacing; + + // if(position.x >= scissor.position.x + scissor.size.x) + // break; } break; } case MGUI_LIST_VERTICAL: { for(size_t i = 0; i < self->num_items; ++i) { mgui_widget *widget = self->items[i].widget; - mgui_widget_set_position(widget, position); + mgui_widget_set_position(widget, (mgl_vec2i){ position.x + widget->margin.left, position.y + widget->margin.top }); mgui_widget_draw(widget, window); - position.y += widget->size.y; + position.y += widget->size.y + self->spacing; + + // if(position.y >= scissor.position.y + scissor.size.y) + // break; } break; } diff --git a/src/mgui/mgui.c b/src/mgui/mgui.c index 3c1d955..0d9f20d 100644 --- a/src/mgui/mgui.c +++ b/src/mgui/mgui.c @@ -1,29 +1,47 @@ #include "../../include/mgui/mgui.h" #include "../../include/mgui/widget.h" +#include "../../include/async_image.h" #include <mgl/window/event.h> #include <mgl/system/clock.h> +static mgl_vec2i root_widget_size; static mgl_clock global_timer; +static double frame_time; void mgui_init() { mgl_clock_init(&global_timer); + mgui_async_image_init(); + frame_time = 0.0; +} + +void mgui_deinit() { + mgui_async_image_deinit(); } 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 }); + root_widget_size = (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_calculate_size(root_widget, root_widget_size); + mgui_widget_set_position(root_widget, (mgl_vec2i){ root_widget->margin.left, root_widget->margin.top }); mgui_widget_draw(root_widget, window); + mgui_async_image_unload_unreferenced(); + frame_time = mgl_clock_restart(&global_timer); + if(frame_time > 1.0) + frame_time = 1.0; } double mgui_get_seconds_since_last_update() { - double elapsed_time_sec = mgl_clock_restart(&global_timer); + double elapsed_time_sec = mgl_clock_get_elapsed_time_seconds(&global_timer); if(elapsed_time_sec > 1.0) elapsed_time_sec = 1.0; return elapsed_time_sec; } + +double mgui_get_frame_time_seconds() { + return frame_time; +} diff --git a/src/mgui/richtext.c b/src/mgui/richtext.c index 9b1acfc..77ee3c1 100644 --- a/src/mgui/richtext.c +++ b/src/mgui/richtext.c @@ -105,6 +105,10 @@ static void mgui_richtext_vertices_free(mgui_richtext *self, size_t vertex_index } mgui_richtext* mgui_richtext_create(const char *str, size_t size, unsigned char character_size) { + /* TODO: Make this work for character size >= 100 */ + if(character_size >= 100) + character_size = 99; + mgui_richtext *richtext = mgui_alloc(sizeof(mgui_richtext)); mgui_widget_init(&richtext->widget, MGUI_WIDGET_RICHTEXT); richtext->str = mgui_alloc(size); @@ -120,6 +124,7 @@ mgui_richtext* mgui_richtext_create(const char *str, size_t size, unsigned char richtext->vertex_data[i].vertex_count = 0; } richtext->dirty = true; + richtext->vertices_dirty = true; return richtext; } @@ -177,7 +182,7 @@ static void mgui_richtext_append_glyph(mgui_richtext *self, size_t vertex_index, mgui_richtext_vertices_append(self, vertex_index, &top_right_vertex); } -static void mgui_richtext_update(mgui_richtext *self) { +static void mgui_richtext_update(mgui_richtext *self, bool build_vertices) { for(size_t i = 0; i < NUM_VERTEX_DATA; ++i) { mgui_richtext_vertices_clear(self, i); } @@ -231,9 +236,11 @@ static void mgui_richtext_update(mgui_richtext *self) { if(position.x + glyph.size.x > self->width) { position.x = 0; position.y += self->character_size; + self->render_size.y += self->character_size; } - mgui_richtext_append_glyph(self, vertex_index, position, color, &glyph); + if(build_vertices) + mgui_richtext_append_glyph(self, vertex_index, position, color, &glyph); position.x += glyph.advance + mgl_font_get_kerning(font, prev_codepoint, codepoint); self->render_size.x = max_int(self->render_size.x, position.x); } @@ -249,13 +256,16 @@ 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; + const bool is_multiple_lines = self->render_size.y > (int)self->character_size; + if(is_multiple_lines || self->width < self->render_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); + mgui_richtext_update(self, false); + self->vertices_dirty = true; self->widget.size.x = self->render_size.x; self->widget.size.y = min_int(self->render_size.y, max_size.y); } @@ -271,9 +281,9 @@ void mgui_richtext_on_event(mgui_richtext *self, mgl_window *window, mgl_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); + if(self->vertices_dirty) { + self->vertices_dirty = false; + mgui_richtext_update(self, true); } const mgui_font_type font_types[NUM_VERTEX_DATA] = { @@ -295,6 +305,6 @@ void mgui_richtext_draw(mgui_richtext *self, mgl_window *window) { for(size_t i = 0; i < NUM_VERTEX_DATA; ++i) { mgui_richtext_vertices_free(self, i); } - self->dirty = true; + self->vertices_dirty = true; } } diff --git a/src/mgui/scrollview.c b/src/mgui/scrollview.c index c7a4075..a11862f 100644 --- a/src/mgui/scrollview.c +++ b/src/mgui/scrollview.c @@ -4,6 +4,7 @@ #include <mgl/mgl.h> #include <mgl/window/window.h> #include <mgl/window/event.h> +#include <mgl/graphics/rectangle.h> #include <limits.h> #include <assert.h> @@ -68,14 +69,15 @@ void mgui_scrollview_set_position(mgui_scrollview *self, mgl_vec2i position) { 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) + if(self->widget.size.x >= WIDGET_NATURAL_SIZE/2 || self->widget.size.y >= WIDGET_NATURAL_SIZE/2) { + self->widget.size.x = 500; self->widget.size.y = 600; + } + /* TODO: this assumes child list uses vertical scroll. Make this work for horizontal scroll as well */ if(self->child) - mgui_widget_calculate_size(self->child, (mgl_vec2i){ WIDGET_NATURAL_SIZE, WIDGET_NATURAL_SIZE }); + mgui_widget_calculate_size(self->child, (mgl_vec2i){ max_size.x, WIDGET_NATURAL_SIZE }); } void mgui_scrollview_on_event(mgui_scrollview *self, mgl_window *window, mgl_event *event) { @@ -90,7 +92,7 @@ void mgui_scrollview_on_event(mgui_scrollview *self, mgl_window *window, mgl_eve /* TODO: Check if visible in scissor */ void mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window) { - const double frame_time = mgui_get_seconds_since_last_update(); + const double frame_time = mgui_get_frame_time_seconds(); 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)); @@ -127,15 +129,41 @@ void mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window) { mgl_scissor prev_scissor; mgl_window_get_scissor(window, &prev_scissor); + /* TODO: Fix all this margin crap, it should be invisible */ + const int margin_width = self->widget.margin.top + self->widget.margin.bottom; + const int margin_height = self->widget.margin.top + self->widget.margin.bottom; + mgl_scissor new_scissor = { .position = self->position, - .size = self->widget.size + .size = (mgl_vec2i){ self->widget.size.x - margin_width, self->widget.size.y - margin_height } }; 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 }); + mgui_widget_set_position(self->child, + (mgl_vec2i){ self->position.x + self->scroll.x + self->child->margin.left, self->position.y + self->scroll.y + self->child->margin.top }); mgui_widget_draw(self->child, window); mgl_window_set_scissor(window, &prev_scissor); + + { + /* TODO: Fix all this margin crap, it should be invisible */ + const int margin_height = self->widget.margin.top + self->widget.margin.bottom; + const int height = self->widget.size.y - margin_height; + const double scrollbar_height_ratio = child_size.y == 0 ? 0.0 : (double)height / (double)child_size.y; + const int scrollbar_height = scrollbar_height_ratio * height; + + const double scroll_ratio = child_size.y == 0 ? 0.0 : (double)-self->scroll.y / (double)child_size.y; + const int scrollbar_offset_y = height * scroll_ratio; + + const int scrollbar_width = 5; + const int right = self->widget.size.x - self->widget.margin.left - self->widget.margin.right; + mgl_rectangle rect = { + .position = { self->position.x + right - scrollbar_width, self->position.y + scrollbar_offset_y }, + .size = { scrollbar_width, scrollbar_height }, + .color = { 55, 60, 68, 255 } + }; + + mgl_rectangle_draw(mgl_get_context(), &rect); + } } } diff --git a/src/mgui/widget.c b/src/mgui/widget.c index ed50154..4e93b8a 100644 --- a/src/mgui/widget.c +++ b/src/mgui/widget.c @@ -9,7 +9,6 @@ #include <stdio.h> #include <stdlib.h> -/* TODO: Use margin */ /* TODO: Use alignment */ /* TODO: Use visible flag */ @@ -34,6 +33,7 @@ void mgui_widget_init(mgui_widget *self, mgui_widget_type type) { self->alignment = MGUI_WIDGET_ALIGN_TOP_LEFT; mgui_widget_set_margin(self, (mgui_margin){ 0, 0, 0, 0 }); self->size = (mgl_vec2i){ 0, 0 }; + self->userdata = NULL; } void mgui_widget_destroy(mgui_widget *widget) { @@ -104,26 +104,33 @@ void mgui_widget_set_position(mgui_widget *self, mgl_vec2i position) { } void mgui_widget_calculate_size(mgui_widget *self, mgl_vec2i max_size) { + const int margin_width = self->margin.left + self->margin.right; + const int margin_height = self->margin.top + self->margin.bottom; + const mgl_vec2i max_size_result = (mgl_vec2i){ max_size.x - margin_width, max_size.y - margin_height }; + switch(self->type) { case MGUI_WIDGET_LIST: - mgui_list_calculate_size(mgui_widget_to_list(self), max_size); + mgui_list_calculate_size(mgui_widget_to_list(self), max_size_result); break; case MGUI_WIDGET_SCROLLVIEW: - mgui_scrollview_calculate_size(mgui_widget_to_scrollview(self), max_size); + mgui_scrollview_calculate_size(mgui_widget_to_scrollview(self), max_size_result); break; case MGUI_WIDGET_BUTTON: - mgui_button_calculate_size(mgui_widget_to_button(self), max_size); + mgui_button_calculate_size(mgui_widget_to_button(self), max_size_result); break; case MGUI_WIDGET_LABEL: - mgui_label_calculate_size(mgui_widget_to_label(self), max_size); + mgui_label_calculate_size(mgui_widget_to_label(self), max_size_result); break; case MGUI_WIDGET_RICHTEXT: - mgui_richtext_calculate_size(mgui_widget_to_richtext(self), max_size); + mgui_richtext_calculate_size(mgui_widget_to_richtext(self), max_size_result); break; case MGUI_WIDGET_IMAGE: - mgui_image_calculate_size(mgui_widget_to_image(self), max_size); + mgui_image_calculate_size(mgui_widget_to_image(self), max_size_result); break; } + + self->size.x += margin_width; + self->size.y += margin_height; } void mgui_widget_set_has_parent(mgui_widget *self) { |