changeset 150:9733d379be89

ui: add a standalone align() function
author David Demelier <markand@malikania.fr>
date Thu, 15 Oct 2020 13:13:38 +0200
parents a43e79d489ea
children b19d076856d2
files examples/example-drawable.c examples/example-label.c examples/example-sound.c libcore/core/maths.c libcore/core/maths.h librpg/rpg/inventory_dialog.c librpg/rpg/message.c libui/CMakeLists.txt libui/ui/align.c libui/ui/align.h libui/ui/label.c libui/ui/label.h libui/ui/theme.c
diffstat 13 files changed, 206 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
--- a/examples/example-drawable.c	Thu Oct 15 10:45:40 2020 +0200
+++ b/examples/example-drawable.c	Thu Oct 15 13:13:38 2020 +0200
@@ -46,7 +46,7 @@
 	.y = 10,
 	.w = W,
 	.h = H,
-	.align = LABEL_ALIGN_TOP_LEFT,
+	.align = ALIGN_TOP_LEFT,
 	.flags = LABEL_FLAGS_SHADOW
 };
 
--- a/examples/example-label.c	Thu Oct 15 10:45:40 2020 +0200
+++ b/examples/example-label.c	Thu Oct 15 13:13:38 2020 +0200
@@ -58,7 +58,7 @@
 			.w = W,
 			.h = H,
 			.text = "Top left",
-			.align = LABEL_ALIGN_TOP_LEFT
+			.align = ALIGN_TOP_LEFT
 		},
 		{
 			.x = 0,
@@ -66,7 +66,7 @@
 			.w = W,
 			.h = H,
 			.text = "Top",
-			.align = LABEL_ALIGN_TOP
+			.align = ALIGN_TOP
 		},
 		{
 			.x = 0,
@@ -74,7 +74,7 @@
 			.w = W,
 			.h = H,
 			.text = "Top right",
-			.align = LABEL_ALIGN_TOP_RIGHT
+			.align = ALIGN_TOP_RIGHT
 		},
 		{
 			.x = 0,
@@ -82,7 +82,7 @@
 			.w = W,
 			.h = H,
 			.text = "Right",
-			.align = LABEL_ALIGN_RIGHT
+			.align = ALIGN_RIGHT
 		},
 		{
 			.x = 0,
@@ -90,7 +90,7 @@
 			.w = W,
 			.h = H,
 			.text = "Bottom right",
-			.align = LABEL_ALIGN_BOTTOM_RIGHT
+			.align = ALIGN_BOTTOM_RIGHT
 		},
 		{
 			.x = 0,
@@ -98,7 +98,7 @@
 			.w = W,
 			.h = H,
 			.text = "Bottom",
-			.align = LABEL_ALIGN_BOTTOM
+			.align = ALIGN_BOTTOM
 		},
 		{
 			.x = 0,
@@ -106,7 +106,7 @@
 			.w = W,
 			.h = H,
 			.text = "Bottom left",
-			.align = LABEL_ALIGN_BOTTOM_LEFT
+			.align = ALIGN_BOTTOM_LEFT
 		},
 		{
 			.x = 0,
@@ -114,7 +114,7 @@
 			.w = W,
 			.h = H,
 			.text = "Left",
-			.align = LABEL_ALIGN_LEFT
+			.align = ALIGN_LEFT
 		},
 		{
 			.x = 0,
@@ -123,7 +123,7 @@
 			.h = H,
 			.text = "The world is Malikania.",
 			.flags = LABEL_FLAGS_SHADOW,
-			.align = LABEL_ALIGN_CENTER
+			.align = ALIGN_CENTER
 		},
 	};
 	struct label mlabel = {
--- a/examples/example-sound.c	Thu Oct 15 10:45:40 2020 +0200
+++ b/examples/example-sound.c	Thu Oct 15 13:13:38 2020 +0200
@@ -41,7 +41,7 @@
 	.y = 10,
 	.w = W,
 	.h = H,
-	.align = LABEL_ALIGN_TOP_LEFT,
+	.align = ALIGN_TOP_LEFT,
 	.flags = LABEL_FLAGS_SHADOW
 };
 
--- a/libcore/core/maths.c	Thu Oct 15 10:45:40 2020 +0200
+++ b/libcore/core/maths.c	Thu Oct 15 13:13:38 2020 +0200
@@ -26,19 +26,3 @@
 	       px <= x + (int)w &&
 	       py <= y + (int)h;
 }
