changeset 618:509b395171f2

ui: simplify button
author David Demelier <markand@malikania.fr>
date Mon, 21 Aug 2023 21:24:30 +0200
parents 19b195954ec3
children b8fd5c112538
files examples/example-ui/button-glower.c examples/example-ui/button-glower.h examples/example-ui/example-ui.c libmlk-core/CMakeLists.txt libmlk-core/mlk/core/color.c libmlk-core/mlk/core/color.h libmlk-core/mlk/core/util.c libmlk-core/mlk/core/util.h libmlk-ui/mlk/ui/button.c libmlk-ui/mlk/ui/button.h libmlk-ui/mlk/ui/ui.c
diffstat 11 files changed, 264 insertions(+), 115 deletions(-) [+]
line wrap: on
line diff
--- a/examples/example-ui/button-glower.c	Mon Aug 21 20:23:35 2023 +0200
+++ b/examples/example-ui/button-glower.c	Mon Aug 21 21:24:30 2023 +0200
@@ -21,15 +21,14 @@
 #include "button-glower.h"
 
 static void
-update(struct mlk_button_delegate *delegate, struct mlk_button *button, unsigned int ticks)
+update(struct mlk_button_style *self, struct mlk_button *button, unsigned int ticks)
 {
-	struct button_glower *glower = delegate->data;
+	struct button_glower *glower = self->data;
 
 	/* Don't update if pressed. */
 	if (!button->pressed) {
 		mlk_glower_update(&glower->glower, ticks);
-		glower->style.bg_color = glower->glower.color;
-		glower->style.pressed_bg_color = glower->glower.color;
+		glower->style.background = glower->glower.color;
 	}
 }
 
@@ -37,15 +36,13 @@
 button_glower_init(struct button_glower *glower, struct mlk_button *button)
 {
 	assert(glower);
+	assert(button);
 
-	glower->style.bg_color = glower->glower.start;
-	glower->style.pressed_bg_color = glower->glower.start;
-	glower->delegate.data = glower;
-	glower->delegate.update = update;
+	glower->style.background = glower->glower.start;
+	glower->style.data = glower;
+	glower->style.update = update;
 
-	/* Link this style and delegate to the button. */
 	button->style = &glower->style;
-	button->delegate = &glower->delegate;
 
 	mlk_glower_init(&glower->glower);
 }
--- a/examples/example-ui/button-glower.h	Mon Aug 21 20:23:35 2023 +0200
+++ b/examples/example-ui/button-glower.h	Mon Aug 21 21:24:30 2023 +0200
@@ -30,7 +30,6 @@
 struct button_glower {
 	struct mlk_glower glower;
 	struct mlk_button_style style;
-	struct mlk_button_delegate delegate;
 };
 
 void
--- a/examples/example-ui/example-ui.c	Mon Aug 21 20:23:35 2023 +0200
+++ b/examples/example-ui/example-ui.c	Mon Aug 21 21:24:30 2023 +0200
@@ -135,10 +135,8 @@
 			.h = ELEMENT_HEIGHT
 		},
 		.quit_style = {
-			.bg_color = 0x24aed6ff,
-			.pressed_bg_color = 0x328ca7ff,
-			.text_color = 0xffffffff,
-			.pressed_text_color = 0xffffffff
+			.background = 0x24aed6ff,
+			.color = 0xffffffff
 		},
 		.quit = {
 			.text = "Quit",
@@ -152,10 +150,9 @@
 				.delay = BUTTON_STYLE_GLOW_DELAY
 			},
 			.style = {
-				.text_color = 0xffffffff,
-				.pressed_text_color = 0xffffffff,
-				.border_color = BUTTON_STYLE_GLOW_COLOR_1,
-				.pressed_border_color = BUTTON_STYLE_GLOW_COLOR_1,
+				.color = 0xffffffff,
+				.border = BUTTON_STYLE_GLOW_COLOR_1,
+				.background = BUTTON_STYLE_GLOW_COLOR_1,
 				.border_size = 2
 			}
 		},
--- a/libmlk-core/CMakeLists.txt	Mon Aug 21 20:23:35 2023 +0200
+++ b/libmlk-core/CMakeLists.txt	Mon Aug 21 21:24:30 2023 +0200
@@ -26,7 +26,7 @@
 	${libmlk-core_SOURCE_DIR}/mlk/core/alloc.c
 	${libmlk-core_SOURCE_DIR}/mlk/core/animation.c
 	${libmlk-core_SOURCE_DIR}/mlk/core/clock.c
