From 251bd41c4499521baa2c810155f85a7fcb528116 Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Wed, 6 Jul 2022 23:46:59 +0200 Subject: [PATCH] Allow multiple button types --- src/gui/CMakeLists.txt | 1 + src/gui/inc/gui/button.h | 25 ++++- src/gui/privinc/gui_button_private.h | 22 ++++ src/gui/src/button.c | 144 +++++++-------------------- src/gui/src/button_type1.c | 114 +++++++++++++++++++++ src/menu/src/menu.c | 37 +++++-- 6 files changed, 222 insertions(+), 121 deletions(-) create mode 100644 src/gui/privinc/gui_button_private.h create mode 100644 src/gui/src/button_type1.c diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 1d7e686..b7fe2c1 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(gui "src/bar.c" "src/button.c" + "src/button_type1.c" "src/container.c" "src/gui.c" "src/label.c" diff --git a/src/gui/inc/gui/button.h b/src/gui/inc/gui/button.h index acfc6c1..b712e29 100644 --- a/src/gui/inc/gui/button.h +++ b/src/gui/inc/gui/button.h @@ -15,8 +15,27 @@ extern "C" struct gui_button { struct gui_common common; - struct gui_label label; - short w; + + enum gui_button_type + { + GUI_BUTTON_TYPE_1, + GUI_BUTTON_TYPE_SPRITE + } type; + + union + { + struct + { + short w; + struct gui_label label; + } type1; + + struct + { + const struct sprite *s; + } sprite; + } u; + void *arg; void (*on_pressed)(void *); }; @@ -24,7 +43,7 @@ struct gui_button UTIL_STATIC_ASSERT(!offsetof(struct gui_button, common), "unexpected offset for struct gui_button"); -void gui_button_init(struct gui_button *b); +void gui_button_init(struct gui_button *b, enum gui_button_type t); enum { diff --git a/src/gui/privinc/gui_button_private.h b/src/gui/privinc/gui_button_private.h new file mode 100644 index 0000000..7c2f897 --- /dev/null +++ b/src/gui/privinc/gui_button_private.h @@ -0,0 +1,22 @@ +#ifndef GUI_BUTTON_PRIVATE_H +#define GUI_BUTTON_PRIVATE_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +void gui_button_init_type1(struct gui_button *b); +void gui_button_init_sprite(struct gui_button *b); +int gui_button_render_type1(const struct gui_button *b); +int gui_button_render_sprite(const struct gui_button *b); +void gui_button_get_dim_type1(const struct gui_button *b, short *w, short *h); +void gui_button_get_dim_sprite(const struct gui_button *b, short *w, short *h); + +#ifdef __cplusplus +} +#endif + +#endif /* GUI_BUTTON_PRIVATE_H */ diff --git a/src/gui/src/button.c b/src/gui/src/button.c index e16db31..f4f94e0 100644 --- a/src/gui/src/button.c +++ b/src/gui/src/button.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,98 +8,31 @@ #include #include -struct sprite gui_button_sprites[MAX_GUI_BUTTON_SPRITES]; - -/* Alias for readability. */ -static const struct sprite *const refs = gui_button_sprites; - -static int render_left(const struct gui_button *const b, - short *const x, const short y) -{ - sprite_get_or_ret(s, -1); - - if (sprite_clone(&refs[GUI_BUTTON_LEFT], s)) - return -1; - - s->x = *x; - s->y = y; - sprite_sort(s); - *x = s->x + s->w; - return 0; -} - -static int render_mid(const struct gui_button *const b, - short *const x, const short y) -{ - const short mid_w = refs[GUI_BUTTON_MID].w; - const short lw = refs[GUI_BUTTON_LEFT].w; - const short rw = refs[GUI_BUTTON_RIGHT].w; - const short w = b->w - lw - rw; - - if (w > 0) - { - const short rem_mid = w > 0 ? w % mid_w : 0; - const short whole_mid = w / mid_w; - const short n_mid = rem_mid ? whole_mid + 1 : whole_mid; - - for (struct - { - size_t i; - short x; - } a = {.x = lw}; - a.i < n_mid; - a.i++, a.x += mid_w) - { - sprite_get_or_ret(m, -1); - - if (sprite_clone(&refs[GUI_BUTTON_MID], m)) - return -1; - - m->x = *x; - m->y = y; - - if (rem_mid && a.i + 1 == n_mid) - m->w = rem_mid; - else - m->w = mid_w; - - sprite_sort(m); - *x += m->w; - } - } - else - return -1; - - return 0; -} - -static int render_right(const struct gui_button *const b, - const short x, const short y) -{ - sprite_get_or_ret(s, -1); - - if (sprite_clone(&refs[GUI_BUTTON_RIGHT], s)) - return -1; - - s->x = x; - s->y = y; - sprite_sort(s); - return 0; -} - static int render(const struct gui_common *const g) { + static int (*const f[])(const struct gui_button *) = + { + [GUI_BUTTON_TYPE_1] = gui_button_render_type1, + /* [GUI_BUTTON_TYPE_SPRITE] = gui_button_render_sprite */ + }; + const struct gui_button *const b = (const struct gui_button *)g; - short x, y; - gui_coords(&b->common, &x, &y); + return f[b->type](b); +} - if (render_left(b, &x, y) - || render_mid(b, &x, y) - || render_right(b, x, y)) - return -1; +static void get_dim(const struct gui_common *const g, + short *const w, short *const h) +{ + static void (*const f[])(const struct gui_button *, short *, short *) = + { + [GUI_BUTTON_TYPE_1] = gui_button_get_dim_type1, + /* [GUI_BUTTON_TYPE_SPRITE] = gui_button_get_dim_sprite */ + }; - return 0; + const struct gui_button *const b = (const struct gui_button *)g; + + f[b->type](b, w, h); } static bool pressed(const struct gui_button *const b, @@ -125,16 +59,12 @@ static bool pressed(const struct gui_button *const b, if (check) { short x, y; + struct util_rect d; gui_coords(&b->common, &x, &y); - - const struct util_rect d = - { - .x = x, - .y = y, - .w = b->w, - .h = refs[GUI_BUTTON_LEFT].h - }; + get_dim(&b->common, &d.w, &d.h); + d.x = x; + d.y = y; return cursor_collision(cam, &d); } @@ -153,16 +83,7 @@ static int update(struct gui_common *const g, return 0; } -static void get_dim(const struct gui_common *const g, - short *const w, short *const h) -{ - const struct gui_button *const b = (const struct gui_button *)g; - - *w = b->w; - *h = refs[GUI_BUTTON_MID].h; -} - -void gui_button_init(struct gui_button *const b) +void gui_button_init(struct gui_button *const b, const enum gui_button_type t) { static const struct gui_common_cb cb = { @@ -176,11 +97,16 @@ void gui_button_init(struct gui_button *const b) .common = { .cb = &cb - } + }, + + .type = t }; - gui_label_init(&b->label); - b->label.common.hcentered = true; - b->label.common.vcentered = true; - gui_add_child(&b->common, &b->label.common); + static void (*const f[])(struct gui_button *) = + { + [GUI_BUTTON_TYPE_1] = gui_button_init_type1, + /* [GUI_BUTTON_TYPE_SPRITE] = gui_button_get_dim_sprite */ + }; + + f[b->type](b); } diff --git a/src/gui/src/button_type1.c b/src/gui/src/button_type1.c new file mode 100644 index 0000000..16038b5 --- /dev/null +++ b/src/gui/src/button_type1.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include + +struct sprite gui_button_sprites[MAX_GUI_BUTTON_SPRITES]; + +/* Alias for readability. */ +static const struct sprite *const refs = gui_button_sprites; + +static int render_left(const struct gui_button *const b, + short *const x, const short y) +{ + sprite_get_or_ret(s, -1); + + if (sprite_clone(&refs[GUI_BUTTON_LEFT], s)) + return -1; + + s->x = *x; + s->y = y; + sprite_sort(s); + *x = s->x + s->w; + return 0; +} + +static int render_mid(const struct gui_button *const b, + short *const x, const short y) +{ + const short mid_w = refs[GUI_BUTTON_MID].w, + lw = refs[GUI_BUTTON_LEFT].w, + rw = refs[GUI_BUTTON_RIGHT].w, + w = b->u.type1.w - lw - rw; + + if (w > 0) + { + const short rem_mid = w > 0 ? w % mid_w : 0, + whole_mid = w / mid_w, + n_mid = rem_mid ? whole_mid + 1 : whole_mid; + + for (struct + { + size_t i; + short x; + } a = {.x = lw}; + a.i < n_mid; + a.i++, a.x += mid_w) + { + sprite_get_or_ret(m, -1); + + if (sprite_clone(&refs[GUI_BUTTON_MID], m)) + return -1; + + m->x = *x; + m->y = y; + + if (rem_mid && a.i + 1 == n_mid) + m->w = rem_mid; + else + m->w = mid_w; + + sprite_sort(m); + *x += m->w; + } + } + else + return -1; + + return 0; +} + +static int render_right(const struct gui_button *const b, + const short x, const short y) +{ + sprite_get_or_ret(s, -1); + + if (sprite_clone(&refs[GUI_BUTTON_RIGHT], s)) + return -1; + + s->x = x; + s->y = y; + sprite_sort(s); + return 0; +} + +int gui_button_render_type1(const struct gui_button *const b) +{ + short x, y; + + gui_coords(&b->common, &x, &y); + + if (render_left(b, &x, y) + || render_mid(b, &x, y) + || render_right(b, x, y)) + return -1; + + return 0; +} + +void gui_button_get_dim_type1(const struct gui_button *const b, + short *const w, short *const h) +{ + *w = b->u.type1.w; + *h = refs[GUI_BUTTON_MID].h; +} + +void gui_button_init_type1(struct gui_button *const b) +{ + struct gui_label *const l = &b->u.type1.label; + + gui_label_init(l); + l->common.hcentered = true; + l->common.vcentered = true; + gui_add_child(&b->common, &l->common); +} diff --git a/src/menu/src/menu.c b/src/menu/src/menu.c index 38f8632..c2f1e96 100644 --- a/src/menu/src/menu.c +++ b/src/menu/src/menu.c @@ -29,18 +29,19 @@ int menu(void) cnt.mode = GUI_CONTAINER_MODE_V; cnt.common.hcentered = true; cnt.common.vcentered = true; - gui_button_init(&play); - gui_button_init(&exit_btn); + cnt.spacing = 4; + gui_button_init(&play, GUI_BUTTON_TYPE_1); + gui_button_init(&exit_btn, GUI_BUTTON_TYPE_1); play.on_pressed = on_pressed; play.arg = &start; - play.w = 140; + play.u.type1.w = 140; play.common.hcentered = true; - play.label.text = "Play"; + play.u.type1.label.text = "Play"; exit_btn.arg = &exit; - exit_btn.w = 140; + exit_btn.u.type1.w = 140; exit_btn.common.hcentered = true; - exit_btn.label.text = "Exit"; + exit_btn.u.type1.label.text = "Exit"; exit_btn.on_pressed = on_pressed; gui_add_child(&cnt.common, &play.common); gui_add_child(&cnt.common, &exit_btn.common); @@ -72,9 +73,27 @@ int menu(void) if (p.common.exit || exit) return 0; - if (gui_render(&cnt.common) - || cursor_render(&cam.cursor) - || gfx_draw()) + if (gui_render(&cnt.common)) + return -1; + + switch (p.common.type) + { + case PERIPHERAL_TYPE_PAD: + /* Fall through. */ + case PERIPHERAL_TYPE_KEYBOARD_MOUSE: + if (cursor_render(&cam.cursor)) + return -1; + + break; + + case PERIPHERAL_TYPE_TOUCH: + break; + + default: + return -1; + } + + if (gfx_draw()) return -1; }