-
-void
-maths_centerize(int *x,
-               int *y,
-               unsigned int w,
-               unsigned int h,
-               int px,
-               int py,
-               unsigned int pw,
-               unsigned int ph)
-{
-	if (x)
-		*x = px + (pw / 2) - (w / 2);
-	if (y)
-		*y = py + (ph / 2) - (h / 2);
-}
--- a/libcore/core/maths.h	Thu Oct 15 10:45:40 2020 +0200
+++ b/libcore/core/maths.h	Thu Oct 15 13:13:38 2020 +0200
@@ -40,29 +40,4 @@
 bool
 maths_is_boxed(int x, int y, unsigned int w, unsigned int h, int px, int py);
 
-/**
- * Update x, y to be centered into a parent region.
- *
- * You can select to ignore horizontal/vertical centering by passing NULL to x
- * or y respectively.
- *
- * \param x the pointer to x coordinate to modify
- * \param y the pointer yo y coordinate to modify
- * \param w the object width
- * \param h the object height
- * \param px the parent region start
- * \param py the parent region start
- * \param pw the parent region width
- * \param ph the parent region height
- */
-void
-maths_centerize(int *x,
-                int *y,
-                unsigned int w,
-                unsigned int h,
-                int px,
-                int py,
-                unsigned int pw,
-                unsigned int ph);
-
 #endif /* !MOLKO_MATHS_H */
--- a/librpg/rpg/inventory_dialog.c	Thu Oct 15 10:45:40 2020 +0200
+++ b/librpg/rpg/inventory_dialog.c	Thu Oct 15 13:13:38 2020 +0200
@@ -195,7 +195,7 @@
 	dlg->fname.x = dlg->lname.x = dlg->x;
 	dlg->fname.y = dlg->lname.y = dlg->y + GRID_HEIGHT;
 	dlg->lname.x += ITEM_PADDING;
-	dlg->lname.align = LABEL_ALIGN_LEFT;
+	dlg->lname.align = ALIGN_LEFT;
 
 	/* Description label. */
 	dlg->fdesc.w = dlg->ldesc.w = LABEL_WIDTH;
@@ -203,7 +203,7 @@
 	dlg->fdesc.x = dlg->ldesc.x = dlg->y;
 	dlg->fdesc.y = dlg->ldesc.y = dlg->y + GRID_HEIGHT + (LABEL_HEIGHT / 2);
 	dlg->ldesc.x += ITEM_PADDING;
-	dlg->ldesc.align = LABEL_ALIGN_LEFT;
+	dlg->ldesc.align = ALIGN_LEFT;
 
 	/* Button sort. */
 	dlg->bsort.x = dlg->x;
--- a/librpg/rpg/message.c	Thu Oct 15 10:45:40 2020 +0200
+++ b/librpg/rpg/message.c	Thu Oct 15 13:13:38 2020 +0200
@@ -30,6 +30,7 @@
 #include <core/trace.h>
 #include <core/util.h>
 
+#include <ui/align.h>
 #include <ui/frame.h>
 #include <ui/label.h>
 #include <ui/theme.h>
@@ -99,7 +100,7 @@
 			.h = msg->h,
 			.theme = &theme,
 			.text = msg->text[i],
-			.align = LABEL_ALIGN_TOP_LEFT,
+			.align = ALIGN_TOP_LEFT,
 			.flags = LABEL_FLAGS_SHADOW
 		};
 
@@ -239,7 +240,7 @@
 	h = msg->h * msg->scale;
 
 	/* Centerize within its drawing area. */
-	maths_centerize(&x, &y, w, h, msg->x, msg->y, msg->w, msg->h);
+	align(ALIGN_CENTER, &x, &y, w, h, msg->x, msg->y, msg->w, msg->h);
 
 	/* Draw and clear. */
 	texture_scale(&tex, 0, 0, msg->w, msg->h, x, y, w, h, 0);