-	${libmlk-core_SOURCE_DIR}/mlk/core/core.c
+	${libmlk-core_SOURCE_DIR}/mlk/core/color.c
 	${libmlk-core_SOURCE_DIR}/mlk/core/core.c
 	${libmlk-core_SOURCE_DIR}/mlk/core/core_p.h
 	${libmlk-core_SOURCE_DIR}/mlk/core/drawable-stack.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-core/mlk/core/color.c	Mon Aug 21 21:24:30 2023 +0200
@@ -0,0 +1,37 @@
+/*
+ * color.c -- basic color routines
+ *
+ * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "color.h"
+#include "util.h"
+
+unsigned long
+mlk_color_darken(unsigned long color, float perc)
+{
+	unsigned int r = MLK_COLOR_R(color) * perc;
+	unsigned int g = MLK_COLOR_G(color) * perc;
+	unsigned int b = MLK_COLOR_B(color) * perc;
+	unsigned int a = MLK_COLOR_A(color) * perc;
+
+	return MLK_COLOR_HEX(
+		mlk_clampu(r, 0, 255),
+		mlk_clampu(g, 0, 255),
+		mlk_clampu(b, 0, 255),
+		mlk_clampu(a, 0, 255)
+	);
+	
+}
--- a/libmlk-core/mlk/core/color.h	Mon Aug 21 20:23:35 2023 +0200
+++ b/libmlk-core/mlk/core/color.h	Mon Aug 21 21:24:30 2023 +0200
@@ -89,4 +89,7 @@
          ((b << 8)  & 0x0000ff00) |     \
          ((a)       & 0x000000ff))
 
+unsigned long
+mlk_color_darken(unsigned long color, float perc);
+
 #endif /* !MLK_CORE_COLOR_H */
--- a/libmlk-core/mlk/core/util.c	Mon Aug 21 20:23:35 2023 +0200
+++ b/libmlk-core/mlk/core/util.c	Mon Aug 21 21:24:30 2023 +0200
@@ -52,3 +52,16 @@
 
 	return (rand() % (upper - lower)) + lower;
 }
+
+intmax_t
+mlk_clampi(intmax_t v, intmax_t min, intmax_t max)
+{
+	return v < min ? min : v > max ? max : v;
+	
+}
+
+uintmax_t
+mlk_clampu(uintmax_t v, uintmax_t min, uintmax_t max)
+{
+	return v < min ? min : v > max ? max : v;
+}
--- a/libmlk-core/mlk/core/util.h	Mon Aug 21 20:23:35 2023 +0200
+++ b/libmlk-core/mlk/core/util.h	Mon Aug 21 21:24:30 2023 +0200
@@ -24,6 +24,8 @@
  * \brief libmlk-core utilities
  */
 
