From a315d72a57049179df77ff0da5deda25b03502f5 Mon Sep 17 00:00:00 2001 From: Patrick Date: Tue, 7 Oct 2025 23:39:22 +0200 Subject: [PATCH] better layout management --- include/pgpl/gui/helpers.h | 11 ++----- include/pgpl/gui/predef.h | 11 +++---- src/gui/gui.c | 4 +-- src/gui/helpers.c | 38 ++++++++++-------------- src/gui/widgets/button.c | 1 + src/gui/widgets/container.c | 58 ++++++++++++++++++++++++++++--------- src/gui/widgets/empty.c | 1 + src/gui/widgets/slider.c | 1 + src/gui/widgets/text.c | 1 + tests/plugin.cpp | 11 ------- tests/program.c | 28 ++++++++---------- 11 files changed, 86 insertions(+), 79 deletions(-) diff --git a/include/pgpl/gui/helpers.h b/include/pgpl/gui/helpers.h index a37b8a7..3dbd4df 100644 --- a/include/pgpl/gui/helpers.h +++ b/include/pgpl/gui/helpers.h @@ -50,15 +50,8 @@ bool pgpl_gui_widget_within_bounds(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, double max_width, double max_height, double x, double y); -/* This configures all of the widget properties that should be configurable by - * the user. Check the PGPL_GuiWidget struct comment for more info. */ -void pgpl_gui_widget_configure(PGPL_GuiWidget *widget, double offset_x, - double offset_y, bool expand_x, bool expand_y, - bool border, bool background, - PGPL_GuiFontSize font_size, - PGPL_GuiTheme *theme_override, - bool use_theme_override, bool ignore_margin, - bool ignore_border, bool ignore_padding); +/* This initializes all of the widget properties to their default values. */ +void pgpl_gui_widget_default_config(PGPL_GuiWidget *widget); #ifdef __cplusplus } diff --git a/include/pgpl/gui/predef.h b/include/pgpl/gui/predef.h index 59124ae..4f44e63 100644 --- a/include/pgpl/gui/predef.h +++ b/include/pgpl/gui/predef.h @@ -80,12 +80,13 @@ struct PGPL_GuiWidget { PGPL_GuiFontSize font_size; /* This picks out which color from the theme to use. */ PGPL_GuiStatusColor gui_color; + /* This is used to determine what fraction of the space should be taken up by + * this widget in a layout. */ + uint32_t expansion_fraction; /* This is the theme that should be used instead of the main theme. Note that - * this theme should propagate to any possible child widgets as well. */ - PGPL_GuiTheme theme_override; - /* This determines if the override theme should even be used. If this is - * false, the theme_override is simply ignored. */ - bool use_theme_override; + * this theme should propagate to any possible child widgets as well. Will not + * be used if it is NULL. */ + PGPL_GuiTheme *theme_override; /* These attributes determine whether or not margin, border and padding sizes * respectively should be ignored when rendering. */ bool ignore_margin, ignore_border, ignore_padding; diff --git a/src/gui/gui.c b/src/gui/gui.c index 6e2bbf2..a0e22ab 100644 --- a/src/gui/gui.c +++ b/src/gui/gui.c @@ -23,8 +23,8 @@ static bool pgpl_gui_internal_event_loop(PGPL_Window *window, *(PGPL_GuiWidget **)pgpl_vector_get_index(gui->widgets, i); PGPL_GuiTheme *theme = &gui->theme; - if (widget->use_theme_override) { - theme = &widget->theme_override; + if (widget->theme_override) { + theme = widget->theme_override; } pgpl_gui_widget_render_full(widget, renderer, theme, 0, 0, width, height); diff --git a/src/gui/helpers.c b/src/gui/helpers.c index 78a8776..3f2f4b4 100644 --- a/src/gui/helpers.c +++ b/src/gui/helpers.c @@ -128,8 +128,8 @@ void pgpl_gui_widget_render_full(PGPL_GuiWidget *widget, double max_height) { double width, height; - if (widget->use_theme_override) { - theme = &widget->theme_override; + if (widget->theme_override) { + theme = widget->theme_override; } x += widget->offset_x; @@ -233,25 +233,17 @@ bool pgpl_gui_widget_within_bounds(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, max_height); } -void pgpl_gui_widget_configure(PGPL_GuiWidget *widget, double offset_x, - double offset_y, bool expand_x, bool expand_y, - bool border, bool background, - PGPL_GuiFontSize font_size, - PGPL_GuiTheme *theme_override, - bool use_theme_override, bool ignore_margin, - bool ignore_border, bool ignore_padding) { - widget->offset_x = offset_x; - widget->offset_y = offset_y; - widget->expand_x = expand_x; - widget->expand_y = expand_y; - widget->border = border; - widget->background = background; - widget->font_size = font_size; - if (theme_override != NULL) { - widget->theme_override = *theme_override; - } - widget->use_theme_override = use_theme_override; - widget->ignore_margin = ignore_margin; - widget->ignore_border = ignore_border; - widget->ignore_padding = ignore_padding; +void pgpl_gui_widget_default_config(PGPL_GuiWidget *widget) { + widget->offset_x = 0; + widget->offset_y = 0; + widget->expand_x = true; + widget->expand_y = true; + widget->border = false; + widget->background = false; + widget->font_size = PGPL_GUI_FONT_SIZE_CONTENT; + widget->expansion_fraction = 1; + widget->theme_override = NULL; + widget->ignore_margin = false; + widget->ignore_border = false; + widget->ignore_padding = false; } diff --git a/src/gui/widgets/button.c b/src/gui/widgets/button.c index 33889d1..76ef487 100644 --- a/src/gui/widgets/button.c +++ b/src/gui/widgets/button.c @@ -70,6 +70,7 @@ PGPL_GuiButtonWidget * pgpl_gui_button_widget_create(const char *text, void (*click_callback)(void *app_data)) { PGPL_GuiButtonWidget *button_widget = calloc(1, sizeof(*button_widget)); + pgpl_gui_widget_default_config(&button_widget->parent); button_widget->parent.id = "PGPL_GuiButtonWidget"; button_widget->parent.get_content_size = get_content_size; button_widget->parent.render_content = render_content; diff --git a/src/gui/widgets/container.c b/src/gui/widgets/container.c index a485309..29234aa 100644 --- a/src/gui/widgets/container.c +++ b/src/gui/widgets/container.c @@ -16,13 +16,21 @@ static void render_content(PGPL_GuiWidget *widget, PGPL_Renderer *renderer, double max_width, double max_height) { PGPL_GuiContainerLayout *container_layout = (PGPL_GuiContainerLayout *)widget; uint32_t length = pgpl_vector_get_length(container_layout->widgets); + uint32_t fraction_total = 0; + + for (uint32_t i = 0; i < length; i++) { + PGPL_GuiWidget *child_widget = + *(PGPL_GuiWidget **)pgpl_vector_get_index(container_layout->widgets, i); + + fraction_total += child_widget->expansion_fraction; + } switch (container_layout->direction) { case PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_VERTICAL: - max_height /= length; + max_height /= fraction_total; break; case PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_HORIZONTAL: - max_width /= length; + max_width /= fraction_total; break; } @@ -30,15 +38,23 @@ static void render_content(PGPL_GuiWidget *widget, PGPL_Renderer *renderer, PGPL_GuiWidget *child_widget = *(PGPL_GuiWidget **)pgpl_vector_get_index(container_layout->widgets, i); - pgpl_gui_widget_render_full(child_widget, renderer, theme, x, y, max_width, - max_height); + pgpl_gui_widget_render_full( + child_widget, renderer, theme, x, y, + container_layout->direction == + PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_HORIZONTAL + ? max_width * child_widget->expansion_fraction + : max_width, + container_layout->direction == + PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_VERTICAL + ? max_height * child_widget->expansion_fraction + : max_height); switch (container_layout->direction) { case PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_VERTICAL: - y += max_height; + y += max_height * child_widget->expansion_fraction; break; case PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_HORIZONTAL: - x += max_width; + x += max_width * child_widget->expansion_fraction; break; } } @@ -50,16 +66,24 @@ static void event(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, PGPL_Gui *gui, double max_width, double max_height) { PGPL_GuiContainerLayout *container_layout = (PGPL_GuiContainerLayout *)widget; uint32_t length = pgpl_vector_get_length(container_layout->widgets); + uint32_t fraction_total = 0; + + for (uint32_t i = 0; i < length; i++) { + PGPL_GuiWidget *child_widget = + *(PGPL_GuiWidget **)pgpl_vector_get_index(container_layout->widgets, i); + + fraction_total += child_widget->expansion_fraction; + } pgpl_gui_widget_max_content_size(widget, theme, &max_width, &max_height, max_width, max_height); switch (container_layout->direction) { case PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_VERTICAL: - max_height /= length; + max_height /= fraction_total; break; case PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_HORIZONTAL: - max_width /= length; + max_width /= fraction_total; break; } @@ -83,22 +107,29 @@ static void event(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, PGPL_Gui *gui, *(PGPL_GuiWidget **)pgpl_vector_get_index(container_layout->widgets, i); PGPL_GuiTheme *child_theme; - if (child_widget->use_theme_override) { - child_theme = &child_widget->theme_override; + if (child_widget->theme_override) { + child_theme = child_widget->theme_override; } else { child_theme = theme; } child_widget->event(child_widget, child_theme, gui, event_type, event_data, x + child_widget->offset_x, y + child_widget->offset_y, - max_width, max_height); + container_layout->direction == + PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_HORIZONTAL + ? max_width * child_widget->expansion_fraction + : max_width, + container_layout->direction == + PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_VERTICAL + ? max_height * child_widget->expansion_fraction + : max_height); switch (container_layout->direction) { case PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_VERTICAL: - y += max_height; + y += max_height * child_widget->expansion_fraction; break; case PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_HORIZONTAL: - x += max_width; + x += max_width * child_widget->expansion_fraction; break; } } @@ -112,6 +143,7 @@ PGPL_GuiContainerLayout * pgpl_gui_container_layout_create(PGPL_GuiContainerLayoutDirection direction) { PGPL_GuiContainerLayout *container_layout = calloc(1, sizeof(*container_layout)); + pgpl_gui_widget_default_config(&container_layout->parent); container_layout->parent.id = "PGPL_GuiContainerLayout"; container_layout->parent.get_content_size = get_content_size; container_layout->parent.render_content = render_content; diff --git a/src/gui/widgets/empty.c b/src/gui/widgets/empty.c index 22a9437..443461d 100644 --- a/src/gui/widgets/empty.c +++ b/src/gui/widgets/empty.c @@ -46,6 +46,7 @@ static void destroy(PGPL_GuiWidget *widget) { PGPL_GuiWidget *pgpl_gui_empty_widget_create(void) { PGPL_GuiWidget *empty_widget = calloc(1, sizeof(*empty_widget)); + pgpl_gui_widget_default_config(empty_widget); empty_widget->id = "PGPL_GuiWidget"; empty_widget->get_content_size = get_content_size; empty_widget->render_content = render_content; diff --git a/src/gui/widgets/slider.c b/src/gui/widgets/slider.c index 9ca403c..2a06a55 100644 --- a/src/gui/widgets/slider.c +++ b/src/gui/widgets/slider.c @@ -183,6 +183,7 @@ PGPL_GuiSliderWidget *pgpl_gui_slider_widget_create( uint32_t bar_height, bool inversed, bool vertical, double value, void (*slide_callback)(void *app_data, double value)) { PGPL_GuiSliderWidget *slider_widget = calloc(1, sizeof(*slider_widget)); + pgpl_gui_widget_default_config(&slider_widget->parent); slider_widget->parent.id = "PGPL_GuiSliderWidget"; slider_widget->parent.get_content_size = get_content_size; slider_widget->parent.render_content = render_content; diff --git a/src/gui/widgets/text.c b/src/gui/widgets/text.c index 0ab6f2f..ae66f66 100644 --- a/src/gui/widgets/text.c +++ b/src/gui/widgets/text.c @@ -51,6 +51,7 @@ static void destroy(PGPL_GuiWidget *widget) { PGPL_GuiTextWidget *pgpl_gui_text_widget_create(const char *text) { PGPL_GuiTextWidget *text_widget = calloc(1, sizeof(*text_widget)); + pgpl_gui_widget_default_config(&text_widget->parent); text_widget->parent.id = "PGPL_GuiTextWidget"; text_widget->parent.get_content_size = get_content_size; text_widget->parent.render_content = render_content; diff --git a/tests/plugin.cpp b/tests/plugin.cpp index 11353c1..9822a8f 100644 --- a/tests/plugin.cpp +++ b/tests/plugin.cpp @@ -55,28 +55,17 @@ private: } } - static void configure_widget_default(PGPL_GuiWidget *widget) { - pgpl_gui_widget_configure(widget, 0, 0, true, true, true, true, - PGPL_GUI_FONT_SIZE_CONTENT, NULL, false, false, - false, false); - } - PGPL_GuiWidget *create_main_view() { PGPL_GuiButtonWidget *counter_button; PGPL_GuiTextWidget *counter; column_layout = pgpl_gui_container_layout_create( PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_VERTICAL); - pgpl_gui_widget_configure(&column_layout->parent, 0, 0, true, true, false, - false, PGPL_GUI_FONT_SIZE_CONTENT, NULL, false, - true, true, false); counter_button = pgpl_gui_button_widget_create("Click me!", on_counter_button_click); - configure_widget_default(&counter_button->parent); counter = pgpl_gui_text_widget_create(counter_buffer); - configure_widget_default(&counter->parent); counter->parent.font_size = PGPL_GUI_FONT_SIZE_TITLE; counter->parent.background = false; counter->parent.border = false; diff --git a/tests/program.c b/tests/program.c index ba3f191..a0539e2 100644 --- a/tests/program.c +++ b/tests/program.c @@ -15,29 +15,25 @@ static void slide_callback(void *data, double value) { snprintf(app_data->buffer, 127, "%d", (int)(value * 100)); } -static void configure_widget_default(PGPL_GuiWidget *widget) { - pgpl_gui_widget_configure(widget, 0, 0, true, true, false, false, - PGPL_GUI_FONT_SIZE_CONTENT, NULL, false, false, - false, false); -} - PGPL_GuiWidget *create_main_view(struct AppData *app) { PGPL_GuiContainerLayout *layout; PGPL_GuiSliderWidget *slider; PGPL_GuiTextWidget *text; layout = pgpl_gui_container_layout_create( - PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_HORIZONTAL); - pgpl_gui_widget_configure(&layout->parent, 0, 0, true, true, false, false, - PGPL_GUI_FONT_SIZE_CONTENT, NULL, false, true, true, - false); + PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_VERTICAL); + layout->parent.ignore_margin = true; + layout->parent.ignore_border = true; - slider = pgpl_gui_slider_widget_create(16, true, true, 0.0, slide_callback); - configure_widget_default(&slider->parent); + slider = pgpl_gui_slider_widget_create(16, false, false, 0.0, slide_callback); + slider->parent.border = true; + slider->parent.background = true; text = pgpl_gui_text_widget_create(app->buffer); - configure_widget_default(&text->parent); + text->parent.border = true; + text->parent.background = true; text->parent.font_size = PGPL_GUI_FONT_SIZE_TITLE; + text->parent.expansion_fraction = 3; pgpl_gui_container_layout_widget_add(layout, &text->parent); pgpl_gui_container_layout_widget_add(layout, &slider->parent); @@ -57,12 +53,12 @@ int32_t main(void) { strcpy(app.buffer, "0"); - font = pgpl_font_create_from_file("../roboto.ttf", 128); + font = pgpl_font_create_from_file("../roboto.ttf", 256); - pgpl_gui_theme_configure(&theme, pgpl_color_create(255, 255, 255, 255), 48, + pgpl_gui_theme_configure(&theme, pgpl_color_create(255, 255, 255, 255), 64, font); - gui = pgpl_gui_create("PGPL Test", 480, 240, 0, 0, &theme, &app); + gui = pgpl_gui_create("PGPL Test", 480, 320, 0, 0, &theme, &app); app.gui = gui;