--- a/libui/CMakeLists.txt	Thu Oct 15 10:45:40 2020 +0200
+++ b/libui/CMakeLists.txt	Thu Oct 15 13:13:38 2020 +0200
@@ -20,6 +20,8 @@
 
 set(
 	SOURCES
+	${libui_SOURCE_DIR}/ui/align.c
+	${libui_SOURCE_DIR}/ui/align.h
 	${libui_SOURCE_DIR}/ui/button.c
 	${libui_SOURCE_DIR}/ui/button.h
 	${libui_SOURCE_DIR}/ui/checkbox.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libui/ui/align.c	Thu Oct 15 13:13:38 2020 +0200
@@ -0,0 +1,75 @@
+/*
+ * align.h -- user interface alignment
+ *
+ * Copyright (c) 2020 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 "align.h"
+
+#define SET(p, v) if (p) *p = v
+#define CENTER(p, c, rs, es) if (p) (*p) = c + (rs / 2) - (es / 2)
+
+void
+align(enum align align,
+      int *x,
+      int *y,
+      unsigned int w,
+      unsigned int h,
+      int px,
+      int py,
+      unsigned int pw,
+      unsigned int ph)
+{
+	switch (align) {
+	case ALIGN_CENTER:
+		CENTER(x, px, pw, w);
+		CENTER(y, py, ph, h);
+		break;
+	case ALIGN_TOP_LEFT:
+		SET(x, px);
+		SET(y, py);
+		break;
+	case ALIGN_TOP:
+		CENTER(x, px, pw, w);
+		SET(y, py);
+		break;
+	case ALIGN_TOP_RIGHT:
+		SET(x, px + pw - w);
+		SET(y, py);
+		break;
+	case ALIGN_RIGHT:
+		SET(x, px + pw - w);
+		CENTER(y, py, ph, h);
+		break;
+	case ALIGN_BOTTOM_RIGHT:
+		SET(x, px + pw - w);
+		SET(y, py + ph - h);
+		break;
+	case ALIGN_BOTTOM:
+		CENTER(x, px, pw, w);
+		SET(y, py + ph - h);
+		break;
+	case ALIGN_BOTTOM_LEFT:
+		SET(x, px);
+		SET(y, py + ph - h);
+		break;
+	case ALIGN_LEFT:
+		CENTER(y, py, ph, h);
+		SET(x, px);
+		break;
+	default:
+		break;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libui/ui/align.h	Thu Oct 15 13:13:38 2020 +0200
@@ -0,0 +1,102 @@
+/*
+ * align.h -- user interface alignment
+ *
+ * Copyright (c) 2020 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.
+ */
+
+#ifndef MOLKO_ALIGN_H
+#define MOLKO_ALIGN_H
+
+/**
+ * \file align.h
+ * \brief User interface alignment.
+ */
+
+/**
+ * \brief Label alignment in bounding box.
+ *
+ * The alignment is described as following:
+ *
+ * ```
+ * +---------------------+
+ * | 2        3        4 |
+ * |                     |
+ * | 9        1        5 |
+ * |                     |
+ * | 8        7        6 |
+ * +---------------------+
+ * ```
+ *
+ * The default value of 0 (LABEL_ALIGN_NONE) means the alignment isn't used.
+ */
+enum align {
+	ALIGN_NONE,             /*!< No alignment. */
+	ALIGN_CENTER,           /*!< Align to the center. */
+	ALIGN_TOP_LEFT,         /*!< Top left. */
+	ALIGN_TOP,              /*!< Top center (aligned horizontally). */
+	ALIGN_TOP_RIGHT,        /*!< Top right. */
+	ALIGN_RIGHT,            /*!< Right (aligned vertically). */
+	ALIGN_BOTTOM_RIGHT,     /*!< Bottom right. */
+	ALIGN_BOTTOM,           /*!< Bottom (aligned horizontally). */
+	ALIGN_BOTTOM_LEFT,      /*!< Bottom left. */
+	ALIGN_LEFT              /*!< Left (aligned vertically). */
+};
+
+/**
+ * Align the given object relative to its parent region.
+ *
+ * The arguments are described as following:
+ *
+ * ```
+ * Example of ALIGN_LEFT (centered vertically but placed on the left.)
+ *
+ *    px, py
+ *      +----------pw----------+
+ *      |                      |
+ *      | x, y                 |
+ *      | +---w---+            |
+ *     ph h       |            |
+ *      | +-------+            |
+ *      |                      |
+ *      |                      |
+ *      +----------------------+
+ * ```
+ *
+ * As a convenience, x and y are left untouched if align is ALIGN_NONE which
+ * means you can set the coordinates to default values and still call the align
+ * function without need to check.
+ *
+ * \param align the desired alignment
+ * \param x the pointer to x coordinate to modify (may be NULL)
+ * \param y the pointer yo y coordinate to modify (may be NULL)
+ * \param w the object width
+ * \param h the object height
+ * \param px the parent region start
+ * \param py the parent region start
+ * \param pw the parent region width
+ * \param ph the parent region height
+ */
+void
+align(enum align align,
+      int *x,
+      int *y,
+      unsigned int w,
+      unsigned int h,
+      int px,
+      int py,
+      unsigned int pw,
+      unsigned int ph);
+
+#endif /* !MOLKO_ALIGN_H */
--- a/libui/ui/label.c	Thu Oct 15 10:45:40 2020 +0200
+++ b/libui/ui/label.c	Thu Oct 15 13:13:38 2020 +0200
@@ -29,7 +29,7 @@
 	assert(label);
 	assert(label->text);
 
-	if (label->align != LABEL_ALIGN_NONE && (label->w == 0 || label->h == 0))
+	if (label->align != ALIGN_NONE && (label->w == 0 || label->h == 0))
 		trace("label %p has alignment but null dimensions", label);
 
 	theme_draw_label(label->theme, label);
--- a/libui/ui/label.h	Thu Oct 15 10:45:40 2020 +0200
+++ b/libui/ui/label.h	Thu Oct 15 13:13:38 2020 +0200
@@ -24,6 +24,8 @@
  * \brief GUI label.
  */
 
+#include "align.h"
+
 struct theme;
 
 /**
@@ -35,34 +37,6 @@
 };
 
 /**
- * \brief Label alignment in bounding box.
- *
- * The alignment is described as following:
- *
- * ```
- * +---------------------+
- * | 1        2        3 |
- * |                     |
- * | 8        0        4 |
- * |                     |
- * | 7        6        5 |
- * +---------------------+
- * ```
- */
-enum label_align {
-	LABEL_ALIGN_NONE,               /*!< No alignment. */
-	LABEL_ALIGN_CENTER,             /*!< Align to the center. */
-	LABEL_ALIGN_TOP_LEFT,           /*!< Top left. */
-	LABEL_ALIGN_TOP,                /*!< Top center (aligned horizontally). */
-	LABEL_ALIGN_TOP_RIGHT,          /*!< Top right. */
-	LABEL_ALIGN_RIGHT,              /*!< Right (aligned vertically). */
-	LABEL_ALIGN_BOTTOM_RIGHT,       /*!< Bottom right. */
-	LABEL_ALIGN_BOTTOM,             /*!< Bottom (aligned horizontally). */
-	LABEL_ALIGN_BOTTOM_LEFT,        /*!< Bottom left. */
-	LABEL_ALIGN_LEFT                /*!< Left (aligned vertically). */
-};
-
-/**
  * \brief GUI label.
  *
  * A label can be conveniently positioned using a bounding box and an alignment
@@ -76,7 +50,7 @@
 	unsigned int h;                 /*!< (+?) Height. */
 	const char *text;               /*!< (+&) Text to show. */
 	enum label_flags flags;         /*!< (+) Optional flags. */
-	enum label_align align;         /*!< (+) How to positionate label. */
+	enum align align;               /*!< (+) How to positionate label. */
 	struct theme *theme;            /*!< (+&?) Theme to use. */
 };
 
