diff options
-rw-r--r-- | TODO | 7 | ||||
m--------- | depends/mgl | 0 | ||||
-rw-r--r-- | include/mgui/button.h | 4 | ||||
-rw-r--r-- | include/mgui/image.h | 22 | ||||
-rw-r--r-- | include/mgui/label.h | 27 | ||||
-rw-r--r-- | include/mgui/list.h | 9 | ||||
-rw-r--r-- | include/mgui/widget.h | 4 | ||||
-rw-r--r-- | src/mgui/button.c | 19 | ||||
-rw-r--r-- | src/mgui/image.c | 54 | ||||
-rw-r--r-- | src/mgui/label.c | 64 | ||||
-rw-r--r-- | src/mgui/list.c | 52 | ||||
-rw-r--r-- | src/mgui/widget.c | 26 | ||||
-rw-r--r-- | tests/main.c | 25 |
13 files changed, 275 insertions, 38 deletions
@@ -1 +1,6 @@ -Destroy widgets when the container is destroyed.
\ No newline at end of file +Widget alignment. +Widget horizontal/vertical expand. +Destroy widgets when the container is destroyed. +Homogeneous sizing for list items. +Allow setting list direction. This is more efficient than prepending widgets to a list. +To do not render widgets outside the current scissor (or window). Also stop rendering scroll view when reaching outside the scissor view.
\ No newline at end of file diff --git a/depends/mgl b/depends/mgl -Subproject 8792ee2cc5b501f0611e6304f529226a495825d +Subproject a77da0acc88c7fb861043fd0dcb9cc6536e591f diff --git a/include/mgui/button.h b/include/mgui/button.h index aefc3fe..d9e8783 100644 --- a/include/mgui/button.h +++ b/include/mgui/button.h @@ -1,14 +1,14 @@ #ifndef MGUI_BUTTON_H #define MGUI_BUTTON_H +#include "widget.h" #include <mgl/graphics/rectangle.h> #include <mgl/graphics/text.h> -#include "widget.h" typedef struct { mgui_widget widget; mgl_rectangle background; - mgl_text label; + mgl_text text; } mgui_button; mgui_button* mgui_button_create(); diff --git a/include/mgui/image.h b/include/mgui/image.h new file mode 100644 index 0000000..c1072d4 --- /dev/null +++ b/include/mgui/image.h @@ -0,0 +1,22 @@ +#ifndef MGUI_IMAGE_H +#define MGUI_IMAGE_H + +#include "widget.h" +#include <mgl/graphics/sprite.h> + +typedef struct { + mgui_widget widget; + mgl_sprite sprite; +} mgui_image; + +mgui_image* mgui_image_create(const char *filepath); +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_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); + +#endif /* MGUI_IMAGE_H */ diff --git a/include/mgui/label.h b/include/mgui/label.h new file mode 100644 index 0000000..920ecf9 --- /dev/null +++ b/include/mgui/label.h @@ -0,0 +1,27 @@ +#ifndef MGUI_LABEL_H +#define MGUI_LABEL_H + +#include "widget.h" +#include <stddef.h> +#include <mgl/graphics/text.h> + +typedef struct { + mgui_widget widget; + 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); +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_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); + +#endif /* MGUI_LABEL_H */ diff --git a/include/mgui/list.h b/include/mgui/list.h index 6f359c9..f0080c8 100644 --- a/include/mgui/list.h +++ b/include/mgui/list.h @@ -3,6 +3,7 @@ #include "widget.h" #include <stddef.h> +#include <mgl/graphics/color.h> typedef struct mgl_window mgl_window; typedef struct mgl_event mgl_event; @@ -16,19 +17,19 @@ typedef struct { mgui_widget widget; mgui_list_direction direction; mgl_vec2i position; - mgl_vec2i size; + mgl_color background_color; mgui_widget **items; - size_t num_items; size_t items_capacity; + size_t num_items; } mgui_list; -mgui_list* mgui_list_create(mgui_list_direction direction, mgl_vec2i size); +mgui_list* mgui_list_create(mgui_list_direction direction); 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_size(mgui_list *self, mgl_vec2i size); 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_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 */ diff --git a/include/mgui/widget.h b/include/mgui/widget.h index c831325..ec19a98 100644 --- a/include/mgui/widget.h +++ b/include/mgui/widget.h @@ -9,7 +9,9 @@ typedef struct mgui_widget mgui_widget; typedef enum { MGUI_WIDGET_LIST, - MGUI_WIDGET_BUTTON + MGUI_WIDGET_BUTTON, + MGUI_WIDGET_LABEL, + MGUI_WIDGET_IMAGE } mgui_widget_type; typedef struct { diff --git a/src/mgui/button.c b/src/mgui/button.c index b548140..08cf91c 100644 --- a/src/mgui/button.c +++ b/src/mgui/button.c @@ -12,8 +12,8 @@ mgui_button* mgui_button_create() { button->background.position = (mgl_vec2f){ 0.0f, 0.0f }; button->background.size = (mgl_vec2f){ 0.0f, 0.0f }; button->background.color = (mgl_color){ 45, 45, 45, 255 }; - mgl_text_init(&button->label, mgui_get_font(MGUI_FONT_LATIN, 32), "Label", 5); - button->background.size = mgl_text_get_bounds(&button->label); + mgl_text_init(&button->text, mgui_get_font(MGUI_FONT_LATIN, 32), "Label", 5); + button->background.size = mgl_text_get_bounds(&button->text); return button; } @@ -27,11 +27,11 @@ mgui_button* mgui_widget_to_button(mgui_widget *widget) { } void mgui_button_set_position(mgui_button *self, mgl_vec2i position) { - const mgl_vec2f label_bounds = mgl_text_get_bounds(&self->label); + const mgl_vec2f text_bounds = mgl_text_get_bounds(&self->text); self->background.position = (mgl_vec2f){ position.x, position.y }; - mgl_text_set_position(&self->label, (mgl_vec2f){ - (int)(self->background.position.x + self->background.size.x * 0.5f - label_bounds.x * 0.5f), - (int)(self->background.position.y + self->background.size.y * 0.5f - label_bounds.y * 0.5f) + mgl_text_set_position(&self->text, (mgl_vec2f){ + (int)(self->background.position.x + self->background.size.x * 0.5f - text_bounds.x * 0.5f), + (int)(self->background.position.y + self->background.size.y * 0.5f - text_bounds.y * 0.5f) }); } @@ -40,13 +40,12 @@ static int max_int(int a, int b) { } void mgui_button_set_width(mgui_button *self, int width) { - mgl_vec2f label_bounds = mgl_text_get_bounds(&self->label); - self->background.size.x = max_int(label_bounds.x, width); + const mgl_vec2f text_bounds = mgl_text_get_bounds(&self->text); + self->background.size.x = max_int(text_bounds.x, width); mgui_button_set_position(self, (mgl_vec2i){ self->background.position.x, self->background.position.y }); } void mgui_button_on_event(mgui_button *self, mgl_window *window, mgl_event *event) { - // TODO: Implement (void)window; if(event->type == MGL_EVENT_MOUSE_MOVED) { if(mgui_rectangle_contains(self->background.position, self->background.size, (mgl_vec2f){ event->mouse_move.x, event->mouse_move.y })) { @@ -64,6 +63,6 @@ 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)window; mgl_rectangle_draw(mgl_get_context(), &self->background); - mgl_text_draw(mgl_get_context(), &self->label); + mgl_text_draw(mgl_get_context(), &self->text); return (mgl_vec2i){ self->background.size.x, self->background.size.y }; } diff --git a/src/mgui/image.c b/src/mgui/image.c new file mode 100644 index 0000000..ad8a7d2 --- /dev/null +++ b/src/mgui/image.c @@ -0,0 +1,54 @@ +#include "../../include/mgui/image.h" +#include "../../include/resource_loader.h" +#include "../../include/common.h" +#include "../../include/alloc.h" +#include <mgl/mgl.h> +#include <mgl/window/event.h> +#include <mgl/graphics/texture.h> +#include <assert.h> + +/* TODO: Load image asynchronously and support network files */ + +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); + return image; +} + +mgui_widget* mgui_image_to_widget(mgui_image *list) { + return &list->widget; +} + +mgui_image* mgui_widget_to_image(mgui_widget *widget) { + assert(widget->type == MGUI_WIDGET_IMAGE); + return (mgui_image*)widget; +} + +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_on_event(mgui_image *self, mgl_window *window, mgl_event *event) { + (void)self; + (void)window; + (void)event; + /* TODO: Implement */ +} + +mgl_vec2i mgui_image_draw(mgui_image *self, mgl_window *window) { + (void)window; + mgl_sprite_draw(mgl_get_context(), &self->sprite); + if(self->sprite.texture) + return (mgl_vec2i){ self->sprite.texture->width, self->sprite.texture->height }; + else + return (mgl_vec2i){ 0, 0 }; +} diff --git a/src/mgui/label.c b/src/mgui/label.c new file mode 100644 index 0000000..5ab1bc0 --- /dev/null +++ b/src/mgui/label.c @@ -0,0 +1,64 @@ +#include "../../include/mgui/label.h" +#include "../../include/resource_loader.h" +#include "../../include/common.h" +#include "../../include/alloc.h" +#include <mgl/mgl.h> +#include <mgl/window/event.h> +#include <string.h> +#include <assert.h> + +/* TODO: Scale label by scale setting */ + +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); + label->str = mgui_alloc(size); + 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; +} + +mgui_widget* mgui_label_to_widget(mgui_label *list) { + return &list->widget; +} + +mgui_label* mgui_widget_to_label(mgui_widget *widget) { + assert(widget->type == MGUI_WIDGET_LABEL); + return (mgui_label*)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 + }); +} + +static int max_int(int a, int b) { + return a >= b ? a : b; +} + +void mgui_label_set_width(mgui_label *self, int width) { + 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); +} + +void mgui_label_on_event(mgui_label *self, mgl_window *window, mgl_event *event) { + /* TODO: Implement */ + (void)self; + (void)window; + (void)event; +} + +mgl_vec2i mgui_label_draw(mgui_label *self, mgl_window *window) { + (void)window; + const mgl_vec2f text_bounds = mgl_text_get_bounds(&self->text); + mgl_text_draw(mgl_get_context(), &self->text); + return (mgl_vec2i){ text_bounds.x, text_bounds.y }; +} diff --git a/src/mgui/list.c b/src/mgui/list.c index 9923c4f..a3a2422 100644 --- a/src/mgui/list.c +++ b/src/mgui/list.c @@ -1,17 +1,24 @@ #include "../../include/mgui/list.h" #include "../../include/alloc.h" #include <mgl/window/window.h> +#include <mgl/graphics/rectangle.h> +#include <mgl/mgl.h> #include <assert.h> -mgui_list* mgui_list_create(mgui_list_direction direction, mgl_vec2i size) { +/* + TODO: Optimize for lists with 2 items or less by setting |items| and |items_capacity| to the first and second item + if num_items <= 2. +*/ + +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->size = size; + list->background_color = (mgl_color){ 0, 0, 0, 0 }; list->items = NULL; - list->num_items = 0; list->items_capacity = 0; + list->num_items = 0; return list; } @@ -28,20 +35,19 @@ void mgui_list_set_position(mgui_list *self, mgl_vec2i position) { self->position = position; } -void mgui_list_set_size(mgui_list *self, mgl_vec2i size) { - self->size = size; +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], size.x); + mgui_widget_set_width(self->items[i], width); } } } -void mgui_list_set_width(mgui_list *self, int width) { - mgui_list_set_size(self, (mgl_vec2i){ width, self->size.y }); +void mgui_list_set_background_color(mgui_list *self, mgl_color color) { + self->background_color = color; } static void mgui_list_ensure_capacity(mgui_list *self, size_t new_capacity) { @@ -77,18 +83,33 @@ static int max_int(int a, int b) { } mgl_vec2i mgui_list_draw(mgui_list *self, mgl_window *window) { - mgl_vec2i position = (mgl_vec2i){ 0, 0 }; + mgl_vec2i position = self->position; /* TODO: */ mgl_vec2i size = (mgl_vec2i){ 0, 0 }; - mgl_view prev_view; - mgl_window_get_view(window, &prev_view); + /* TODO: + mgl_scissor prev_scissor; + mgl_window_get_scissor(window, &prev_scissor); - mgl_view new_view = { - .position = { self->position.x, self->position.y }, + mgl_scissor new_scissor = { + .position = self->position, .size = self->size }; - mgl_window_set_view(window, &new_view); + mgl_window_set_scissor(window, &new_scissor); + */ + + /* 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 */ switch(self->direction) { case MGUI_LIST_HORIZONITAL: { @@ -113,6 +134,7 @@ mgl_vec2i mgui_list_draw(mgui_list *self, mgl_window *window) { } } - mgl_window_set_view(window, &prev_view); /* TODO: Remove */ + /* TODO: Remove */ + /*mgl_window_set_scissor(window, &prev_scissor);*/ return size; } diff --git a/src/mgui/widget.c b/src/mgui/widget.c index 195d253..63bc97b 100644 --- a/src/mgui/widget.c +++ b/src/mgui/widget.c @@ -1,6 +1,10 @@ #include "../../include/mgui/widget.h" #include "../../include/mgui/list.h" #include "../../include/mgui/button.h" +#include "../../include/mgui/label.h" +#include "../../include/mgui/image.h" + +/* TODO: Use margin */ void mgui_widget_init(mgui_widget *self, mgui_widget_type type) { self->type = type; @@ -22,6 +26,12 @@ void mgui_widget_set_position(mgui_widget *self, mgl_vec2i position) { case MGUI_WIDGET_BUTTON: mgui_button_set_position(mgui_widget_to_button(self), position); break; + case MGUI_WIDGET_LABEL: + mgui_label_set_position(mgui_widget_to_label(self), position); + break; + case MGUI_WIDGET_IMAGE: + mgui_image_set_position(mgui_widget_to_image(self), position); + break; } } @@ -33,6 +43,12 @@ void mgui_widget_set_width(mgui_widget *self, int width) { case MGUI_WIDGET_BUTTON: mgui_button_set_width(mgui_widget_to_button(self), width); break; + case MGUI_WIDGET_LABEL: + mgui_label_set_width(mgui_widget_to_label(self), width); + break; + case MGUI_WIDGET_IMAGE: + mgui_image_set_width(mgui_widget_to_image(self), width); + break; } } @@ -44,6 +60,12 @@ void mgui_widget_on_event(mgui_widget *self, mgl_window *window, mgl_event *even case MGUI_WIDGET_BUTTON: mgui_button_on_event(mgui_widget_to_button(self), window, event); break; + case MGUI_WIDGET_LABEL: + mgui_label_on_event(mgui_widget_to_label(self), window, event); + break; + case MGUI_WIDGET_IMAGE: + mgui_image_on_event(mgui_widget_to_image(self), window, event); + break; } } @@ -53,6 +75,10 @@ mgl_vec2i mgui_widget_draw(mgui_widget *self, mgl_window *window) { return mgui_list_draw(mgui_widget_to_list(self), window); case MGUI_WIDGET_BUTTON: return mgui_button_draw(mgui_widget_to_button(self), window); + case MGUI_WIDGET_LABEL: + return mgui_label_draw(mgui_widget_to_label(self), window); + case MGUI_WIDGET_IMAGE: + return mgui_image_draw(mgui_widget_to_image(self), window); } return (mgl_vec2i){ 0, 0 }; } diff --git a/tests/main.c b/tests/main.c index 5f07558..2356cb3 100644 --- a/tests/main.c +++ b/tests/main.c @@ -1,8 +1,22 @@ #include "../include/mgui/list.h" #include "../include/mgui/button.h" +#include "../include/mgui/label.h" #include <mgl/mgl.h> #include <mgl/window/window.h> #include <mgl/window/event.h> +#include <string.h> + +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())); + + mgui_list *list = mgui_list_create(MGUI_LIST_VERTICAL); + mgui_list_append(container, mgui_list_to_widget(list)); + mgui_list_append(list, mgui_label_to_widget(mgui_label_create(title, strlen(title), 30))); + mgui_list_append(list, mgui_label_to_widget(mgui_label_create(description, strlen(description), 24))); + return container; +} int main() { if(mgl_init() != 0) @@ -12,20 +26,21 @@ int main() { if(mgl_window_create(&window, "mgl", &(mgl_window_create_params){ .size = { 1280, 720 } }) != 0) return 1; - mgui_list *list = mgui_list_create(MGUI_LIST_VERTICAL, (mgl_vec2i){ 1280, 720 }); - mgui_list_append(list, mgui_button_to_widget(mgui_button_create())); - mgui_list_append(list, mgui_button_to_widget(mgui_button_create())); + mgui_list *list = mgui_list_create(MGUI_LIST_VERTICAL); + mgui_list_append(list, mgui_list_to_widget(create_list_item("Slashbash", "A government has a duty to its own people, first and foremost. If they don't protect their people, they are failing their duties and should be removed."))); + mgui_list_append(list, mgui_list_to_widget(create_list_item("Andy F.", "Immigration to ANY nation is a privilege given by that nation, not a right."))); mgl_event event; while(mgl_window_is_open(&window)) { while(mgl_window_poll_event(&window, &event)) { + /* TODO: if(event.type == MGL_EVENT_RESIZED) { mgui_list_set_size(list, (mgl_vec2i){ event.size.width, event.size.height }); - } + }*/ mgui_list_on_event(list, &window, &event); } - mgl_window_clear(&window, (mgl_color){0, 0, 0, 0}); + mgl_window_clear(&window, (mgl_color){ 0, 0, 0, 0 }); mgui_list_draw(list, &window); mgl_window_display(&window); } |