From e98cd1355d0f63e329334888883d4a56deb4a22f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 2 Jul 2023 15:04:22 +0900 Subject: [PATCH] [ui] Implement auto-layout TextContent seems redundant at this stage since a text view is always sized to its content, and PercentOfParent doesn't work yet. Pixels definitely works and Null seems to work in that it does no sizing or positioning. Vertical layout is supported but not yet tested, similar for ChildrenSum, but I can have two buttons side by side. --- include/QF/ui/imui.h | 16 ------- include/QF/ui/view.h | 3 ++ libs/ui/imui.c | 100 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 100 insertions(+), 19 deletions(-) diff --git a/include/QF/ui/imui.h b/include/QF/ui/imui.h index 2508657ff..f4a56ef11 100644 --- a/include/QF/ui/imui.h +++ b/include/QF/ui/imui.h @@ -43,22 +43,6 @@ typedef enum IMUI_SizeKind { IMUI_SizeKind_ChildrenSum, } IMUI_SizeKind; -typedef enum IMUI_Axis { - IMUI_Axis_X, - IMUI_Axis_Y, - IMUI_Axis_count, -} IMUI_Axis; - -typedef struct imui_size { - IMUI_SizeKind kind; - float value; - float strictness; -} imui_size; - -typedef struct imui_layout_s { - imui_size semantic_size[IMUI_Axis_count]; -} imui_layout_t; - imui_ctx_t *IMUI_NewContext (struct canvas_system_s canvas_sys, const char *font, float fontsize); void IMUI_DestroyContext (imui_ctx_t *ctx); diff --git a/include/QF/ui/view.h b/include/QF/ui/view.h index 3a39ee95b..f9c1c1981 100644 --- a/include/QF/ui/view.h +++ b/include/QF/ui/view.h @@ -83,6 +83,9 @@ typedef struct viewcont_s { unsigned resize_y:1; ///< If true, view's height follows parent's. unsigned bol_suppress:1; ///< If true, view_flow skips at start of line. unsigned flow_size:1; ///< If true, view's size is adjusted to flow. + unsigned semantic_x:3; ///< layout size control (IMUI_SizeKind) + unsigned semantic_y:3; ///< layout size control (IMUI_SizeKind) + unsigned vertical:1; ///< true: layout is vertical, else horizontal } viewcont_t; enum { diff --git a/libs/ui/imui.c b/libs/ui/imui.c index aa7f9a8ca..d13f89340 100644 --- a/libs/ui/imui.c +++ b/libs/ui/imui.c @@ -35,6 +35,7 @@ #include "QF/ecs.h" #include "QF/hash.h" +#include "QF/mathlib.h" #include "QF/progs.h" #include "QF/quakeio.h" @@ -249,13 +250,102 @@ prune_objects (imui_ctx_t *ctx) } } +//FIXME currently works properly only for grav_northwest +static void +layout_objects (imui_ctx_t *ctx) +{ + auto ref = View_GetRef (ctx->root_view); + auto h = ref->hierarchy; + + view_pos_t *pos = h->components[view_pos]; + view_pos_t *len = h->components[view_len]; + viewcont_t *cont = h->components[view_control]; + uint32_t *parent = h->parentIndex; + struct boolpair { + bool x, y; + } down_depend[h->num_objects]; + + // the root view size is always explicity + down_depend[0] = (struct boolpair) { false, false }; + for (uint32_t i = 1; i < h->num_objects; i++) { + if (cont[i].semantic_x == IMUI_SizeKind_ChildrenSum) { + down_depend[i].x = 1; + } else if (!(down_depend[i].x = down_depend[parent[i]].x) + && cont[i].semantic_x == IMUI_SizeKind_PercentOfParent) { + len[i].x = (len[parent[i]].x * 100) / 100; //FIXME precent + } + if (cont[i].semantic_y == IMUI_SizeKind_ChildrenSum) { + down_depend[i].y = 1; + } else if (!(down_depend[i].y = down_depend[parent[i]].y) + && cont[i].semantic_y == IMUI_SizeKind_PercentOfParent) { + len[i].y = (len[parent[i]].y * 100) / 100; //FIXME precent + } + } + for (uint32_t i = h->num_objects; --i > 0; ) { + view_pos_t clen = len[i]; + if (cont[i].semantic_x == IMUI_SizeKind_ChildrenSum) { + clen.x = 0; + if (cont[i].vertical) { + for (uint32_t j = 0; j < h->childCount[i]; j++) { + uint32_t child = h->childIndex[i] + j; + clen.x = max (clen.x, len[child].x); + } + } else { + for (uint32_t j = 0; j < h->childCount[i]; j++) { + uint32_t child = h->childIndex[i] + j; + clen.x += len[child].x; + } + } + } + if (cont[i].semantic_y == IMUI_SizeKind_ChildrenSum) { + clen.y = 0; + if (!cont[i].vertical) { + for (uint32_t j = 0; j < h->childCount[i]; j++) { + uint32_t child = h->childIndex[i] + j; + clen.y = max (clen.y, len[child].y); + } + } else { + for (uint32_t j = 0; j < h->childCount[i]; j++) { + uint32_t child = h->childIndex[i] + j; + clen.y += len[child].y; + } + } + } + len[i] = clen; + } + + view_pos_t cpos = {}; + uint32_t cur_parent = 0; + for (uint32_t i = 1; i < h->num_objects; i++) { + if (parent[i] != cur_parent) { + cur_parent = parent[i]; + cpos = (view_pos_t) {}; + } + if (cont[i].semantic_x != IMUI_SizeKind_Null + && cont[i].semantic_y != IMUI_SizeKind_Null) { + pos[i] = cpos; + } else if (cont[i].semantic_x != IMUI_SizeKind_Null) { + pos[i].x = cpos.x; + } else if (cont[i].semantic_y != IMUI_SizeKind_Null) { + pos[i].y = cpos.y; + } + if (cont[parent[i]].vertical) { + cpos.y += cont[i].semantic_y == IMUI_SizeKind_Null ? 0 : len[i].y; + } else { + cpos.x += cont[i].semantic_x == IMUI_SizeKind_Null ? 0 : len[i].x; + } + } + + View_UpdateHierarchy (ctx->root_view); +} + void IMUI_Draw (imui_ctx_t *ctx) { ctx->frame_draw = Sys_LongTime (); prune_objects (ctx); - View_UpdateHierarchy (ctx->root_view); + layout_objects (ctx); ctx->frame_end = Sys_LongTime (); } @@ -322,8 +412,12 @@ IMUI_Button (imui_ctx_t *ctx, const char *label) ctx->csys.reg) = 0; View_SetVisible (view, 1); - View_SetGravity (view, grav_northwest); - View_SetResize (view, 0, 0); + *View_Control (view) = (viewcont_t) { + .gravity = grav_northwest, + .visible = 1, + .semantic_x = IMUI_SizeKind_Pixels, + .semantic_y = IMUI_SizeKind_Pixels, + }; auto text = add_text (view, state, ctx); auto len = View_GetLen (text);