From a9a15fd4c8b0151159e7f97d058703f4dc83bada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sun, 20 Jun 2021 21:18:52 +0200 Subject: [PATCH] feat: add base gui functions --- lib-pheripherals/src/direction.c | 18 ++++ text-viewer/include/gui.h | 148 ++++++++++++++++++++++++++ text-viewer/src/gui.c | 56 ++++++++++ text-viewer/src/gui_component.c | 56 ++++++++++ text-viewer/src/gui_container.c | 35 ++++++ text-viewer/src/gui_group_container.c | 40 +++++++ text-viewer/src/gui_one_container.c | 37 +++++++ text-viewer/src/gui_window.c | 20 ++++ 8 files changed, 410 insertions(+) create mode 100644 lib-pheripherals/src/direction.c create mode 100644 text-viewer/include/gui.h create mode 100644 text-viewer/src/gui.c create mode 100644 text-viewer/src/gui_component.c create mode 100644 text-viewer/src/gui_container.c create mode 100644 text-viewer/src/gui_group_container.c create mode 100644 text-viewer/src/gui_one_container.c create mode 100644 text-viewer/src/gui_window.c diff --git a/lib-pheripherals/src/direction.c b/lib-pheripherals/src/direction.c new file mode 100644 index 0000000..7c7410f --- /dev/null +++ b/lib-pheripherals/src/direction.c @@ -0,0 +1,18 @@ +#include "direction.h" + +void direction_move_xy(direction_t direction, int32_t *x, int32_t *y, int16_t amount) { + switch (direction) { + case LEFT: + *x -= amount; + break; + case RIGHT: + *x += amount; + break; + case UP: + *y -= amount; + break; + case DOWN: + *y += amount; + break; + } +} diff --git a/text-viewer/include/gui.h b/text-viewer/include/gui.h new file mode 100644 index 0000000..70879ec --- /dev/null +++ b/text-viewer/include/gui.h @@ -0,0 +1,148 @@ +#ifndef __GUI_H__ +#define __GUI_H__ + +#include "display_utils.h" +#include "font.h" +#include "input.h" +#include "logger.h" +#include "mzapo_pheripherals.h" + +typedef struct renderer_t renderer_t; +typedef struct component_t component_t; +typedef struct gui_t gui_t; +typedef struct container_t container_t; + +typedef void (*render_function)(container_t *container, component_t *component, + gui_t *gui); +typedef void (*update_function)(container_t *container, component_t *component, + gui_t *gui); + +struct component_t { + int16_t x; + int16_t y; + + uint16_t width; + uint16_t height; + + render_function render; + update_function update; + + bool focusable; + bool focused; + + void *state; +}; + +typedef enum { + CONT_TABLE, + CONT_GROUP, + CONT_ONE, +} container_type_t; + +typedef struct { + // items + // scroll +} list_container_t; + +typedef struct { + component_t *components; + uint16_t size; + uint16_t count; +} group_container_t; + +typedef struct { + component_t component; + bool set; +} one_container_t; + +typedef union { + list_container_t list; + group_container_t group; + one_container_t one; +} container_inner_t; + +struct container_t { + container_type_t type; + container_inner_t inner; + + bool focusable; + bool focused; + + int16_t x; + int16_t y; + + uint16_t width; + uint16_t height; +}; + +typedef struct { + container_t *containers; + uint16_t containers_size; + uint16_t containers_count; +} window_t; + +struct gui_t { + window_t *active_window; + commands_t *commands; + renderer_t *renderer; + mzapo_pheripherals_t *pheripherals; + logger_t *logger; + + size2d_t size; +}; + +gui_t gui_create(logger_t *logger, commands_t *commands, + renderer_t *renderer, mzapo_pheripherals_t *pheripherals); + +void gui_render(gui_t *gui); +void gui_update(gui_t *gui); + +void gui_set_active_window(gui_t *gui, window_t *window); + +// gui_window.c +window_t gui_window_create(container_t *containers, uint16_t size); +container_t *gui_window_add_container(window_t *window, container_t container); + +// gui_container.c +void gui_container_render(gui_t *gui, container_t *container); +void gui_container_update(gui_t *gui, container_t *container); + +// gui_component.c +component_t gui_component_create(int16_t x, int16_t y, uint16_t w, uint16_t h, render_function render, update_function update); + +bool gui_is_component_visible(gui_t *gui, container_t *container, + component_t *component); + +void gui_component_render(gui_t *gui, container_t *container, + component_t *component); + +void gui_component_update(gui_t *gui, container_t *container, + component_t *component); + +coords_t gui_component_get_absolute_position(container_t *container, + component_t *component); +coords_t gui_component_get_screen_position(container_t *container, + component_t *component); + +// gui_one_container.c +container_t gui_one_container_create(int16_t x, int16_t y); + +component_t *gui_one_container_set_component(container_t *container, + component_t component); +component_t *gui_one_container_get_component(container_t *container); + +void gui_one_container_render(gui_t *gui, container_t *container); +void gui_one_container_update(gui_t *gui, container_t *container); + +// gui_group_container.c +container_t gui_group_container_create(int16_t x, int16_t y, component_t *components, uint16_t components_size); + +component_t *gui_group_container_add_component(container_t *container, + component_t component); + +void gui_group_container_render(gui_t *gui, container_t *container); +void gui_group_container_update(gui_t *gui, container_t *container); + +// handle commands + +#endif // __GUI_H__ diff --git a/text-viewer/src/gui.c b/text-viewer/src/gui.c new file mode 100644 index 0000000..9ff6fd4 --- /dev/null +++ b/text-viewer/src/gui.c @@ -0,0 +1,56 @@ +#include "gui.h" +#include "input.h" +#include "logger.h" +#include "renderer.h" +#include + +gui_t gui_create(logger_t *logger, commands_t *commands, renderer_t *renderer, + mzapo_pheripherals_t *pheripherals) { + gui_t gui = { + .pheripherals = pheripherals, + .renderer = renderer, + .active_window = NULL, + .commands = commands, + .logger = logger, + .size = {.x = DISPLAY_WIDTH, .y = DISPLAY_HEIGHT}, + }; + + return gui; +} + +void gui_render(gui_t *gui) { + renderer_clear(gui->renderer); + window_t *window = gui->active_window; + if (window == NULL) { + logger_warn(gui->logger, __FILE__, __FUNCTION__, __LINE__, + "No active window"); + return; + } + + for (int i = 0; i < window->containers_count; i++) { + gui_container_render(gui, &window->containers[i]); + } + + renderer_render(gui->renderer); +} + +component_t *gui_one_container_get_component(container_t *container) { + return &container->inner.one.component; +} + +void gui_update(gui_t *gui) { + window_t *window = gui->active_window; + if (window == NULL) { + logger_warn(gui->logger, __FILE__, __FUNCTION__, __LINE__, + "No active window"); + return; + } + + for (int i = 0; i < window->containers_count; i++) { + gui_container_update(gui, &window->containers[i]); + } +} + +void gui_set_active_window(gui_t *gui, window_t *window) { + gui->active_window = window; +} diff --git a/text-viewer/src/gui_component.c b/text-viewer/src/gui_component.c new file mode 100644 index 0000000..5933f10 --- /dev/null +++ b/text-viewer/src/gui_component.c @@ -0,0 +1,56 @@ +#include "gui.h" + +component_t gui_component_create(int16_t x, int16_t y, uint16_t w, uint16_t h, + render_function render, + update_function update) { + component_t component = { + .x = x, + .y = y, + .width = w, + .height = h, + .render = render, + .update = update, + .focused = false, + .focusable = false, + .state = NULL + }; + + return component; +} + +bool gui_is_component_visible(gui_t *gui, container_t *container, + component_t *component) { + coords_t pos = gui_component_get_screen_position(container, component); + + bool visible_x = (pos.x >= 0 && pos.x < gui->size.x) || + (pos.x < 0 && pos.x + component->width > 0); + bool visible_y = (pos.y >= 0 && pos.y < gui->size.y) || + (pos.y < 0 && pos.y + component->height > 0); + + return visible_x && visible_y; +} + +void gui_component_render(gui_t *gui, container_t *container, + component_t *component) { + component->render(container, component, gui); +} + +void gui_component_update(gui_t *gui, container_t *container, + component_t *component) { + component->update(container, component, gui); +} + +coords_t gui_component_get_absolute_position(container_t *container, + component_t *component) { + coords_t pos = { + .x = container->x + component->x, + .y = container->y + component->y + }; + + return pos; +} + +coords_t gui_component_get_screen_position(container_t *container, + component_t *component) { + return gui_component_get_absolute_position(container, component); +} diff --git a/text-viewer/src/gui_container.c b/text-viewer/src/gui_container.c new file mode 100644 index 0000000..2be2239 --- /dev/null +++ b/text-viewer/src/gui_container.c @@ -0,0 +1,35 @@ +#include "gui.h" +#include "renderer.h" + +void gui_container_render(gui_t *gui, container_t *container) { + renderer_translate(gui->renderer, container->x, container->y); + renderer_set_draw_area(gui->renderer, container->width, container->height); + + switch (container->type) { + case CONT_TABLE: + // TODO: implement + break; + case CONT_GROUP: + gui_group_container_render(gui, container); + break; + case CONT_ONE: + gui_one_container_render(gui, container); + break; + } + + renderer_clear_translate(gui->renderer); +} + +void gui_container_update(gui_t *gui, container_t *container) { + switch (container->type) { + case CONT_TABLE: + // TODO: implement + break; + case CONT_GROUP: + gui_group_container_update(gui, container); + break; + case CONT_ONE: + gui_one_container_update(gui, container); + break; + } +} diff --git a/text-viewer/src/gui_group_container.c b/text-viewer/src/gui_group_container.c new file mode 100644 index 0000000..03a6dc4 --- /dev/null +++ b/text-viewer/src/gui_group_container.c @@ -0,0 +1,40 @@ +#include "gui.h" + +component_t *gui_group_container_add_component(container_t *container, + component_t component) { + group_container_t group = container->inner.group; + if (group.count >= group.size) { + return false; + } + + group.components[group.count++] = component; + container->inner.group = group; + return &group.components[group.count - 1]; +} + +void gui_group_container_render(gui_t *gui, container_t *container) { + group_container_t group = container->inner.group; + for (int i = 0; i < group.size; i++) { + gui_component_render(gui, container, &group.components[i]); + } +} + +void gui_group_container_update(gui_t *gui, container_t *container) { + group_container_t group = container->inner.group; + for (int i = 0; i < group.size; i++) { + gui_component_update(gui, container, &group.components[i]); + } + container->inner.group = group; +} + +container_t gui_group_container_create(int16_t x, int16_t y, component_t *components, uint16_t components_size) { + container_t container = {.x = x, + .y = y, + .type = CONT_GROUP, + .focusable = false, + .focused = false, + .inner = {.group = {.components = components, + .size = components_size, + .count = 0}}}; + return container; +} diff --git a/text-viewer/src/gui_one_container.c b/text-viewer/src/gui_one_container.c new file mode 100644 index 0000000..b2b1dab --- /dev/null +++ b/text-viewer/src/gui_one_container.c @@ -0,0 +1,37 @@ +#include "gui.h" + +component_t* gui_one_container_set_component(container_t *container, + component_t component) { + container->inner.one.component = component; + container->inner.one.set = true; + + return &container->inner.one.component; +} + +void gui_one_container_render(gui_t *gui, container_t *container) { + if (container->inner.one.set) { + gui_component_render(gui, container, &container->inner.one.component); + } +} + +void gui_one_container_update(gui_t *gui, container_t *container) { + if (container->inner.one.set) { + gui_component_update(gui, container, &container->inner.one.component); + + if (container->inner.one.component.focusable) { + container->inner.one.component.focused = container->focused; + } + } +} + +container_t gui_one_container_create(int16_t x, int16_t y) { + container_t container = {.x = x, + .y = y, + .type = CONT_ONE, + .focusable = false, + .focused = false, + .inner = {.one = { + .set = false, + }}}; + return container; +} diff --git a/text-viewer/src/gui_window.c b/text-viewer/src/gui_window.c new file mode 100644 index 0000000..1556c2e --- /dev/null +++ b/text-viewer/src/gui_window.c @@ -0,0 +1,20 @@ +#include "gui.h" + +window_t gui_window_create(container_t *containers, uint16_t size) { + window_t window = { + .containers = containers, + .containers_size = size, + .containers_count = 0, + }; + + return window; +} + +container_t *gui_window_add_container(window_t *window, container_t container) { + if (window->containers_count >= window->containers_size) { + return NULL; + } + + window->containers[window->containers_count++] = container; + return &window->containers[window->containers_count - 1]; +} -- 2.49.0