changeset 433:862b15c3a3ae

ui: cleanup hierarchy
author David Demelier <markand@malikania.fr>
date Sat, 15 Oct 2022 21:19:25 +0200
parents 38cf60f5a1c4
children 4e78f045e8c0
files GNUmakefile examples/example-action/example-action.c examples/example-animation/example-animation.c examples/example-audio/example-audio.c examples/example-cursor/example-cursor.c examples/example-debug/example-debug.c examples/example-drawable/example-drawable.c examples/example-font/example-font.c examples/example-gridmenu/example-gridmenu.c examples/example-label/example-label.c examples/example-message/example-message.c examples/example-notify/example-notify.c examples/example-sprite/example-sprite.c examples/example-ui/example-ui.c examples/example/spell-fire.c examples/example/trace_hud.c libmlk-core/mlk/core/alloc.h libmlk-ui/assets/fonts/opensans-light.ttf libmlk-ui/assets/fonts/opensans-medium.ttf libmlk-ui/assets/fonts/opensans-regular.ttf libmlk-ui/mlk/ui/align.c libmlk-ui/mlk/ui/align.h libmlk-ui/mlk/ui/button.c libmlk-ui/mlk/ui/button.h libmlk-ui/mlk/ui/checkbox.c libmlk-ui/mlk/ui/checkbox.h libmlk-ui/mlk/ui/debug.c libmlk-ui/mlk/ui/debug.h libmlk-ui/mlk/ui/frame.c libmlk-ui/mlk/ui/frame.h libmlk-ui/mlk/ui/gridmenu.c libmlk-ui/mlk/ui/gridmenu.h libmlk-ui/mlk/ui/label.c libmlk-ui/mlk/ui/label.h libmlk-ui/mlk/ui/notify.c libmlk-ui/mlk/ui/notify.h libmlk-ui/mlk/ui/theme.c libmlk-ui/mlk/ui/theme.h libmlk-ui/mlk/ui/ui.c libmlk-ui/mlk/ui/ui.h src/libmlk-rpg/rpg/battle-bar-default.c src/libmlk-rpg/rpg/battle-bar-default.h src/libmlk-rpg/rpg/battle-entity.c src/libmlk-rpg/rpg/battle-entity.h src/libmlk-rpg/rpg/battle-indicator.c src/libmlk-rpg/rpg/battle-message.c src/libmlk-rpg/rpg/battle-state-selection.c src/libmlk-rpg/rpg/battle.c src/libmlk-rpg/rpg/battle.h src/libmlk-rpg/rpg/map-file.c src/libmlk-rpg/rpg/map.c src/libmlk-rpg/rpg/message.c src/libmlk-ui/assets/fonts/opensans-light.ttf src/libmlk-ui/assets/fonts/opensans-medium.ttf src/libmlk-ui/assets/fonts/opensans-regular.ttf src/libmlk-ui/ui/align.c src/libmlk-ui/ui/align.h src/libmlk-ui/ui/button.c src/libmlk-ui/ui/button.h src/libmlk-ui/ui/checkbox.c src/libmlk-ui/ui/checkbox.h src/libmlk-ui/ui/debug.c src/libmlk-ui/ui/debug.h src/libmlk-ui/ui/frame.c src/libmlk-ui/ui/frame.h src/libmlk-ui/ui/gridmenu.c src/libmlk-ui/ui/gridmenu.h src/libmlk-ui/ui/label.c src/libmlk-ui/ui/label.h src/libmlk-ui/ui/notify.c src/libmlk-ui/ui/notify.h src/libmlk-ui/ui/theme.c src/libmlk-ui/ui/theme.h src/libmlk-ui/ui/ui.c src/libmlk-ui/ui/ui.h
diffstat 75 files changed, 1832 insertions(+), 1825 deletions(-) [+]
line wrap: on
line diff
--- a/GNUmakefile	Sat Oct 15 20:28:59 2022 +0200
+++ b/GNUmakefile	Sat Oct 15 21:19:25 2022 +0200
@@ -43,7 +43,7 @@
                         -Iextern/libsqlite \
                         -Ilibmlk-util \
                         -Ilibmlk-core \
-                        -Isrc/libmlk-ui \
+                        -Ilibmlk-ui \
                         -Isrc/libmlk-rpg \
                         -I. \
                         $(SDL2_INCS) \
@@ -161,6 +161,13 @@
 
 -include $(LIBMLK_SQLITE_DEPS)
 
+$(LIBMLK_SQLITE_OBJS): private DEFS += -DSQLITE_THREADSAFE=0 \
+                                       -DSQLITE_DEFAULT_MEMSTATUS=0 \
+                                       -DSQLITE_OMIT_DECLTYPE \
+                                       -DSQLITE_OMIT_DEPRECATED \
+                                       -DSQLITE_OMIT_LOAD_EXTENSION \
+                                       -DSQLITE_DEFAULT_FOREIGN_KEY=0
+
 $(LIBMLK_SQLITE): private INCS :=
 $(LIBMLK_SQLITE): private OBJS := $(LIBMLK_SQLITE_OBJS)
 $(LIBMLK_SQLITE): $(LIBMLK_SQLITE_OBJS)
@@ -215,22 +222,22 @@
 # {{{ libmlk-ui
 
 LIBMLK_UI :=            libmlk-ui.a
-LIBMLK_UI_SRCS :=       src/libmlk-ui/ui/align.c \
-                        src/libmlk-ui/ui/button.c \
-                        src/libmlk-ui/ui/checkbox.c \
-                        src/libmlk-ui/ui/debug.c \
-                        src/libmlk-ui/ui/frame.c \
-                        src/libmlk-ui/ui/gridmenu.c \
-                        src/libmlk-ui/ui/label.c \
-                        src/libmlk-ui/ui/notify.c \
-                        src/libmlk-ui/ui/theme.c \
-                        src/libmlk-ui/ui/ui.c
+LIBMLK_UI_SRCS :=       libmlk-ui/mlk/ui/align.c \
+                        libmlk-ui/mlk/ui/button.c \
+                        libmlk-ui/mlk/ui/checkbox.c \
+                        libmlk-ui/mlk/ui/debug.c \
+                        libmlk-ui/mlk/ui/frame.c \
+                        libmlk-ui/mlk/ui/gridmenu.c \
+                        libmlk-ui/mlk/ui/label.c \
+                        libmlk-ui/mlk/ui/notify.c \
+                        libmlk-ui/mlk/ui/theme.c \
+                        libmlk-ui/mlk/ui/ui.c
 
 LIBMLK_UI_OBJS :=       $(LIBMLK_UI_SRCS:.c=.o)
 LIBMLK_UI_DEPS :=       $(LIBMLK_UI_SRCS:.c=.d)
-LIBMLK_UI_DATA_SRCS :=  src/libmlk-ui/assets/fonts/opensans-light.ttf \
-                        src/libmlk-ui/assets/fonts/opensans-medium.ttf \
-                        src/libmlk-ui/assets/fonts/opensans-regular.ttf
+LIBMLK_UI_DATA_SRCS :=  libmlk-ui/assets/fonts/opensans-light.ttf \
+                        libmlk-ui/assets/fonts/opensans-medium.ttf \
+                        libmlk-ui/assets/fonts/opensans-regular.ttf
 LIBMLK_UI_DATA_OBJS :=  $(addsuffix .h,$(basename $(LIBMLK_UI_DATA_SRCS)))
 
 $(LIBMLK_UI_DATA_OBJS): $(MLK_BCC)
--- a/examples/example-action/example-action.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-action/example-action.c	Sat Oct 15 21:19:25 2022 +0200
@@ -35,8 +35,8 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/theme.h>
-#include <ui/ui.h>
+#include <mlk/ui/theme.h>
+#include <mlk/ui/ui.h>
 
 #include <rpg/message.h>
 #include <rpg/rpg.h>
--- a/examples/example-animation/example-animation.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-animation/example-animation.c	Sat Oct 15 21:19:25 2022 +0200
@@ -30,8 +30,8 @@
 #include <mlk/core/texture.h>
 #include <mlk/core/util.h>
 
-#include <ui/label.h>
-#include <ui/ui.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/ui.h>
 
 #include <assets/sprites/numbers.h>
 
--- a/examples/example-audio/example-audio.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-audio/example-audio.c	Sat Oct 15 21:19:25 2022 +0200
@@ -28,9 +28,9 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/label.h>
-#include <ui/theme.h>
-#include <ui/ui.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/theme.h>
+#include <mlk/ui/ui.h>
 
 #include <assets/music/vabsounds-romance.h>
 #include <assets/sounds/fire.h>
--- a/examples/example-cursor/example-cursor.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-cursor/example-cursor.c	Sat Oct 15 21:19:25 2022 +0200
@@ -29,8 +29,8 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/label.h>
-#include <ui/ui.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/ui.h>
 
 #define W 1280
 #define H 720
--- a/examples/example-debug/example-debug.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-debug/example-debug.c	Sat Oct 15 21:19:25 2022 +0200
@@ -25,9 +25,9 @@
 #include <mlk/core/state.h>
 #include <mlk/core/util.h>
 
-#include <ui/debug.h>
-#include <ui/theme.h>
-#include <ui/ui.h>
+#include <mlk/ui/debug.h>
+#include <mlk/ui/theme.h>
+#include <mlk/ui/ui.h>
 
 #define W 1280
 #define H 720
--- a/examples/example-drawable/example-drawable.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-drawable/example-drawable.c	Sat Oct 15 21:19:25 2022 +0200
@@ -37,9 +37,9 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/label.h>
-#include <ui/theme.h>
-#include <ui/ui.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/theme.h>
+#include <mlk/ui/ui.h>
 
 #include <assets/sprites/explosion.h>
 
--- a/examples/example-font/example-font.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-font/example-font.c	Sat Oct 15 21:19:25 2022 +0200
@@ -28,8 +28,8 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/theme.h>
-#include <ui/ui.h>
+#include <mlk/ui/theme.h>
+#include <mlk/ui/ui.h>
 
 #define W       (1280)
 #define H       (720)
--- a/examples/example-gridmenu/example-gridmenu.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-gridmenu/example-gridmenu.c	Sat Oct 15 21:19:25 2022 +0200
@@ -27,11 +27,11 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/align.h>
-#include <ui/gridmenu.h>
-#include <ui/label.h>
-#include <ui/theme.h>
-#include <ui/ui.h>
+#include <mlk/ui/align.h>
+#include <mlk/ui/gridmenu.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/theme.h>
+#include <mlk/ui/ui.h>
 
 #define W       (1280)
 #define H       (720)
--- a/examples/example-label/example-label.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-label/example-label.c	Sat Oct 15 21:19:25 2022 +0200
@@ -28,10 +28,10 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/align.h>
-#include <ui/label.h>
-#include <ui/theme.h>
-#include <ui/ui.h>
+#include <mlk/ui/align.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/theme.h>
+#include <mlk/ui/ui.h>
 
 #define W       (1280)
 #define H       (720)
--- a/examples/example-message/example-message.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-message/example-message.c	Sat Oct 15 21:19:25 2022 +0200
@@ -28,9 +28,9 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/frame.h>
-#include <ui/theme.h>
-#include <ui/ui.h>
+#include <mlk/ui/frame.h>
+#include <mlk/ui/theme.h>
+#include <mlk/ui/ui.h>
 
 #include <rpg/message.h>
 #include <rpg/rpg.h>
