changeset 620:91ef0df9f501

ui: simplify gridmenu
author David Demelier <markand@malikania.fr>
date Tue, 22 Aug 2023 19:23:00 +0200
parents b8fd5c112538
children eecdf5140245
files examples/example-gridmenu/example-gridmenu.c libmlk-ui/CMakeLists.txt libmlk-ui/mlk/ui/checkbox.c libmlk-ui/mlk/ui/gridmenu.c libmlk-ui/mlk/ui/gridmenu.h
diffstat 5 files changed, 176 insertions(+), 247 deletions(-) [+]
line wrap: on
line diff
--- a/examples/example-gridmenu/example-gridmenu.c	Mon Aug 21 21:42:17 2023 +0200
+++ b/examples/example-gridmenu/example-gridmenu.c	Tue Aug 22 19:23:00 2023 +0200
@@ -59,15 +59,13 @@
 	"Double tour"
 };
 
-static struct mlk_style style;
-
 static struct mlk_gridmenu menu = {
+	.w = 300,
+	.h = 100,
 	.nrows = 3,
 	.ncols = 2,
 	.items = items,
-	.itemsz = MLK_UTIL_SIZE(items),
-	.delegate = &mlk_gridmenu_delegate,
-	.style = &style,
+	.itemsz = MLK_UTIL_SIZE(items)
 };
 static struct mlk_glower menu_glower = {
 	.start = 0x00bfa3ff,
@@ -79,7 +77,7 @@
 update_color(unsigned int ticks)
 {
 	mlk_glower_update(&menu_glower, ticks);
-	style.selected.color.text = menu_glower.color;
+	mlk_gridmenu_style->color_selected = menu_glower.color;
 }
 
 static void
@@ -89,7 +87,6 @@
 		mlk_panic();
 
 	/* Copy style. */
-	style = mlk_style;
 	mlk_glower_init(&menu_glower);
 }
 
@@ -138,7 +135,7 @@
 		.draw = draw,
 	};
 
-	mlk_gridmenu_resize(&menu, 0, 0, 300, 100);
+	mlk_gridmenu_resize(&menu);
 	mlk_align(MLK_ALIGN_CENTER, &menu.x, &menu.y, menu.w, menu.h, 0, 0, mlk_window.w, mlk_window.h);
 
 	mlk_game_init();
--- a/libmlk-ui/CMakeLists.txt	Mon Aug 21 21:42:17 2023 +0200
+++ b/libmlk-ui/CMakeLists.txt	Tue Aug 22 19:23:00 2023 +0200
@@ -28,7 +28,6 @@
 	${libmlk-ui_SOURCE_DIR}/mlk/ui/gridmenu.c
 	${libmlk-ui_SOURCE_DIR}/mlk/ui/label.c
 	${libmlk-ui_SOURCE_DIR}/mlk/ui/notify.c
-	${libmlk-ui_SOURCE_DIR}/mlk/ui/style.c
 	${libmlk-ui_SOURCE_DIR}/mlk/ui/ui.c
 	${libmlk-ui_SOURCE_DIR}/mlk/ui/ui_p.h
 )
@@ -43,7 +42,6 @@
 	${libmlk-ui_SOURCE_DIR}/mlk/ui/gridmenu.h
 	${libmlk-ui_SOURCE_DIR}/mlk/ui/label.h
 	${libmlk-ui_SOURCE_DIR}/mlk/ui/notify.h
-	${libmlk-ui_SOURCE_DIR}/mlk/ui/style.h
 	${libmlk-ui_SOURCE_DIR}/mlk/ui/ui.h
 )
 
--- a/libmlk-ui/mlk/ui/checkbox.c	Mon Aug 21 21:42:17 2023 +0200
+++ b/libmlk-ui/mlk/ui/checkbox.c	Tue Aug 22 19:23:00 2023 +0200
@@ -24,7 +24,6 @@
 #include <mlk/core/painter.h>
 
 #include "checkbox.h"
-#include "style.h"
 #include "ui_p.h"
 
 static inline int
--- a/libmlk-ui/mlk/ui/gridmenu.c	Mon Aug 21 21:42:17 2023 +0200
+++ b/libmlk-ui/mlk/ui/gridmenu.c	Tue Aug 22 19:23:00 2023 +0200
@@ -27,10 +27,11 @@
 #include <mlk/core/trace.h>
 #include <mlk/core/window.h>
 
-#include "gridmenu.h"
+#include "align.h"
 #include "frame.h"
+#include "gridmenu.h"
 #include "label.h"