+#include <stdint.h>
+
 /**
  * Compute the length of an fixed size array.
  *
@@ -66,6 +68,12 @@
 unsigned int
 mlk_util_nrand(unsigned int min, unsigned int max);
 
+intmax_t
+mlk_clampi(intmax_t v, intmax_t min, intmax_t max);
+
+uintmax_t
+mlk_clampu(uintmax_t v, uintmax_t min, uintmax_t max);
+
 #if defined(__cplusplus)
 }
 #endif
--- a/libmlk-ui/mlk/ui/button.c	Mon Aug 21 20:23:35 2023 +0200
+++ b/libmlk-ui/mlk/ui/button.c	Mon Aug 21 21:24:30 2023 +0200
@@ -19,6 +19,7 @@
 #include <assert.h>
 #include <string.h>
 
+#include <mlk/core/color.h>
 #include <mlk/core/event.h>
 #include <mlk/core/maths.h>
 #include <mlk/core/painter.h>
@@ -40,61 +41,35 @@
 	    button->x, button->y, button->w, button->h);
 }
 
-static inline struct mlk_font *
-style_font(const struct mlk_button *button)
+static void
+draw_frame(struct mlk_button_style *self, struct mlk_button *button)
 {
-	const struct mlk_button_style *style = MLK__STYLE(button, mlk_button_style);
-
-	if (style->text_font)
-		return style->text_font;
-
-	return &mlk_ui_fonts[MLK_UI_FONT_INTERFACE];
-}
-
-static void
-delegate_draw_frame(struct mlk_button_delegate *delegate, const struct mlk_button *button)
-{
-	(void)delegate;
-
-	const struct mlk_button_style *style = MLK__STYLE(button, mlk_button_style);
-	unsigned long long border_color, bg_color;
+	unsigned long background = self->background;
+	unsigned long border = self->border;
 
 	if (button->pressed) {
-		bg_color = style->pressed_bg_color;
-		border_color = style->pressed_border_color;
-	} else {
-		bg_color = style->bg_color;
-		border_color = style->border_color;
+		background = mlk_color_darken(background, 0.9);
+		border = mlk_color_darken(border, 0.9);
 	}
 
-	mlk_painter_set_color(border_color);
+	mlk_painter_set_color(border);
 	mlk_painter_draw_rectangle(button->x, button->y, button->w, button->h);
-	mlk_painter_set_color(bg_color);
+	mlk_painter_set_color(background);
 	mlk_painter_draw_rectangle(
-		button->x + style->border_size,
-		button->y + style->border_size,
-		button->w - (style->border_size * 2),
-		button->h - (style->border_size * 2)
+		button->x + self->border_size,
+		button->y + self->border_size,
+		button->w - (self->border_size * 2),
+		button->h - (self->border_size * 2)
 	);
 }
 
 static void
-delegate_draw_text(struct mlk_button_delegate *delegate, const struct mlk_button *button)
+draw_text(struct mlk_button_style *style, struct mlk_button *button)
 {
-	(void)delegate;
-
-	const struct mlk_button_style *style = MLK__STYLE(button, mlk_button_style);
-	unsigned long long text_color;
-
-	if (button->pressed)
-		text_color = style->pressed_text_color;
-	else
-		text_color = style->text_color;
-
 	mlk_ui_draw_text(
 		MLK_ALIGN_CENTER,
-		style_font(button),
-		text_color,
+		MLK__STYLE_FONT(style->font, MLK_UI_FONT_INTERFACE),
+		style->color,
 		button->text,
 		button->x,
 		button->y,
@@ -103,31 +78,25 @@
 	);
 }
 
-struct mlk_button_style mlk_button_style = {
-	.bg_color               = MLK_UI_COLOR_BG,
-	.pressed_bg_color       = 0xcdd2daff,
-	.border_color           = MLK_UI_COLOR_BORDER,
-	.pressed_border_color   = 0xa6aebaff,
-	.border_size            = 1,
-	.text_color             = MLK_UI_COLOR_TEXT,
-	.pressed_text_color     = MLK_UI_COLOR_TEXT
+struct mlk_button_style mlk_button_style_dark = {
+	.background = 0x222323ff,
+	.border = 0x141414ff,
+	.border_size = 2,
+	.color = 0xffffffff,
+	.draw_frame = draw_frame,
+	.draw_text = draw_text
 };
 
-struct mlk_button_delegate mlk_button_delegate = {
-	.draw_frame     = delegate_draw_frame,
-	.draw_text      = delegate_draw_text
+struct mlk_button_style mlk_button_style_light = {
+	.background = 0xf5f7faff,
+	.border = 0xcdd2daff,
+	.border_size = 2,
+	.color = 0x000000ff,
+	.draw_frame = draw_frame,
+	.draw_text = draw_text
 };
 
-int
-mlk_button_ok(const struct mlk_button *button)
-{
-	if (!button)
-		return 0;
-	if (button->text && strlen(button->text) == 0)
-		return 0;
-
-	return 1;
-}
+struct mlk_button_style *mlk_button_style = &mlk_button_style_light;
 
 int
 mlk_button_handle(struct mlk_button *button, const union mlk_event *ev)
@@ -165,16 +134,16 @@
 {
 	assert(button);
 
-	MLK__DELEGATE_INVOKE(button->delegate, mlk_button_delegate, update, button, ticks);
+	MLK__STYLE_CALL(button->style, mlk_button_style, update, button, ticks);
 }
 
 void
-mlk_button_draw(const struct mlk_button *button)
+mlk_button_draw(struct mlk_button *button)
 {
 	assert(button);
 
-	MLK__DELEGATE_INVOKE(button->delegate, mlk_button_delegate, draw_frame, button);
+	MLK__STYLE_CALL(button->style, mlk_button_style, draw_frame, button);
 
 	if (button->text)
-		MLK__DELEGATE_INVOKE(button->delegate, mlk_button_delegate, draw_text, button);
+		MLK__STYLE_CALL(button->style, mlk_button_style, draw_text, button);
 }
--- a/libmlk-ui/mlk/ui/button.h	Mon Aug 21 20:23:35 2023 +0200
+++ b/libmlk-ui/mlk/ui/button.h	Mon Aug 21 21:24:30 2023 +0200
@@ -22,53 +22,176 @@
 union mlk_event;
 
 struct mlk_button;
+struct mlk_button_style;
 struct mlk_font;
 
-struct mlk_button_style {
-	unsigned long bg_color;
-	unsigned long pressed_bg_color;
-	unsigned long border_color;
-	unsigned long pressed_border_color;
-	unsigned long border_size;
-	unsigned long text_color;
-	unsigned long pressed_text_color;
-	struct mlk_font *text_font;
+struct mlk_button {
+	/**
+	 * (read-write)
+	 *
+	 * Position in x.
+	 */
+	int x;
+
+	/**
+	 * (read-write)
+	 *
+	 * Position in y.
+	 */
+	int y;
+
+	/**
+	 * (read-write)
+	 *
+	 * Frame width.
+	 */
+	unsigned int w;
+
+	/**
+	 * (read-write)
+	 *
+	 * Frame height.
+	 */
+	unsigned int h;
+
+	/**
+	 * (read-write, borrowed, optional)
+	 *
+	 * Button text.
+	 */
+	const char *text;
+
+	/**
+	 * (read-only)
+	 *
+	 * Indicate if the button is pressed.
+	 *
+	 * This value goes non-zero when the user clicks the button even if the
+	 * mouse is not released which is different than considered active. For
+	 * example, if the user clicks the button but release the mouse outside
+	 * of the button region it is no longer considered active and no action
+	 * should be performed.
+	 */
+	int pressed;
+
+	/**
+	 * (read-write, borrowed, optional)
+	 *
+	 * Style to use for drawing this button.
+	 */
+	struct mlk_button_style *style;
 };
 
