# HG changeset patch # User David Demelier # Date 1602691898 -7200 # Node ID 7f1af54bb35a912eecac940384a3b15c3cfd4131 # Parent 28d9bb62fcb1c1f505009030934faf9e741ee5a6 core: rework label alignment, closes #2494 @1h Now labels can be positioned on a bounding box with much more convenient possibilities. diff -r 28d9bb62fcb1 -r 7f1af54bb35a examples/CMakeLists.txt --- a/examples/CMakeLists.txt Wed Oct 14 16:40:34 2020 +0200 +++ b/examples/CMakeLists.txt Wed Oct 14 18:11:38 2020 +0200 @@ -46,6 +46,12 @@ ) molko_define_executable( + TARGET example-label + SOURCES example-label.c + LIBRARIES libcore +) + +molko_define_executable( TARGET example-message SOURCES example-message.c FOLDER examples diff -r 28d9bb62fcb1 -r 7f1af54bb35a examples/example-drawable.c --- a/examples/example-drawable.c Wed Oct 14 16:40:34 2020 +0200 +++ b/examples/example-drawable.c Wed Oct 14 18:11:38 2020 +0200 @@ -44,9 +44,9 @@ .x = 10, .y = 10, .w = W, - .h = 32, - .flags = LABEL_NO_HCENTER, - .color = 0x4f8fbaff + .h = H, + .align = LABEL_ALIGN_TOP_LEFT, + .flags = LABEL_FLAGS_SHADOW }; #if 0 diff -r 28d9bb62fcb1 -r 7f1af54bb35a examples/example-label.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-label.c Wed Oct 14 18:11:38 2020 +0200 @@ -0,0 +1,168 @@ +/* + * example-label.c -- show how to use label and alignments + * + * Copyright (c) 2020 David Demelier + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define W (1280) +#define H (720) + +static void +init(void) +{ + if (!sys_init() || + !window_init("Example - Label", W, H) || + !theme_init()) + panic(); +} + +static void +quit(void) +{ + theme_finish(); + window_finish(); + sys_finish(); +} + +static void +run(void) +{ + struct clock clock = {0}; + struct label labels[] = { + { + .x = 0, + .y = 0, + .w = W, + .h = H, + .text = "Top left", + .align = LABEL_ALIGN_TOP_LEFT + }, + { + .x = 0, + .y = 0, + .w = W, + .h = H, + .text = "Top", + .align = LABEL_ALIGN_TOP + }, + { + .x = 0, + .y = 0, + .w = W, + .h = H, + .text = "Top right", + .align = LABEL_ALIGN_TOP_RIGHT + }, + { + .x = 0, + .y = 0, + .w = W, + .h = H, + .text = "Right", + .align = LABEL_ALIGN_RIGHT + }, + { + .x = 0, + .y = 0, + .w = W, + .h = H, + .text = "Bottom right", + .align = LABEL_ALIGN_BOTTOM_RIGHT + }, + { + .x = 0, + .y = 0, + .w = W, + .h = H, + .text = "Bottom", + .align = LABEL_ALIGN_BOTTOM + }, + { + .x = 0, + .y = 0, + .w = W, + .h = H, + .text = "Bottom left", + .align = LABEL_ALIGN_BOTTOM_LEFT + }, + { + .x = 0, + .y = 0, + .w = W, + .h = H, + .text = "Left", + .align = LABEL_ALIGN_LEFT + }, + { + .x = 0, + .y = 0, + .w = W, + .h = H, + .text = "The world is Malikania.", + .flags = LABEL_FLAGS_SHADOW + }, + }; + + clock_start(&clock); + + for (;;) { + union event ev; + unsigned int elapsed = clock_elapsed(&clock); + + clock_start(&clock); + + while (event_poll(&ev)) { + switch (ev.type) { + case EVENT_QUIT: + return; + default: + break; + } + } + + painter_set_color(0x4f8fbaff); + painter_clear(); + + for (size_t i = 0; i < NELEM(labels); ++i) + label_draw(&labels[i]); + + painter_present(); + + if ((elapsed = clock_elapsed(&clock)) < 20) + delay(20 - elapsed); + } +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +} + diff -r 28d9bb62fcb1 -r 7f1af54bb35a examples/example-sound.c --- a/examples/example-sound.c Wed Oct 14 16:40:34 2020 +0200 +++ b/examples/example-sound.c Wed Oct 14 18:11:38 2020 +0200 @@ -39,8 +39,9 @@ .x = 10, .y = 10, .w = W, - .h = 32, - .flags = LABEL_NO_HCENTER + .h = H, + .align = LABEL_ALIGN_TOP_LEFT, + .flags = LABEL_FLAGS_SHADOW }; static void diff -r 28d9bb62fcb1 -r 7f1af54bb35a libadventure/adventure/trace_hud.c --- a/libadventure/adventure/trace_hud.c Wed Oct 14 16:40:34 2020 +0200 +++ b/libadventure/adventure/trace_hud.c Wed Oct 14 18:11:38 2020 +0200 @@ -98,7 +98,7 @@ .y = y, .text = data.lines[i], .theme = th, - .flags = LABEL_NO_HCENTER + .flags = LABEL_ALIGN_LEFT }); y += font_height(th->fonts[THEME_FONT_INTERFACE]); diff -r 28d9bb62fcb1 -r 7f1af54bb35a libcore/core/inventory_dialog.c --- a/libcore/core/inventory_dialog.c Wed Oct 14 16:40:34 2020 +0200 +++ b/libcore/core/inventory_dialog.c Wed Oct 14 18:11:38 2020 +0200 @@ -196,7 +196,7 @@ dlg->fname.x = dlg->lname.x = dlg->x; dlg->fname.y = dlg->lname.y = dlg->y + GRID_HEIGHT; dlg->lname.x += ITEM_PADDING; - dlg->lname.flags = LABEL_NO_HCENTER; + dlg->lname.align = LABEL_ALIGN_LEFT; /* Description label. */ dlg->fdesc.w = dlg->ldesc.w = LABEL_WIDTH; @@ -204,7 +204,7 @@ dlg->fdesc.x = dlg->ldesc.x = dlg->y; dlg->fdesc.y = dlg->ldesc.y = dlg->y + GRID_HEIGHT + (LABEL_HEIGHT / 2); dlg->ldesc.x += ITEM_PADDING; - dlg->ldesc.flags = LABEL_NO_HCENTER; + dlg->ldesc.align = LABEL_ALIGN_LEFT; /* Button sort. */ dlg->bsort.x = dlg->x; diff -r 28d9bb62fcb1 -r 7f1af54bb35a libcore/core/label.c --- a/libcore/core/label.c Wed Oct 14 16:40:34 2020 +0200 +++ b/libcore/core/label.c Wed Oct 14 18:11:38 2020 +0200 @@ -20,11 +20,16 @@ #include "label.h" #include "theme.h" +#include "trace.h" void label_draw(const struct label *label) { assert(label); + assert(label->text); + + if (label->w == 0 || label->h == 0) + trace("label %p has null dimensions", label); theme_draw_label(label->theme, label); } diff -r 28d9bb62fcb1 -r 7f1af54bb35a libcore/core/label.h --- a/libcore/core/label.h Wed Oct 14 16:40:34 2020 +0200 +++ b/libcore/core/label.h Wed Oct 14 18:11:38 2020 +0200 @@ -30,10 +30,35 @@ * \brief Label flags. */ enum label_flags { - LABEL_NONE, /*!< No flags. */ - LABEL_NO_SHADOW = (1 << 0), /*!< Disable shadow. */ - LABEL_NO_VCENTER = (1 << 1), /*!< Disable vertical centering. */ - LABEL_NO_HCENTER = (1 << 2) /*!< Disable horizontal centering. */ + LABEL_FLAGS_NONE, /*!< No flags. */ + LABEL_FLAGS_SHADOW = (1 << 0), /*!< Enable shadow. */ +}; + +/** + * \brief Label alignment in bounding box. + * + * The alignment is described as following: + * + * ``` + * +---------------------+ + * | 1 2 3 | + * | | + * | 8 0 4 | + * | | + * | 7 6 5 | + * +---------------------+ + * ``` + */ +enum label_align { + LABEL_ALIGN_CENTER, /*!< Align to the center (default). */ + LABEL_ALIGN_TOP_LEFT, /*!< Top left. */ + LABEL_ALIGN_TOP, /*!< Top center (aligned horizontally). */ + LABEL_ALIGN_TOP_RIGHT, /*!< Top right. */ + LABEL_ALIGN_RIGHT, /*!< Right (aligned vertically). */ + LABEL_ALIGN_BOTTOM_RIGHT, /*!< Bottom right. */ + LABEL_ALIGN_BOTTOM, /*!< Bottom (aligned horizontally). */ + LABEL_ALIGN_BOTTOM_LEFT, /*!< Bottom left. */ + LABEL_ALIGN_LEFT /*!< Left (aligned vertically). */ }; /** @@ -46,7 +71,7 @@ unsigned int h; /*!< (RW) Height. */ const char *text; /*!< (RW, ref) Text to show. */ enum label_flags flags; /*!< (RW) Optional flags. */ - unsigned long color; /*!< (RW) Color to use (0 = use theme). */ + enum label_align align; /*!< (RW) How to positionate label. */ struct theme *theme; /*!< (RW, ref, optional) Theme to use. */ }; diff -r 28d9bb62fcb1 -r 7f1af54bb35a libcore/core/message.c --- a/libcore/core/message.c Wed Oct 14 16:40:34 2020 +0200 +++ b/libcore/core/message.c Wed Oct 14 18:11:38 2020 +0200 @@ -79,12 +79,14 @@ static void draw_lines(const struct message *msg) { - struct theme *theme; + struct theme theme; struct font *font; unsigned int lineh; - theme = THEME(msg); - font = theme->fonts[THEME_FONT_INTERFACE]; + /* Shallow copy theme to modify colors. */ + memcpy(&theme, THEME(msg), sizeof (theme)); + + font = theme.fonts[THEME_FONT_INTERFACE]; lineh = font_height(font); for (int i = 0; i < 6; ++i) { @@ -92,20 +94,24 @@ continue; struct label label = { - .x = theme->padding, - .y = theme->padding + (i * lineh), - .h = lineh, - .theme = msg->theme, + .y = i * lineh, + .w = msg->w, + .h = msg->h, + .theme = &theme, .text = msg->text[i], - .flags = LABEL_NO_HCENTER + .align = LABEL_ALIGN_TOP_LEFT, + .flags = LABEL_FLAGS_SHADOW }; /* - * The function label_draw will normally use - * THEME_FONT_INTERFACE so update its color if needed. + * The function label_draw will use THEME_COLOR_NORMAL to draw + * text and THEME_COLOR_SHADOW so if we have selected a line + * we need to cheat the normal color. */ if (msg->flags & MESSAGE_FLAGS_QUESTION && msg->index == (unsigned int)i) - label.color = theme->colors[THEME_COLOR_SELECTED]; + theme.colors[THEME_COLOR_NORMAL] = THEME(msg)->colors[THEME_COLOR_SELECTED]; + else + theme.colors[THEME_COLOR_NORMAL] = THEME(msg)->colors[THEME_COLOR_NORMAL]; label_draw(&label); } diff -r 28d9bb62fcb1 -r 7f1af54bb35a libcore/core/theme.c --- a/libcore/core/theme.c Wed Oct 14 16:40:34 2020 +0200 +++ b/libcore/core/theme.c Wed Oct 14 18:11:38 2020 +0200 @@ -69,40 +69,81 @@ static void draw_label(struct theme *t, const struct label *label) { + struct font *font; struct texture tex; - int x = label->x, y = label->y; - int *px = &x, *py = &y; + int x, y, bx, by; + unsigned int tw, th, bw, bh; + + /* Compute real box size according to padding. */ + bx = label->x + t->padding; + by = label->y + t->padding; + bw = label->w - (t->padding * 2); + bh = label->h - (t->padding * 2); + + /* Make a shallow copy of the interface font. */ + font = t->fonts[THEME_FONT_INTERFACE]; + + /* Compute text size. */ + if (!font_box(font, label->text, &tw, &th)) + panic(); - if (label->flags & LABEL_NO_HCENTER) - px = NULL; - if (label->flags & LABEL_NO_VCENTER) - py = NULL; + /* Compute position according to alignment and box. */ + switch (label->align) { + case LABEL_ALIGN_CENTER: + maths_centerize(&x, &y, tw, th, bx, by, bw, bh); + break; + case LABEL_ALIGN_TOP_LEFT: + x = bx; + y = by; + break; + case LABEL_ALIGN_TOP: + maths_centerize(&x, NULL, tw, th, bx, by, bw, bh); + y = by; + break; + case LABEL_ALIGN_TOP_RIGHT: + x = bx + bw - tw; + y = by; + break; + case LABEL_ALIGN_RIGHT: + maths_centerize(NULL, &y, tw, th, bx, by, bw, bh); + x = bx + bw - tw; + break; + case LABEL_ALIGN_BOTTOM_RIGHT: + x = bx + bw - tw; + y = by + bh - th; + break; + case LABEL_ALIGN_BOTTOM: + maths_centerize(&x, NULL, tw, th, bx, by, bw, bh); + y = by + bh - th; + break; + case LABEL_ALIGN_BOTTOM_LEFT: + x = bx; + y = by + bh - th; + break; + case LABEL_ALIGN_LEFT: + maths_centerize(NULL, &y, tw, th, bx, by, bw, bh); + x = bx; + default: + break; + } /* Shadow text, only if enabled. */ - if (!(label->flags & LABEL_NO_SHADOW)) { - t->fonts[THEME_FONT_INTERFACE]->color = t->colors[THEME_COLOR_SHADOW]; + if (label->flags & LABEL_FLAGS_SHADOW) { + font->color = t->colors[THEME_COLOR_SHADOW]; - if (!font_render(t->fonts[THEME_FONT_INTERFACE], &tex, label->text)) + if (!font_render(font, &tex, label->text)) panic(); - maths_centerize(px, py, tex.w, tex.h, - label->x, label->y, label->w, label->h); - texture_draw(&tex, x + 1, y + 1); texture_finish(&tex); } /* Normal text. */ - t->fonts[THEME_FONT_INTERFACE]->color = label->color - ? label->color - : t->colors[THEME_COLOR_NORMAL]; + font->color = t->colors[THEME_COLOR_NORMAL]; - if (!font_render(t->fonts[THEME_FONT_INTERFACE], &tex, label->text)) + if (!font_render(font, &tex, label->text)) panic(); - maths_centerize(px, py, tex.w, tex.h, - label->x, label->y, label->w, label->h); - texture_draw(&tex, x, y); texture_finish(&tex); } @@ -142,7 +183,7 @@ struct label label = { .text = cb->label, - .flags = LABEL_NO_HCENTER, + .align = LABEL_ALIGN_LEFT, .x = x, .y = cb->y, .w = w,