Mercurial > molko
changeset 608:2527b000aaa5
ui: do the same with gridmenu
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 11 Aug 2023 19:45:00 +0200 |
parents | 8444f83d48af |
children | d97674d33764 |
files | examples/example-gridmenu/example-gridmenu.c libmlk-ui/mlk/ui/gridmenu.c libmlk-ui/mlk/ui/gridmenu.h |
diffstat | 3 files changed, 332 insertions(+), 146 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/example-gridmenu/example-gridmenu.c Fri Aug 11 13:34:17 2023 +0200 +++ b/examples/example-gridmenu/example-gridmenu.c Fri Aug 11 19:45:00 2023 +0200 @@ -32,14 +32,13 @@ #include <mlk/ui/frame.h> #include <mlk/ui/gridmenu.h> #include <mlk/ui/label.h> +#include <mlk/ui/style.h> #include <mlk/ui/ui.h> #include <mlk/example/example.h> #include <mlk/example/glower.h> #include <mlk/example/registry.h> -static void menu_update(struct mlk_gridmenu_delegate *, struct mlk_gridmenu *, unsigned int); - static const char * const items[] = { "Feu mineur", "Feu majeur", @@ -60,21 +59,21 @@ "Double tour" }; +static struct mlk_style style; + static struct mlk_frame frame = { .w = 300, - .h = 100 -}; -static struct mlk_gridmenu_style menu_style = {0}; -static struct mlk_gridmenu_delegate menu_delegate = { - .update = menu_update + .h = 100, + .delegate = &mlk_frame_delegate, + .style = &mlk_style }; static struct mlk_gridmenu menu = { .nrows = 3, .ncols = 2, .items = items, .itemsz = MLK_UTIL_SIZE(items), - .style = &menu_style, - .delegate = &menu_delegate + .delegate = &mlk_gridmenu_delegate, + .style = &style, }; static struct mlk_glower menu_glower = { .start = 0x00bfa3ff, @@ -83,13 +82,10 @@ }; static void -menu_update(struct mlk_gridmenu_delegate *delegate, struct mlk_gridmenu *menu, unsigned int ticks) +update_color(unsigned int ticks) { - (void)delegate; - (void)menu; - mlk_glower_update(&menu_glower, ticks); - menu_style.selected_color = menu_glower.color; + style.selected.color.text = menu_glower.color; } static void @@ -98,7 +94,8 @@ if (mlk_example_init("example-gridmenu") < 0) mlk_panic(); - menu_style = mlk_gridmenu_style; + /* Copy style. */ + style = mlk_style; mlk_glower_init(&menu_glower); } @@ -123,7 +120,7 @@ { (void)st; - mlk_glower_update(&menu_glower, ticks); + update_color(ticks); mlk_gridmenu_update(&menu, ticks); }
--- a/libmlk-ui/mlk/ui/gridmenu.c Fri Aug 11 13:34:17 2023 +0200 +++ b/libmlk-ui/mlk/ui/gridmenu.c Fri Aug 11 19:45:00 2023 +0200 @@ -18,19 +18,18 @@ #include <assert.h> #include <math.h> -#include <string.h> #include <mlk/core/err.h> #include <mlk/core/event.h> #include <mlk/core/font.h> #include <mlk/core/maths.h> #include <mlk/core/painter.h> -#include <mlk/core/panic.h> #include <mlk/core/texture.h> #include <mlk/core/trace.h> +#include <mlk/core/window.h> #include "gridmenu.h" -#include "ui.h" +#include "style.h" #include "ui_p.h" struct index { @@ -38,15 +37,6 @@ unsigned int col; }; -static inline struct mlk_font * -style_font(struct mlk_gridmenu_style *style) -{ - if (style && style->text_font) - return style->text_font; - - return &mlk_ui_fonts[MLK_UI_FONT_INTERFACE]; -} - static struct index get_index(const struct mlk_gridmenu *menu) { @@ -56,53 +46,6 @@ }; } -static void -geometry(struct mlk_gridmenu *menu) -{ - const struct mlk_gridmenu_style *style; - unsigned int reqw = 0, reqh = 0, lw, lh; - - /* Compute which item has the bigger width/height to create a spacing. */ - menu->eltw = menu->elth = 0; - menu->spacew = menu->spaceh = 0; - - style = MLK__STYLE(menu, mlk_gridmenu_style); - - for (size_t i = 0; i < menu->itemsz; ++i) { - if (!(menu->items[i])) - continue; - - mlk_font_query(style_font(menu->style), menu->items[i], &lw, &lh); - - menu->eltw = fmax(menu->eltw, lw); - menu->elth = fmax(menu->elth, lh); - } - - /* Total texture size required to draw items. */ - reqw = (style->padding * 3) + (menu->eltw * menu->ncols); - reqh = (style->padding * 3) + (menu->elth * menu->nrows); - - /* - * Compute spacing between elements. We remove the padding because it - * is outside of the elements. - */ - if (reqw > menu->w) { - mlk_tracef(_("gridmenu width is too small: %u < %u"), menu->w, reqw); - menu->spacew = 1; - } else if (menu->ncols > 1) { - reqw -= style->padding * 2; - menu->spacew = (menu->w - reqw) / menu->ncols; - } - - if (reqh > menu->h) { - mlk_tracef(_("gridmenu height is too small: %u < %u"), menu->h, reqh); - menu->spaceh = 1; - } else if (menu->nrows > 1) { - reqh -= style->padding * 2; - menu->spaceh = (menu->h - reqh) / menu->nrows; - } -} - static int handle_keydown(struct mlk_gridmenu *menu, const struct mlk_event_key *key) { @@ -145,17 +88,16 @@ { assert(click->type == MLK_EVENT_CLICKDOWN); - const struct mlk_gridmenu_style *style; + const struct mlk_style_attr *attr = &menu->style->normal; size_t pagesz, pagenr, selected, c = 0, r = 0; int x, y; - style = MLK__STYLE(menu, mlk_gridmenu_style); pagesz = menu->nrows * menu->ncols; pagenr = menu->selected / pagesz; for (size_t i = 0; i < pagesz; ++i) { - x = (int)(menu->x + style->padding + (c * menu->eltw) + (c * menu->spacew)); - y = (int)(menu->y + style->padding + (r * menu->elth) + (r * menu->spaceh)); + x = (int)(menu->x + attr->geo.padding + (c * menu->eltw) + (c * menu->spacew)); + y = (int)(menu->y + attr->geo.padding + (r * menu->elth) + (r * menu->spaceh)); if (mlk_maths_is_boxed(click->x, click->y, x, y, menu->eltw, menu->elth)) { selected = c + r * menu->ncols; @@ -177,12 +119,78 @@ } static void -draw(struct mlk_gridmenu_delegate *delegate, const struct mlk_gridmenu *menu) +resize(struct mlk_gridmenu_delegate *self, struct mlk_gridmenu *menu) { - (void)delegate; + (void)self; + + const struct mlk_style_attr *attr = &menu->style->normal; + unsigned int reqw = 0, reqh = 0, lw, lh; + + /* Compute which item has the bigger width/height to create a spacing. */ + menu->eltw = menu->elth = 0; + menu->spacew = menu->spaceh = 0; + + for (size_t i = 0; i < menu->itemsz; ++i) { + if (!(menu->items[i])) + continue; + + mlk_font_query(attr->font, menu->items[i], &lw, &lh); + + menu->eltw = fmax(menu->eltw, lw); + menu->elth = fmax(menu->elth, lh); + } + + /* Total texture size required to draw items. */ + reqw = (attr->geo.padding * 3) + (menu->eltw * menu->ncols); + reqh = (attr->geo.padding * 3) + (menu->elth * menu->nrows); + + /* + * Compute spacing between elements. We remove the padding because it + * is outside of the elements. + */ + if (reqw > menu->w) { + mlk_tracef(_("gridmenu width is too small: %u < %u"), menu->w, reqw); + menu->spacew = 1; + } else if (menu->ncols > 1) { + reqw -= attr->geo.padding * 2; + menu->spacew = (menu->w - reqw) / menu->ncols; + } + if (reqh > menu->h) { + mlk_tracef(_("gridmenu height is too small: %u < %u"), menu->h, reqh); + menu->spaceh = 1; + } else if (menu->nrows > 1) { + reqh -= attr->geo.padding * 2; + menu->spaceh = (menu->h - reqh) / menu->nrows; + } +} + +static int +handle(struct mlk_gridmenu_delegate *self, + struct mlk_gridmenu *menu, + const union mlk_event *ev) +{ + (void)self; + + switch (ev->type) { + case MLK_EVENT_KEYDOWN: + return handle_keydown(menu, &ev->key); + case MLK_EVENT_CLICKDOWN: + return handle_clickdown(menu, &ev->click); + default: + break; + } + + return 0; +} + +static void +draw(struct mlk_gridmenu_delegate *self, const struct mlk_gridmenu *menu) +{ + (void)self; + + const struct mlk_style *st = menu->style; size_t pagesz, pagenr, item, c = 0, r = 0; - const struct mlk_gridmenu_style *style; struct mlk_texture tex; struct mlk_font *font; unsigned long color; @@ -195,22 +203,22 @@ pagesz = menu->nrows * menu->ncols; pagenr = menu->selected / pagesz; - style = MLK__STYLE(menu, mlk_gridmenu_style); - font = style_font(menu->style); - for (size_t i = 0; i < pagesz; ++i) { item = i + pagenr * pagesz; if (item >= menu->itemsz || !menu->items[item]) continue; - x = (int)(menu->x + style->padding + (c * menu->eltw) + (c * menu->spacew)); - y = (int)(menu->y + style->padding + (r * menu->elth) + (r * menu->spaceh)); + x = (int)(menu->x + st->normal.geo.padding + (c * menu->eltw) + (c * menu->spacew)); + y = (int)(menu->y + st->normal.geo.padding + (r * menu->elth) + (r * menu->spaceh)); - if (i == menu->selected % pagesz) - color = style->selected_color; - else - color = style->text_color; + if (i == menu->selected % pagesz) { + color = st->selected.color.text; + font = st->selected.font; + } else { + color = st->normal.color.text; + font = st->normal.font; + } if (mlk_font_render(font, &tex, menu->items[item], color) < 0) { mlk_tracef(_("unable to render grid menu item: %s"), mlk_err()); @@ -227,24 +235,43 @@ } } -struct mlk_gridmenu_style mlk_gridmenu_style = { - .padding = 10, - .text_color = MLK_UI_COLOR_TEXT, - .selected_color = MLK_UI_COLOR_SELECTED +struct mlk_gridmenu_delegate mlk_gridmenu_delegate = { + .resize = resize, + .handle = handle, + .draw = draw }; -struct mlk_gridmenu_delegate mlk_gridmenu_delegate = { - .draw = draw -}; +void +mlk_gridmenu_init(struct mlk_gridmenu *menu, + struct mlk_gridmenu_delegate *dt, + struct mlk_style *st) +{ + assert(menu); -int -mlk_gridmenu_ok(const struct mlk_gridmenu *menu) -{ - return menu && menu->items && menu->itemsz; + menu->x = 0; + menu->y = 0; + menu->w = 0; + menu->h = 0; + menu->items = NULL; + menu->itemsz = 0; + menu->nrows = 0; + menu->ncols = 0; + menu->delegate = dt ? dt : &mlk_gridmenu_delegate; + menu->style = st ? st : &mlk_style; + + /* Can't be computed yet. */ + menu->eltw = 0; + menu->elth = 0; + menu->spacew = 0; + menu->spaceh = 0; } void -mlk_gridmenu_resize(struct mlk_gridmenu *menu, int x, int y, unsigned int w, unsigned int h) +mlk_gridmenu_resize(struct mlk_gridmenu *menu, + int x, + int y, + unsigned int w, + unsigned int h) { assert(menu); @@ -253,7 +280,8 @@ menu->w = w; menu->h = h; - geometry(menu); + if (menu->delegate->resize) + menu->delegate->resize(menu->delegate, menu); } int @@ -262,16 +290,8 @@ assert(menu); assert(ev); - switch (ev->type) { - case MLK_EVENT_KEYDOWN: - return handle_keydown(menu, &ev->key); - break; - case MLK_EVENT_CLICKDOWN: - return handle_clickdown(menu, &ev->click); - break; - default: - break; - } + if (menu->delegate->handle) + return menu->delegate->handle(menu->delegate, menu, ev); return 0; } @@ -279,9 +299,10 @@ void mlk_gridmenu_update(struct mlk_gridmenu *menu, unsigned int ticks) { - assert(mlk_gridmenu_ok(menu)); + assert(menu); - MLK__DELEGATE_INVOKE(menu->delegate, mlk_gridmenu_delegate, update, menu, ticks); + if (menu->delegate->update) + menu->delegate->update(menu->delegate, menu, ticks); } void @@ -289,5 +310,6 @@ { assert(menu); - MLK__DELEGATE_INVOKE(menu->delegate, mlk_gridmenu_delegate, draw, menu); + if (menu->delegate->draw) + menu->delegate->draw(menu->delegate, menu); }
--- a/libmlk-ui/mlk/ui/gridmenu.h Fri Aug 11 13:34:17 2023 +0200 +++ b/libmlk-ui/mlk/ui/gridmenu.h Fri Aug 11 19:45:00 2023 +0200 @@ -21,66 +21,233 @@ #include <stddef.h> -#include "label.h" +struct mlk_gridmenu; +struct mlk_gridmenu_delegate; +struct mlk_style; union mlk_event; -struct mlk_font; -struct mlk_gridmenu; +struct mlk_gridmenu { + /** + * (read-write) + * + * Position in x. + */ + int x; -struct mlk_gridmenu_style { - unsigned int padding; - unsigned long text_color; - struct mlk_font *text_font; - unsigned long selected_color; -}; + /** + * (read-write) + * + * Position in y. + */ + int y; + + /** + * (read-write) + * + * Menu frame width. + */ + unsigned int w; + + /** + * (read-write) + * + * Menu frame height. + */ + unsigned int h; -struct mlk_gridmenu_delegate { - void *data; - void (*update)(struct mlk_gridmenu_delegate *, struct mlk_gridmenu *, unsigned int); - void (*draw)(struct mlk_gridmenu_delegate *, const struct mlk_gridmenu *); -}; + /** + * (read-write, borrowed) + * + * List of strings to show. + */ + const char * const *items; + + /** + * (read-write) + * + * Number of items in ::mlk_gridmenu::items. + */ + size_t itemsz; -struct mlk_gridmenu { - /* public */ - int x, y; - unsigned int w, h; - const char * const *items; - size_t itemsz; + /** + * (read-write) + * + * Current selected item in the grid. + */ size_t selected; + + /** + * (read-write) + * + * Number of rows to be shown within the frame height. + */ unsigned int nrows; + + /** + * (read-write) + * + * Number of colums to be shown within the frame width. + */ unsigned int ncols; - struct mlk_gridmenu_style *style; + + /** + * (read-write, borrowed) + * + * Grid menu delegate. + */ struct mlk_gridmenu_delegate *delegate; - /* private */ + /** + * (read-write, borrowed) + * + * Grid menu style. + */ + struct mlk_style *style; + + /** \cond MLK_PRIVATE_DECLS */ unsigned int eltw; /* maximum entry label width */ unsigned int elth; /* maximum entry label height */ unsigned int spacew; /* space between element horizontally */ unsigned int spaceh; /* and vertically */ + /** \endcond MLK_PRIVATE_DECLS */ }; -extern struct mlk_gridmenu_style mlk_gridmenu_style; +/** + * \struct mlk_gridmenu_delegate + * \brief Grid menu delegate. + */ +struct mlk_gridmenu_delegate { + /* + * (read-write, borrowed, optional) + * + * Arbitrary user data. + */ + void *data; + + /** + * (read-write, optional) + * + * Called after resizing the grid menu dimensions. + * + * \param self this delegate + * \param menu the grid menu + */ + void (*resize)(struct mlk_gridmenu_delegate *self, + struct mlk_gridmenu *menu); + + /** + * (read-write, optional) + * + * Handle an event. + * + * \param self this delegate + * \param menu the menu + * \param ev the event + * \return non-zero if an item has been selected + */ + int (*handle)(struct mlk_gridmenu_delegate *self, + struct mlk_gridmenu *menu, + const union mlk_event *ev); + + /** + * (read-write, optional) + * + * Update the grid menu. + * + * \param self this delegate + * \param menu the menu to update + * \param ticks number of ticks since last frame + */ + void (*update)(struct mlk_gridmenu_delegate *self, + struct mlk_gridmenu *menu, + unsigned int ticks); + + /** + * (read-write, optional) + * + * Draw this menu. + * + * \param self this delegate + * \param menu the menu to draw + */ + void (*draw)(struct mlk_gridmenu_delegate *self, + const struct mlk_gridmenu *menu); + + /** + * (read-write, optional) + * + * Cleanup this delegate associated with the menu. + * + * \param self this delegate + * \param frame the underlying frame + */ + void (*finish)(struct mlk_gridmenu_delegate *self, + struct mlk_gridmenu *menu); + +}; + extern struct mlk_gridmenu_delegate mlk_gridmenu_delegate; #if defined(__cplusplus) extern "C" { #endif -int -mlk_gridmenu_ok(const struct mlk_gridmenu *); +/** + * Initialize the menu with default values. + * + * This is not required if you use designated initializers. + * + * \pre menu != NULL + * \param menu the grid menu to default initialize + * \param st style to use (or NULL to use a default) + * \param dt delegate to use (or NULL to use a default) + */ +void +mlk_gridmenu_init(struct mlk_gridmenu *menu, + struct mlk_gridmenu_delegate *dt, + struct mlk_style *st); +/** + * Copy new dimensions and then invoke ::mlk_gridmenu_delegate::resize. + * + * \pre menu != NULL + * \param menu the menu to resize + * \param x new position in x + * \param y new position in y + * \param w new width + * \param h new height + */ void -mlk_gridmenu_resize(struct mlk_gridmenu *, int, int, unsigned int, unsigned int); +mlk_gridmenu_resize(struct mlk_gridmenu *menu, + int x, + int y, + unsigned int w, + unsigned int h); +/** + * Invoke ::mlk_gridmenu_delegate::handle. + */ int -mlk_gridmenu_handle(struct mlk_gridmenu *, const union mlk_event *); +mlk_gridmenu_handle(struct mlk_gridmenu *menu, const union mlk_event *ev); +/** + * Invoke ::mlk_gridmenu_delegate::update. + */ void -mlk_gridmenu_update(struct mlk_gridmenu *, unsigned int); +mlk_gridmenu_update(struct mlk_gridmenu *menu, unsigned int ticks); +/** + * Invoke ::mlk_gridmenu_delegate::draw. + */ void -mlk_gridmenu_draw(const struct mlk_gridmenu *); +mlk_gridmenu_draw(const struct mlk_gridmenu *menu); + +/** + * Invoke ::mlk_gridmenu_delegate::finish. + */ +void +mlk_gridmenu_finish(struct mlk_gridmenu *menu); #if defined(__cplusplus) }