--- a/examples/example-notify/example-notify.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-notify/example-notify.c	Sat Oct 15 21:19:25 2022 +0200
@@ -29,9 +29,9 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/notify.h>
-#include <ui/label.h>
-#include <ui/ui.h>
+#include <mlk/ui/notify.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/ui.h>
 
 /* Sword by Icongeek26 (https://www.flaticon.com). */
 #include <assets/images/sword.h>
--- a/examples/example-sprite/example-sprite.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-sprite/example-sprite.c	Sat Oct 15 21:19:25 2022 +0200
@@ -33,9 +33,9 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/align.h>
-#include <ui/label.h>
-#include <ui/ui.h>
+#include <mlk/ui/align.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/ui.h>
 
 #include <assets/sprites/people.h>
 
--- a/examples/example-ui/example-ui.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example-ui/example-ui.c	Sat Oct 15 21:19:25 2022 +0200
@@ -27,13 +27,13 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/align.h>
-#include <ui/button.h>
-#include <ui/checkbox.h>
-#include <ui/frame.h>
-#include <ui/label.h>
-#include <ui/theme.h>
-#include <ui/ui.h>
+#include <mlk/ui/align.h>
+#include <mlk/ui/button.h>
+#include <mlk/ui/checkbox.h>
+#include <mlk/ui/frame.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/theme.h>
+#include <mlk/ui/ui.h>
 
 #define W               (1280)
 #define H               (720)
--- a/examples/example/spell-fire.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example/spell-fire.c	Sat Oct 15 21:19:25 2022 +0200
@@ -23,7 +23,7 @@
 #include <mlk/core/drawable.h>
 #include <mlk/core/alloc.h>
 
-#include <ui/align.h>
+#include <mlk/ui/align.h>
 
 #include <rpg/battle-state-check.h>
 #include <rpg/battle-state-rendering.h>
--- a/examples/example/trace_hud.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/examples/example/trace_hud.c	Sat Oct 15 21:19:25 2022 +0200
@@ -25,8 +25,8 @@
 #include <mlk/core/trace.h>
 #include <mlk/core/window.h>
 
-#include <ui/label.h>
-#include <ui/theme.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/theme.h>
 
 #include "trace_hud.h"
 
--- a/libmlk-core/mlk/core/alloc.h	Sat Oct 15 20:28:59 2022 +0200
+++ b/libmlk-core/mlk/core/alloc.h	Sat Oct 15 21:19:25 2022 +0200
@@ -22,7 +22,6 @@
 #include <stddef.h>
 
 #include "core.h"
-#include "util.h"
 
 /* Must be power of 2. */
 #define ALLOC_POOL_INIT_DEFAULT (32)
