# HG changeset patch # User David Demelier # Date 1602607175 -7200 # Node ID 453651d76f7c8d2f3f83ed9fa69968ee252d6f6f # Parent 8b035f7f978af438d89ad81eea8665a631c61c0c core: upgrade message in terms of customization diff -r 8b035f7f978a -r 453651d76f7c examples/example-action.c --- a/examples/example-action.c Tue Oct 13 15:15:40 2020 +0200 +++ b/examples/example-action.c Tue Oct 13 18:39:35 2020 +0200 @@ -37,8 +37,13 @@ #include #include -#define W 1280 -#define H 720 +#define W (1280) +#define H (720) + +#define MW (W * 0.75) +#define MH (H * 0.125) +#define MX ((W / 2) - (MW / 2)) +#define MY (100) /* This is a stack of "parallel" events. */ static struct action_stack events; @@ -60,6 +65,10 @@ struct action event; } chest = { .msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, .text = { "100000 pièces.", "Te voilà riche sale file de crevette." @@ -106,6 +115,12 @@ .msgs = { { .msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, + .delay = MESSAGE_DELAY_DEFAULT, + .flags = MESSAGE_FLAGS_FADEIN | MESSAGE_FLAGS_AUTOMATIC, .text = { "Bienvenue dans ce monde Molko." } @@ -113,6 +128,10 @@ }, { .msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, .text = { "Penses tu vraiment pouvoir me battre ?" } @@ -120,7 +139,11 @@ }, { .msg = { - .flags = MESSAGE_QUESTION, + .x = MX, + .y = MY, + .w = MW, + .h = MH, + .flags = MESSAGE_FLAGS_QUESTION, .text = { "Non j'ai la trouille.", "Bien sûr, je suis la légende." @@ -131,6 +154,10 @@ /* In case of NO. */ { .msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, .text = { "Poule mouillée." } @@ -140,6 +167,10 @@ /* In case of YES. */ { .msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, .text = { "Prépare toi à souffrir." } diff -r 8b035f7f978a -r 453651d76f7c examples/example-message.c --- a/examples/example-message.c Tue Oct 13 15:15:40 2020 +0200 +++ b/examples/example-message.c Tue Oct 13 18:39:35 2020 +0200 @@ -16,8 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include #include +#include #include #include #include @@ -26,8 +29,13 @@ #include #include -#define W 1280 -#define H 720 +#define W (1280) +#define H (720) + +#define MW (W * 0.75) +#define MH (H * 0.125) +#define MX ((W / 2) - (MW / 2)) +#define MY (100) static void init(void) @@ -63,7 +71,7 @@ while (event_poll(&ev)) { switch (ev.type) { case EVENT_QUIT: - msg->state = MESSAGE_NONE; + msg->state = MESSAGE_STATE_NONE; break; default: message_handle(msg, &ev); @@ -83,9 +91,22 @@ } static void +my_draw_frame(struct theme *th, const struct frame *f) +{ + (void)th; + + painter_set_color(0xff0000ff); + painter_draw_rectangle(f->x, f->y, f->w, f->h); +} + +static void basic(void) { struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, .text = { "This is a basic message.", "You need to press to close it." @@ -99,12 +120,71 @@ automatic(void) { struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, + .timeout = MESSAGE_TIMEOUT_DEFAULT, .text = { "This is a an automatic message.", "It will disappear in a few seconds.", "You can still press to close it quicker." }, - .flags = MESSAGE_AUTOMATIC + .flags = MESSAGE_FLAGS_AUTOMATIC + }; + + run(&msg); +} + +static void +fadein(void) +{ + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, + .delay = MESSAGE_DELAY_DEFAULT, + .text = { + "This message will fade in." + }, + .flags = MESSAGE_FLAGS_FADEIN + }; + + run(&msg); +} + +static void +fadeout(void) +{ + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, + .delay = MESSAGE_DELAY_DEFAULT, + .text = { + "This message will fade out." + }, + .flags = MESSAGE_FLAGS_FADEOUT + }; + + run(&msg); +} + +static void +fade(void) +{ + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, + .delay = MESSAGE_DELAY_DEFAULT, + .text = { + "This message will fade in and out." + }, + .flags = MESSAGE_FLAGS_FADEIN | MESSAGE_FLAGS_FADEOUT }; run(&msg); @@ -114,16 +194,67 @@ question(void) { struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, .text = { "Okay, I've understood.", "Nevermind, I'll do it again." }, - .flags = MESSAGE_QUESTION + .flags = MESSAGE_FLAGS_QUESTION + }; + + run(&msg); +} + +static void +smallbottom(void) +{ + const unsigned int w = window.w / 4; + const unsigned int h = 50; + const int x = (window.w / 2) - (w / 2); + const int y = (window.h - h - 10); + + struct message msg = { + .x = x, + .y = y, + .w = w, + .h = h, + .delay = MESSAGE_DELAY_DEFAULT, + .flags = MESSAGE_FLAGS_FADEIN | MESSAGE_FLAGS_FADEOUT, + .text = { + "This one is small here." + } }; run(&msg); } +static void +custom(void) +{ + struct theme theme; + struct message msg = { + .x = MX, + .y = MY, + .w = MW, + .h = MH, + .text = { + "This one will destroy your eyes.", + "Because it use a terrible custom theme." + }, + .theme = &theme + }; + + /* Borrow default theme and change its frame drawing. */ + memcpy(&theme, theme_default(), sizeof (theme)); + theme.draw_frame = my_draw_frame; + theme.colors[THEME_COLOR_NORMAL] = 0x0000ffff; + + run(&msg); +} + int main(int argc, char **argv) { @@ -132,7 +263,12 @@ init(); basic(); + fadein(); + fadeout(); + fade(); automatic(); question(); + smallbottom(); + custom(); quit(); } diff -r 8b035f7f978a -r 453651d76f7c libcore/core/message.c --- a/libcore/core/message.c Tue Oct 13 15:15:40 2020 +0200 +++ b/libcore/core/message.c Tue Oct 13 18:39:35 2020 +0200 @@ -25,6 +25,7 @@ #include "font.h" #include "frame.h" #include "label.h" +#include "maths.h" #include "message.h" #include "painter.h" #include "panic.h" @@ -32,15 +33,8 @@ #include "texture.h" #include "theme.h" #include "util.h" -#include "window.h" -#define MESSAGE_SPEED 100 /* Time delay for animations */ -#define MESSAGE_TIMEOUT 5000 /* Time for auto-closing */ - -#define WIDTH (window.w * 0.75) -#define HEIGHT (window.h * 0.125) - -#define THEME(msg) (msg->theme ? msg->theme : theme_default()) +#define THEME(msg) (msg->theme ? msg->theme : theme_default()) static void handle(struct action *action, const union event *ev) @@ -67,14 +61,65 @@ message_draw(action->data); } +static void +draw_frame(const struct message *msg) +{ + assert(msg); + + struct frame frame = { + .w = msg->w, + .h = msg->h, + .theme = msg->theme + }; + + frame_draw(&frame); +} + +static void +draw_lines(const struct message *msg) +{ + struct theme *theme; + struct font *font; + unsigned int lineh; + + theme = THEME(msg); + font = theme->fonts[THEME_FONT_INTERFACE]; + lineh = font_height(font); + + for (int i = 0; i < 6; ++i) { + if (!msg->text[i]) + continue; + + struct label label = { + .x = theme->padding, + .y = theme->padding + (i * lineh), + .h = lineh, + .theme = msg->theme, + .text = msg->text[i], + .flags = LABEL_NO_HCENTER + }; + + /* + * The function label_draw will normally use + * THEME_FONT_INTERFACE so update its color if needed. + */ + if (msg->flags & MESSAGE_FLAGS_QUESTION && msg->index == (unsigned int)i) + label.color = theme->colors[THEME_COLOR_SELECTED]; + + label_draw(&label); + } +} + void message_start(struct message *msg) { assert(msg); msg->elapsed = 0; - msg->scale = 0.0; - msg->state = msg->flags & MESSAGE_QUICK ? MESSAGE_SHOWING : MESSAGE_OPENING; + msg->scale = msg->flags & MESSAGE_FLAGS_FADEIN ? 0.0 : 1.0; + msg->state = msg->flags & MESSAGE_FLAGS_FADEIN + ? MESSAGE_STATE_OPENING + : MESSAGE_STATE_SHOWING; } void @@ -84,11 +129,11 @@ assert(ev); /* Skip if the message animation hasn't complete. */ - if (msg->state != MESSAGE_SHOWING) + if (msg->state != MESSAGE_STATE_SHOWING) return; /* Only keyboard event are valid. */ - if (ev->type != EVENT_KEYDOWN || msg->state == MESSAGE_NONE) + if (ev->type != EVENT_KEYDOWN || msg->state == MESSAGE_STATE_NONE) return; switch (ev->key.key) { @@ -101,7 +146,9 @@ msg->index++; break; case KEY_ENTER: - msg->state = msg->flags & MESSAGE_QUICK ? MESSAGE_NONE : MESSAGE_HIDING; + msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT + ? MESSAGE_STATE_HIDING + : MESSAGE_STATE_NONE; msg->elapsed = 0; break; default: @@ -117,33 +164,35 @@ msg->elapsed += ticks; switch (msg->state) { - case MESSAGE_OPENING: - msg->scale = (double)msg->elapsed / (double)MESSAGE_SPEED; + case MESSAGE_STATE_OPENING: + msg->scale = (double)msg->elapsed / (double)msg->delay; if (msg->scale > 1) msg->scale = 1; - if (msg->elapsed >= MESSAGE_SPEED) { - msg->state = MESSAGE_SHOWING; + if (msg->elapsed >= msg->delay) { + msg->state = MESSAGE_STATE_SHOWING; msg->elapsed = 0; } break; - case MESSAGE_SHOWING: + case MESSAGE_STATE_SHOWING: /* Do automatically switch state if requested by the user. */ - if (msg->flags & MESSAGE_AUTOMATIC && msg->elapsed >= MESSAGE_TIMEOUT) { - msg->state = msg->flags & MESSAGE_QUICK ? MESSAGE_NONE : MESSAGE_HIDING; + if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->elapsed >= msg->timeout) { + msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT + ? MESSAGE_STATE_HIDING + : MESSAGE_STATE_NONE; msg->elapsed = 0; } break; - case MESSAGE_HIDING: - msg->scale = 1 - (double)msg->elapsed / (double)MESSAGE_SPEED; + case MESSAGE_STATE_HIDING: + msg->scale = 1 - (double)msg->elapsed / (double)msg->delay; if (msg->scale < 0) msg->scale = 0; - if (msg->elapsed >= MESSAGE_SPEED) { - msg->state = MESSAGE_NONE; + if (msg->elapsed >= msg->delay) { + msg->state = MESSAGE_STATE_NONE; msg->elapsed = 0; } @@ -152,53 +201,7 @@ break; } - return msg->state == MESSAGE_NONE; -} - -static void -draw_frame(const struct message *msg) -{ - assert(msg); - - struct frame frame = { - .w = WIDTH, - .h = HEIGHT - }; - - frame_draw(&frame); -} - -static void -draw_lines(const struct message *msg) -{ - struct font *font; - unsigned int lineh; - - font = THEME(msg)->fonts[THEME_FONT_INTERFACE]; - lineh = font_height(font); - - for (int i = 0; i < 6; ++i) { - if (!msg->text[i]) - continue; - - struct label label = { - .x = 10, - .y = 10 + (i * lineh), - .h = lineh, - .theme = msg->theme, - .text = msg->text[i], - .flags = LABEL_NO_HCENTER - }; - - /* - * The function label_draw will normally use - * THEME_FONT_INTERFACE so update its color if needed. - */ - if (msg->flags & MESSAGE_QUESTION && msg->index == (unsigned int)i) - label.color = THEME(msg)->colors[THEME_COLOR_SELECTED]; - - label_draw(&label); - } + return msg->state == MESSAGE_STATE_NONE; } void @@ -207,9 +210,10 @@ assert(msg); struct texture tex; - int x, y, w, h; + int x, y; + unsigned int w, h; - if (!texture_new(&tex, WIDTH, HEIGHT)) + if (!texture_new(&tex, msg->w, msg->h)) panic(); PAINTER_BEGIN(&tex); @@ -218,14 +222,14 @@ PAINTER_END(); /* Compute scaling. */ - w = WIDTH * msg->scale; - h = HEIGHT * msg->scale; + w = msg->w * msg->scale; + h = msg->h * msg->scale; - /* Compute position. */ - x = (window.w / 2) - (w / 2); - y = HEIGHT; + /* Centerize within its drawing area. */ + maths_centerize(&x, &y, w, h, msg->x, msg->y, msg->w, msg->h); - texture_scale(&tex, 0, 0, WIDTH, HEIGHT, x, y, w, h, 0.0); + /* Draw and clear. */ + texture_scale(&tex, 0, 0, msg->w, msg->h, x, y, w, h, 0); texture_finish(&tex); } @@ -234,7 +238,7 @@ { assert(msg); - msg->state = MESSAGE_HIDING; + msg->state = MESSAGE_STATE_HIDING; msg->elapsed = 0; } diff -r 8b035f7f978a -r 453651d76f7c libcore/core/message.h --- a/libcore/core/message.h Tue Oct 13 15:15:40 2020 +0200 +++ b/libcore/core/message.h Tue Oct 13 18:39:35 2020 +0200 @@ -74,22 +74,33 @@ union event; /** + * \brief Default animation speed in milliseconds. + */ +#define MESSAGE_DELAY_DEFAULT (150) + +/** + * \brief Default timeout in milliseconds for automatic messages. + */ +#define MESSAGE_TIMEOUT_DEFAULT (5000) + +/** * \brief Message flags. */ enum message_flags { - MESSAGE_AUTOMATIC = (1 << 0), /*!< Will automatically change state by itself. */ - MESSAGE_QUESTION = (1 << 1), /*!< The message is a question. */ - MESSAGE_QUICK = (1 << 2), /*!< Avoid animations. */ + MESSAGE_FLAGS_AUTOMATIC = (1 << 0), /*!< Will automatically change state by itself. */ + MESSAGE_FLAGS_QUESTION = (1 << 1), /*!< The message is a question. */ + MESSAGE_FLAGS_FADEIN = (1 << 2), /*!< Animate opening. */ + MESSAGE_FLAGS_FADEOUT = (1 << 3) /*!< Animate closing. */ }; /** * \brief Message state. */ enum message_state { - MESSAGE_NONE, /*!< Message hasn't start yet or is finished */ - MESSAGE_OPENING, /*!< Message animation is opening */ - MESSAGE_SHOWING, /*!< Message is displaying */ - MESSAGE_HIDING /*!< Message animation for hiding */ + MESSAGE_STATE_NONE, /*!< Message hasn't start yet or is finished */ + MESSAGE_STATE_OPENING, /*!< Message animation is opening */ + MESSAGE_STATE_SHOWING, /*!< Message is displaying */ + MESSAGE_STATE_HIDING /*!< Message animation for hiding */ }; /** @@ -99,8 +110,13 @@ * any user properties and therefore must exist while using it. */ struct message { + int x; /*!< (RW) Position in x. */ + int y; /*!< (RW) Position in y. */ + unsigned int w; /*!< (RW) Width. */ + unsigned int h; /*!< (RW) Height. */ + unsigned int delay; /*!< (RW) Delay for animations. */ + unsigned int timeout; /*!< (RW) Timeout in milliseconds. */ const char *text[6]; /*!< (RW) Lines of text to show. */ - struct texture *frame; /*!< (RW, ref) Frame to use. */ struct texture *avatar; /*!< (RW, ref, optional) Avatar face. */ unsigned int index; /*!< (RW) Line selected */ enum message_flags flags; /*!< (RW) Message flags */