# HG changeset patch # User David Demelier # Date 1677789403 -3600 # Node ID d49a05e7a5b5e66bba2c19085ea94d345735fd67 # Parent e205625015baace6448eff512e8c5a978f2195d0 ui: separate delegate/style Now UI elements do have different styling properties: - _delegate: functions used to update, draw or perform specific actions on the UI element. - _style: basic properties that the delegate should support if possible. diff -r e205625015ba -r d49a05e7a5b5 examples/example-animation/example-animation.c --- a/examples/example-animation/example-animation.c Thu Mar 02 08:54:00 2023 +0100 +++ b/examples/example-animation/example-animation.c Thu Mar 02 21:36:43 2023 +0100 @@ -39,7 +39,6 @@ .text = "Keys: start or reset the animation.", .x = 10, .y = 10, - .flags = MLK_LABEL_FLAGS_SHADOW }; static struct mlk_state *states[1]; diff -r e205625015ba -r d49a05e7a5b5 examples/example-debug/example-debug.c --- a/examples/example-debug/example-debug.c Thu Mar 02 08:54:00 2023 +0100 +++ b/examples/example-debug/example-debug.c Thu Mar 02 21:36:43 2023 +0100 @@ -27,7 +27,6 @@ #include #include -#include #include #include @@ -72,7 +71,7 @@ struct mlk_debug_report report = {0}; - mlk_painter_set_color(0x4f8fbaff); + mlk_painter_set_color(MLK_EXAMPLE_BG); mlk_painter_clear(); mlk_debugf(&report, "Game running."); mlk_debugf(&report, "mouse: %d, %d", mouse_x, mouse_y); diff -r e205625015ba -r d49a05e7a5b5 examples/example-gridmenu/example-gridmenu.c --- a/examples/example-gridmenu/example-gridmenu.c Thu Mar 02 08:54:00 2023 +0100 +++ b/examples/example-gridmenu/example-gridmenu.c Thu Mar 02 21:36:43 2023 +0100 @@ -38,6 +38,8 @@ #include #include +static void menu_update(struct mlk_gridmenu_delegate *, struct mlk_gridmenu *, unsigned int); + static struct mlk_state *states[8]; static const char * const items[] = { @@ -64,25 +66,35 @@ .w = 300, .h = 100 }; -static struct mlk_gridmenu_style menu_style = { - .padding = 10, - .text_color = 0x222323ff +static struct mlk_gridmenu_style menu_style = {0}; +static struct mlk_gridmenu_delegate menu_delegate = { + .update = menu_update }; static struct mlk_gridmenu menu = { .nrows = 3, .ncols = 2, .items = items, .itemsz = MLK_UTIL_SIZE(items), - .style = &menu_style + .style = &menu_style, + .delegate = &menu_delegate }; static struct mlk_glower menu_glower = { - .color = &menu_style.text_selected_color, .start = 0x00bfa3ff, .end = 0x006b6dff, .delay = 20 }; static void +menu_update(struct mlk_gridmenu_delegate *delegate, struct mlk_gridmenu *menu, unsigned int ticks) +{ + (void)delegate; + (void)menu; + + mlk_glower_update(&menu_glower, ticks); + menu_style.selected_color = menu_glower.color; +} + +static void init(void) { int err; @@ -90,6 +102,7 @@ if ((err = mlk_example_init("example-gridmenu")) < 0) mlk_panicf("mlk_example_init: %s", mlk_err_string(err)); + menu_style = mlk_gridmenu_style; mlk_glower_init(&menu_glower); } @@ -139,7 +152,6 @@ .draw = draw, }; - mlk_gridmenu_init(&menu); mlk_gridmenu_resize(&menu, 0, 0, 300, 100); mlk_align(MLK_ALIGN_CENTER, &menu.x, &menu.y, menu.w, menu.h, 0, 0, mlk_window.w, mlk_window.h); diff -r e205625015ba -r d49a05e7a5b5 examples/example-label/example-label.c --- a/examples/example-label/example-label.c Thu Mar 02 08:54:00 2023 +0100 +++ b/examples/example-label/example-label.c Thu Mar 02 21:36:43 2023 +0100 @@ -31,77 +31,115 @@ #include #include -#include #include #include +#include -struct { +static struct mlk_state *states[8]; + +static struct mlk_label_style style = { + .color = 0x005162ff +}; + +/* + * Add a glower effect to the main label in the middle. + */ +static void main_update(struct mlk_label_delegate *, struct mlk_label *, unsigned int); + +static struct mlk_glower main_glower = { + .start = 0xffce7fff, + .end = 0xd58d6bff, + .delay = 22 +}; +static struct mlk_label_delegate main_delegate = { + .update = main_update +}; +static struct mlk_label_style main_style; + +static struct { enum mlk_align align; struct mlk_label label; } table[] = { { + .align = MLK_ALIGN_CENTER, + .label = { + .text = "The world is Malikania.", + .style = &main_style, + .delegate = &main_delegate + } + }, + { .align = MLK_ALIGN_TOP_LEFT, .label = { - .text = "Top left" + .text = "Top left", + .style = &style } }, { .align = MLK_ALIGN_TOP, .label = { .text = "Top", + .style = &style } }, { .align = MLK_ALIGN_TOP_RIGHT, .label = { .text = "Top right", + .style = &style } }, { .align = MLK_ALIGN_RIGHT, .label = { .text = "Right", + .style = &style } }, { .align = MLK_ALIGN_BOTTOM_RIGHT, .label = { .text = "Bottom right", + .style = &style } }, { .align = MLK_ALIGN_BOTTOM, .label = { .text = "Bottom", + .style = &style } }, { .align = MLK_ALIGN_BOTTOM_LEFT, .label = { .text = "Bottom left", + .style = &style } }, { .align = MLK_ALIGN_LEFT, .label = { .text = "Left", - } - }, - { - .align = MLK_ALIGN_CENTER, - .label = { - .text = "The world is Malikania.", - .flags = MLK_LABEL_FLAGS_SHADOW + .style = &style } } }; -static struct mlk_label mlabel = { - .text = "This one follows your mouse and is not aligned." +static struct mlk_label mouse_label = { + .text = "This one follows your mouse and is not aligned.", + .style = &style }; -static struct mlk_state *states[1]; +static void +main_update(struct mlk_label_delegate *delegate, struct mlk_label *label, unsigned int ticks) +{ + (void)delegate; + + mlk_glower_update(&main_glower, ticks); + label->style->color = main_glower.color; +} static void init(void) @@ -115,10 +153,11 @@ for (size_t i = 0; i < MLK_UTIL_SIZE(table); ++i) { l = &table[i].label; - mlk_label_query(l, &w, &h); mlk_align(table[i].align, &l->x, &l->y, w, h, 0, 0, mlk_window.w, mlk_window.h); } + + mlk_glower_init(&main_glower); } static void @@ -128,8 +167,8 @@ switch (ev->type) { case MLK_EVENT_MOUSE: - mlabel.x = ev->mouse.x; - mlabel.y = ev->mouse.y; + mouse_label.x = ev->mouse.x; + mouse_label.y = ev->mouse.y; break; case MLK_EVENT_QUIT: mlk_game_quit(); @@ -140,17 +179,28 @@ } static void +update(struct mlk_state *st, unsigned int ticks) +{ + (void)st; + + for (size_t i = 0; i < MLK_UTIL_SIZE(table); ++i) + mlk_label_update(&table[i].label, ticks); + + mlk_label_update(&mouse_label, ticks); +} + +static void draw(struct mlk_state *st) { (void)st; - mlk_painter_set_color(0x4f8fbaff); + mlk_painter_set_color(MLK_EXAMPLE_BG); mlk_painter_clear(); for (size_t i = 0; i < MLK_UTIL_SIZE(table); ++i) mlk_label_draw(&table[i].label); - mlk_label_draw(&mlabel); + mlk_label_draw(&mouse_label); mlk_painter_present(); } @@ -159,6 +209,7 @@ { struct mlk_state state = { .handle = handle, + .update = update, .draw = draw }; diff -r e205625015ba -r d49a05e7a5b5 examples/example-ui/CMakeLists.txt --- a/examples/example-ui/CMakeLists.txt Thu Mar 02 08:54:00 2023 +0100 +++ b/examples/example-ui/CMakeLists.txt Thu Mar 02 21:36:43 2023 +0100 @@ -20,8 +20,8 @@ set( SOURCES - ${example-ui_SOURCE_DIR}/button-style-glow.c - ${example-ui_SOURCE_DIR}/button-style-glow.h + ${example-ui_SOURCE_DIR}/button-glower.c + ${example-ui_SOURCE_DIR}/button-glower.h ${example-ui_SOURCE_DIR}/example-ui.c ) diff -r e205625015ba -r d49a05e7a5b5 examples/example-ui/button-glower.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-ui/button-glower.c Thu Mar 02 21:36:43 2023 +0100 @@ -0,0 +1,48 @@ +/* + * button-style-glow.c -- example of glowing button + * + * Copyright (c) 2020-2023 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 "button-glower.h" + +static void +update(struct mlk_button_delegate *delegate, struct mlk_button *button, unsigned int ticks) +{ + (void)button; + + struct button_glower *glower = delegate->data; + + mlk_glower_update(&glower->glower, ticks); + glower->style.bg_color = glower->glower.color; +} + +void +button_glower_init(struct button_glower *glower, struct mlk_button *button) +{ + assert(glower); + + glower->style.bg_color = glower->glower.start; + glower->delegate.data = glower; + glower->delegate.update = update; + + /* Link this style and delegate to the button. */ + button->style = &glower->style; + button->delegate = &glower->delegate; + + mlk_glower_init(&glower->glower); +} diff -r e205625015ba -r d49a05e7a5b5 examples/example-ui/button-glower.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-ui/button-glower.h Thu Mar 02 21:36:43 2023 +0100 @@ -0,0 +1,39 @@ +/* + * button-style-glow.h -- example of glowing button + * + * Copyright (c) 2020-2023 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. + */ + +#ifndef MLK_EXAMPLE_UI_BUTTON_GLOWER_H +#define MLK_EXAMPLE_UI_BUTTON_GLOWER_H + +#include + +#include + +#define BUTTON_STYLE_GLOW_COLOR_1 0x7da42dff +#define BUTTON_STYLE_GLOW_COLOR_2 0xa6cc34ff +#define BUTTON_STYLE_GLOW_DELAY 20 + +struct button_glower { + struct mlk_glower glower; + struct mlk_button_style style; + struct mlk_button_delegate delegate; +}; + +void +button_glower_init(struct button_glower *glower, struct mlk_button *button); + +#endif /* !MLK_EXAMPLE_UI_BUTTON_GLOWER_H */ diff -r e205625015ba -r d49a05e7a5b5 examples/example-ui/button-style-glow.c --- a/examples/example-ui/button-style-glow.c Thu Mar 02 08:54:00 2023 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * button-style-glow.c -- example of glowing button - * - * Copyright (c) 2020-2023 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 "button-style-glow.h" - -/* - * This button style illuminates the background color by periodically changing - * its red, green, blue components to the target color and then go back to the - * original transition. - * - * Its sole purpose is to demonstrates how style works. Because the style needs - * a state it is implemented through a parent button_style_glow structure which - * holds an underlying style. - * - * This style does not override the glow function because we just change the - * bg_color property that will be reused. - */ - -static void -init(struct mlk_button_style *style, struct mlk_button *button) -{ - (void)button; - - struct button_style_glow *styler = style->data; - - styler->glow->color = &style->bg_color; - - mlk_glower_init(styler->glow); -} - -static void -update(struct mlk_button_style *style, struct mlk_button *button, unsigned int ticks) -{ - (void)button; - - struct button_style_glow *styler = style->data; - - mlk_glower_update(styler->glow, ticks); -} - -void -button_style_glow_init(struct button_style_glow *styler) -{ - assert(styler); - assert(styler->glow); - - styler->style.data = styler; - styler->style.init = init; - styler->style.update = update; -} diff -r e205625015ba -r d49a05e7a5b5 examples/example-ui/button-style-glow.h --- a/examples/example-ui/button-style-glow.h Thu Mar 02 08:54:00 2023 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * button-style-glow.h -- example of glowing button - * - * Copyright (c) 2020-2023 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. - */ - -#ifndef MLK_EXAMPLE_BUTTON_STYLE_H -#define MLK_EXAMPLE_BUTTON_STYLE_H - -#include - -#define BUTTON_STYLE_GLOW_COLOR_1 0x7da42dff -#define BUTTON_STYLE_GLOW_COLOR_2 0xa6cc34ff -#define BUTTON_STYLE_GLOW_DELAY 20 - -struct mlk_glower; - -struct button_style_glow { - struct mlk_glower *glow; - struct mlk_button_style style; -}; - -void -button_style_glow_init(struct button_style_glow *); - -#endif /* !MLK_EXAMPLE_BUTTON_GLOW_STYLE_H */ diff -r e205625015ba -r d49a05e7a5b5 examples/example-ui/example-ui.c --- a/examples/example-ui/example-ui.c Thu Mar 02 08:54:00 2023 +0100 +++ b/examples/example-ui/example-ui.c Thu Mar 02 21:36:43 2023 +0100 @@ -41,7 +41,7 @@ #include #include -#include "button-style-glow.h" +#include "button-glower.h" #define FRAME_ORIGIN_X (10) #define FRAME_ORIGIN_Y (10) @@ -54,6 +54,8 @@ #define PADDING (10) +static struct mlk_state *states[8]; + /* * We design a basic UI like this. * @@ -92,15 +94,13 @@ struct mlk_button hello; /* [Quit] with custom style color. */ - struct mlk_label_style quit_text_style; struct mlk_button_style quit_style; struct mlk_button quit; /* - * [Download free RAM] with custom style drawing. + * [Download free RAM] with custom style using a delegate. */ - struct mlk_glower download_glow; - struct button_style_glow download_style; + struct button_glower download_glower; struct mlk_button download; } buttons; } ui = { @@ -135,40 +135,33 @@ }, .quit_style = { .bg_color = 0x24aed6ff, - .border_color = 0x328ca7ff - }, - .quit_text_style = { - .text_color = 0xf5f7faff + .text_color = 0xffffffff }, .quit = { .text = "Quit", .h = ELEMENT_HEIGHT, - .style = &ui.buttons.quit_style, - .text_style = &ui.buttons.quit_text_style + .style = &ui.buttons.quit_style }, - .download_glow = { - .start = BUTTON_STYLE_GLOW_COLOR_1, - .end = BUTTON_STYLE_GLOW_COLOR_2, - .delay = BUTTON_STYLE_GLOW_DELAY - }, - .download_style = { - .glow = &ui.buttons.download_glow, + .download_glower = { + .glower = { + .start = BUTTON_STYLE_GLOW_COLOR_1, + .end = BUTTON_STYLE_GLOW_COLOR_2, + .delay = BUTTON_STYLE_GLOW_DELAY + }, .style = { - .border_color = BUTTON_STYLE_GLOW_COLOR_1 + .text_color = 0xffffffff, + .border_color = BUTTON_STYLE_GLOW_COLOR_1, + .border_size = 2 } }, .download = { .w = 180, .h = 32, .text = "!! Download free RAM !!", - .style = &ui.buttons.download_style.style, - .text_style = &ui.buttons.quit_text_style } } }; -static struct mlk_state *states[1]; - static void resize_header(void) { @@ -333,11 +326,7 @@ if ((err = mlk_example_init("example-ui")) < 0) mlk_panicf("mlk_example_init: %s", mlk_err_string(err)); - button_style_glow_init(&ui.buttons.download_style); - - mlk_button_init(&ui.buttons.hello); - mlk_button_init(&ui.buttons.quit); - mlk_button_init(&ui.buttons.download); + button_glower_init(&ui.buttons.download_glower, &ui.buttons.download); } static void diff -r e205625015ba -r d49a05e7a5b5 libmlk-example/mlk/example/glower.c --- a/libmlk-example/mlk/example/glower.c Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-example/mlk/example/glower.c Thu Mar 02 21:36:43 2023 +0100 @@ -37,9 +37,8 @@ mlk_glower_init(struct mlk_glower *glow) { assert(glow); - assert(glow->color); - *glow->color = glow->start; + glow->color = glow->start; glow->target = glow->end; } @@ -56,14 +55,14 @@ glow->elapsed = 0; /* Color target reached, invert target color. */ - if (*glow->color == glow->target) + if (glow->color == glow->target) glow->target = glow->target == glow->start ? glow->end : glow->start; else { - r = increment(MLK_COLOR_R(*glow->color), MLK_COLOR_R(glow->target)); - g = increment(MLK_COLOR_G(*glow->color), MLK_COLOR_G(glow->target)); - b = increment(MLK_COLOR_B(*glow->color), MLK_COLOR_B(glow->target)); + r = increment(MLK_COLOR_R(glow->color), MLK_COLOR_R(glow->target)); + g = increment(MLK_COLOR_G(glow->color), MLK_COLOR_G(glow->target)); + b = increment(MLK_COLOR_B(glow->color), MLK_COLOR_B(glow->target)); - *glow->color = MLK_COLOR_HEX(r, g, b, 0xff); + glow->color = MLK_COLOR_HEX(r, g, b, 0xff); } } } diff -r e205625015ba -r d49a05e7a5b5 libmlk-example/mlk/example/glower.h --- a/libmlk-example/mlk/example/glower.h Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-example/mlk/example/glower.h Thu Mar 02 21:36:43 2023 +0100 @@ -23,7 +23,7 @@ /* public */ unsigned long start; unsigned long end; - unsigned long *color; + unsigned long color; unsigned int delay; /* private */ diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/CMakeLists.txt --- a/libmlk-ui/CMakeLists.txt Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/CMakeLists.txt Thu Mar 02 21:36:43 2023 +0100 @@ -38,6 +38,7 @@ ${libmlk-ui_SOURCE_DIR}/mlk/ui/notify.h ${libmlk-ui_SOURCE_DIR}/mlk/ui/ui.c ${libmlk-ui_SOURCE_DIR}/mlk/ui/ui.h + ${libmlk-ui_SOURCE_DIR}/mlk/ui/ui_p.h ) set( diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/align.c --- a/libmlk-ui/mlk/ui/align.c Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/align.c Thu Mar 02 21:36:43 2023 +0100 @@ -23,14 +23,14 @@ void mlk_align(enum mlk_align align, - int *x, - int *y, - unsigned int w, - unsigned int h, - int px, - int py, - unsigned int pw, - unsigned int ph) + int *x, + int *y, + unsigned int w, + unsigned int h, + int px, + int py, + unsigned int pw, + unsigned int ph) { switch (align) { case MLK_ALIGN_CENTER: @@ -70,6 +70,8 @@ SET(x, px); break; default: + *x = px; + *y = py; break; } } diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/align.h --- a/libmlk-ui/mlk/ui/align.h Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/align.h Thu Mar 02 21:36:43 2023 +0100 @@ -22,6 +22,7 @@ #include enum mlk_align { + MLK_ALIGN_NONE, MLK_ALIGN_CENTER, MLK_ALIGN_TOP_LEFT, MLK_ALIGN_TOP, @@ -37,14 +38,14 @@ void mlk_align(enum mlk_align, - int *, - int *, - unsigned int, - unsigned int, - int, - int, - unsigned int, - unsigned int); + int *, + int *, + unsigned int, + unsigned int, + int, + int, + unsigned int, + unsigned int); MLK_CORE_END_DECLS diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/button.c --- a/libmlk-ui/mlk/ui/button.c Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/button.c Thu Mar 02 21:36:43 2023 +0100 @@ -26,41 +26,8 @@ #include "align.h" #include "button.h" -#include "label.h" - -#define STYLE_INVOKE(s, f, ...) \ -do { \ - if (s && s->f) \ - s->f(s, __VA_ARGS__); \ - else if (mlk_button_style.f) \ - mlk_button_style.f(s ? s : &mlk_button_style, __VA_ARGS__); \ -} while (0) - -static void -draw(struct mlk_button_style *style, const struct mlk_button *button) -{ - struct mlk_label label = { - .text = button->text, - .style = button->text_style - }; - unsigned int lw, lh; - - mlk_label_query(&label, &lw, &lh); - - if (lw > button->w) - mlk_tracef("button width is too small for text: %u < %u", button->w, lw); - if (lh > button->h) - mlk_tracef("button height is too small for text: %u < %u", button->h, lh); - - mlk_align(MLK_ALIGN_CENTER, &label.x, &label.y, lw, lh, - button->x, button->y, button->w, button->h); - - mlk_painter_set_color(style->border_color); - mlk_painter_draw_rectangle(button->x, button->y, button->w, button->h); - mlk_painter_set_color(style->bg_color); - mlk_painter_draw_rectangle(button->x + 1, button->y + 1, button->w - 2, button->h - 2); - mlk_label_draw(&label); -} +#include "ui.h" +#include "ui_p.h" static inline int is_boxed(const struct mlk_button *button, const struct mlk_event_click *click) @@ -73,18 +40,75 @@ click->x, click->y); } +static inline struct mlk_font * +style_font(const struct mlk_button *button) +{ + const struct mlk_button_style *style = MLK__STYLE(button, mlk_button_style); + + if (style->text_font) + return style->text_font; + + return mlk_ui_fonts[MLK_UI_FONT_INTERFACE]; +} + +static void +delegate_draw_frame(struct mlk_button_delegate *delegate, const struct mlk_button *button) +{ + (void)delegate; + + const struct mlk_button_style *style = MLK__STYLE(button, mlk_button_style); + + mlk_painter_set_color(style->border_color); + mlk_painter_draw_rectangle(button->x, button->y, button->w, button->h); + mlk_painter_set_color(style->bg_color); + mlk_painter_draw_rectangle( + button->x + style->border_size, + button->y + style->border_size, + button->w - (style->border_size * 2), + button->h - (style->border_size * 2) + ); +} + +static void +delegate_draw_text(struct mlk_button_delegate *delegate, const struct mlk_button *button) +{ + (void)delegate; + + const struct mlk_button_style *style = MLK__STYLE(button, mlk_button_style); + + mlk_ui_draw_text( + MLK_ALIGN_CENTER, + style_font(button), + style->text_color, + button->text, + button->x, + button->y, + button->w, + button->h + ); +} + struct mlk_button_style mlk_button_style = { - .bg_color = 0xebf0f6ff, - .border_color = 0xbac7dbff, - .draw = draw + .bg_color = MLK_UI_COLOR_BG, + .text_color = MLK_UI_COLOR_TEXT, + .border_color = MLK_UI_COLOR_BORDER, + .border_size = 1 }; -void -mlk_button_init(struct mlk_button *button) +struct mlk_button_delegate mlk_button_delegate = { + .draw_frame = delegate_draw_frame, + .draw_text = delegate_draw_text +}; + +int +mlk_button_ok(const struct mlk_button *button) { - assert(button); + if (!button) + return 0; + if (button->text && strlen(button->text) == 0) + return 0; - STYLE_INVOKE(button->style, init, button); + return 1; } int @@ -123,7 +147,7 @@ { assert(button); - STYLE_INVOKE(button->style, update, button, ticks); + MLK__DELEGATE_INVOKE(button->delegate, mlk_button_delegate, update, button, ticks); } void @@ -131,13 +155,8 @@ { assert(button); - STYLE_INVOKE(button->style, draw, button); -} + MLK__DELEGATE_INVOKE(button->delegate, mlk_button_delegate, draw_frame, button); -void -mlk_button_finish(struct mlk_button *button) -{ - assert(button); - - STYLE_INVOKE(button->style, finish, button); + if (button->text) + MLK__DELEGATE_INVOKE(button->delegate, mlk_button_delegate, draw_text, button); } diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/button.h --- a/libmlk-ui/mlk/ui/button.h Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/button.h Thu Mar 02 21:36:43 2023 +0100 @@ -24,34 +24,39 @@ union mlk_event; struct mlk_button; -struct mlk_label_style; -struct mlk_theme; +struct mlk_font; struct mlk_button_style { - void *data; unsigned long bg_color; unsigned long border_color; - void (*init)(struct mlk_button_style *, struct mlk_button *); - void (*update)(struct mlk_button_style *, struct mlk_button *, unsigned int); - void (*draw)(struct mlk_button_style *, const struct mlk_button *); - void (*finish)(struct mlk_button_style *, struct mlk_button *); + unsigned long border_size; + unsigned long text_color; + struct mlk_font *text_font; +}; + +struct mlk_button_delegate { + void *data; + void (*update)(struct mlk_button_delegate *delegate, struct mlk_button *button, unsigned int ticks); + void (*draw_frame)(struct mlk_button_delegate *delegate, const struct mlk_button *button); + void (*draw_text)(struct mlk_button_delegate *delegate, const struct mlk_button *button); }; struct mlk_button { int x, y; unsigned int w, h; const char *text; + int pressed; struct mlk_button_style *style; - struct mlk_label_style *text_style; - int pressed; + struct mlk_button_delegate *delegate; }; extern struct mlk_button_style mlk_button_style; +extern struct mlk_button_delegate mlk_button_delegate; MLK_CORE_BEGIN_DECLS -void -mlk_button_init(struct mlk_button *); +int +mlk_button_ok(const struct mlk_button *); int mlk_button_handle(struct mlk_button *, const union mlk_event *); @@ -62,9 +67,6 @@ void mlk_button_draw(const struct mlk_button *); -void -mlk_button_finish(struct mlk_button *); - MLK_CORE_END_DECLS #endif /* !MLK_UI_BUTTON_H */ diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/checkbox.c --- a/libmlk-ui/mlk/ui/checkbox.c Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/checkbox.c Thu Mar 02 21:36:43 2023 +0100 @@ -23,16 +23,9 @@ #include #include -#include "label.h" #include "checkbox.h" - -#define STYLE_INVOKE(s, f, ...) \ -do { \ - if (s && s->f) \ - s->f(s, __VA_ARGS__); \ - else if (mlk_checkbox_style.f) \ - mlk_checkbox_style.f(s ? s : &mlk_checkbox_style, __VA_ARGS__); \ -} while (0) +#include "ui.h" +#include "ui_p.h" static int is_boxed(const struct mlk_checkbox *cb, const struct mlk_event_click *click) @@ -44,12 +37,26 @@ } static void -draw(struct mlk_checkbox_style *style, const struct mlk_checkbox *cb) +draw(struct mlk_checkbox_delegate *delegate, const struct mlk_checkbox *cb) { - mlk_painter_set_color(style->border_color); - mlk_painter_draw_rectangle(cb->x, cb->y, cb->w, cb->h); - mlk_painter_set_color(style->bg_color); - mlk_painter_draw_rectangle(cb->x + 1, cb->y + 1, cb->w - 2, cb->h - 2); + (void)delegate; + + const struct mlk_checkbox_style *style = MLK__STYLE(cb, mlk_checkbox_style); + + if (!style->border_size) { + mlk_painter_set_color(style->bg_color); + mlk_painter_draw_rectangle(cb->x, cb->y, cb->w, cb->h); + } else { + mlk_painter_set_color(style->border_color); + mlk_painter_draw_rectangle(cb->x, cb->y, cb->w, cb->h); + mlk_painter_set_color(style->bg_color); + mlk_painter_draw_rectangle( + cb->x + style->border_size, + cb->y + style->border_size, + cb->w - (style->border_size * 2), + cb->h - (style->border_size * 2) + ); + } if (cb->checked) { mlk_painter_set_color(style->check_color); @@ -58,24 +65,26 @@ } struct mlk_checkbox_style mlk_checkbox_style = { - .bg_color = 0xebf0f6ff, - .border_color = 0xbac7dbff, - .check_color = 0x848795ff, - .draw = draw + .bg_color = MLK_UI_COLOR_BG, + .check_color = MLK_UI_COLOR_TEXT, + .border_color = MLK_UI_COLOR_BORDER, + .border_size = 1 }; -void -mlk_checkbox_init(struct mlk_checkbox *cb) +struct mlk_checkbox_delegate mlk_checkbox_delegate = { + .draw = draw +}; + +int +mlk_checkbox_ok(const struct mlk_checkbox *cb) { - assert(cb); - - STYLE_INVOKE(cb->style, init, cb); + return cb != NULL; } int mlk_checkbox_handle(struct mlk_checkbox *cb, const union mlk_event *ev) { - assert(cb); + assert(mlk_checkbox_ok(cb)); assert(ev); switch (ev->type) { @@ -91,18 +100,17 @@ } void -mlk_checkbox_draw(const struct mlk_checkbox *cb) +mlk_checkbox_update(struct mlk_checkbox *cb, unsigned int ticks) { - assert(cb); + assert(mlk_checkbox_ok(cb)); - STYLE_INVOKE(cb->style, draw, cb); + MLK__DELEGATE_INVOKE(cb->delegate, mlk_checkbox_delegate, update, cb, ticks); } void -mlk_checkbox_finish(struct mlk_checkbox *cb) +mlk_checkbox_draw(const struct mlk_checkbox *cb) { - assert(cb); + assert(mlk_checkbox_ok(cb)); - STYLE_INVOKE(cb->style, finish, cb); - + MLK__DELEGATE_INVOKE(cb->delegate, mlk_checkbox_delegate, draw, cb); } diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/checkbox.h --- a/libmlk-ui/mlk/ui/checkbox.h Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/checkbox.h Thu Mar 02 21:36:43 2023 +0100 @@ -26,40 +26,42 @@ struct mlk_checkbox; struct mlk_checkbox_style { - void *data; unsigned long bg_color; - unsigned long border_color; unsigned long check_color; - void (*init)(struct mlk_checkbox_style *, struct mlk_checkbox *); - void (*update)(struct mlk_checkbox_style *, struct mlk_checkbox *, unsigned int); - void (*draw)(struct mlk_checkbox_style *, const struct mlk_checkbox *); - void (*finish)(struct mlk_checkbox_style *, struct mlk_checkbox *); + unsigned long border_color; + unsigned int border_size; +}; + +struct mlk_checkbox_delegate { + void *data; + void (*update)(struct mlk_checkbox_delegate *, struct mlk_checkbox *, unsigned int); + void (*draw)(struct mlk_checkbox_delegate *, const struct mlk_checkbox *); }; struct mlk_checkbox { - int x; - int y; - unsigned int w; - unsigned int h; + int x, y; + unsigned int w, h; int checked; + struct mlk_checkbox_delegate *delegate; struct mlk_checkbox_style *style; }; extern struct mlk_checkbox_style mlk_checkbox_style; +extern struct mlk_checkbox_delegate mlk_checkbox_delegate; MLK_CORE_BEGIN_DECLS -void -mlk_checkbox_init(struct mlk_checkbox *); +int +mlk_checkbox_ok(const struct mlk_checkbox *cb); int mlk_checkbox_handle(struct mlk_checkbox *, const union mlk_event *); void -mlk_checkbox_draw(const struct mlk_checkbox *); +mlk_checkbox_update(struct mlk_checkbox *cb, unsigned int ticks); void -mlk_checkbox_finish(struct mlk_checkbox *); +mlk_checkbox_draw(const struct mlk_checkbox *); MLK_CORE_END_DECLS diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/debug.c --- a/libmlk-ui/mlk/ui/debug.c Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/debug.c Thu Mar 02 21:36:43 2023 +0100 @@ -22,6 +22,7 @@ #include #include "debug.h" +#include "ui.h" struct mlk_debug_options mlk_debug_options = { #if !defined(NDEBUG) @@ -48,32 +49,30 @@ void mlk_debugva(struct mlk_debug_report *report, const char *fmt, va_list ap) { -#if 0 assert(report); assert(fmt); - if (!mlk_debug_options.enable) - return; - char line[MLK_DEBUG_LINE_MAX]; - const struct mlk_theme *theme; struct mlk_font *font; struct mlk_texture tex; int x, y; + if (!mlk_debug_options.enable) + return; + vsnprintf(line, sizeof (line), fmt, ap); - theme = &mlk_theme; - font = theme->fonts[MLK_THEME_FONT_DEBUG]; + // TODO: add style support. + font = mlk_ui_fonts[MLK_UI_FONT_INTERFACE]; - if (mlk_font_render(font, &tex, line, MLK_THEME_COLOR_DEBUG) < 0) + if (mlk_font_render(font, &tex, line, MLK_UI_COLOR_DEBUG) < 0) return; - x = theme->padding; - y = (theme->padding * (report->count + 1)) + (tex.h * (report->count)); + // TODO: same here. + x = 10; + y = (10 * (report->count + 1)) + (tex.h * (report->count)); report->count++; mlk_texture_draw(&tex, x, y); mlk_texture_finish(&tex); -#endif } diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/debug.h --- a/libmlk-ui/mlk/ui/debug.h Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/debug.h Thu Mar 02 21:36:43 2023 +0100 @@ -33,7 +33,6 @@ }; struct mlk_debug_report { - const struct mlk_theme *theme; unsigned int count; }; @@ -44,7 +43,6 @@ void mlk_debugf(struct mlk_debug_report *, const char *, ...); - void mlk_debugva(struct mlk_debug_report *, const char *, va_list); diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/frame.c --- a/libmlk-ui/mlk/ui/frame.c Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/frame.c Thu Mar 02 21:36:43 2023 +0100 @@ -17,40 +17,54 @@ */ #include +#include #include #include "frame.h" - -#define STYLE_INVOKE(s, f, ...) \ -do { \ - if (s && s->f) \ - s->f(s, __VA_ARGS__); \ - else if (mlk_frame_style.f) \ - mlk_frame_style.f(s ? s : &mlk_frame_style, __VA_ARGS__); \ -} while (0) +#include "ui.h" +#include "ui_p.h" static void -draw(struct mlk_frame_style *style, const struct mlk_frame *frame) +delegate_draw(struct mlk_frame_delegate *delegate, const struct mlk_frame *frame) { + (void)delegate; + + const struct mlk_frame_style *style = MLK__STYLE(frame, mlk_frame_style); + mlk_painter_set_color(style->border_color); mlk_painter_draw_rectangle(frame->x, frame->y, frame->w, frame->h); mlk_painter_set_color(style->bg_color); - mlk_painter_draw_rectangle(frame->x + 1, frame->y + 1, frame->w - 2, frame->h - 2); + mlk_painter_draw_rectangle( + frame->x + style->border_size, + frame->y + style->border_size, + frame->w - (style->border_size * 2), + frame->h - (style->border_size * 2) + ); } struct mlk_frame_style mlk_frame_style = { - .bg_color = 0xf5f7faff, - .border_color = 0xcdd2daff, - .draw = draw + .bg_color = MLK_UI_COLOR_BG, + .border_color = MLK_UI_COLOR_BORDER, + .border_size = 2 +}; + +struct mlk_frame_delegate mlk_frame_delegate = { + .draw = delegate_draw }; +int +mlk_frame_ok(const struct mlk_frame *frame) +{ + return frame != NULL; +} + void -mlk_frame_init(struct mlk_frame *frame) +mlk_frame_update(struct mlk_frame *frame, unsigned int ticks) { assert(frame); - STYLE_INVOKE(frame->style, init, frame); + MLK__DELEGATE_INVOKE(frame->delegate, mlk_frame_delegate, update, frame, ticks); } void @@ -58,13 +72,5 @@ { assert(frame); - STYLE_INVOKE(frame->style, draw, frame); + MLK__DELEGATE_INVOKE(frame->delegate, mlk_frame_delegate, draw, frame); } - -void -mlk_frame_finish(struct mlk_frame *frame) -{ - assert(frame); - - STYLE_INVOKE(frame->style, finish, frame); -} diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/frame.h --- a/libmlk-ui/mlk/ui/frame.h Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/frame.h Thu Mar 02 21:36:43 2023 +0100 @@ -26,30 +26,35 @@ struct mlk_frame_style { unsigned long bg_color; unsigned long border_color; - void (*init)(struct mlk_frame_style *, struct mlk_frame *); - void (*update)(struct mlk_frame_style *, struct mlk_frame *, unsigned int); - void (*draw)(struct mlk_frame_style *, const struct mlk_frame *); - void (*finish)(struct mlk_frame_style *, struct mlk_frame *); + unsigned long border_size; +}; + +struct mlk_frame_delegate { + void *data; + void (*update)(struct mlk_frame_delegate *, struct mlk_frame *, unsigned int); + void (*draw)(struct mlk_frame_delegate *, const struct mlk_frame *); }; struct mlk_frame { int x, y; unsigned int w, h; struct mlk_frame_style *style; + struct mlk_frame_delegate *delegate; }; extern struct mlk_frame_style mlk_frame_style; +extern struct mlk_frame_delegate mlk_frame_delegate; MLK_CORE_BEGIN_DECLS -void -mlk_frame_init(struct mlk_frame *); +int +mlk_frame_ok(const struct mlk_frame *frame); void -mlk_frame_draw(const struct mlk_frame *); +mlk_frame_update(struct mlk_frame *frame, unsigned int ticks); void -mlk_frame_finish(struct mlk_frame *); +mlk_frame_draw(const struct mlk_frame *frame); MLK_CORE_END_DECLS diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/gridmenu.c --- a/libmlk-ui/mlk/ui/gridmenu.c Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/gridmenu.c Thu Mar 02 21:36:43 2023 +0100 @@ -30,16 +30,7 @@ #include "gridmenu.h" #include "ui.h" - -#define STYLE_INVOKE(s, f, ...) \ -do { \ - if (s && s->f) \ - s->f(s, __VA_ARGS__); \ - else if (mlk_gridmenu_style.f) \ - mlk_gridmenu_style.f(s ? s : &mlk_gridmenu_style, __VA_ARGS__); \ -} while (0) - -#define STYLE_GET(s, p) (s ? s->p : mlk_gridmenu_style.p) +#include "ui_p.h" struct index { unsigned int row; @@ -67,12 +58,15 @@ static void geometry(struct mlk_gridmenu *menu) { + const struct mlk_gridmenu_style *style; 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; + style = MLK__STYLE(menu, mlk_gridmenu_style); + for (size_t i = 0; i < menu->itemsz; ++i) { if (!(menu->items[i])) continue; @@ -84,8 +78,8 @@ } /* Total texture size required to draw items. */ - reqw = (STYLE_GET(menu->style, padding) * 3) + (menu->eltw * menu->ncols); - reqh = (STYLE_GET(menu->style, padding) * 3) + (menu->elth * menu->nrows); + reqw = (style->padding * 3) + (menu->eltw * menu->ncols); + reqh = (style->padding * 3) + (menu->elth * menu->nrows); /* * Compute spacing between elements. We remove the padding because it @@ -95,7 +89,7 @@ mlk_tracef("gridmenu width is too small: %u < %u", menu->w, reqw); menu->spacew = 1; } else if (menu->ncols > 1) { - reqw -= STYLE_GET(menu->style, padding) * 2; + reqw -= style->padding * 2; menu->spacew = (menu->w - reqw) / menu->ncols; } @@ -103,7 +97,7 @@ mlk_tracef("gridmenu height is too small: %u < %u", menu->h, reqh); menu->spaceh = 1; } else if (menu->nrows > 1) { - reqh -= STYLE_GET(menu->style, padding) * 2; + reqh -= style->padding * 2; menu->spaceh = (menu->h - reqh) / menu->nrows; } } @@ -150,15 +144,17 @@ { assert(click->type == MLK_EVENT_CLICKDOWN); + const struct mlk_gridmenu_style *style; size_t pagesz, pagenr, selected, c = 0, r = 0; int x, y; + style = MLK__STYLE(menu, mlk_gridmenu_style); pagesz = menu->nrows * menu->ncols; pagenr = menu->selected / pagesz; for (size_t i = 0; i < pagesz; ++i) { - x = (int)(menu->x + STYLE_GET(menu->style, padding) + (c * menu->eltw) + (c * menu->spacew)); - y = (int)(menu->y + STYLE_GET(menu->style, padding) + (r * menu->elth) + (r * menu->spaceh)); + x = (int)(menu->x + style->padding + (c * menu->eltw) + (c * menu->spacew)); + y = (int)(menu->y + style->padding + (r * menu->elth) + (r * menu->spaceh)); if (mlk_maths_is_boxed(x, y, menu->eltw, menu->elth, click->x, click->y)) { selected = c + r * menu->ncols; @@ -180,9 +176,10 @@ } static void -draw(struct mlk_gridmenu_style *style, const struct mlk_gridmenu *menu) +draw(struct mlk_gridmenu_delegate *delegate, const struct mlk_gridmenu *menu) { size_t pagesz, pagenr, item, c = 0, r = 0; + const struct mlk_gridmenu_style *style; struct mlk_texture tex; struct mlk_font *font; unsigned long color; @@ -195,6 +192,7 @@ pagesz = menu->nrows * menu->ncols; pagenr = menu->selected / pagesz; + style = MLK__STYLE(menu, mlk_gridmenu_style); font = style_font(menu->style); for (size_t i = 0; i < pagesz; ++i) { @@ -203,13 +201,13 @@ if (item >= menu->itemsz || !menu->items[item]) continue; - x = (int)(menu->x + STYLE_GET(menu->style, padding) + (c * menu->eltw) + (c * menu->spacew)); - y = (int)(menu->y + STYLE_GET(menu->style, padding) + (r * menu->elth) + (r * menu->spaceh)); + x = (int)(menu->x + style->padding + (c * menu->eltw) + (c * menu->spacew)); + y = (int)(menu->y + style->padding + (r * menu->elth) + (r * menu->spaceh)); if (i == menu->selected % pagesz) - color = STYLE_GET(menu->style, text_selected_color); + color = style->selected_color; else - color = STYLE_GET(menu->style, text_color); + color = style->text_color; if ((err = mlk_font_render(font, &tex, menu->items[item], color)) < 0) { mlk_tracef("unable to render grid menu item: %s", mlk_err_string(err)); @@ -228,18 +226,13 @@ struct mlk_gridmenu_style mlk_gridmenu_style = { .padding = 10, - .text_color = 0x000000ff, - .text_selected_color = 0x328ca7ff, - .draw = draw + .text_color = MLK_UI_COLOR_TEXT, + .selected_color = MLK_UI_COLOR_SELECTED }; -void -mlk_gridmenu_init(struct mlk_gridmenu *menu) -{ - assert(menu); - - STYLE_INVOKE(menu->style, init, menu); -} +struct mlk_gridmenu_delegate mlk_gridmenu_delegate = { + .draw = draw +}; int mlk_gridmenu_ok(const struct mlk_gridmenu *menu) @@ -285,7 +278,7 @@ { assert(mlk_gridmenu_ok(menu)); - STYLE_INVOKE(menu->style, update, menu, ticks); + MLK__DELEGATE_INVOKE(menu->delegate, mlk_gridmenu_delegate, update, menu, ticks); } void @@ -293,13 +286,5 @@ { assert(menu); - STYLE_INVOKE(menu->style, draw, menu); + MLK__DELEGATE_INVOKE(menu->delegate, mlk_gridmenu_delegate, draw, menu); } - -void -mlk_gridmenu_finish(struct mlk_gridmenu *menu) -{ - assert(menu); - - STYLE_INVOKE(menu->style, finish, menu); -} diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/gridmenu.h --- a/libmlk-ui/mlk/ui/gridmenu.h Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/gridmenu.h Thu Mar 02 21:36:43 2023 +0100 @@ -31,15 +31,16 @@ struct mlk_gridmenu; struct mlk_gridmenu_style { - void *data; unsigned int padding; unsigned long text_color; - unsigned long text_selected_color; struct mlk_font *text_font; - void (*init)(struct mlk_gridmenu_style *, struct mlk_gridmenu *); - void (*update)(struct mlk_gridmenu_style *, struct mlk_gridmenu *, unsigned int); - void (*draw)(struct mlk_gridmenu_style *, const struct mlk_gridmenu *); - void (*finish)(struct mlk_gridmenu_style *, struct mlk_gridmenu *); + unsigned long selected_color; +}; + +struct mlk_gridmenu_delegate { + void *data; + void (*update)(struct mlk_gridmenu_delegate *, struct mlk_gridmenu *, unsigned int); + void (*draw)(struct mlk_gridmenu_delegate *, const struct mlk_gridmenu *); }; struct mlk_gridmenu { @@ -52,6 +53,7 @@ unsigned int nrows; unsigned int ncols; struct mlk_gridmenu_style *style; + struct mlk_gridmenu_delegate *delegate; /* private */ unsigned int eltw; /* maximum entry label width */ @@ -61,12 +63,10 @@ }; extern struct mlk_gridmenu_style mlk_gridmenu_style; +extern struct mlk_gridmenu_delegate mlk_gridmenu_delegate; MLK_CORE_BEGIN_DECLS -void -mlk_gridmenu_init(struct mlk_gridmenu *); - int mlk_gridmenu_ok(const struct mlk_gridmenu *); @@ -82,9 +82,6 @@ void mlk_gridmenu_draw(const struct mlk_gridmenu *); -void -mlk_gridmenu_finish(struct mlk_gridmenu *); - MLK_CORE_END_DECLS #endif /* !MLK_UI_GRIDMENU_H */ diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/label.c --- a/libmlk-ui/mlk/ui/label.c Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/label.c Thu Mar 02 21:36:43 2023 +0100 @@ -19,58 +19,68 @@ #include #include +#include #include -#include #include +#include +#include "align.h" #include "label.h" #include "ui.h" - -#define STYLE_INVOKE(s, f, ...) \ -do { \ - if (s && s->f) \ - s->f(s, __VA_ARGS__); \ - else if (mlk_label_style.f) \ - mlk_label_style.f(s ? s : &mlk_label_style, __VA_ARGS__); \ -} while (0) +#include "ui_p.h" static inline struct mlk_font * -style_font(struct mlk_label_style *style) +style_font(const struct mlk_label *label) { - if (style && style->text_font) - return style->text_font; + const struct mlk_label_style *style = MLK__STYLE(label, mlk_label_style); + + if (style->font) + return style->font; return mlk_ui_fonts[MLK_UI_FONT_INTERFACE]; } static void -draw(struct mlk_label_style *style, const struct mlk_label *label) +delegate_query(struct mlk_label_delegate *delegate, const struct mlk_label *label, unsigned int *w, unsigned *h) { + (void)delegate; + struct mlk_font *font; - struct mlk_texture tex; int err; - font = style_font(style); + font = style_font(label); + + if ((err = mlk_font_query(font, label->text, w, h)) < 0) + mlk_tracef("mlk_font_query: %s", mlk_err_string(err)); +} + +static void +delegate_draw(struct mlk_label_delegate *delegate, const struct mlk_label *label) +{ + (void)delegate; - if ((err = mlk_font_render(font, &tex, label->text, style->text_color)) < 0) - mlk_panic(err); + const struct mlk_label_style *style = MLK__STYLE(label, mlk_label_style); - mlk_texture_draw(&tex, label->x, label->y); - mlk_texture_finish(&tex); + mlk_ui_draw_text( + MLK_ALIGN_NONE, + style_font(label), + style->color, + label->text, + label->x, + label->y, + 0, + 0 + ); } struct mlk_label_style mlk_label_style = { - .text_color = 0x000000ff, - .draw = draw + .color = MLK_UI_COLOR_TEXT }; -void -mlk_label_init(struct mlk_label *label) -{ - assert(mlk_label_ok(label)); - - STYLE_INVOKE(label->style, init, label); -} +struct mlk_label_delegate mlk_label_delegate = { + .query = delegate_query, + .draw = delegate_draw +}; int mlk_label_ok(const struct mlk_label *label) @@ -83,15 +93,15 @@ { assert(mlk_label_ok(label)); - struct mlk_font *font; - int err; - - font = style_font(label->style); + MLK__DELEGATE_INVOKE(label->delegate, mlk_label_delegate, query, label, w, h); +} - if ((err = mlk_font_query(font, label->text, w, h)) < 0) - return err; +void +mlk_label_update(struct mlk_label *label, unsigned int ticks) +{ + assert(mlk_label_ok(label)); - return err; + MLK__DELEGATE_INVOKE(label->delegate, mlk_label_delegate, update, label, ticks); } void @@ -99,13 +109,5 @@ { assert(mlk_label_ok(label)); - STYLE_INVOKE(label->style, draw, label); + MLK__DELEGATE_INVOKE(label->delegate, mlk_label_delegate, draw, label); } - -void -mlk_label_finish(struct mlk_label *label) -{ - assert(mlk_label_ok(label)); - - STYLE_INVOKE(label->style, finish, label); -} diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/label.h --- a/libmlk-ui/mlk/ui/label.h Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/label.h Thu Mar 02 21:36:43 2023 +0100 @@ -25,28 +25,29 @@ struct mlk_label; struct mlk_label_style { + unsigned long color; + struct mlk_font *font; +}; + +struct mlk_label_delegate { void *data; - unsigned long text_color; - struct mlk_font *text_font; - void (*init)(struct mlk_label_style *, struct mlk_label *); - void (*update)(struct mlk_label_style *, struct mlk_label *, unsigned int); - void (*draw)(struct mlk_label_style *, const struct mlk_label *); - void (*finish)(struct mlk_label_style *, struct mlk_label *); + void (*query)(struct mlk_label_delegate *, const struct mlk_label *, unsigned int *, unsigned *); + void (*update)(struct mlk_label_delegate *, struct mlk_label *, unsigned int); + void (*draw)(struct mlk_label_delegate *, const struct mlk_label *); }; struct mlk_label { int x, y; const char *text; struct mlk_label_style *style; + struct mlk_label_delegate *delegate; }; extern struct mlk_label_style mlk_label_style; +extern struct mlk_label_delegate mlk_label_delegate; MLK_CORE_BEGIN_DECLS -void -mlk_label_init(struct mlk_label *); - int mlk_label_ok(const struct mlk_label *); @@ -54,10 +55,10 @@ mlk_label_query(const struct mlk_label *, unsigned int *, unsigned int *); void -mlk_label_draw(const struct mlk_label *); +mlk_label_update(struct mlk_label *, unsigned int ticks); void -mlk_label_finish(struct mlk_label *); +mlk_label_draw(const struct mlk_label *); MLK_CORE_END_DECLS diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/notify.c --- a/libmlk-ui/mlk/ui/notify.c Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/notify.c Thu Mar 02 21:36:43 2023 +0100 @@ -21,17 +21,20 @@ #include #include +#include #include #include +#include #include #include "align.h" -#include "frame.h" -#include "label.h" #include "notify.h" +#include "ui.h" -#define WIDTH (mlk_window.w / 3) +#define WIDTH (mlk_window.w / 2.5) #define HEIGHT (mlk_window.h / 10) +#define MAX (4) +#define FONT (mlk_notify_style.text_font ? mlk_notify_style.text_font : mlk_ui_fonts[MLK_UI_FONT_INTERFACE]) struct geo { const struct mlk_theme *theme; @@ -47,31 +50,23 @@ int body_y; }; -static void draw(const struct mlk_notify *, size_t); - -static const struct mlk_notify_system default_system = { - .draw = draw -}; -static const struct mlk_notify_system *system = &default_system; -static struct mlk_notify stack[MLK_NOTIFY_MAX]; -static size_t stacksz; +static struct mlk_notify stack[MAX]; static void geometry(struct geo *geo, const struct mlk_notify *n, size_t index) { -#if 0 + struct mlk_font *font; int x, y; - /* Determine theme. */ - geo->theme = system->theme ? system->theme : &mlk_theme; - /* Determine notification position. */ - x = mlk_window.w - geo->theme->padding; + x = mlk_window.w - mlk_notify_style.padding; x -= WIDTH; - y = geo->theme->padding * (index + 1);; + y = mlk_notify_style.padding * (index + 1); y += HEIGHT * index; + font = mlk_ui_fonts[MLK_UI_FONT_INTERFACE]; + /* Content frame. */ geo->frame_x = x; geo->frame_y = y; @@ -81,36 +76,36 @@ /* Align icon at the left center. */ if (n->icon->h >= HEIGHT) { mlk_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; + geo->icon_x = x + mlk_notify_style.padding; + geo->icon_y = y + mlk_notify_style.padding; } else { mlk_align(MLK_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 -= mlk_font_height(geo->theme->fonts[MLK_THEME_FONT_INTERFACE]) / 2; + geo->title_x = geo->icon_x + n->icon->w + mlk_notify_style.padding; + geo->title_y = geo->icon_y + (mlk_notify_style.padding / 2); + geo->title_y -= mlk_font_height(font) / 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 -= mlk_font_height(geo->theme->fonts[MLK_THEME_FONT_INTERFACE]) / 2; -#endif + geo->body_y = geo->icon_y + n->icon->h - (mlk_notify_style.padding / 2); + geo->body_y -= mlk_font_height(font) / 2; } static void draw_frame(const struct geo *geo) { - const struct mlk_frame f = { - .x = geo->frame_x, - .y = geo->frame_y, - .w = geo->frame_w, - .h = geo->frame_h - }; - - mlk_frame_draw(&f); + mlk_painter_set_color(mlk_notify_style.border_color); + mlk_painter_draw_rectangle(geo->frame_x, geo->frame_y, geo->frame_w, geo->frame_h); + mlk_painter_set_color(mlk_notify_style.bg_color); + mlk_painter_draw_rectangle( + geo->frame_x + mlk_notify_style.border_size, + geo->frame_y + mlk_notify_style.border_size, + geo->frame_w - (mlk_notify_style.border_size * 2), + geo->frame_h - (mlk_notify_style.border_size * 2) + ); } static void @@ -122,35 +117,35 @@ static void draw_title(const struct geo *geo, const struct mlk_notify *n) { -#if 0 - const struct mlk_label l = { - .x = geo->title_x, - .y = geo->title_y, - .text = n->title, - .flags = MLK_LABEL_FLAGS_SHADOW - }; - - mlk_label_draw(&l); -#endif + mlk_ui_draw_text( + MLK_ALIGN_NONE, + FONT, + mlk_notify_style.text_color, + n->title, + geo->title_x, + geo->title_y, + 0, + 0 + ); } static void draw_body(const struct geo *geo, const struct mlk_notify *n) { -#if 0 - const struct mlk_label l = { - .x = geo->body_x, - .y = geo->body_y, - .text = n->body, - .flags = MLK_LABEL_FLAGS_SHADOW - }; - - mlk_label_draw(&l); -#endif + mlk_ui_draw_text( + MLK_ALIGN_NONE, + FONT, + mlk_notify_style.text_color, + n->body, + geo->body_x, + geo->body_y, + 0, + 0 + ); } static void -draw(const struct mlk_notify *n, size_t index) +delegate_draw(const struct mlk_notify *n, size_t index) { struct geo geo; @@ -163,6 +158,20 @@ draw_body(&geo, n); } +struct mlk_notify_style mlk_notify_style = { + .bg_color = MLK_UI_COLOR_BG, + .border_color = MLK_UI_COLOR_BORDER, + .border_size = 2, + .delay = 5000, + .padding = 10 +}; + +struct mlk_notify_delegate mlk_notify_delegate = { + .stack = stack, + .stacksz = MLK_UTIL_SIZE(stack), + .draw = delegate_draw +}; + void mlk_notify(const struct mlk_texture *icon, const char *title, const char *body) { @@ -172,11 +181,13 @@ struct mlk_notify *n; - if (stacksz >= MLK_NOTIFY_MAX) { - memmove(&stack[0], &stack[1], sizeof (stack[0]) - MLK_NOTIFY_MAX - 1); - n = &stack[MLK_NOTIFY_MAX - 1]; + if (mlk_notify_delegate.length >= mlk_notify_delegate.stacksz) { + memmove(&mlk_notify_delegate.stack[0], + &mlk_notify_delegate.stack[1], + sizeof (mlk_notify_delegate.stack[0]) - mlk_notify_delegate.stacksz - 1); + n = &mlk_notify_delegate.stack[mlk_notify_delegate.length - 1]; } else - n = &stack[stacksz++]; + n = &mlk_notify_delegate.stack[mlk_notify_delegate.length++]; memset(n, 0, sizeof (*n)); n->icon = icon; @@ -189,24 +200,19 @@ { struct mlk_notify *n; - for (size_t i = 0; i < stacksz; ++i) { - n = &stack[i]; + for (size_t i = 0; i < mlk_notify_delegate.length; ++i) { + n = &mlk_notify_delegate.stack[i]; n->elapsed += ticks; - if (n->elapsed >= MLK_NOTIFY_TIMEOUT_DEFAULT) - memmove(n, n + 1, sizeof (*n) * (--stacksz - i)); + if (n->elapsed >= mlk_notify_style.delay) + memmove(n, n + 1, sizeof (*n) * (--mlk_notify_delegate.length - i)); } } void mlk_notify_draw(void) { - for (size_t i = 0; i < stacksz; ++i) - system->draw(&stack[i], i); + for (size_t i = 0; i < mlk_notify_delegate.length; ++i) + if (mlk_notify_delegate.draw) + mlk_notify_delegate.draw(&mlk_notify_delegate.stack[i], i); } - -void -mlk_notify_set_system(const struct mlk_notify_system *sys) -{ - system = sys ? sys : &default_system; -} diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/notify.h --- a/libmlk-ui/mlk/ui/notify.h Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/notify.h Thu Mar 02 21:36:43 2023 +0100 @@ -23,12 +23,8 @@ #include -/* TODO: make this configurable at runtime. */ -#define MLK_NOTIFY_MAX (4) -#define MLK_NOTIFY_TIMEOUT_DEFAULT (5000) - +struct mlk_font; struct mlk_texture; -struct mlk_theme; struct mlk_notify { const struct mlk_texture *icon; @@ -37,11 +33,27 @@ unsigned int elapsed; }; -struct mlk_notify_system { - struct mlk_theme *theme; - void (*draw)(const struct mlk_notify *, size_t); +struct mlk_notify_style { + unsigned long bg_color; + unsigned long text_color; + struct mlk_font *text_font; + unsigned long border_color; + unsigned int border_size; + unsigned int delay; + unsigned int padding; }; +struct mlk_notify_delegate { + struct mlk_notify *stack; + size_t stacksz; + size_t length; + void (*update)(unsigned int ticks); + void (*draw)(const struct mlk_notify *notif, size_t index); +}; + +extern struct mlk_notify_style mlk_notify_style; +extern struct mlk_notify_delegate mlk_notify_delegate; + MLK_CORE_BEGIN_DECLS void @@ -53,9 +65,6 @@ void mlk_notify_draw(void); -void -mlk_notify_set_system(const struct mlk_notify_system *); - MLK_CORE_END_DECLS #endif /*! MLK_UI_NOTIFY_H */ diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/ui.c --- a/libmlk-ui/mlk/ui/ui.c Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/ui.c Thu Mar 02 21:36:43 2023 +0100 @@ -16,13 +16,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include +#include +#include #include +#include +#include #include #include +#include "align.h" #include "ui.h" /* Default font catalog. */ @@ -72,6 +78,31 @@ } void +mlk_ui_draw_text(enum mlk_align align, + struct mlk_font *font, + unsigned long color, + const char *text, + int px, + int py, + unsigned int pw, + unsigned int ph) +{ + assert(font); + assert(text && strlen(text) > 0); + + struct mlk_texture texture; + int x, y, err; + + if ((err = mlk_font_render(font, &texture, text, color)) < 0) + mlk_tracef("mlk_font_render: %s", mlk_err_string(err)); + else { + mlk_align(align, &x, &y, texture.w, texture.h, px, py, pw, ph); + mlk_texture_draw(&texture, x, y); + mlk_texture_finish(&texture); + } +} + +void mlk_ui_finish(void) { } diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/ui.h --- a/libmlk-ui/mlk/ui/ui.h Thu Mar 02 08:54:00 2023 +0100 +++ b/libmlk-ui/mlk/ui/ui.h Thu Mar 02 21:36:43 2023 +0100 @@ -23,6 +23,16 @@ MLK_CORE_BEGIN_DECLS +/* TODO: make this a global variable to allow modification of default theme. */ +/* https://lospec.com/palette-list/duel */ +#define MLK_UI_COLOR_TEXT 0x222323ff +#define MLK_UI_COLOR_SELECTED 0x55b67dff +#define MLK_UI_COLOR_BG 0xf5f7faff +#define MLK_UI_COLOR_BORDER 0xcdd2daff +#define MLK_UI_COLOR_DEBUG 0xe45c5fff + +enum mlk_align; + struct mlk_font; enum mlk_ui_font { @@ -35,6 +45,17 @@ int mlk_ui_init(void); +/* TODO: probably better somewhere else? */ +void +mlk_ui_draw_text(enum mlk_align align, + struct mlk_font *font, + unsigned long color, + const char *text, + int x, + int y, + unsigned int w, + unsigned int h); + void mlk_ui_finish(void); diff -r e205625015ba -r d49a05e7a5b5 libmlk-ui/mlk/ui/ui_p.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-ui/mlk/ui/ui_p.h Thu Mar 02 21:36:43 2023 +0100 @@ -0,0 +1,33 @@ +/* + * ui_p.h -- private helpers for libmlk-ui + * + * Copyright (c) 2020-2023 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. + */ + +#ifndef MLK_UI_P_H +#define MLK_UI_P_H + +#define MLK__DELEGATE_INVOKE(d, def, f, ...) \ +do { \ + if (d && d->f) \ + d->f(d, __VA_ARGS__); \ + else if (def.f) \ + def.f(&def, __VA_ARGS__); \ +} while (0) + +#define MLK__STYLE(w, d) \ + (w->style ? w->style : &d) + +#endif /* !MLK_UI_P_H */