-struct mlk_button_delegate {
+/**
+ * \struct mlk_label_button
+ * \brief Button style.
+ */
+struct mlk_button_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, borrowed, optional)
+	 *
+	 * Text font.
+	 */
+	struct mlk_font *font;
+	
+	/**
+	 * (read-write, borrowed, optional)
+	 *
+	 * Arbitrary user data.
+	 */
 	void *data;
-	void (*update)(struct mlk_button_delegate *delegate, struct mlk_button *button, unsigned int ticks);
-	void (*draw_frame)(struct mlk_button_delegate *delegate, const struct mlk_button *button);
-	void (*draw_text)(struct mlk_button_delegate *delegate, const struct mlk_button *button);
+
+	/**
+	 * (read-write, optional)
+	 *
+	 * Update this label.
+	 *
+	 * \param self this style
+	 * \param button the button to update
+	 * \param ticks frame ticks
+	 */
+	void (*update)(struct mlk_button_style *style,
+	               struct mlk_button *button,
+	               unsigned int ticks);
+
+	/**
+	 * (read-write, optional)
+	 *
+	 * Draw bounding frame owning the button.
+	 *
+	 * \param self this style
+	 * \param button the button
+	 */
+	void (*draw_frame)(struct mlk_button_style *style,
+	                   struct mlk_button *button);
+
+	/**
+	 * (read-write, optional)
+	 *
+	 * Draw the butotn text.
+	 *
+	 * \param self this style
+	 * \param button the button
+	 */
+	void (*draw_text)(struct mlk_button_style *style,
+	                  struct mlk_button *button);
 };
 
-struct mlk_button {
-	int x, y;
-	unsigned int w, h;
-	const char *text;
-	int pressed;
-	struct mlk_button_style *style;
-	struct mlk_button_delegate *delegate;
-};
+/**
+ * \brief Dark default style for button.
+ */
+extern struct mlk_button_style mlk_button_style_dark;
 
-extern struct mlk_button_style mlk_button_style;
-extern struct mlk_button_delegate mlk_button_delegate;
+/**
+ * \brief Light default style for button.
+ */
+extern struct mlk_button_style mlk_button_style_light;
+
+/**
+ * \brief Default style for all labels.
+ */
+extern struct mlk_button_style *mlk_button_style;
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
 int
-mlk_button_ok(const struct mlk_button *);
-
-int
 mlk_button_handle(struct mlk_button *, const union mlk_event *);
 
 void
 mlk_button_update(struct mlk_button *, unsigned int);
 
 void
-mlk_button_draw(const struct mlk_button *);
+mlk_button_draw(struct mlk_button *);
 
 #if defined(__cplusplus)
 }
--- a/libmlk-ui/mlk/ui/ui.c	Mon Aug 21 20:23:35 2023 +0200
+++ b/libmlk-ui/mlk/ui/ui.c	Mon Aug 21 21:24:30 2023 +0200
@@ -37,6 +37,7 @@
 #include <assets/fonts/opensans-regular.h>
 
 #include "align.h"
+#include "button.h"
 #include "frame.h"
 #include "label.h"
 #include "ui.h"
@@ -96,11 +97,13 @@
 mlk_ui_set_theme(enum mlk_window_theme theme)
 {
 	if (theme == MLK_WINDOW_THEME_DARK) {
+		mlk_button_style = &mlk_button_style_dark;
+		mlk_frame_style = &mlk_frame_style_dark;
 		mlk_label_style = &mlk_label_style_dark;
-		mlk_frame_style = &mlk_frame_style_dark;
 	} else {
+		mlk_button_style = &mlk_button_style_light;
+		mlk_frame_style = &mlk_frame_style_light;
 		mlk_label_style = &mlk_label_style_light;
-		mlk_frame_style = &mlk_frame_style_light;
 	}
 }