-#include "style.h"
+#include "ui.h"
 #include "ui_p.h"
 
 struct index {
@@ -89,7 +90,6 @@
 {
 	assert(click->type == MLK_EVENT_CLICKDOWN);
 
-	const struct mlk_style_attr *attr = &menu->style->normal;
 	size_t pagesz, pagenr, selected, c = 0, r = 0;
 	int x, y;
 
@@ -97,8 +97,8 @@
 	pagenr = menu->selected / pagesz;
 
 	for (size_t i = 0; i < pagesz; ++i) {
-		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));
+		x = (int)(menu->x + (c * menu->eltw) + (c * menu->spacew));
+		y = (int)(menu->y + (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;
@@ -120,73 +120,7 @@
 }
 
 static void
-resize(struct mlk_gridmenu_delegate *self, struct mlk_gridmenu *menu)
-{
-	(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_frame(struct mlk_gridmenu_delegate *self, const struct mlk_gridmenu *menu)
+draw_frame(struct mlk_gridmenu_style *self, struct mlk_gridmenu *menu)
 {
 	(void)self;
 
@@ -201,75 +135,94 @@
 }
 
 static void
-draw_item(struct mlk_gridmenu_delegate *self,
-          const struct mlk_gridmenu *menu,
+draw_text(struct mlk_gridmenu_style *self,
+          struct mlk_gridmenu *menu,
           const char *item,
           unsigned int row,
           unsigned int col,
           int selected)
 {
-	(void)self;
-	(void)selected;
-
-	struct mlk_label label = {};
+	unsigned long color = selected ? self->color_selected : self->color;
 
-	label.x = menu->x + menu->style->normal.geo.padding + (col * menu->eltw) + (col * menu->spacew);
-	label.y = menu->y + menu->style->normal.geo.padding + (row * menu->elth) + (row * menu->spaceh);
-	label.text = item;
-
-	mlk_label_draw(&label);
-
-	// TODO: use a different style if selected.
+	mlk_ui_draw_text(
+		MLK_ALIGN_CENTER,
+		MLK__STYLE_FONT(self->font, MLK_UI_FONT_INTERFACE),
+		color,
+		item,
+		menu->x + (col * menu->eltw) + (col * menu->spacew),
+		menu->y + (row * menu->elth) + (row * menu->spaceh),
+		menu->eltw,
+		menu->elth
+	);
 }
 
-struct mlk_gridmenu_delegate mlk_gridmenu_delegate = {
-	.resize = resize,
-	.handle = handle,
+struct mlk_gridmenu_style mlk_gridmenu_style_dark = {
+	.background = 0x222323ff,
+	.border = 0x141414ff,
+	.border_size = 2,
+	.color = 0xffffffff,
+	.color_selected = 0x518822ff,
 	.draw_frame = draw_frame,
-	.draw_item = draw_item
+	.draw_text = draw_text
 };
 
+struct mlk_gridmenu_style mlk_gridmenu_style_light = {
+	.background = 0x222323ff,
+	.border = 0x141414ff,
+	.border_size = 2,
+	.color = 0x000000ff,
+	.color_selected = 0x518822ff,
+	.draw_frame = draw_frame,
+	.draw_text = draw_text
+};
+
+struct mlk_gridmenu_style *mlk_gridmenu_style = &mlk_gridmenu_style_light;
+
 void
-mlk_gridmenu_init(struct mlk_gridmenu *menu,
-                  struct mlk_gridmenu_delegate *dt,
-                  struct mlk_style *st)
+mlk_gridmenu_resize(struct mlk_gridmenu *menu)
 {
-	assert(menu);
+	unsigned int reqw = 0, reqh = 0, lw, lh;
+	struct mlk_font *font;
+
+	/* Compute which item has the bigger width/height to create a spacing. */
+	menu->eltw = menu->elth = 0;
+	menu->spacew = menu->spaceh = 0;
 
-	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;
+	/* Get appropriate font. */
+	if (menu->style)
+		font = MLK__STYLE_FONT(menu->style->font, MLK_UI_FONT_INTERFACE);
+	else
+		font = &mlk_ui_fonts[MLK_UI_FONT_INTERFACE];
+
+	for (size_t i = 0; i < menu->itemsz; ++i) {
+		if (!(menu->items[i]))
+			continue;
+
+		mlk_font_query(font, menu->items[i], &lw, &lh);
 
-	/* Can't be computed yet. */
-	menu->eltw = 0;
-	menu->elth = 0;
-	menu->spacew = 0;
-	menu->spaceh = 0;
-}
+		menu->eltw = fmax(menu->eltw, lw);
+		menu->elth = fmax(menu->elth, lh);
+	}
+
+	/* Total texture size required to draw items. */
+	reqw = menu->eltw * menu->ncols;
+	reqh = menu->elth * menu->nrows;
 
-void
-mlk_gridmenu_resize(struct mlk_gridmenu *menu,
-                    int x,
-                    int y,
-                    unsigned int w,
-                    unsigned int h)
-{
-	assert(menu);
+	/*
+	 * 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)
+		menu->spacew = (menu->w - reqw) / menu->ncols;
 
-	menu->x = x;
-	menu->y = y;
-	menu->w = w;
-	menu->h = h;
-
-	if (menu->delegate->resize)
-		menu->delegate->resize(menu->delegate, menu);
+	if (reqh > menu->h) {
+		mlk_tracef(_("gridmenu height is too small: %u < %u"), menu->h, reqh);
+		menu->spaceh = 1;
+	} else if (menu->nrows > 1)
+		menu->spaceh = (menu->h - reqh) / menu->nrows;
 }
 
 int
@@ -278,8 +231,14 @@
 	assert(menu);
 	assert(ev);
 
-	if (menu->delegate->handle)
-		return menu->delegate->handle(menu->delegate, menu, ev);
+	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;
 }
@@ -289,12 +248,11 @@
 {
 	assert(menu);
 
-	if (menu->delegate->update)
-		menu->delegate->update(menu->delegate, menu, ticks);
+	MLK__STYLE_CALL(menu->style, mlk_gridmenu_style, update, menu, ticks);
 }
 
 void
-mlk_gridmenu_draw(const struct mlk_gridmenu *menu)
+mlk_gridmenu_draw(struct mlk_gridmenu *menu)
 {
 	assert(menu);
 
@@ -302,8 +260,7 @@
 	unsigned int row = 0, col = 0;
 	int selected;
 
-	if (menu->delegate->draw_frame)
-		menu->delegate->draw_frame(menu->delegate, menu);
+	MLK__STYLE_CALL(menu->style, mlk_gridmenu_style, draw_frame, menu);
 
 	/*
 	 * Select the first top-left column based on the current selection and
@@ -320,15 +277,8 @@
 
 		selected = i == menu->selected % pagesz;
 
-		if (menu->delegate->draw_item)
-			menu->delegate->draw_item(
-			    menu->delegate,
-			    menu,
-			    menu->items[item],
-			    row,
-			    col,
-			    selected
-			);
+		MLK__STYLE_CALL(menu->style, mlk_gridmenu_style, draw_text,
+		    menu, menu->items[item], row, col, selected);
 
 		if (++col >= menu->ncols) {
 			++row;
--- a/libmlk-ui/mlk/ui/gridmenu.h	Mon Aug 21 21:42:17 2023 +0200
+++ b/libmlk-ui/mlk/ui/gridmenu.h	Tue Aug 22 19:23:00 2023 +0200
@@ -21,9 +21,9 @@
 
 #include <stddef.h>
 
+struct mlk_font;
 struct mlk_gridmenu;
-struct mlk_gridmenu_delegate;
-struct mlk_style;
+struct mlk_gridmenu_style;
 
 union mlk_event;
 
@@ -94,16 +94,9 @@
 	/**
 	 * (read-write, borrowed)
 	 *
-	 * Grid menu delegate.
+	 * Style to use for drawing this menu.
 	 */
-	struct mlk_gridmenu_delegate *delegate;
-
-	/**
-	 * (read-write, borrowed)
-	 *
-	 * Grid menu style.
-	 */
-	struct mlk_style *style;
+	struct mlk_gridmenu_style *style;
 
 	/** \cond MLK_PRIVATE_DECLS */
 	unsigned int eltw;      /* maximum entry label width */
@@ -114,10 +107,52 @@
 };
 
 /**
- * \struct mlk_gridmenu_delegate
- * \brief Grid menu delegate.
+ * \struct mlk_gridmenu_style
+ * \brief Grid menu style.
  */
-struct mlk_gridmenu_delegate {
+struct mlk_gridmenu_style {
+	/**
+	 * (read-write)
+	 *
+	 * Background color.
+	 */
+	unsigned long background;
+
+	/**
+	 * (read-write)
+	 *
+	 * Border color.
+	 */
+	unsigned long border;
+
+	/**
+	 * (read-write)
+	 *
+	 * Border size.
+	 */
+	unsigned int border_size;
+
+	/**
+	 * (read-write)
+	 *
+	 * Text color.
+	 */
+	unsigned long color;
+
+	/**
+	 * (read-write)
+	 *
+	 * Selected color.
+	 */
+	unsigned long color_selected;
+
+	/**
+	 * (read-write, borrowed, optional)
+	 *
+	 * Font for drawing text.
+	 */
+	struct mlk_font *font;
+
 	/*
 	 * (read-write, borrowed, optional)
 	 *
@@ -128,38 +163,13 @@
 	/**
 	 * (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 self this style
 	 * \param menu the menu to update
 	 * \param ticks number of ticks since last frame
 	 */
-	void (*update)(struct mlk_gridmenu_delegate *self,
+	void (*update)(struct mlk_gridmenu_style *self,
 	               struct mlk_gridmenu *menu,
 	               unsigned int ticks);
 
@@ -168,93 +178,74 @@
 	 *
 	 * Draw a frame box for this menu.
 	 *
-	 * \param self this delegate
+	 * \param self this style
 	 * \param menu the underlying menu
 	 */
-	void (*draw_frame)(struct mlk_gridmenu_delegate *self,
-	                   const struct mlk_gridmenu *menu);
+	void (*draw_frame)(struct mlk_gridmenu_style *self,
+	                   struct mlk_gridmenu *menu);
 
 	/**
 	 * (read-write, optional)
 	 *
 	 * Draw a specific item.
 	 *
-	 * \param self this delegate
+	 * \param self this style
 	 * \param menu the underlying menu
 	 * \param item the item content
 	 * \param row the row number (relative)
 	 * \param col the column number (relative)
 	 * \param selected non-zero if the item is currently selected
 	 */
-	void (*draw_item)(struct mlk_gridmenu_delegate *self,
-	                  const struct mlk_gridmenu *menu,
+	void (*draw_text)(struct mlk_gridmenu_style *self,
+	                  struct mlk_gridmenu *menu,
 	                  const char *item,
 	                  unsigned int row,
 	                  unsigned int col,
 	                  int selected);
-
-	/**
-	 * (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);
-
 };
 
 /**
- * \brief Default stateless delegate for gridmenu.
+ * \brief Dark default style for gridmenu.
+ */
+extern struct mlk_gridmenu_style mlk_gridmenu_style_dark;
+
+/**
+ * \brief Light default style for gridmenu.
  */
-extern struct mlk_gridmenu_delegate mlk_gridmenu_delegate;
+extern struct mlk_gridmenu_style mlk_gridmenu_style_light;
+
+/**
+ * \brief Default style for all gridmenus.
+ */
+extern struct mlk_gridmenu_style *mlk_gridmenu_style;
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
 /**
- * Initialize the menu with default values.
- *
- * This is not required if you use designated initializers.
+ * Resize the grid menu window.
  *
  * \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)
+ * \param menu the menu
  */
 void
-mlk_gridmenu_init(struct mlk_gridmenu *menu,
-                  struct mlk_gridmenu_delegate *dt,
-                  struct mlk_style *st);
+mlk_gridmenu_resize(struct mlk_gridmenu *menu);
 
 /**
- * Copy new dimensions and then invoke ::mlk_gridmenu_delegate::resize.
+ * Handle an event.
  *
  * \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 *menu,
-                    int x,
-                    int y,
-                    unsigned int w,
-                    unsigned int h);
-
-/**
- * Invoke ::mlk_gridmenu_delegate::handle.
+ * \pre ev != NULL
+ * \param menu the menu
+ * \param ev the event
+ * \return non-zero if a new item is selected, 0 otherwise
  */
 int
 mlk_gridmenu_handle(struct mlk_gridmenu *menu, const union mlk_event *ev);
 
 /**
- * Invoke ::mlk_gridmenu_delegate::update.
+ * Invoke ::mlk_gridmenu_style::update.
  */
 void
 mlk_gridmenu_update(struct mlk_gridmenu *menu, unsigned int ticks);
@@ -262,17 +253,11 @@
 /**
  * Invoke the functions:
  *
- * - ::mlk_gridmenu_delegate::draw_frame,
- * - ::mlk_gridmenu_delegate::draw_item.
+ * - ::mlk_gridmenu_style::draw_frame,
+ * - ::mlk_gridmenu_style::draw_item.
  */
 void
-mlk_gridmenu_draw(const struct mlk_gridmenu *menu);
-
-/**
- * Invoke ::mlk_gridmenu_delegate::finish.
- */
-void
-mlk_gridmenu_finish(struct mlk_gridmenu *menu);
+mlk_gridmenu_draw(struct mlk_gridmenu *menu);
 
 #if defined(__cplusplus)
 }