changeset 622:ec334c61bb81

rpg: simplify message
author David Demelier <markand@malikania.fr>
date Tue, 22 Aug 2023 22:25:34 +0200
parents eecdf5140245
children 20b818193ce0
files examples/example-message/example-message.c libmlk-rpg/mlk/rpg/message.c libmlk-rpg/mlk/rpg/message.h libmlk-ui/mlk/ui/ui_p.h
diffstat 4 files changed, 363 insertions(+), 123 deletions(-) [+]
line wrap: on
line diff
--- a/examples/example-message/example-message.c	Tue Aug 22 21:36:49 2023 +0200
+++ b/examples/example-message/example-message.c	Tue Aug 22 22:25:34 2023 +0200
@@ -291,7 +291,7 @@
 		"This one will destroy your eyes.",
 		"Because it use a terrible custom theme."
 	};
-	struct mlk_message_style style = mlk_message_style;
+	struct mlk_message_style style = *mlk_message_style;
 	struct mlk_message msg = {
 		.x = MX,
 		.y = MY,
@@ -301,9 +301,9 @@
 		.style = &style
 	};
 
-	style.bg_color = 0xf85d80ff;
-	style.border_color = 0xd94a69ff;
-	style.text_color = 0xffffffff;
+	style.background = 0xf85d80ff;
+	style.border = 0xd94a69ff;
+	style.color = 0xffffffff;
 
 	mlk_message_query(&msg, NULL, &msg.h);
 	run(&msg);
--- a/libmlk-rpg/mlk/rpg/message.c	Tue Aug 22 21:36:49 2023 +0200
+++ b/libmlk-rpg/mlk/rpg/message.c	Tue Aug 22 22:25:34 2023 +0200
@@ -27,6 +27,7 @@
 #include <mlk/core/painter.h>
 #include <mlk/core/panic.h>
 #include <mlk/core/sprite.h>
+#include <mlk/core/texture.h>
 #include <mlk/core/trace.h>
 #include <mlk/core/util.h>
 
@@ -36,28 +37,26 @@
 
 #include "message.h"
 
-static inline struct mlk_font *
-style_font(const struct mlk_message *message)
+static inline struct mlk_message_style *
+get_style(struct mlk_message *msg)
 {
-	const struct mlk_message_style *style = MLK__STYLE(message, mlk_message_style);
+	return msg->style ? msg->style : mlk_message_style;
+}
 
-	if (style->text_font)
-		return style->text_font;
-
-	return &mlk_ui_fonts[MLK_UI_FONT_INTERFACE];
+static inline struct mlk_font *
+get_font(struct mlk_message *msg)
+{
+	return MLK__STYLE_FONT(get_style(msg)->font, MLK_UI_FONT_INTERFACE);
 }
 
 static unsigned int
