Allow multiple button types

This commit is contained in:
Xavier Del Campo Romero 2022-07-06 23:46:59 +02:00
parent a0363cef85
commit 251bd41c44
6 changed files with 222 additions and 121 deletions

View File

@ -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"

View File

@ -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
{

View File

@ -0,0 +1,22 @@
#ifndef GUI_BUTTON_PRIVATE_H
#define GUI_BUTTON_PRIVATE_H
#include <gui/button.h>
#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 */

View File

@ -1,5 +1,6 @@
#include <gui.h>
#include <gui/button.h>
#include <gui_button_private.h>
#include <gui_private.h>
#include <camera.h>
#include <gfx.h>
@ -7,98 +8,31 @@
#include <pad.h>
#include <peripheral.h>
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);
}

114
src/gui/src/button_type1.c Normal file
View File

@ -0,0 +1,114 @@
#include <gui.h>
#include <gui/button.h>
#include <gui_private.h>
#include <gui_button_private.h>
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);
}

View File

@ -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;
}