Binary file libmlk-ui/assets/fonts/opensans-light.ttf has changed
Binary file libmlk-ui/assets/fonts/opensans-medium.ttf has changed
Binary file libmlk-ui/assets/fonts/opensans-regular.ttf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/align.c	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,75 @@
+/*
+ * align.h -- user interface alignment
+ *
+ * Copyright (c) 2020-2022 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/libmlk-ui/mlk/ui/align.h	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,52 @@
+/*
+ * align.h -- user interface alignment
+ *
+ * Copyright (c) 2020-2022 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 MLK_UI_ALIGN_H
+#define MLK_UI_ALIGN_H
+
+#include <mlk/core/core.h>
+
+enum align {
+	ALIGN_NONE,
+	ALIGN_CENTER,
+	ALIGN_TOP_LEFT,
+	ALIGN_TOP,
+	ALIGN_TOP_RIGHT,
+	ALIGN_RIGHT,
+	ALIGN_BOTTOM_RIGHT,
+	ALIGN_BOTTOM,
+	ALIGN_BOTTOM_LEFT,
+	ALIGN_LEFT
+};
+
+CORE_BEGIN_DECLS
+
+void
+align(enum align,
+      int *,
+      int *,
+      unsigned int,
+      unsigned int,
+      int,
+      int,
+      unsigned int,
+      unsigned int);
+
+CORE_END_DECLS
+
+#endif /* !MLK_UI_ALIGN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/button.c	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,115 @@
+/*
+ * button.c -- GUI button
+ *
+ * Copyright (c) 2020-2022 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 <assert.h>
+#include <string.h>
+
+#include <mlk/core/event.h>
+#include <mlk/core/maths.h>
+#include <mlk/core/painter.h>
+#include <mlk/core/trace.h>
+
+#include "align.h"
+#include "button.h"
+#include "label.h"
+#include "theme.h"
+
+static int
+is_boxed(const struct button *button, const struct event_click *click)
+{
+	assert(button);
+	assert(click);
+	assert(click->type == EVENT_CLICKDOWN || click->type == EVENT_CLICKUP);
+
+	return maths_is_boxed(button->x, button->y, button->w, button->h,
+	    click->x, click->y);
+}
+
+void
+button_draw_default(const struct theme *t, const struct button *button)
+{
+	assert(t);
+	assert(button);
+
+	(void)t;
+
+	struct label label = {
+		.text = button->text,
+	};
+	unsigned int lw, lh;
+
+	label_query(&label, &lw, &lh);
+
+	if (lw > button->w)
+		tracef("button width is too small for text: %u < %u", button->w, lw);
+	if (lh > button->h)
+		tracef("button height is too small for text: %u < %u", button->h, lh);
+
+	align(ALIGN_CENTER, &label.x, &label.y, lw, lh,
+	    button->x, button->y, button->w, button->h);
+
+	painter_set_color(0x577277ff);
+	painter_draw_rectangle(button->x, button->y, button->w, button->h);
+
+	label_draw(&label);
+}
+
+int
+button_handle(struct button *button, const union event *ev)
+{
+	assert(button);
+	assert(ev);
+
+	switch (ev->type) {
+	case EVENT_CLICKDOWN:
+		if (is_boxed(button, &ev->click))
+			button->state = BUTTON_STATE_PRESSED;
+		break;
+	case EVENT_CLICKUP:
+		/*
+		 * If the button was pressed, indicate that the button is
+		 * finally activated. This let the user to move the cursor
+		 * outside the button to "forget" the press.
+		 */
+		if (!is_boxed(button, &ev->click))
+			button->state = BUTTON_STATE_NONE;
+		else if (button->state == BUTTON_STATE_PRESSED)
+			button->state = BUTTON_STATE_ACTIVATED;
+		break;
+	default:
+		break;
+	}
+
+	return button->state == BUTTON_STATE_ACTIVATED;
+}
+
+void
+button_reset(struct button *button)
+{
+	assert(button);
+
+	button->state = BUTTON_STATE_NONE;
+}
+
+void
+button_draw(const struct button *button)
+{
+	assert(button);
+
+	theme_draw_button(button->theme, button);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/button.h	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,60 @@
+/*
+ * button.h -- GUI button
+ *
+ * Copyright (c) 2020-2022 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 MLK_UI_BUTTON_H
+#define MLK_UI_BUTTON_H
+
+#include <mlk/core/core.h>
+
+union event;
+
+struct theme;
+
+enum button_state {
+	BUTTON_STATE_NONE,
+	BUTTON_STATE_PRESSED,
+	BUTTON_STATE_ACTIVATED
+};
+
+struct button {
+	int x;
+	int y;
+	unsigned int w;
+	unsigned int h;
+	const char *text;
+	enum button_state state;
+	const struct theme *theme;
+};
+
+CORE_BEGIN_DECLS
+
+int
+button_handle(struct button *, const union event *);
+
+void
+button_reset(struct button *);
+
+void
+button_draw_default(const struct theme *, const struct button *);
+
+void
+button_draw(const struct button *);
+
+CORE_END_DECLS
+
+#endif /* !MLK_UI_BUTTON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/checkbox.c	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,79 @@
+/*
+ * checkbox.c -- GUI checkbox
+ *
+ * Copyright (c) 2020-2022 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 <assert.h>
+#include <string.h>
+
+#include <mlk/core/event.h>
+#include <mlk/core/maths.h>
+#include <mlk/core/painter.h>
+
+#include "label.h"
+#include "checkbox.h"
+#include "theme.h"
+
+static int
+is_boxed(const struct checkbox *cb, const struct event_click *click)
+{
+	assert(cb);
+	assert(click && click->type == EVENT_CLICKDOWN);
+
+	return maths_is_boxed(cb->x, cb->y, cb->w, cb->h, click->x, click->y);
+}
+
+void
+checkbox_draw_default(const struct theme *t, const struct checkbox *cb)
+{
+	(void)t;
+
+	assert(cb);
+
+	painter_set_color(0x151d28ff);
+	painter_draw_rectangle(cb->x, cb->y, cb->w, cb->h);
+	painter_set_color(0xd7b594ff);
+	painter_draw_rectangle(cb->x + 1, cb->y + 1, cb->w - 2, cb->h - 2);
+
+	if (cb->checked) {
+		painter_set_color(0x341c27ff);
+		painter_draw_rectangle(cb->x + 5, cb->y + 5, cb->w - 10, cb->h - 10);
+	}
+}
+
+int
+checkbox_handle(struct checkbox *cb, const union event *ev)
+{
+	assert(cb);
+	assert(ev);
+
+	switch (ev->type) {
+	case EVENT_CLICKDOWN:
+		if (is_boxed(cb, &ev->click))
+			return cb->checked = !cb->checked;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+void
+checkbox_draw(const struct checkbox *cb)
+{
+	theme_draw_checkbox(cb->theme, cb);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/checkbox.h	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,50 @@
+/*
+ * checkbox.h -- GUI checkbox
+ *
+ * Copyright (c) 2020-2022 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 MLK_UI_CHECKBOX_H
+#define MLK_UI_CHECKBOX_H
+
+#include <mlk/core/core.h>
+
+union event;
+
+struct theme;
+
+struct checkbox {
+	int x;
+	int y;
+	unsigned int w;
+	unsigned int h;
+	int checked;
+	const struct theme *theme;
+};
+
+CORE_BEGIN_DECLS
+
+void
+checkbox_draw_default(const struct theme *, const struct checkbox *);
+
+int
+checkbox_handle(struct checkbox *, const union event *);
+
+void
+checkbox_draw(const struct checkbox *);
+
+CORE_END_DECLS
+
+#endif /* !MLK_UI_CHECKBOX_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/debug.c	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,78 @@
+/*
+ * debug.c -- debugging interfaces
+ *
+ * Copyright (c) 2020-2022 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 <assert.h>
+#include <stdio.h>
+
+#include <mlk/core/texture.h>
+
+#include "debug.h"
+#include "theme.h"
+
+struct debug_options debug_options = {
+#if !defined(NDEBUG)
+	.enable = 1
+#endif
+};
+
+void
+debugf(struct debug_report *report, const char *fmt, ...)
+{
+	assert(report);
+	assert(fmt);
+
+	if (!debug_options.enable)
+		return;
+
+	va_list ap;
+
+	va_start(ap, fmt);
+	debugva(report, fmt, ap);
+	va_end(ap);
+}
+
+void
+debugva(struct debug_report *report, const char *fmt, va_list ap)
+{
+	assert(report);
+	assert(fmt);
+
+	if (!debug_options.enable)
+		return;
+
+	char line[DEBUG_LINE_MAX];
+	const struct theme *theme;
+	struct font *font;
+	struct texture tex;
+	int x, y;
+
+	vsnprintf(line, sizeof (line), fmt, ap);
+
+	theme = report->theme ? report->theme : theme_default();
+	font = theme->fonts[THEME_FONT_DEBUG];
+
+	if (font_render(font, &tex, line, theme->colors[THEME_COLOR_DEBUG]) < 0)
+		return;
+
+	x = theme->padding;
+	y = (theme->padding * (report->count + 1)) + (tex.h * (report->count));
+	report->count++;
+
+	texture_draw(&tex, x, y);
+	texture_finish(&tex);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/debug.h	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,53 @@
+/*
+ * debug.h -- debugging interfaces
+ *
+ * Copyright (c) 2020-2022 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 MLK_UI_DEBUG_H
+#define MLK_UI_DEBUG_H
+
+#include <stdarg.h>
+
+#include <mlk/core/core.h>
+#include <mlk/core/font.h>
+
+#define DEBUG_LINE_MAX 1024
+
+struct theme;
+
+struct debug_options {
+	int enable;
+};
+
+struct debug_report {
+	const struct theme *theme;
+	unsigned int count;
+};
+
+CORE_BEGIN_DECLS
+
+extern struct debug_options debug_options;
+
+void
+debugf(struct debug_report *, const char *, ...);
+
+
+void
+debugva(struct debug_report *, const char *, va_list);
+
+CORE_END_DECLS
+
+#endif /* !MLK_UI_DEBUG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/frame.c	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,49 @@
+/*
+ * frame.h -- GUI frame
+ *
+ * Copyright (c) 2020-2022 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 <assert.h>
+#include <string.h>
+
+#include <mlk/core/painter.h>
+
+#include "frame.h"
+#include "theme.h"
+
+void
+frame_draw_default(const struct theme *t, const struct frame *frame)
+{
+	assert(t);
+	assert(frame);
+
+	(void)t;
+
+	if (frame->style == FRAME_STYLE_BOX)
+		painter_set_color(0x7a4841ff);
+	else
+		painter_set_color(0xad7757ff);
+
+	painter_draw_rectangle(frame->x, frame->y, frame->w, frame->h);
+}
+
+void
+frame_draw(const struct frame *frame)
+{
+	assert(frame);
+
+	theme_draw_frame(frame->theme, frame);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/frame.h	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,50 @@
+/*
+ * frame.h -- GUI frame
+ *
+ * Copyright (c) 2020-2022 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 MLK_UI_FRAME_H
+#define MLK_UI_FRAME_H
+
+#include <mlk/core/core.h>
+
+struct theme;
+
+enum frame_style {
+	FRAME_STYLE_NORMAL,
+	FRAME_STYLE_BOX
+};
+
+struct frame {
+	int x;
+	int y;
+	unsigned int w;
+	unsigned int h;
+	enum frame_style style;
+	const struct theme *theme;
+};
+
+CORE_BEGIN_DECLS
+
+void
+frame_draw_default(const struct theme *, const struct frame *);
+
+void
+frame_draw(const struct frame *);
+
+CORE_END_DECLS
+
+#endif /* !MLK_UI_FRAME_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/gridmenu.c	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,287 @@
+/*
+ * gridmenu.c -- GUI grid menu
+ *
+ * Copyright (c) 2020-2022 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 <assert.h>
+#include <math.h>
+#include <string.h>
+
+#include <mlk/core/event.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 "frame.h"
+#include "label.h"
+#include "gridmenu.h"
+#include "theme.h"
+
+#define THEME(m) ((m)->theme ? (m)->theme : theme_default())
+
+struct index {
+	unsigned int row;
+	unsigned int col;
+};
+
+static struct index
+get_index(const struct gridmenu *menu)
+{
+	return (struct index) {
+		.row = menu->selected / menu->ncols,
+		.col = menu->selected % menu->ncols
+	};
+}
+
+static void
+geometry(struct gridmenu *menu)
+{
+	const struct theme *theme = THEME(menu);
+	struct label label = {
+		.theme = theme,
+		.flags = LABEL_FLAGS_SHADOW
+	};
+	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 (!(label.text = menu->items[i]))
+			continue;
+
+
+		label_query(&label, &lw, &lh);
+
+		menu->eltw = fmax(menu->eltw, lw);
+		menu->elth = fmax(menu->elth, lh);
+	}
+
+	/* Total texture size required to draw items. */
+	reqw = (theme->padding * 2) + (menu->eltw * menu->ncols);
+	reqh = (theme->padding * 2) + (menu->elth * menu->nrows);
+
+	/*
+	 * Compute spacing between elements. We remove the padding because it
+	 * is outside of the elements.
+	 */
+	if (reqw > menu->w) {
+		tracef("gridmenu width is too small: %u < %u", menu->w, reqw);
+		menu->spacew = 1;
+	} else if (menu->ncols > 1) {
+		reqw -= theme->padding * 2;
+		menu->spacew = (menu->w - reqw) / menu->ncols;
+	}
+
+	if (reqh > menu->h) {
+		tracef("gridmenu height is too small: %u < %u", menu->h, reqh);
+		menu->spaceh = 1;
+	} else if (menu->nrows > 1) {
+		reqh -= theme->padding * 2;
+		menu->spaceh = (menu->h - reqh) / menu->nrows;
+	}
+}
+
+static void
+draw_frame(const struct gridmenu *menu)
+{
+	const struct frame f = {
+		.x = menu->x,
+		.y = menu->y,
+		.w = menu->w,
+		.h = menu->h,
+		.theme = menu->theme,
+	};
+
+	frame_draw(&f);
+}
+
+static void
+draw_labels(const struct gridmenu *menu)
+{
+	size_t pagesz, pagenr, item, c = 0, r = 0;
+	struct label label = {0};
+	const struct theme *theme = THEME(menu);
+
+	label.theme = theme;
+	label.flags = LABEL_FLAGS_SHADOW;
+
+	/*
+	 * Select the first top-left column based on the current selection and
+	 * the number of rows/columns.
+	 */
+	pagesz = menu->nrows * menu->ncols;
+	pagenr = menu->selected / pagesz;
+
+	for (size_t i = 0; i < pagesz; ++i) {
+		item = i + pagenr * pagesz;
+
+		if (item >= menu->itemsz || !menu->items[item])
+			continue;
+
+		label.text = menu->items[item];
+		label.x = menu->x + theme->padding + (c * menu->eltw) + (c * menu->spacew);
+		label.y = menu->y + theme->padding + (r * menu->elth) + (r * menu->spaceh);
+
+		if (i == menu->selected % pagesz)
+			label.flags |= LABEL_FLAGS_SELECTED;
+		else
+			label.flags &= ~(LABEL_FLAGS_SELECTED);
+
+		label_draw(&label);
+
+		if (++c >= menu->ncols) {
+			++r;
+			c = 0;
+		}
+	}
+}
+
+static int
+handle_keydown(struct gridmenu *menu, const struct event_key *key)
+{
+	assert(key->type == EVENT_KEYDOWN);
+
+	const struct index idx = get_index(menu);
+	int validate = 0;
+
+	switch (key->key) {
+	case KEY_UP:
+		if (idx.row > 0)
+			menu->selected -= menu->ncols;
+		break;
+	case KEY_RIGHT:
+		if (menu->selected + 1U < menu->itemsz)
+			menu->selected += 1;
+		break;
+	case KEY_DOWN:
+		if (idx.row + 1U < menu->itemsz / menu->ncols)
+			menu->selected += menu->ncols;
+		else
+			menu->selected = menu->itemsz - 1;
+		break;
+	case KEY_LEFT:
+		if (idx.col > 0)
+			menu->selected -= 1;
+		break;
+	case KEY_ENTER:
+		validate = 1;
+		break;
+	default:
+		break;
+	}
+
+	return validate;
+}
+
+static int
+handle_clickdown(struct gridmenu *menu, const struct event_click *click)
+{
+	assert(click->type == EVENT_CLICKDOWN);
+
+	const struct theme *theme = THEME(menu);
+	size_t pagesz, pagenr, selected, c = 0, r = 0;
+	int x, y;
+
+	pagesz = menu->nrows * menu->ncols;
+	pagenr = menu->selected / pagesz;
+
+	for (size_t i = 0; i < pagesz; ++i) {
+		x = menu->x + theme->padding + (c * menu->eltw) + (c * menu->spacew);
+		y = menu->y + theme->padding + (r * menu->elth) + (r * menu->spaceh);
+
+		if (maths_is_boxed(x, y, menu->eltw, menu->elth, click->x, click->y)) {
+			selected  = c + r * menu->ncols;
+			selected += pagesz * pagenr;
+
+			if (selected < menu->itemsz) {
+				menu->selected = selected;
+				return 1;
+			}
+		}
+
+		if (++c >= menu->ncols) {
+			++r;
+			c = 0;
+		}
+	}
+
+	return 0;
+}
+
+void
+gridmenu_init(struct gridmenu *menu,
+              unsigned int nr,
+              unsigned int nc,
+              const char * const *items,
+              size_t itemsz)
+{
+	assert(menu);
+	assert(nr);
+	assert(nc);
+
+	memset(menu, 0, sizeof (*menu));
+
+	menu->nrows = nr;
+	menu->ncols = nc;
+	menu->items = items;
+	menu->itemsz = itemsz;
+}
+
+void
+gridmenu_resize(struct gridmenu *menu, int x, int y, unsigned int w, unsigned int h)
+{
+	assert(menu);
+
+	menu->x = x;
+	menu->y = y;
+	menu->w = w;
+	menu->h = h;
+
+	geometry(menu);
+}
+
+int
+gridmenu_handle(struct gridmenu *menu, const union event *ev)
+{
+	assert(menu);
+	assert(ev);
+
+	switch (ev->type) {
+	case EVENT_KEYDOWN:
+		return handle_keydown(menu, &ev->key);
+		break;
+	case EVENT_CLICKDOWN:
+		return handle_clickdown(menu, &ev->click);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+void
+gridmenu_draw(const struct gridmenu *menu)
+{
+	assert(menu);
+
+	draw_frame(menu);
+	draw_labels(menu);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/gridmenu.h	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,67 @@
+/*
+ * gridmenu.h -- GUI grid menu
+ *
+ * Copyright (c) 2020-2022 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 MLK_UI_GRIDMENU_H
+#define MLK_UI_GRIDMENU_H
+
+#include <stddef.h>
+
+#include <mlk/core/core.h>
+
+#include "label.h"
+
+struct theme;
+
+union event;
+
+struct gridmenu {
+	int x;
+	int y;
+	unsigned int w;
+	unsigned int h;
+	size_t selected;
+	const struct theme *theme;
+	const char * const *items;
+	size_t itemsz;
+	unsigned int nrows;
+	unsigned int ncols;
+
+	/* Private fields. */
+	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 */
+};
+
+CORE_BEGIN_DECLS
+
+void
+gridmenu_init(struct gridmenu *, unsigned int, unsigned int, const char * const *, size_t);
+
+void
+gridmenu_resize(struct gridmenu *, int, int, unsigned int, unsigned int);
+
+int
+gridmenu_handle(struct gridmenu *, const union event *);
+
+void
+gridmenu_draw(const struct gridmenu *);
+
+CORE_END_DECLS
+
+#endif /* !MLK_UI_GRIDMENU_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/label.c	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,91 @@
+/*
+ * label.c -- GUI label
+ *
+ * Copyright (c) 2020-2022 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 <assert.h>
+#include <string.h>
+
+#include <mlk/core/font.h>
+#include <mlk/core/panic.h>
+#include <mlk/core/texture.h>
+
+#include "label.h"
+#include "theme.h"
+
+void
+label_draw_default(const struct theme *t, const struct label *label)
+{
+	assert(t);
+	assert(label);
+
+	struct font *font;
+	struct texture tex;
+	unsigned long color;
+
+	font = label->flags & LABEL_FLAGS_IMPORTANT
+		? t->fonts[THEME_FONT_IMPORTANT]
+		: t->fonts[THEME_FONT_INTERFACE];
+	color = label->flags & LABEL_FLAGS_SELECTED
+		? t->colors[THEME_COLOR_SELECTED]
+	        : t->colors[THEME_COLOR_NORMAL];
+
+	/* Shadow text, only if enabled. */
+	if (label->flags & LABEL_FLAGS_SHADOW) {
+		if (font_render(font, &tex, label->text, t->colors[THEME_COLOR_SHADOW]) < 0)
+			panic();
+
+		texture_draw(&tex, label->x + 1, label->y + 1);
+		texture_finish(&tex);
+	}
+
+	/* Normal text. */
+	if (font_render(font, &tex, label->text, color) < 0)
+		panic();
+
+	texture_draw(&tex, label->x, label->y);
+	texture_finish(&tex);
+}
+
+int
+label_ok(const struct label *label)
+{
+	return label && label->text && strlen(label->text) > 0;
+}
+
+void
+label_query(const struct label *label, unsigned int *w, unsigned int *h)
+{
+	assert(label);
+	assert(label->text);
+
+	const struct theme *t = label->theme ? label->theme : theme_default();
+	const struct font *f = label->flags & LABEL_FLAGS_IMPORTANT
+		? t->fonts[THEME_FONT_IMPORTANT]
+		: t->fonts[THEME_FONT_INTERFACE];
+
+	if (font_query(f, label->text, w, h) < 0)
+		panic();
+}
+
+void
+label_draw(const struct label *label)
+{
+	assert(label);
+	assert(label->text);
+
+	theme_draw_label(label->theme, label);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/label.h	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,57 @@
+/*
+ * label.h -- GUI label
+ *
+ * Copyright (c) 2020-2022 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 MLK_UI_LABEL_H
+#define MLK_UI_LABEL_H
+
+#include <mlk/core/core.h>
+
+struct theme;
+
+enum label_flags {
+	LABEL_FLAGS_NONE,
+	LABEL_FLAGS_SHADOW      = (1 << 0),
+	LABEL_FLAGS_IMPORTANT   = (1 << 1),
+	LABEL_FLAGS_SELECTED    = (1 << 2)
+};
+
+struct label {
+	int x;
+	int y;
+	const char *text;
+	enum label_flags flags;
+	const struct theme *theme;
+};
+
+CORE_BEGIN_DECLS
+
+void
+label_draw_default(const struct theme *, const struct label *);
+
+int
+label_ok(const struct label *);
+
+void
+label_query(const struct label *, unsigned int *, unsigned int *);
+
+void
+label_draw(const struct label *);
+
+CORE_END_DECLS
+
+#endif /* !MLK_UI_LABEL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/notify.c	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,209 @@
+/*
+ * notify.c -- in game notifications
+ *
+ * Copyright (c) 2020-2022 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 <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <mlk/core/font.h>
+#include <mlk/core/texture.h>
+#include <mlk/core/trace.h>
+#include <mlk/core/window.h>
+
+#include "align.h"
+#include "frame.h"
+#include "label.h"
+#include "notify.h"
+#include "theme.h"
+
+#define WIDTH   (window.w / 3)
+#define HEIGHT  (window.h / 10)
+
+struct geo {
+	const struct theme *theme;
+	int frame_x;
+	int frame_y;
+	unsigned int frame_w;
+	unsigned int frame_h;
+	int icon_x;
+	int icon_y;
+	int title_x;
+	int title_y;
+	int body_x;
+	int body_y;
+};
+
+static void draw(const struct notify *, size_t);
+
+static const struct notify_system default_system = {
+	.draw = draw
+};
+static const struct notify_system *system = &default_system;
+static struct notify stack[NOTIFY_MAX];
+static size_t stacksz;
+
+static void
+geometry(struct geo *geo, const struct notify *n, size_t index)
+{
+	int x, y;
+
+	/* Determine theme. */
+	geo->theme = system->theme ? system->theme : theme_default();
+
+	/* Determine notification position. */
+	x  = window.w - geo->theme->padding;
+	x -= WIDTH;
+
+	y  = geo->theme->padding * (index + 1);;
+	y += HEIGHT * index;
+
+	/* Content frame. */
+	geo->frame_x = x;
+	geo->frame_y = y;
+	geo->frame_w = WIDTH;
+	geo->frame_h = HEIGHT;
+
+	/* Align icon at the left center. */
+	if (n->icon->h >= HEIGHT) {
+		tracef("notification icon is too large: %u > %u", n->icon->h, HEIGHT);
+		geo->icon_x = x + geo->theme->padding;
+		geo->icon_y = y + geo->theme->padding;
+	} else {
+		align(ALIGN_LEFT, &geo->icon_x, &geo->icon_y, n->icon->w, n->icon->h, x, y, WIDTH, HEIGHT);
+		geo->icon_x += geo->icon_y - y;
+	}
+
+	/* Align title to the right of the icon at the same y coordinate. */
+	geo->title_x  = geo->icon_x + n->icon->w + geo->theme->padding;
+	geo->title_y  = geo->icon_y;
+	geo->title_y -= font_height(geo->theme->fonts[THEME_FONT_IMPORTANT]) / 2;
+
+	/* Align body so it ends at the end of the icon. */
+	geo->body_x  = geo->title_x;
+	geo->body_y  = geo->icon_y + n->icon->h;
+	geo->body_y -= font_height(geo->theme->fonts[THEME_FONT_INTERFACE]) / 2;
+}
+
+static void
+draw_frame(const struct geo *geo)
+{
+	const struct frame f = {
+		.x = geo->frame_x,
+		.y = geo->frame_y,
+		.w = geo->frame_w,
+		.h = geo->frame_h
+	};
+
+	frame_draw(&f);
+}
+
+static void
+draw_icon(const struct geo *geo, const struct notify *n)
+{
+	texture_draw(n->icon, geo->icon_x, geo->icon_y);
+}
+
+#include <stdio.h>
+
+static void
+draw_title(const struct geo *geo, const struct notify *n)
+{
+	const struct label l = {
+		.x = geo->title_x,
+		.y = geo->title_y,
+		.text = n->title,
+		.flags = LABEL_FLAGS_SHADOW | LABEL_FLAGS_IMPORTANT
+	};
+
+	label_draw(&l);
+}
+
+static void
+draw_body(const struct geo *geo, const struct notify *n)
+{
+	const struct label l = {
+		.x = geo->body_x,
+		.y = geo->body_y,
+		.text = n->body,
+		.flags = LABEL_FLAGS_SHADOW
+	};
+
+	label_draw(&l);
+}
+
+static void
+draw(const struct notify *n, size_t index)
+{
+	struct geo geo;
+
+	/* Compute notification size and widgets. */
+	geometry(&geo, n, index);
+
+	draw_frame(&geo);
+	draw_icon(&geo, n);
+	draw_title(&geo, n);
+	draw_body(&geo, n);
+}
+
+void
+notify(const struct texture *icon, const char *title, const char *body)
+{
+	assert(icon);
+	assert(title);
+	assert(body);
+
+	struct notify *n;
+
+	if (stacksz >= NOTIFY_MAX) {
+		memmove(&stack[0], &stack[1], sizeof (stack[0]) - NOTIFY_MAX - 1);
+		n = &stack[NOTIFY_MAX - 1];
+	} else
+		n = &stack[stacksz++];
+
+	memset(n, 0, sizeof (*n));
+	n->icon = icon;
+	n->title = title;
+	n->body = body;
+}
+
+void
+notify_update(unsigned int ticks)
+{
+	struct notify *n;
+
+	for (size_t i = 0; i < stacksz; ++i) {
+		n = &stack[i];
+		n->elapsed += ticks;
+
+		if (n->elapsed >= NOTIFY_TIMEOUT_DEFAULT)
+			memmove(n, n + 1, sizeof (*n) * (--stacksz - i));
+	}
+}
+
+void
+notify_draw(void)
+{
+	for (size_t i = 0; i < stacksz; ++i)
+		system->draw(&stack[i], i);
+}
+
+void
+notify_set_system(const struct notify_system *sys)
+{
+	system = sys ? sys : &default_system;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/notify.h	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,60 @@
+/*
+ * notify.h -- in game notifications
+ *
+ * Copyright (c) 2020-2022 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 MLK_UI_NOTIFY_H
+#define MLK_UI_NOTIFY_H
+
+#include <stddef.h>
+
+#include <mlk/core/core.h>
+
+#define NOTIFY_MAX              (4)
+#define NOTIFY_TIMEOUT_DEFAULT  (5000)
+
+struct texture;
+struct theme;
+
+struct notify {
+	const struct texture *icon;
+	const char *title;
+	const char *body;
+	unsigned int elapsed;
+};
+
+struct notify_system {
+	struct theme *theme;
+	void (*draw)(const struct notify *, size_t);
+};
+
+CORE_BEGIN_DECLS
+
+void
+notify(const struct texture *, const char *, const char *);
+
+void
+notify_update(unsigned int ticks);
+
+void
+notify_draw(void);
+
+void
+notify_set_system(const struct notify_system *);
+
+CORE_END_DECLS
+
+#endif /*! MLK_UI_NOTIFY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/theme.c	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,155 @@
+/*
+ * theme.c -- abstract theming
+ *
+ * Copyright (c) 2020-2022 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 <assert.h>
+#include <stddef.h>
+#include <string.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/util.h>
+
+#include <assets/fonts/opensans-light.h>
+#include <assets/fonts/opensans-medium.h>
+#include <assets/fonts/opensans-regular.h>
+
+#include "align.h"
+#include "button.h"
+#include "checkbox.h"
+#include "frame.h"
+#include "label.h"
+#include "theme.h"
+
+#define THEME(t) (t ? t : &default_theme)
+
+/* Default font catalog. */
+#define FONT(bin, size, index)                                          \
+	{ bin, sizeof (bin), size, &default_theme.fonts[index], {0} }
+
+/* Default theme. */
+static struct theme default_theme = {
+	.colors = {
+		[THEME_COLOR_DEBUG]     = 0xff0000ff,
+		[THEME_COLOR_NORMAL]    = 0xffffffff,
+		[THEME_COLOR_SELECTED]  = 0x006554ff,
+		[THEME_COLOR_SHADOW]    = 0x000000ff
+	},
+	.padding = 10,
+	.draw_frame = frame_draw_default,
+	.draw_label = label_draw_default,
+	.draw_button = button_draw_default,
+	.draw_checkbox = checkbox_draw_default
+};
+
+static struct font_catalog {
+	const unsigned char *data;
+	const size_t datasz;
+	unsigned int size;
+	struct font **dest;
+	struct font font;
+} default_fonts[] = {
+	FONT(assets_opensans_light, 12, THEME_FONT_DEBUG),
+	FONT(assets_opensans_regular, 14, THEME_FONT_INTERFACE),
+	FONT(assets_opensans_medium, 14, THEME_FONT_IMPORTANT)
+};
+
+int
+theme_init(void)
+{
+	/* Open all fonts. */
+	for (size_t i = 0; i < UTIL_SIZE(default_fonts); ++i) {
+		struct font_catalog *fc = &default_fonts[i];
+
+		if (font_openmem(&fc->font, fc->data, fc->datasz, fc->size) < 0)
+			goto failed;
+
+		/* Reference this font into the catalog. */
+		*default_fonts[i].dest = &default_fonts[i].font;
+	}
+
+	return 0;
+
+failed:
+	theme_finish();
+
+	return -1;
+}
+
+struct theme *
+theme_default(void)
+{
+	return &default_theme;
+}
+
+unsigned int
+theme_padding(const struct theme *t)
+{
+	return THEME(t)->padding;
+}
+
+void
+theme_shallow(struct theme *dst, const struct theme *src)
+{
+	assert(dst);
+
+	memcpy(dst, src ? src : &default_theme, sizeof (*src));
+}
+
+void
+theme_draw_frame(const struct theme *t, const struct frame *frame)
+{
+	assert(frame);
+
+	THEME(t)->draw_frame(THEME(t), frame);
+}
+
+void
+theme_draw_label(const struct theme *t, const struct label *label)
+{
+	assert(label);
+
+	THEME(t)->draw_label(THEME(t), label);
+}
+
+void
+theme_draw_button(const struct theme *t, const struct button *button)
+{
+	assert(button);
+
+	THEME(t)->draw_button(THEME(t), button);
+}
+
+void
+theme_draw_checkbox(const struct theme *t, const struct checkbox *cb)
+{
+	assert(cb);
+
+	THEME(t)->draw_checkbox(THEME(t), cb);
+}
+
+void
+theme_finish(void)
+{
+	for (size_t i = 0; i < UTIL_SIZE(default_fonts); ++i) {
+		font_finish(&default_fonts[i].font);
+		*default_fonts[i].dest = NULL;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/theme.h	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,91 @@
+/*
+ * theme.h -- abstract theming
+ *
+ * Copyright (c) 2020-2022 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 MLK_UI_THEME_H
+#define MLK_UI_THEME_H
+
+#include <mlk/core/core.h>
+
+struct button;
+struct checkbox;
+struct font;
+struct frame;
+struct label;
+struct sprite;
+
+enum theme_font {
+	THEME_FONT_DEBUG,
+	THEME_FONT_INTERFACE,
+	THEME_FONT_IMPORTANT,
+	THEME_FONT_NUM
+};
+
+enum theme_color {
+	THEME_COLOR_DEBUG,
+	THEME_COLOR_NORMAL,
+	THEME_COLOR_SELECTED,
+	THEME_COLOR_SHADOW,
+	THEME_COLOR_NUM
+};
+
+enum theme_sprite {
+	THEME_SPRITE_CURSOR,
+	THEME_SPRITE_NUM
+};
+
+struct theme {
+	struct font *fonts[THEME_FONT_NUM];
+	const struct sprite *sprites[THEME_SPRITE_NUM];
+	unsigned long colors[THEME_COLOR_NUM];
+	unsigned int padding;
+
+	void (*draw_frame)(const struct theme *, const struct frame *);
+	void (*draw_label)(const struct theme *, const struct label *);
+	void (*draw_button)(const struct theme *, const struct button *);
+	void (*draw_checkbox)(const struct theme *t, const struct checkbox *);
+};
+
+CORE_BEGIN_DECLS
+
+int
+theme_init(void);
+
+struct theme *
+theme_default(void);
+
+void
+theme_shallow(struct theme *, const struct theme *);
+
+void
+theme_draw_frame(const struct theme *, const struct frame *);
+
+void
+theme_draw_label(const struct theme *, const struct label *);
+
+void
+theme_draw_button(const struct theme *, const struct button *);
+
+void
+theme_draw_checkbox(const struct theme *, const struct checkbox *);
+
+void
+theme_finish(void);
+
+CORE_END_DECLS
+
+#endif /* !MLK_UI_THEME_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/ui.c	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,32 @@
+/*
+ * ui.c -- libui convenient header
+ *
+ * Copyright (c) 2020-2022 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 "theme.h"
+#include "ui.h"
+
+int
+ui_init(void)
+{
+	return theme_init();
+}
+
+void
+ui_finish(void)
+{
+	theme_finish();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmlk-ui/mlk/ui/ui.h	Sat Oct 15 21:19:25 2022 +0200
@@ -0,0 +1,34 @@
+/*
+ * ui.h -- libui convenient header
+ *
+ * Copyright (c) 2020-2022 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 MLK_UI_UI_H
+#define MLK_UI_UI_H
+
+#include <mlk/core/core.h>
+
+CORE_BEGIN_DECLS
+
+int
+ui_init(void);
+
+void
+ui_finish(void);
+
+CORE_END_DECLS
+
+#endif /* !MLK_UI_UI_H */
--- a/src/libmlk-rpg/rpg/battle-bar-default.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/battle-bar-default.c	Sat Oct 15 21:19:25 2022 +0200
@@ -29,8 +29,8 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/align.h>
-#include <ui/theme.h>
+#include <mlk/ui/align.h>
+#include <mlk/ui/theme.h>
 
 #include "battle-bar-default.h"
 #include "battle-bar.h"
--- a/src/libmlk-rpg/rpg/battle-bar-default.h	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/battle-bar-default.h	Sat Oct 15 21:19:25 2022 +0200
@@ -21,7 +21,7 @@
 
 #include <mlk/core/core.h>
 
-#include <ui/gridmenu.h>
+#include <mlk/ui/gridmenu.h>
 
 struct battle;
 struct battle_bar;
--- a/src/libmlk-rpg/rpg/battle-entity.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/battle-entity.c	Sat Oct 15 21:19:25 2022 +0200
@@ -21,7 +21,7 @@
 #include <mlk/core/sprite.h>
 #include <mlk/core/texture.h>
 
-#include <ui/theme.h>
+#include <mlk/ui/theme.h>
 
 #include "battle.h"
 #include "battle-entity.h"
--- a/src/libmlk-rpg/rpg/battle-entity.h	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/battle-entity.h	Sat Oct 15 21:19:25 2022 +0200
@@ -21,7 +21,7 @@
 
 #include <mlk/core/core.h>
 
-#include <ui/label.h>
+#include <mlk/ui/label.h>
 
 struct battle;
 struct battle_entity_state;
--- a/src/libmlk-rpg/rpg/battle-indicator.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/battle-indicator.c	Sat Oct 15 21:19:25 2022 +0200
@@ -25,7 +25,7 @@
 #include <mlk/core/font.h>
 #include <mlk/core/panic.h>
 
-#include <ui/theme.h>
+#include <mlk/ui/theme.h>
 
 #include "battle-indicator.h"
 
--- a/src/libmlk-rpg/rpg/battle-message.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/battle-message.c	Sat Oct 15 21:19:25 2022 +0200
@@ -20,9 +20,9 @@
 
 #include <mlk/core/window.h>
 
-#include <ui/align.h>
-#include <ui/frame.h>
-#include <ui/label.h>
+#include <mlk/ui/align.h>
+#include <mlk/ui/frame.h>
+#include <mlk/ui/label.h>
 
 #include "battle-message.h"
 
--- a/src/libmlk-rpg/rpg/battle-state-selection.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/battle-state-selection.c	Sat Oct 15 21:19:25 2022 +0200
@@ -26,7 +26,7 @@
 #include <mlk/core/sprite.h>
 #include <mlk/core/util.h>
 
-#include <ui/theme.h>
+#include <mlk/ui/theme.h>
 
 #include "battle-bar.h"
 #include "battle-state-item.h"
--- a/src/libmlk-rpg/rpg/battle.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/battle.c	Sat Oct 15 21:19:25 2022 +0200
@@ -31,10 +31,10 @@
 #include <mlk/core/util.h>
 #include <mlk/core/window.h>
 
-#include <ui/align.h>
-#include <ui/frame.h>
-#include <ui/label.h>
-#include <ui/theme.h>
+#include <mlk/ui/align.h>
+#include <mlk/ui/frame.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/theme.h>
 
 #include "battle-bar.h"
 #include "battle-indicator.h"
--- a/src/libmlk-rpg/rpg/battle.h	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/battle.h	Sat Oct 15 21:19:25 2022 +0200
@@ -25,8 +25,8 @@
 #include <mlk/core/drawable.h>
 #include <mlk/core/drawable-stack.h>
 
-#include <ui/frame.h>
-#include <ui/gridmenu.h>
+#include <mlk/ui/frame.h>
+#include <mlk/ui/gridmenu.h>
 
 #include "battle-entity.h"
 #include "battle-state.h"
--- a/src/libmlk-rpg/rpg/map-file.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/map-file.c	Sat Oct 15 21:19:25 2022 +0200
@@ -30,6 +30,7 @@
 #include <mlk/core/error.h>
 #include <mlk/core/image.h>
 #include <mlk/core/trace.h>
+#include <mlk/core/util.h>
 
 #include "map-file.h"
 
--- a/src/libmlk-rpg/rpg/map.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/map.c	Sat Oct 15 21:19:25 2022 +0200
@@ -31,7 +31,7 @@
 #include <mlk/core/texture.h>
 #include <mlk/core/window.h>
 
-#include <ui/debug.h>
+#include <mlk/ui/debug.h>
 
 #include "map.h"
 #include "tileset.h"
--- a/src/libmlk-rpg/rpg/message.c	Sat Oct 15 20:28:59 2022 +0200
+++ b/src/libmlk-rpg/rpg/message.c	Sat Oct 15 21:19:25 2022 +0200
@@ -30,10 +30,10 @@
 #include <mlk/core/trace.h>
 #include <mlk/core/util.h>
 
-#include <ui/align.h>
-#include <ui/frame.h>
-#include <ui/label.h>
-#include <ui/theme.h>
+#include <mlk/ui/align.h>
+#include <mlk/ui/frame.h>
+#include <mlk/ui/label.h>
+#include <mlk/ui/theme.h>
 
 #include "message.h"
 
Binary file src/libmlk-ui/assets/fonts/opensans-light.ttf has changed
Binary file src/libmlk-ui/assets/fonts/opensans-medium.ttf has changed
Binary file src/libmlk-ui/assets/fonts/opensans-regular.ttf has changed
--- a/src/libmlk-ui/ui/align.c	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
- * align.h -- user interface alignment
- *
- * Copyright (c) 2020-2022 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;
-	}
-}
--- a/src/libmlk-ui/ui/align.h	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * align.h -- user interface alignment
- *
- * Copyright (c) 2020-2022 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 MLK_UI_ALIGN_H
-#define MLK_UI_ALIGN_H
-
-#include <mlk/core/core.h>
-
-enum align {
-	ALIGN_NONE,
-	ALIGN_CENTER,
-	ALIGN_TOP_LEFT,
-	ALIGN_TOP,
-	ALIGN_TOP_RIGHT,
-	ALIGN_RIGHT,
-	ALIGN_BOTTOM_RIGHT,
-	ALIGN_BOTTOM,
-	ALIGN_BOTTOM_LEFT,
-	ALIGN_LEFT
-};
-
-CORE_BEGIN_DECLS
-
-void
-align(enum align,
-      int *,
-      int *,
-      unsigned int,
-      unsigned int,
-      int,
-      int,
-      unsigned int,
-      unsigned int);
-
-CORE_END_DECLS
-
-#endif /* !MLK_UI_ALIGN_H */
--- a/src/libmlk-ui/ui/button.c	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-/*
- * button.c -- GUI button
- *
- * Copyright (c) 2020-2022 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 <assert.h>
-#include <string.h>
-
-#include <mlk/core/event.h>
-#include <mlk/core/maths.h>
-#include <mlk/core/painter.h>
-#include <mlk/core/trace.h>
-
-#include "align.h"
-#include "button.h"
-#include "label.h"
-#include "theme.h"
-
-static int
-is_boxed(const struct button *button, const struct event_click *click)
-{
-	assert(button);
-	assert(click);
-	assert(click->type == EVENT_CLICKDOWN || click->type == EVENT_CLICKUP);
-
-	return maths_is_boxed(button->x, button->y, button->w, button->h,
-	    click->x, click->y);
-}
-
-void
-button_draw_default(const struct theme *t, const struct button *button)
-{
-	assert(t);
-	assert(button);
-
-	(void)t;
-
-	struct label label = {
-		.text = button->text,
-	};
-	unsigned int lw, lh;
-
-	label_query(&label, &lw, &lh);
-
-	if (lw > button->w)
-		tracef("button width is too small for text: %u < %u", button->w, lw);
-	if (lh > button->h)
-		tracef("button height is too small for text: %u < %u", button->h, lh);
-
-	align(ALIGN_CENTER, &label.x, &label.y, lw, lh,
-	    button->x, button->y, button->w, button->h);
-
-	painter_set_color(0x577277ff);
-	painter_draw_rectangle(button->x, button->y, button->w, button->h);
-
-	label_draw(&label);
-}
-
-int
-button_handle(struct button *button, const union event *ev)
-{
-	assert(button);
-	assert(ev);
-
-	switch (ev->type) {
-	case EVENT_CLICKDOWN:
-		if (is_boxed(button, &ev->click))
-			button->state = BUTTON_STATE_PRESSED;
-		break;
-	case EVENT_CLICKUP:
-		/*
-		 * If the button was pressed, indicate that the button is
-		 * finally activated. This let the user to move the cursor
-		 * outside the button to "forget" the press.
-		 */
-		if (!is_boxed(button, &ev->click))
-			button->state = BUTTON_STATE_NONE;
-		else if (button->state == BUTTON_STATE_PRESSED)
-			button->state = BUTTON_STATE_ACTIVATED;
-		break;
-	default:
-		break;
-	}
-
-	return button->state == BUTTON_STATE_ACTIVATED;
-}
-
-void
-button_reset(struct button *button)
-{
-	assert(button);
-
-	button->state = BUTTON_STATE_NONE;
-}
-
-void
-button_draw(const struct button *button)
-{
-	assert(button);
-
-	theme_draw_button(button->theme, button);
-}
--- a/src/libmlk-ui/ui/button.h	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * button.h -- GUI button
- *
- * Copyright (c) 2020-2022 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 MLK_UI_BUTTON_H
-#define MLK_UI_BUTTON_H
-
-#include <mlk/core/core.h>
-
-union event;
-
-struct theme;
-
-enum button_state {
-	BUTTON_STATE_NONE,
-	BUTTON_STATE_PRESSED,
-	BUTTON_STATE_ACTIVATED
-};
-
-struct button {
-	int x;
-	int y;
-	unsigned int w;
-	unsigned int h;
-	const char *text;
-	enum button_state state;
-	const struct theme *theme;
-};
-
-CORE_BEGIN_DECLS
-
-int
-button_handle(struct button *, const union event *);
-
-void
-button_reset(struct button *);
-
-void
-button_draw_default(const struct theme *, const struct button *);
-
-void
-button_draw(const struct button *);
-
-CORE_END_DECLS
-
-#endif /* !MLK_UI_BUTTON_H */
--- a/src/libmlk-ui/ui/checkbox.c	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * checkbox.c -- GUI checkbox
- *
- * Copyright (c) 2020-2022 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 <assert.h>
-#include <string.h>
-
-#include <mlk/core/event.h>
-#include <mlk/core/maths.h>
-#include <mlk/core/painter.h>
-
-#include "label.h"
-#include "checkbox.h"
-#include "theme.h"
-
-static int
-is_boxed(const struct checkbox *cb, const struct event_click *click)
-{
-	assert(cb);
-	assert(click && click->type == EVENT_CLICKDOWN);
-
-	return maths_is_boxed(cb->x, cb->y, cb->w, cb->h, click->x, click->y);
-}
-
-void
-checkbox_draw_default(const struct theme *t, const struct checkbox *cb)
-{
-	(void)t;
-
-	assert(cb);
-
-	painter_set_color(0x151d28ff);
-	painter_draw_rectangle(cb->x, cb->y, cb->w, cb->h);
-	painter_set_color(0xd7b594ff);
-	painter_draw_rectangle(cb->x + 1, cb->y + 1, cb->w - 2, cb->h - 2);
-
-	if (cb->checked) {
-		painter_set_color(0x341c27ff);
-		painter_draw_rectangle(cb->x + 5, cb->y + 5, cb->w - 10, cb->h - 10);
-	}
-}
-
-int
-checkbox_handle(struct checkbox *cb, const union event *ev)
-{
-	assert(cb);
-	assert(ev);
-
-	switch (ev->type) {
-	case EVENT_CLICKDOWN:
-		if (is_boxed(cb, &ev->click))
-			return cb->checked = !cb->checked;
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-void
-checkbox_draw(const struct checkbox *cb)
-{
-	theme_draw_checkbox(cb->theme, cb);
-}
--- a/src/libmlk-ui/ui/checkbox.h	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * checkbox.h -- GUI checkbox
- *
- * Copyright (c) 2020-2022 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 MLK_UI_CHECKBOX_H
-#define MLK_UI_CHECKBOX_H
-
-#include <mlk/core/core.h>
-
-union event;
-
-struct theme;
-
-struct checkbox {
-	int x;
-	int y;
-	unsigned int w;
-	unsigned int h;
-	int checked;
-	const struct theme *theme;
-};
-
-CORE_BEGIN_DECLS
-
-void
-checkbox_draw_default(const struct theme *, const struct checkbox *);
-
-int
-checkbox_handle(struct checkbox *, const union event *);
-
-void
-checkbox_draw(const struct checkbox *);
-
-CORE_END_DECLS
-
-#endif /* !MLK_UI_CHECKBOX_H */
--- a/src/libmlk-ui/ui/debug.c	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * debug.c -- debugging interfaces
- *
- * Copyright (c) 2020-2022 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 <assert.h>
-#include <stdio.h>
-
-#include <mlk/core/texture.h>
-
-#include "debug.h"
-#include "theme.h"
-
-struct debug_options debug_options = {
-#if !defined(NDEBUG)
-	.enable = 1
-#endif
-};
-
-void
-debugf(struct debug_report *report, const char *fmt, ...)
-{
-	assert(report);
-	assert(fmt);
-
-	if (!debug_options.enable)
-		return;
-
-	va_list ap;
-
-	va_start(ap, fmt);
-	debugva(report, fmt, ap);
-	va_end(ap);
-}
-
-void
-debugva(struct debug_report *report, const char *fmt, va_list ap)
-{
-	assert(report);
-	assert(fmt);
-
-	if (!debug_options.enable)
-		return;
-
-	char line[DEBUG_LINE_MAX];
-	const struct theme *theme;
-	struct font *font;
-	struct texture tex;
-	int x, y;
-
-	vsnprintf(line, sizeof (line), fmt, ap);
-
-	theme = report->theme ? report->theme : theme_default();
-	font = theme->fonts[THEME_FONT_DEBUG];
-
-	if (font_render(font, &tex, line, theme->colors[THEME_COLOR_DEBUG]) < 0)
-		return;
-
-	x = theme->padding;
-	y = (theme->padding * (report->count + 1)) + (tex.h * (report->count));
-	report->count++;
-
-	texture_draw(&tex, x, y);
-	texture_finish(&tex);
-}
--- a/src/libmlk-ui/ui/debug.h	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * debug.h -- debugging interfaces
- *
- * Copyright (c) 2020-2022 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 MLK_UI_DEBUG_H
-#define MLK_UI_DEBUG_H
-
-#include <stdarg.h>
-
-#include <mlk/core/core.h>
-#include <mlk/core/font.h>
-
-#define DEBUG_LINE_MAX 1024
-
-struct theme;
-
-struct debug_options {
-	int enable;
-};
-
-struct debug_report {
-	const struct theme *theme;
-	unsigned int count;
-};
-
-CORE_BEGIN_DECLS
-
-extern struct debug_options debug_options;
-
-void
-debugf(struct debug_report *, const char *, ...);
-
-
-void
-debugva(struct debug_report *, const char *, va_list);
-
-CORE_END_DECLS
-
-#endif /* !MLK_UI_DEBUG_H */
--- a/src/libmlk-ui/ui/frame.c	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * frame.h -- GUI frame
- *
- * Copyright (c) 2020-2022 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 <assert.h>
-#include <string.h>
-
-#include <mlk/core/painter.h>
-
-#include "frame.h"
-#include "theme.h"
-
-void
-frame_draw_default(const struct theme *t, const struct frame *frame)
-{
-	assert(t);
-	assert(frame);
-
-	(void)t;
-
-	if (frame->style == FRAME_STYLE_BOX)
-		painter_set_color(0x7a4841ff);
-	else
-		painter_set_color(0xad7757ff);
-
-	painter_draw_rectangle(frame->x, frame->y, frame->w, frame->h);
-}
-
-void
-frame_draw(const struct frame *frame)
-{
-	assert(frame);
-
-	theme_draw_frame(frame->theme, frame);
-}
--- a/src/libmlk-ui/ui/frame.h	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * frame.h -- GUI frame
- *
- * Copyright (c) 2020-2022 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 MLK_UI_FRAME_H
-#define MLK_UI_FRAME_H
-
-#include <mlk/core/core.h>
-
-struct theme;
-
-enum frame_style {
-	FRAME_STYLE_NORMAL,
-	FRAME_STYLE_BOX
-};
-
-struct frame {
-	int x;
-	int y;
-	unsigned int w;
-	unsigned int h;
-	enum frame_style style;
-	const struct theme *theme;
-};
-
-CORE_BEGIN_DECLS
-
-void
-frame_draw_default(const struct theme *, const struct frame *);
-
-void
-frame_draw(const struct frame *);
-
-CORE_END_DECLS
-
-#endif /* !MLK_UI_FRAME_H */
--- a/src/libmlk-ui/ui/gridmenu.c	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,287 +0,0 @@
-/*
- * gridmenu.c -- GUI grid menu
- *
- * Copyright (c) 2020-2022 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 <assert.h>
-#include <math.h>
-#include <string.h>
-
-#include <mlk/core/event.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 "frame.h"
-#include "label.h"
-#include "gridmenu.h"
-#include "theme.h"
-
-#define THEME(m) ((m)->theme ? (m)->theme : theme_default())
-
-struct index {
-	unsigned int row;
-	unsigned int col;
-};
-
-static struct index
-get_index(const struct gridmenu *menu)
-{
-	return (struct index) {
-		.row = menu->selected / menu->ncols,
-		.col = menu->selected % menu->ncols
-	};
-}
-
-static void
-geometry(struct gridmenu *menu)
-{
-	const struct theme *theme = THEME(menu);
-	struct label label = {
-		.theme = theme,
-		.flags = LABEL_FLAGS_SHADOW
-	};
-	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 (!(label.text = menu->items[i]))
-			continue;
-
-
-		label_query(&label, &lw, &lh);
-
-		menu->eltw = fmax(menu->eltw, lw);
-		menu->elth = fmax(menu->elth, lh);
-	}
-
-	/* Total texture size required to draw items. */
-	reqw = (theme->padding * 2) + (menu->eltw * menu->ncols);
-	reqh = (theme->padding * 2) + (menu->elth * menu->nrows);
-
-	/*
-	 * Compute spacing between elements. We remove the padding because it
-	 * is outside of the elements.
-	 */
-	if (reqw > menu->w) {
-		tracef("gridmenu width is too small: %u < %u", menu->w, reqw);
-		menu->spacew = 1;
-	} else if (menu->ncols > 1) {
-		reqw -= theme->padding * 2;
-		menu->spacew = (menu->w - reqw) / menu->ncols;
-	}
-
-	if (reqh > menu->h) {
-		tracef("gridmenu height is too small: %u < %u", menu->h, reqh);
-		menu->spaceh = 1;
-	} else if (menu->nrows > 1) {
-		reqh -= theme->padding * 2;
-		menu->spaceh = (menu->h - reqh) / menu->nrows;
-	}
-}
-
-static void
-draw_frame(const struct gridmenu *menu)
-{
-	const struct frame f = {
-		.x = menu->x,
-		.y = menu->y,
-		.w = menu->w,
-		.h = menu->h,
-		.theme = menu->theme,
-	};
-
-	frame_draw(&f);
-}
-
-static void
-draw_labels(const struct gridmenu *menu)
-{
-	size_t pagesz, pagenr, item, c = 0, r = 0;
-	struct label label = {0};
-	const struct theme *theme = THEME(menu);
-
-	label.theme = theme;
-	label.flags = LABEL_FLAGS_SHADOW;
-
-	/*
-	 * Select the first top-left column based on the current selection and
-	 * the number of rows/columns.
-	 */
-	pagesz = menu->nrows * menu->ncols;
-	pagenr = menu->selected / pagesz;
-
-	for (size_t i = 0; i < pagesz; ++i) {
-		item = i + pagenr * pagesz;
-
-		if (item >= menu->itemsz || !menu->items[item])
-			continue;
-
-		label.text = menu->items[item];
-		label.x = menu->x + theme->padding + (c * menu->eltw) + (c * menu->spacew);
-		label.y = menu->y + theme->padding + (r * menu->elth) + (r * menu->spaceh);
-
-		if (i == menu->selected % pagesz)
-			label.flags |= LABEL_FLAGS_SELECTED;
-		else
-			label.flags &= ~(LABEL_FLAGS_SELECTED);
-
-		label_draw(&label);
-
-		if (++c >= menu->ncols) {
-			++r;
-			c = 0;
-		}
-	}
-}
-
-static int
-handle_keydown(struct gridmenu *menu, const struct event_key *key)
-{
-	assert(key->type == EVENT_KEYDOWN);
-
-	const struct index idx = get_index(menu);
-	int validate = 0;
-
-	switch (key->key) {
-	case KEY_UP:
-		if (idx.row > 0)
-			menu->selected -= menu->ncols;
-		break;
-	case KEY_RIGHT:
-		if (menu->selected + 1U < menu->itemsz)
-			menu->selected += 1;
-		break;
-	case KEY_DOWN:
-		if (idx.row + 1U < menu->itemsz / menu->ncols)
-			menu->selected += menu->ncols;
-		else
-			menu->selected = menu->itemsz - 1;
-		break;
-	case KEY_LEFT:
-		if (idx.col > 0)
-			menu->selected -= 1;
-		break;
-	case KEY_ENTER:
-		validate = 1;
-		break;
-	default:
-		break;
-	}
-
-	return validate;
-}
-
-static int
-handle_clickdown(struct gridmenu *menu, const struct event_click *click)
-{
-	assert(click->type == EVENT_CLICKDOWN);
-
-	const struct theme *theme = THEME(menu);
-	size_t pagesz, pagenr, selected, c = 0, r = 0;
-	int x, y;
-
-	pagesz = menu->nrows * menu->ncols;
-	pagenr = menu->selected / pagesz;
-
-	for (size_t i = 0; i < pagesz; ++i) {
-		x = menu->x + theme->padding + (c * menu->eltw) + (c * menu->spacew);
-		y = menu->y + theme->padding + (r * menu->elth) + (r * menu->spaceh);
-
-		if (maths_is_boxed(x, y, menu->eltw, menu->elth, click->x, click->y)) {
-			selected  = c + r * menu->ncols;
-			selected += pagesz * pagenr;
-
-			if (selected < menu->itemsz) {
-				menu->selected = selected;
-				return 1;
-			}
-		}
-
-		if (++c >= menu->ncols) {
-			++r;
-			c = 0;
-		}
-	}
-
-	return 0;
-}
-
-void
-gridmenu_init(struct gridmenu *menu,
-              unsigned int nr,
-              unsigned int nc,
-              const char * const *items,
-              size_t itemsz)
-{
-	assert(menu);
-	assert(nr);
-	assert(nc);
-
-	memset(menu, 0, sizeof (*menu));
-
-	menu->nrows = nr;
-	menu->ncols = nc;
-	menu->items = items;
-	menu->itemsz = itemsz;
-}
-
-void
-gridmenu_resize(struct gridmenu *menu, int x, int y, unsigned int w, unsigned int h)
-{
-	assert(menu);
-
-	menu->x = x;
-	menu->y = y;
-	menu->w = w;
-	menu->h = h;
-
-	geometry(menu);
-}
-
-int
-gridmenu_handle(struct gridmenu *menu, const union event *ev)
-{
-	assert(menu);
-	assert(ev);
-
-	switch (ev->type) {
-	case EVENT_KEYDOWN:
-		return handle_keydown(menu, &ev->key);
-		break;
-	case EVENT_CLICKDOWN:
-		return handle_clickdown(menu, &ev->click);
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-void
-gridmenu_draw(const struct gridmenu *menu)
-{
-	assert(menu);
-
-	draw_frame(menu);
-	draw_labels(menu);
-}
--- a/src/libmlk-ui/ui/gridmenu.h	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * gridmenu.h -- GUI grid menu
- *
- * Copyright (c) 2020-2022 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 MLK_UI_GRIDMENU_H
-#define MLK_UI_GRIDMENU_H
-
-#include <stddef.h>
-
-#include <mlk/core/core.h>
-
-#include "label.h"
-
-struct theme;
-
-union event;
-
-struct gridmenu {
-	int x;
-	int y;
-	unsigned int w;
-	unsigned int h;
-	size_t selected;
-	const struct theme *theme;
-	const char * const *items;
-	size_t itemsz;
-	unsigned int nrows;
-	unsigned int ncols;
-
-	/* Private fields. */
-	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 */
-};
-
-CORE_BEGIN_DECLS
-
-void
-gridmenu_init(struct gridmenu *, unsigned int, unsigned int, const char * const *, size_t);
-
-void
-gridmenu_resize(struct gridmenu *, int, int, unsigned int, unsigned int);
-
-int
-gridmenu_handle(struct gridmenu *, const union event *);
-
-void
-gridmenu_draw(const struct gridmenu *);
-
-CORE_END_DECLS
-
-#endif /* !MLK_UI_GRIDMENU_H */
--- a/src/libmlk-ui/ui/label.c	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * label.c -- GUI label
- *
- * Copyright (c) 2020-2022 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 <assert.h>
-#include <string.h>
-
-#include <mlk/core/font.h>
-#include <mlk/core/panic.h>
-#include <mlk/core/texture.h>
-
-#include "label.h"
-#include "theme.h"
-
-void
-label_draw_default(const struct theme *t, const struct label *label)
-{
-	assert(t);
-	assert(label);
-
-	struct font *font;
-	struct texture tex;
-	unsigned long color;
-
-	font = label->flags & LABEL_FLAGS_IMPORTANT
-		? t->fonts[THEME_FONT_IMPORTANT]
-		: t->fonts[THEME_FONT_INTERFACE];
-	color = label->flags & LABEL_FLAGS_SELECTED
-		? t->colors[THEME_COLOR_SELECTED]
-	        : t->colors[THEME_COLOR_NORMAL];
-
-	/* Shadow text, only if enabled. */
-	if (label->flags & LABEL_FLAGS_SHADOW) {
-		if (font_render(font, &tex, label->text, t->colors[THEME_COLOR_SHADOW]) < 0)
-			panic();
-
-		texture_draw(&tex, label->x + 1, label->y + 1);
-		texture_finish(&tex);
-	}
-
-	/* Normal text. */
-	if (font_render(font, &tex, label->text, color) < 0)
-		panic();
-
-	texture_draw(&tex, label->x, label->y);
-	texture_finish(&tex);
-}
-
-int
-label_ok(const struct label *label)
-{
-	return label && label->text && strlen(label->text) > 0;
-}
-
-void
-label_query(const struct label *label, unsigned int *w, unsigned int *h)
-{
-	assert(label);
-	assert(label->text);
-
-	const struct theme *t = label->theme ? label->theme : theme_default();
-	const struct font *f = label->flags & LABEL_FLAGS_IMPORTANT
-		? t->fonts[THEME_FONT_IMPORTANT]
-		: t->fonts[THEME_FONT_INTERFACE];
-
-	if (font_query(f, label->text, w, h) < 0)
-		panic();
-}
-
-void
-label_draw(const struct label *label)
-{
-	assert(label);
-	assert(label->text);
-
-	theme_draw_label(label->theme, label);
-}
--- a/src/libmlk-ui/ui/label.h	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * label.h -- GUI label
- *
- * Copyright (c) 2020-2022 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 MLK_UI_LABEL_H
-#define MLK_UI_LABEL_H
-
-#include <mlk/core/core.h>
-
-struct theme;
-
-enum label_flags {
-	LABEL_FLAGS_NONE,
-	LABEL_FLAGS_SHADOW      = (1 << 0),
-	LABEL_FLAGS_IMPORTANT   = (1 << 1),
-	LABEL_FLAGS_SELECTED    = (1 << 2)
-};
-
-struct label {
-	int x;
-	int y;
-	const char *text;
-	enum label_flags flags;
-	const struct theme *theme;
-};
-
-CORE_BEGIN_DECLS
-
-void
-label_draw_default(const struct theme *, const struct label *);
-
-int
-label_ok(const struct label *);
-
-void
-label_query(const struct label *, unsigned int *, unsigned int *);
-
-void
-label_draw(const struct label *);
-
-CORE_END_DECLS
-
-#endif /* !MLK_UI_LABEL_H */
--- a/src/libmlk-ui/ui/notify.c	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,209 +0,0 @@
-/*
- * notify.c -- in game notifications
- *
- * Copyright (c) 2020-2022 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 <assert.h>
-#include <stddef.h>
-#include <string.h>
-
-#include <mlk/core/font.h>
-#include <mlk/core/texture.h>
-#include <mlk/core/trace.h>
-#include <mlk/core/window.h>
-
-#include "align.h"
-#include "frame.h"
-#include "label.h"
-#include "notify.h"
-#include "theme.h"
-
-#define WIDTH   (window.w / 3)
-#define HEIGHT  (window.h / 10)
-
-struct geo {
-	const struct theme *theme;
-	int frame_x;
-	int frame_y;
-	unsigned int frame_w;
-	unsigned int frame_h;
-	int icon_x;
-	int icon_y;
-	int title_x;
-	int title_y;
-	int body_x;
-	int body_y;
-};
-
-static void draw(const struct notify *, size_t);
-
-static const struct notify_system default_system = {
-	.draw = draw
-};
-static const struct notify_system *system = &default_system;
-static struct notify stack[NOTIFY_MAX];
-static size_t stacksz;
-
-static void
-geometry(struct geo *geo, const struct notify *n, size_t index)
-{
-	int x, y;
-
-	/* Determine theme. */
-	geo->theme = system->theme ? system->theme : theme_default();
-
-	/* Determine notification position. */
-	x  = window.w - geo->theme->padding;
-	x -= WIDTH;
-
-	y  = geo->theme->padding * (index + 1);;
-	y += HEIGHT * index;
-
-	/* Content frame. */
-	geo->frame_x = x;
-	geo->frame_y = y;
-	geo->frame_w = WIDTH;
-	geo->frame_h = HEIGHT;
-
-	/* Align icon at the left center. */
-	if (n->icon->h >= HEIGHT) {
-		tracef("notification icon is too large: %u > %u", n->icon->h, HEIGHT);
-		geo->icon_x = x + geo->theme->padding;
-		geo->icon_y = y + geo->theme->padding;
-	} else {
-		align(ALIGN_LEFT, &geo->icon_x, &geo->icon_y, n->icon->w, n->icon->h, x, y, WIDTH, HEIGHT);
-		geo->icon_x += geo->icon_y - y;
-	}
-
-	/* Align title to the right of the icon at the same y coordinate. */
-	geo->title_x  = geo->icon_x + n->icon->w + geo->theme->padding;
-	geo->title_y  = geo->icon_y;
-	geo->title_y -= font_height(geo->theme->fonts[THEME_FONT_IMPORTANT]) / 2;
-
-	/* Align body so it ends at the end of the icon. */
-	geo->body_x  = geo->title_x;
-	geo->body_y  = geo->icon_y + n->icon->h;
-	geo->body_y -= font_height(geo->theme->fonts[THEME_FONT_INTERFACE]) / 2;
-}
-
-static void
-draw_frame(const struct geo *geo)
-{
-	const struct frame f = {
-		.x = geo->frame_x,
-		.y = geo->frame_y,
-		.w = geo->frame_w,
-		.h = geo->frame_h
-	};
-
-	frame_draw(&f);
-}
-
-static void
-draw_icon(const struct geo *geo, const struct notify *n)
-{
-	texture_draw(n->icon, geo->icon_x, geo->icon_y);
-}
-
-#include <stdio.h>
-
-static void
-draw_title(const struct geo *geo, const struct notify *n)
-{
-	const struct label l = {
-		.x = geo->title_x,
-		.y = geo->title_y,
-		.text = n->title,
-		.flags = LABEL_FLAGS_SHADOW | LABEL_FLAGS_IMPORTANT
-	};
-
-	label_draw(&l);
-}
-
-static void
-draw_body(const struct geo *geo, const struct notify *n)
-{
-	const struct label l = {
-		.x = geo->body_x,
-		.y = geo->body_y,
-		.text = n->body,
-		.flags = LABEL_FLAGS_SHADOW
-	};
-
-	label_draw(&l);
-}
-
-static void
-draw(const struct notify *n, size_t index)
-{
-	struct geo geo;
-
-	/* Compute notification size and widgets. */
-	geometry(&geo, n, index);
-
-	draw_frame(&geo);
-	draw_icon(&geo, n);
-	draw_title(&geo, n);
-	draw_body(&geo, n);
-}
-
-void
-notify(const struct texture *icon, const char *title, const char *body)
-{
-	assert(icon);
-	assert(title);
-	assert(body);
-
-	struct notify *n;
-
-	if (stacksz >= NOTIFY_MAX) {
-		memmove(&stack[0], &stack[1], sizeof (stack[0]) - NOTIFY_MAX - 1);
-		n = &stack[NOTIFY_MAX - 1];
-	} else
-		n = &stack[stacksz++];
-
-	memset(n, 0, sizeof (*n));
-	n->icon = icon;
-	n->title = title;
-	n->body = body;
-}
-
-void
-notify_update(unsigned int ticks)
-{
-	struct notify *n;
-
-	for (size_t i = 0; i < stacksz; ++i) {
-		n = &stack[i];
-		n->elapsed += ticks;
-
-		if (n->elapsed >= NOTIFY_TIMEOUT_DEFAULT)
-			memmove(n, n + 1, sizeof (*n) * (--stacksz - i));
-	}
-}
-
-void
-notify_draw(void)
-{
-	for (size_t i = 0; i < stacksz; ++i)
-		system->draw(&stack[i], i);
-}
-
-void
-notify_set_system(const struct notify_system *sys)
-{
-	system = sys ? sys : &default_system;
-}
--- a/src/libmlk-ui/ui/notify.h	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * notify.h -- in game notifications
- *
- * Copyright (c) 2020-2022 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 MLK_UI_NOTIFY_H
-#define MLK_UI_NOTIFY_H
-
-#include <stddef.h>
-
-#include <mlk/core/core.h>
-
-#define NOTIFY_MAX              (4)
-#define NOTIFY_TIMEOUT_DEFAULT  (5000)
-
-struct texture;
-struct theme;
-
-struct notify {
-	const struct texture *icon;
-	const char *title;
-	const char *body;
-	unsigned int elapsed;
-};
-
-struct notify_system {
-	struct theme *theme;
-	void (*draw)(const struct notify *, size_t);
-};
-
-CORE_BEGIN_DECLS
-
-void
-notify(const struct texture *, const char *, const char *);
-
-void
-notify_update(unsigned int ticks);
-
-void
-notify_draw(void);
-
-void
-notify_set_system(const struct notify_system *);
-
-CORE_END_DECLS
-
-#endif /*! MLK_UI_NOTIFY_H */
--- a/src/libmlk-ui/ui/theme.c	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
- * theme.c -- abstract theming
- *
- * Copyright (c) 2020-2022 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 <assert.h>
-#include <stddef.h>
-#include <string.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/util.h>
-
-#include <assets/fonts/opensans-light.h>
-#include <assets/fonts/opensans-medium.h>
-#include <assets/fonts/opensans-regular.h>
-
-#include "align.h"
-#include "button.h"
-#include "checkbox.h"
-#include "frame.h"
-#include "label.h"
-#include "theme.h"
-
-#define THEME(t) (t ? t : &default_theme)
-
-/* Default font catalog. */
-#define FONT(bin, size, index)                                          \
-	{ bin, sizeof (bin), size, &default_theme.fonts[index], {0} }
-
-/* Default theme. */
-static struct theme default_theme = {
-	.colors = {
-		[THEME_COLOR_DEBUG]     = 0xff0000ff,
-		[THEME_COLOR_NORMAL]    = 0xffffffff,
-		[THEME_COLOR_SELECTED]  = 0x006554ff,
-		[THEME_COLOR_SHADOW]    = 0x000000ff
-	},
-	.padding = 10,
-	.draw_frame = frame_draw_default,
-	.draw_label = label_draw_default,
-	.draw_button = button_draw_default,
-	.draw_checkbox = checkbox_draw_default
-};
-
-static struct font_catalog {
-	const unsigned char *data;
-	const size_t datasz;
-	unsigned int size;
-	struct font **dest;
-	struct font font;
-} default_fonts[] = {
-	FONT(assets_opensans_light, 12, THEME_FONT_DEBUG),
-	FONT(assets_opensans_regular, 14, THEME_FONT_INTERFACE),
-	FONT(assets_opensans_medium, 14, THEME_FONT_IMPORTANT)
-};
-
-int
-theme_init(void)
-{
-	/* Open all fonts. */
-	for (size_t i = 0; i < UTIL_SIZE(default_fonts); ++i) {
-		struct font_catalog *fc = &default_fonts[i];
-
-		if (font_openmem(&fc->font, fc->data, fc->datasz, fc->size) < 0)
-			goto failed;
-
-		/* Reference this font into the catalog. */
-		*default_fonts[i].dest = &default_fonts[i].font;
-	}
-
-	return 0;
-
-failed:
-	theme_finish();
-
-	return -1;
-}
-
-struct theme *
-theme_default(void)
-{
-	return &default_theme;
-}
-
-unsigned int
-theme_padding(const struct theme *t)
-{
-	return THEME(t)->padding;
-}
-
-void
-theme_shallow(struct theme *dst, const struct theme *src)
-{
-	assert(dst);
-
-	memcpy(dst, src ? src : &default_theme, sizeof (*src));
-}
-
-void
-theme_draw_frame(const struct theme *t, const struct frame *frame)
-{
-	assert(frame);
-
-	THEME(t)->draw_frame(THEME(t), frame);
-}
-
-void
-theme_draw_label(const struct theme *t, const struct label *label)
-{
-	assert(label);
-
-	THEME(t)->draw_label(THEME(t), label);
-}
-
-void
-theme_draw_button(const struct theme *t, const struct button *button)
-{
-	assert(button);
-
-	THEME(t)->draw_button(THEME(t), button);
-}
-
-void
-theme_draw_checkbox(const struct theme *t, const struct checkbox *cb)
-{
-	assert(cb);
-
-	THEME(t)->draw_checkbox(THEME(t), cb);
-}
-
-void
-theme_finish(void)
-{
-	for (size_t i = 0; i < UTIL_SIZE(default_fonts); ++i) {
-		font_finish(&default_fonts[i].font);
-		*default_fonts[i].dest = NULL;
-	}
-}
--- a/src/libmlk-ui/ui/theme.h	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * theme.h -- abstract theming
- *
- * Copyright (c) 2020-2022 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 MLK_UI_THEME_H
-#define MLK_UI_THEME_H
-
-#include <mlk/core/core.h>
-
-struct button;
-struct checkbox;
-struct font;
-struct frame;
-struct label;
-struct sprite;
-
-enum theme_font {
-	THEME_FONT_DEBUG,
-	THEME_FONT_INTERFACE,
-	THEME_FONT_IMPORTANT,
-	THEME_FONT_NUM
-};
-
-enum theme_color {
-	THEME_COLOR_DEBUG,
-	THEME_COLOR_NORMAL,
-	THEME_COLOR_SELECTED,
-	THEME_COLOR_SHADOW,
-	THEME_COLOR_NUM
-};
-
-enum theme_sprite {
-	THEME_SPRITE_CURSOR,
-	THEME_SPRITE_NUM
-};
-
-struct theme {
-	struct font *fonts[THEME_FONT_NUM];
-	const struct sprite *sprites[THEME_SPRITE_NUM];
-	unsigned long colors[THEME_COLOR_NUM];
-	unsigned int padding;
-
-	void (*draw_frame)(const struct theme *, const struct frame *);
-	void (*draw_label)(const struct theme *, const struct label *);
-	void (*draw_button)(const struct theme *, const struct button *);
-	void (*draw_checkbox)(const struct theme *t, const struct checkbox *);
-};
-
-CORE_BEGIN_DECLS
-
-int
-theme_init(void);
-
-struct theme *
-theme_default(void);
-
-void
-theme_shallow(struct theme *, const struct theme *);
-
-void
-theme_draw_frame(const struct theme *, const struct frame *);
-
-void
-theme_draw_label(const struct theme *, const struct label *);
-
-void
-theme_draw_button(const struct theme *, const struct button *);
-
-void
-theme_draw_checkbox(const struct theme *, const struct checkbox *);
-
-void
-theme_finish(void);
-
-CORE_END_DECLS
-
-#endif /* !MLK_UI_THEME_H */
--- a/src/libmlk-ui/ui/ui.c	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * ui.c -- libui convenient header
- *
- * Copyright (c) 2020-2022 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 "theme.h"
-#include "ui.h"
-
-int
-ui_init(void)
-{
-	return theme_init();
-}
-
-void
-ui_finish(void)
-{
-	theme_finish();
-}
--- a/src/libmlk-ui/ui/ui.h	Sat Oct 15 20:28:59 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * ui.h -- libui convenient header
- *
- * Copyright (c) 2020-2022 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 MLK_UI_UI_H
-#define MLK_UI_UI_H
-
-#include <mlk/core/core.h>
-
-CORE_BEGIN_DECLS
-
-int
-ui_init(void);
-
-void
-ui_finish(void);
-
-CORE_END_DECLS
-
-#endif /* !MLK_UI_UI_H */