-min_width(const struct mlk_message *msg)
+min_width(struct mlk_message_style *style, struct mlk_message *msg)
 {
-	assert(msg);
-
-	const struct mlk_message_style *style = MLK__STYLE(msg, mlk_message_style);
 	struct mlk_font *font;
 	unsigned int maxw = 0, w = 0;
 	int err;
 
-	font = style_font(msg);
+	font = MLK__STYLE_FONT(style->font, MLK_UI_FONT_INTERFACE);
 
 	for (size_t i = 0; i < msg->linesz; ++i) {
 		if (!msg->lines[i])
@@ -72,28 +71,27 @@
 }
 
 static unsigned int
-min_height(const struct mlk_message *msg)
+min_height(struct mlk_message_style *style, struct mlk_message *msg)
 {
 	assert(msg);
 
-	const struct mlk_message_style *style = MLK__STYLE(msg, mlk_message_style);
 	struct mlk_font *font;
 	unsigned int lh;
 
-	font = style_font(msg);
+	font = MLK__STYLE_FONT(style->font, MLK_UI_FONT_INTERFACE);
 	lh = mlk_font_height(font);
 
 	return (style->padding * 2) + (msg->linesz * lh) + ((msg->linesz - 1) * style->padding);
 }
 
 static void
-draw_frame(const struct mlk_message *msg)
+draw_frame(struct mlk_message *msg)
 {
-	const struct mlk_message_style *style = MLK__STYLE(msg, mlk_message_style);
+	struct mlk_message_style *style = get_style(msg);
 
-	mlk_painter_set_color(style->border_color);
+	mlk_painter_set_color(style->border);
 	mlk_painter_draw_rectangle(0, 0, msg->w, msg->h);
-	mlk_painter_set_color(style->bg_color);
+	mlk_painter_set_color(style->background);
 	mlk_painter_draw_rectangle(
 		style->border_size,
 		style->border_size,
@@ -103,25 +101,25 @@
 }
 
 static void
-draw_lines(const struct mlk_message *msg)
+draw_lines(struct mlk_message *msg)
 {
-	const struct mlk_message_style *style;
+	struct mlk_message_style *style;
 	struct mlk_font *font;
 	struct mlk_texture texture;
 	unsigned long color;
 	int x, y;
 
-	style = MLK__STYLE(msg, mlk_message_style);
-	font = style_font(msg);
+	style = get_style(msg);
+	font = get_font(msg);
 
 	for (size_t i = 0; i < msg->linesz; ++i) {
 		if (!msg->lines[i])
 			continue;
 
-		if ((msg->flags & MLK_MESSAGE_FLAGS_QUESTION) && msg->index == (unsigned int)i)
-			color = style->selected_color;
+		if ((msg->flags & MLK_MESSAGE_FLAGS_QUESTION) && msg->index == i)
+			color = style->color_selected;
 		else
-			color = style->text_color;
+			color = style->color;
 
 		if (mlk_font_render(font, &texture, msg->lines[i], color) < 0) {
 			mlk_tracef("unable to render message text", mlk_err());
@@ -132,9 +130,9 @@
 		y = style->padding + (i * (texture.h + style->padding));
 
 		if (x + texture.w > msg->w)
-			mlk_tracef("message width too small: %u < %u", msg->w, min_width(msg));
+			mlk_tracef("message width too small: %u < %u", msg->w, min_width(style, msg));
 		if (y + texture.h > msg->h)
-			mlk_tracef("message height too small: %u < %u", msg->h, min_height(msg));
+			mlk_tracef("message height too small: %u < %u", msg->h, min_height(style, msg));
 
 		mlk_texture_draw(&texture, x, y);
 		mlk_texture_finish(&texture);
@@ -142,25 +140,23 @@
 }
 
 static int
-delegate_query(struct mlk_message_delegate *self,
-               const struct mlk_message *msg,
-               unsigned int *w,
-               unsigned int *h)
+query(struct mlk_message_style *self,
+      struct mlk_message *msg,
+      unsigned int *w,
+      unsigned int *h)
 {
-	(void)self;
-
 	if (w)
-		*w = min_width(msg);
+		*w = min_width(self, msg);
 	if (h)
-		*h = min_height(msg);
+		*h = min_height(self, msg);
 
 	return 0;
 }
 
 static void
-delegate_update(struct mlk_message_delegate *self,
-                struct mlk_message *msg,
-                unsigned int ticks)
+update(struct mlk_message_style *self,
+       struct mlk_message *msg,
+       unsigned int ticks)
 {
 	(void)self;
 
@@ -170,12 +166,12 @@
 
 	switch (msg->state) {
 	case MLK_MESSAGE_STATE_OPENING:
-		msg->scale = (double)msg->elapsed / (double)style->delay;
+		msg->scale = (double)msg->elapsed / (double)style->speed;
 
 		if (msg->scale > 1)
 			msg->scale = 1;
 
-		if (msg->elapsed >= style->delay) {
+		if (msg->elapsed >= style->speed) {
 			msg->state = MLK_MESSAGE_STATE_SHOWING;
 			msg->elapsed = 0;
 		}
@@ -183,7 +179,7 @@
 		break;
 	case MLK_MESSAGE_STATE_SHOWING:
 		/* Do automatically switch state if requested by the user. */
-		if (msg->flags & MLK_MESSAGE_FLAGS_AUTOMATIC && msg->elapsed >= style->duration) {
+		if (msg->flags & MLK_MESSAGE_FLAGS_AUTOMATIC && msg->elapsed >= style->timeout) {
 			msg->state = msg->flags & MLK_MESSAGE_FLAGS_FADEOUT
 			    ? MLK_MESSAGE_STATE_HIDING
 			    : MLK_MESSAGE_STATE_NONE;
@@ -192,11 +188,11 @@
 
 		break;
 	case MLK_MESSAGE_STATE_HIDING:
-		msg->scale = 1 - (double)msg->elapsed / (double)style->delay;
+		msg->scale = 1 - (double)msg->elapsed / (double)style->speed;
 
 		if (msg->scale < 0)
 			msg->scale = 0;
-		if (msg->elapsed >= style->delay) {
+		if (msg->elapsed >= style->speed) {
 			msg->state = MLK_MESSAGE_STATE_NONE;
 			msg->elapsed = 0;
 		}
@@ -209,7 +205,7 @@
 }
 
 static void
-delegate_draw(struct mlk_message_delegate *self, const struct mlk_message *msg)
+draw(struct mlk_message_style *self, struct mlk_message *msg)
 {
 	(void)self;
 
@@ -242,30 +238,45 @@
 	mlk_texture_finish(&tex);
 }
 
-struct mlk_message_style mlk_message_style = {
-	.padding        = MLK_UI_PADDING,
-	.delay          = MLK_MESSAGE_DELAY_DEFAULT,
-	.duration       = MLK_MESSAGE_DURATION_DEFAULT,
-	.bg_color       = MLK_UI_COLOR_BG,
-	.border_color   = MLK_UI_COLOR_BORDER,
+// TODO: add dark variant.
+struct mlk_message_style mlk_message_style_dark = {
+	.background     = MLK_UI_COLOR_BG,
+	.border         = MLK_UI_COLOR_BORDER,
 	.border_size    = MLK_UI_BORDER,
-	.text_color     = MLK_UI_COLOR_TEXT,
-	.selected_color = MLK_UI_COLOR_SELECTED
+	.color          = MLK_UI_COLOR_TEXT,
+	.color_selected = MLK_UI_COLOR_SELECTED,
+	.padding        = MLK_UI_PADDING,
+	.timeout        = MLK_MESSAGE_TIMEOUT_DEFAULT,
+	.speed          = MLK_MESSAGE_SPEED_DEFAULT,
+	.query          = query,
+	.update         = update,
+	.draw           = draw
 };
-struct mlk_message_delegate mlk_message_delegate = {
-	.query          = delegate_query,
-	.update         = delegate_update,
-	.draw           = delegate_draw
+
+struct mlk_message_style mlk_message_style_light = {
+	.background     = MLK_UI_COLOR_BG,
+	.border         = MLK_UI_COLOR_BORDER,
+	.border_size    = MLK_UI_BORDER,
+	.color          = MLK_UI_COLOR_TEXT,
+	.color_selected = MLK_UI_COLOR_SELECTED,
+	.padding        = MLK_UI_PADDING,
+	.timeout        = MLK_MESSAGE_TIMEOUT_DEFAULT,
+	.speed          = MLK_MESSAGE_SPEED_DEFAULT,
+	.query          = query,
+	.update         = update,
+	.draw           = draw
 };
 
+struct mlk_message_style *mlk_message_style = &mlk_message_style_light;
+
 void
 mlk_message_start(struct mlk_message *msg)
 {
 	assert(msg);
 
-	const struct mlk_message_style *style = MLK__STYLE(msg, mlk_message_style);
+	struct mlk_message_style *style = MLK__STYLE(msg, mlk_message_style);
 
-	if ((msg->flags & (MLK_MESSAGE_FLAGS_FADEIN | MLK_MESSAGE_FLAGS_FADEOUT)) && style->delay == 0)
+	if ((msg->flags & (MLK_MESSAGE_FLAGS_FADEIN | MLK_MESSAGE_FLAGS_FADEOUT)) && style->speed == 0)
 		mlk_tracef("message has animation but zero delay");
 
 	msg->elapsed = 0;
@@ -274,23 +285,16 @@
 	    ? MLK_MESSAGE_STATE_OPENING
 	    : MLK_MESSAGE_STATE_SHOWING;
 
-	if (msg->flags & MLK_MESSAGE_FLAGS_AUTOMATIC && style->duration == 0)
-		mlk_tracef("message is automatic but has zero duration");
+	if (msg->flags & MLK_MESSAGE_FLAGS_AUTOMATIC && style->timeout == 0)
+		mlk_tracef("message is automatic but has zero timeout");
 }
 
 int
-mlk_message_query(const struct mlk_message *msg, unsigned int *w, unsigned int *h)
+mlk_message_query(struct mlk_message *msg, unsigned int *w, unsigned int *h)
 {
 	assert(msg);
 
-	MLK__DELEGATE_INVOKE_RET(msg->delegate, mlk_message_delegate, query, msg, w, h);
-
-	if (w)
-		*w = 0;
-	if (h)
-		*h = 0;
-
-	return 0;
+	return MLK__STYLE_CALL(msg->style, mlk_message_style, query, msg, w, h);
 }
 
 void
@@ -332,17 +336,17 @@
 {
 	assert(msg);
 
-	MLK__DELEGATE_INVOKE(msg->delegate, mlk_message_delegate, update, msg, ticks);
+	MLK__STYLE_CALL(msg->style, mlk_message_style, update, msg, ticks);
 
 	return msg->state == MLK_MESSAGE_STATE_NONE;
 }
 
 void
-mlk_message_draw(const struct mlk_message *msg)
+mlk_message_draw(struct mlk_message *msg)
 {
 	assert(msg);
 
-	MLK__DELEGATE_INVOKE(msg->delegate, mlk_message_delegate, draw, msg);
+	MLK__STYLE_CALL(msg->style, mlk_message_style, draw, msg);
 }
 
 void
--- a/libmlk-rpg/mlk/rpg/message.h	Tue Aug 22 21:36:49 2023 +0200
+++ b/libmlk-rpg/mlk/rpg/message.h	Tue Aug 22 22:25:34 2023 +0200
@@ -21,96 +21,332 @@
 
 #include <stddef.h>
 
-#include <mlk/core/texture.h>
-
-#define MLK_MESSAGE_DELAY_DEFAULT       (150)
-#define MLK_MESSAGE_DURATION_DEFAULT    (5000)
+#define MLK_MESSAGE_SPEED_DEFAULT       (150)
+#define MLK_MESSAGE_TIMEOUT_DEFAULT     (5000)
 
 struct mlk_font;
 struct mlk_message;
+struct mlk_message_style;
 
 union mlk_event;
 
+/**
+ * \enum mlk_message_flags
+ * \brief Message flags
+ */
 enum mlk_message_flags {
+	/**
+	 * Message closes automatically after style's duration.
+	 */
 	MLK_MESSAGE_FLAGS_AUTOMATIC     = (1 << 0),
+
+	/**
+	 * Lines can be selected by the user.
+	 */
 	MLK_MESSAGE_FLAGS_QUESTION      = (1 << 1),
+
+	/**
+	 * Add fade in animation.
+	 */
 	MLK_MESSAGE_FLAGS_FADEIN        = (1 << 2),
+
+	/**
+	 * Add fade out animation.
+	 */
 	MLK_MESSAGE_FLAGS_FADEOUT       = (1 << 3)
 };
 
+/**
+ * \enum mlk_message_state
+ * \brief Describe current message state
+ */
 enum mlk_message_state {
+	/**
+	 * Message is not ready yet.
+	 */
 	MLK_MESSAGE_STATE_NONE,
+
+	/**
+	 * Animation opening.
+	 */
 	MLK_MESSAGE_STATE_OPENING,
+
+	/**
+	 * Normal message run.
+	 */
 	MLK_MESSAGE_STATE_SHOWING,
+
+	/**
+	 * Hiding animation.
+	 */
 	MLK_MESSAGE_STATE_HIDING
 };
 
-struct mlk_message_style {
-	unsigned int padding;
-	unsigned int delay;
-	unsigned int duration;
-	unsigned long bg_color;
-	unsigned long border_color;
-	unsigned long border_size;
-	unsigned long text_color;
-	unsigned long selected_color;
-	struct mlk_font *text_font;
+struct mlk_message {
+	/**
+	 * (read-write)
+	 *
+	 * Position in x.
+	 */
+	int x;
+
+	/**
+	 * (read-write)
+	 *
+	 * Position in y.
+	 */
+	int y;
+
+	/**
+	 * (read-write)
+	 *
+	 * Menu frame width.
+	 */
+	unsigned int w;
+
+	/**
+	 * (read-write)
+	 *
+	 * Menu frame height.
+	 */
+	unsigned int h;
+
+	/**
+	 * (read-write, borrowed)
+	 *
+	 * Lines to show.
+	 */
+	const char * const *lines;
+
+	/**
+	 * (read-write)
+	 *
+	 * Number of lines in ::mlk_message::lines.
+	 */
+	size_t linesz;
+
+	/**
+	 * (read-write)
+	 *
+	 * Selected item from the user.
+	 */
+	size_t index;
+
+	/**
+	 * (read-write)
+	 *
+	 * Optional message flags.
+	 */
+	enum mlk_message_flags flags;
+
+	/**
+	 * (read-only)
+	 *
+	 * Current message state.
+	 */
+	enum mlk_message_state state;
+
+	/**
+	 * (read-write, borrowed, optional)
+	 *
+	 * Style to use for drawing this message.
+	 */
+	struct mlk_message_style *style;
+
+	/** \cond MLK_PRIVATE_DECLS */
+	unsigned int elapsed;   /* elapsed time in the state */
+	double scale;           /* texture scaling */
+	/** \endcond MLK_PRIVATE_DECLS */
 };
 
-struct mlk_message_delegate {
+/**
+ * \struct mlk_message_style
+ * \brief Message style.
+ */
+struct mlk_message_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)
+	 *
+	 * Left-right padding.
+	 */
+	unsigned int padding;
+
+	/**
+	 * (read-write, borrowed, optional)
+	 *
+	 * Font for drawing text.
+	 */
+	struct mlk_font *font;
+
+	/**
+	 * (read-write)
+	 *
+	 * Message timeout in milliseconds when set to automatic.
+	 */
+	unsigned int timeout;
+
+	/**
+	 * (read-write)
+	 *
+	 * Opening/hideing animation speed in milliseconds.
+	 */
+	unsigned int speed;
+
+	/**
+	 * (read-write, borrowed, optional)
+	 *
+	 * Arbitrary user data.
+	 */
 	void *data;
 
-	int (*query)(struct mlk_message_delegate *self,
-	             const struct mlk_message *message,
+	/**
+	 * (read-write, optional)
+	 *
+	 * Check the optimal dimensions for this message.
+	 *
+	 * \param self this style
+	 * \param message the message to query dimensions
+	 * \param w destination width (can be NULL)
+	 * \param h destination height (can be NULL)
+	 * \return 0 on success or -1 on error
+	 */
+	int (*query)(struct mlk_message_style *self,
+	             struct mlk_message *message,
 	             unsigned int *w,
 	             unsigned int *h);
 
-	void (*update)(struct mlk_message_delegate *self,
+	/**
+	 * (read-write, optional)
+	 *
+	 * Update this message.
+	 *
+	 * \param self this style
+	 * \param message the message to update
+	 * \param ticks frame ticks
+	 */
+	void (*update)(struct mlk_message_style *self,
 	               struct mlk_message *message,
 	               unsigned int ticks);
 
-	void (*draw)(struct mlk_message_delegate *self,
-	             const struct mlk_message *message);
+	/**
+	 * (read-write, optional)
+	 *
+	 * Draw the message.
+	 *
+	 * \param self this style
+	 * \param message the message to draw
+	 */
+	void (*draw)(struct mlk_message_style *self,
+	             struct mlk_message *message);
 };
 
-struct mlk_message {
-	int x, y;
-	unsigned int w, h;
-	const char * const *lines;
-	size_t linesz;
-	unsigned int index;
-	enum mlk_message_flags flags;
-	enum mlk_message_state state;
-	struct mlk_message_style *style;
-	struct mlk_message_delegate *delegate;
-	unsigned int elapsed;
-	double scale;
-};
+/**
+ * \brief Dark default style for message.
+ */
+extern struct mlk_message_style mlk_message_style_dark;
 
-extern struct mlk_message_style mlk_message_style;
-extern struct mlk_message_delegate mlk_message_delegate;
+/**
+ * \brief Dark default style for message.
+ */
+extern struct mlk_message_style mlk_message_style_light;
+
+/**
+ * \brief Default style for all messages.
+ */
+extern struct mlk_message_style *mlk_message_style;
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
+/**
+ * Reset the message state.
+ *
+ * This function should be called at least once or when its fields change.
+ *
+ * \pre message != NULL
+ * \param message the message to start
+ */
 void
-mlk_message_start(struct mlk_message *msg);
+mlk_message_start(struct mlk_message *message);
 
+/**
+ * Invoke ::mlk_message_style::query.
+ */
 int
-mlk_message_query(const struct mlk_message *msg, unsigned int *w, unsigned int *h);
-
-void
-mlk_message_handle(struct mlk_message *msg, const union mlk_event *ev);
+mlk_message_query(struct mlk_message *message, unsigned int *w, unsigned int *h);
 
-int
-mlk_message_update(struct mlk_message *msg, unsigned int ticks);
-
+/**
+ * Handle an event.
+ *
+ * \pre message != NULL
+ * \pre ev != NULL
+ * \param message the message
+ * \param ev the event
+ */
 void
-mlk_message_draw(const struct mlk_message *msg);
+mlk_message_handle(struct mlk_message *message, const union mlk_event *ev);
+
+/**
+ * Invoke ::mlk_message_style::update.
+ *
+ * \return non-zero if the message has ended
+ */
+int
+mlk_message_update(struct mlk_message *message, unsigned int ticks);
 
+/**
+ * Invoke ::mlk_message_style::draw.
+ */
 void
-mlk_message_hide(struct mlk_message *msg);
+mlk_message_draw(struct mlk_message *message);
+
+/**
+ * Start hiding the message.
+ *
+ * This should be called when the message has fade-out flags and the animation
+ * to close should start, keep updating and drawing until it completes.
+ *
+ * \pre message
+ * \param message the message to hide
+ */
+void
+mlk_message_hide(struct mlk_message *message);
 
 #if defined(__cplusplus)
 }
--- a/libmlk-ui/mlk/ui/ui_p.h	Tue Aug 22 21:36:49 2023 +0200
+++ b/libmlk-ui/mlk/ui/ui_p.h	Tue Aug 22 22:25:34 2023 +0200
@@ -46,7 +46,7 @@
 } while (0)
 
 #define MLK__STYLE(w, d)                                \
-        (w->style ? w->style : &d)
+        (w->style ? w->style : d)
 
 #if defined(MLK_WITH_NLS)
 #       include <libintl.h>