--- a/libui/ui/theme.c	Thu Oct 15 10:45:40 2020 +0200
+++ b/libui/ui/theme.c	Thu Oct 15 13:13:38 2020 +0200
@@ -30,6 +30,7 @@
 #include <core/assets/fonts/f25-bank-printer.h>
 #include <core/assets/fonts/comic-neue.h>
 
+#include "align.h"
 #include "button.h"
 #include "checkbox.h"
 #include "frame.h"
@@ -89,48 +90,11 @@
 	if (!font_box(font, label->text, &tw, &th))
 		panic();
 
-	/* Compute position according to alignment and box. */
-	switch (label->align) {
-	case LABEL_ALIGN_CENTER:
-		maths_centerize(&x, &y, tw, th, bx, by, bw, bh);
-		break;
-	case LABEL_ALIGN_TOP_LEFT:
-		x = bx;
-		y = by;
-		break;
-	case LABEL_ALIGN_TOP:
-		maths_centerize(&x, NULL, tw, th, bx, by, bw, bh);
-		y = by;
-		break;
-	case LABEL_ALIGN_TOP_RIGHT:
-		x = bx + bw - tw;
-		y = by;
-		break;
-	case LABEL_ALIGN_RIGHT:
-		maths_centerize(NULL, &y, tw, th, bx, by, bw, bh);
-		x = bx + bw - tw;
-		break;
-	case LABEL_ALIGN_BOTTOM_RIGHT:
-		x = bx + bw - tw;
-		y = by + bh - th;
-		break;
-	case LABEL_ALIGN_BOTTOM:
-		maths_centerize(&x, NULL, tw, th, bx, by, bw, bh);
-		y = by + bh - th;
-		break;
-	case LABEL_ALIGN_BOTTOM_LEFT:
-		x = bx;
-		y = by + bh - th;
-		break;
-	case LABEL_ALIGN_LEFT:
-		maths_centerize(NULL, &y, tw, th, bx, by, bw, bh);
-		x = bx;
-		break;
-	default:
-		x = label->x;
-		y = label->y;
-		break;
-	}
+	/* Align if needed. */
+	x = label->x;
+	y = label->y;
+
+	align(label->align, &x, &y, tw, th, bx, by, bw, bh);
 
 	/* Shadow text, only if enabled. */
 	if (label->flags & LABEL_FLAGS_SHADOW) {
@@ -188,7 +152,7 @@
 
 		struct label label = {
 			.text = cb->label,
-			.align = LABEL_ALIGN_LEFT,
+			.align = ALIGN_LEFT,
 			.x = x,
 			.y = cb->y,
 			.w = w,