Mercurial > molko
changeset 635:3cb1860d9f11
rpg: improve message selectable lines
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 05 Sep 2023 11:51:46 +0200 |
parents | 3930234ab1f5 |
children | b826e80c53cd |
files | doc/Doxyfile doc/images/example-message.png examples/example-message/example-message.c libmlk-rpg/mlk/rpg/message.c libmlk-rpg/mlk/rpg/message.h |
diffstat | 5 files changed, 143 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/Doxyfile Tue Aug 29 13:34:10 2023 +0200 +++ b/doc/Doxyfile Tue Sep 05 11:51:46 2023 +0200 @@ -5,6 +5,7 @@ PROJECT_BRIEF = "@molko_DESCRIPTION@" OUTPUT_DIRECTORY = "@doc_BINARY_DIR@" +IMAGE_PATH = "@doc_SOURCE_DIR@/images" TAB_SIZE = 8 OPTIMIZE_OUTPUT_FOR_C = YES
--- a/examples/example-message/example-message.c Tue Aug 29 13:34:10 2023 +0200 +++ b/examples/example-message/example-message.c Tue Sep 05 11:51:46 2023 +0200 @@ -207,16 +207,17 @@ question(void) { const char * const text[] = { - "Okay, I've understood.", - "Nevermind, I'll do it again." + "Do you think you're brave enough to fight this Karen?", + "Sure I am.", + "No." }; struct mlk_message msg = { .x = MX, .y = MY, .w = MW, .lines = text, - .linesz = 2, - .flags = MLK_MESSAGE_FLAGS_QUESTION + .linesz = 3, + .selectable = 0x6 }; mlk_message_query(&msg, NULL, &msg.h);
--- a/libmlk-rpg/mlk/rpg/message.c Tue Aug 29 13:34:10 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/message.c Tue Sep 05 11:51:46 2023 +0200 @@ -37,6 +37,12 @@ #include "message.h" +static inline int +is_selectable(const struct mlk_message *msg, size_t n) +{ + return msg->lines[n] && ((msg->selectable >> n) & 0x1) == 1; +} + static inline struct mlk_message_style * get_style(struct mlk_message *msg) { @@ -116,7 +122,7 @@ if (!msg->lines[i]) continue; - if ((msg->flags & MLK_MESSAGE_FLAGS_QUESTION) && msg->index == i) + if (msg->selectable && msg->selected == i && is_selectable(msg, i)) color = style->color_selected; else color = style->color; @@ -287,6 +293,18 @@ if (msg->flags & MLK_MESSAGE_FLAGS_AUTOMATIC && style->timeout == 0) mlk_tracef("message is automatic but has zero timeout"); + + /* + * Make sure selected index goes in the range of the lines and that it + * starts on a proper selectable line. + */ + if (msg->selectable) { + if (msg->selected >= msg->linesz || !is_selectable(msg, msg->selected)) + msg->selected = 0; + + while (!is_selectable(msg, msg->selected)) + msg->selected++; + } } int @@ -297,6 +315,72 @@ return MLK__STYLE_CALL(msg->style, mlk_message_style, query, msg, w, h); } +static inline size_t +first(const struct mlk_message *msg) +{ + size_t ret = -1; + + for (size_t i = 0; i < msg->linesz; ++i) { + if (is_selectable(msg, i)) { + ret = i; + break; + } + } + + return ret; +} + +static inline size_t +last(const struct mlk_message *msg) +{ + size_t ret = -1; + + for (size_t i = msg->linesz; i >= 0; --i) { + if (is_selectable(msg, i)) { + ret = i; + break; + } + } + + return ret; +} + +static inline size_t +previous(const struct mlk_message *msg) +{ + size_t ret; + + /* wrap */ + if (msg->selected == first(msg)) + ret = last(msg); + else { + ret = msg->selected - 1; + + while (ret > 0 && !is_selectable(msg, ret)) + ret--; + } + + return ret; +} + +static inline size_t +next(const struct mlk_message *msg) +{ + size_t ret; + + /* wrap */ + if (msg->selected == last(msg)) + ret = first(msg); + else { + ret = msg->selected + 1; + + while (ret < msg->linesz && !is_selectable(msg, ret)) + ret++; + } + + return ret; +} + void mlk_message_handle(struct mlk_message *msg, const union mlk_event *ev) { @@ -313,12 +397,12 @@ switch (ev->key.key) { case MLK_KEY_UP: - if (msg->index > 0) - msg->index--; + if (msg->selectable && msg->linesz) + msg->selected = previous(msg); break; case MLK_KEY_DOWN: - if (msg->index + 1 < msg->linesz && msg->lines[msg->index + 1]) - msg->index++; + if (msg->selectable && msg->linesz) + msg->selected = next(msg); break; case MLK_KEY_ENTER: msg->state = msg->flags & MLK_MESSAGE_FLAGS_FADEOUT
--- a/libmlk-rpg/mlk/rpg/message.h Tue Aug 29 13:34:10 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/message.h Tue Sep 05 11:51:46 2023 +0200 @@ -19,9 +19,35 @@ #ifndef MLK_RPG_MESSAGE_H #define MLK_RPG_MESSAGE_H +/** + * \file mlk/rpg/message.h + * \brief Message dialog. + * + * This module offers a message box dialog that shows several lines similar to + * old school RPG games. + * + * The dialog can be animated while appearing and hiding using special + * ::MLK_MESSAGE_FLAGS_FADEIN and ::MLK_MESSAGE_FLAGS_FADEOUT which aren't set + * by default. + * + * Lines can be selected by specifying a line mask as a bitmask, see + * ::mlk_message::selectable field for more information. + * + * Example of message dialog: + * + * \image html example-message.png + */ + #include <stddef.h> +/** + * \brief Default message animation speed. + */ #define MLK_MESSAGE_SPEED_DEFAULT (150) + +/** + * \brief Default message automatic close duration. + */ #define MLK_MESSAGE_TIMEOUT_DEFAULT (5000) struct mlk_font; @@ -41,11 +67,6 @@ MLK_MESSAGE_FLAGS_AUTOMATIC = (1 << 0), /** - * Lines can be selected by the user. - */ - MLK_MESSAGE_FLAGS_QUESTION = (1 << 1), - - /** * Add fade in animation. */ MLK_MESSAGE_FLAGS_FADEIN = (1 << 2), @@ -82,6 +103,10 @@ MLK_MESSAGE_STATE_HIDING }; +/** + * \struct mlk_message + * \brief Message box. + */ struct mlk_message { /** * (read-write) @@ -128,9 +153,26 @@ /** * (read-write) * + * Tells which lines can be selected as bitmask, right most bit being + * the first line in the array. + * + * Example: + * + * [0] Would you open this chest? + * [1] Yes. + * [2] No I prefer run away. + * + * Selectables optiong being 1 and 2, this field must be set to + * `(1 << 1) | (1 << 2)`. + */ + size_t selectable; + + /** + * (read-write) + * * Selected item from the user. */ - size_t index; + size_t selected; /** * (read-write)