aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-12-04 01:37:07 +0100
committerdec05eba <dec05eba@protonmail.com>2021-12-04 01:37:07 +0100
commitd3a5b3d579e30ce02afd5e270dfdd511af195c31 (patch)
tree7d5aaa9d8289e7f8af2d62f796336f207375b610
parent9644f3c05b808a3cac3892aae36ffca2cce9357d (diff)
Add image
-rw-r--r--TODO7
m---------depends/mgl0
-rw-r--r--include/mgui/button.h4
-rw-r--r--include/mgui/image.h22
-rw-r--r--include/mgui/label.h27
-rw-r--r--include/mgui/list.h9
-rw-r--r--include/mgui/widget.h4
-rw-r--r--src/mgui/button.c19
-rw-r--r--src/mgui/image.c54
-rw-r--r--src/mgui/label.c64
-rw-r--r--src/mgui/list.c52
-rw-r--r--src/mgui/widget.c26
-rw-r--r--tests/main.c25
13 files changed, 275 insertions, 38 deletions
diff --git a/TODO b/TODO
index 98651c3..d5220a9 100644
--- a/TODO
+++ b/TODO
@@ -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);
}