[ui] Add support for passage views to imui

It was a right cow to get working at all due to the tangled mess of
dependencies between different hierarchies (switching to hierarchies as
components helpt), but other that some vertical positioning (paragraphs
and descenders), it's working fairly well now (and fairly quick other
than I think I need to ensure the shaping cache is used).
This commit is contained in:
Bill Currie 2023-12-31 14:42:02 +09:00
parent 871d8729f5
commit c2316a4173
5 changed files with 108 additions and 15 deletions

View file

@ -36,6 +36,7 @@
typedef struct imui_ctx_s imui_ctx_t; typedef struct imui_ctx_s imui_ctx_t;
struct canvas_system_s; struct canvas_system_s;
struct IE_event_s; struct IE_event_s;
struct passage_s;
enum { enum {
imui_percent_x, ///< int imui_percent_x, ///< int
@ -131,6 +132,8 @@ void IMUI_Style_Fetch (const imui_ctx_t *ctx, imui_style_t *style);
void IMUI_Label (imui_ctx_t *ctx, const char *label); void IMUI_Label (imui_ctx_t *ctx, const char *label);
void IMUI_Labelf (imui_ctx_t *ctx, const char *fmt, ...)__attribute__((format(PRINTF,2,3))); void IMUI_Labelf (imui_ctx_t *ctx, const char *fmt, ...)__attribute__((format(PRINTF,2,3)));
void IMUI_Passage (imui_ctx_t *ctx, const char *name,
struct passage_s *passage);
bool IMUI_Button (imui_ctx_t *ctx, const char *label); bool IMUI_Button (imui_ctx_t *ctx, const char *label);
bool IMUI_Checkbox (imui_ctx_t *ctx, bool *flag, const char *label); bool IMUI_Checkbox (imui_ctx_t *ctx, bool *flag, const char *label);
void IMUI_Radio (imui_ctx_t *ctx, int *curvalue, int value, const char *label); void IMUI_Radio (imui_ctx_t *ctx, int *curvalue, int value, const char *label);
@ -172,6 +175,9 @@ void IMUI_EndScrollBox (imui_ctx_t *ctx);
#define UI_Labelf(fmt...) \ #define UI_Labelf(fmt...) \
IMUI_Labelf(IMUI_context, fmt) IMUI_Labelf(IMUI_context, fmt)
#define UI_Passage(name, psg) \
IMUI_Passage(IMUI_context, name, psg)
#define UI_Button(label) \ #define UI_Button(label) \
IMUI_Button(IMUI_context, label) IMUI_Button(IMUI_context, label)

View file

@ -330,6 +330,15 @@ bi (IMUI_Labelf)
IMUI_Label (bi_ctx->imui_ctx, res->dstr->str); IMUI_Label (bi_ctx->imui_ctx, res->dstr->str);
} }
bi (IMUI_Passage)
{
qfZoneScoped (true);
auto res = (imui_resources_t *) _res;
auto bi_ctx = get_imui_ctx (P_INT (pr, 0));
auto passage = RUA_GUI_GetPassage (pr, P_INT (pr, 2));
IMUI_Passage (bi_ctx->imui_ctx, P_GSTRING (pr, 1), passage);
}
bi (IMUI_Button) bi (IMUI_Button)
{ {
qfZoneScoped (true); qfZoneScoped (true);
@ -498,6 +507,7 @@ static builtin_t builtins[] = {
bi(IMUI_Style_Fetch, 2, p(int), p(ptr)), bi(IMUI_Style_Fetch, 2, p(int), p(ptr)),
bi(IMUI_Label, 2, p(int), p(string)), bi(IMUI_Label, 2, p(int), p(string)),
bi(IMUI_Labelf, -3, p(int), p(string)), bi(IMUI_Labelf, -3, p(int), p(string)),
bi(IMUI_Passage, 3, p(int), p(string), p(int)),
bi(IMUI_Button, 2, p(int), p(string)), bi(IMUI_Button, 2, p(int), p(string)),
bi(IMUI_Checkbox, 3, p(int), p(ptr), p(string)), bi(IMUI_Checkbox, 3, p(int), p(ptr), p(string)),
bi(IMUI_Radio, 4, p(int), p(ptr), p(int), p(string)), bi(IMUI_Radio, 4, p(int), p(ptr), p(int), p(string)),

View file

@ -56,8 +56,9 @@
#define c_percent_x (ctx->csys.imui_base + imui_percent_x) #define c_percent_x (ctx->csys.imui_base + imui_percent_x)
#define c_percent_y (ctx->csys.imui_base + imui_percent_y) #define c_percent_y (ctx->csys.imui_base + imui_percent_y)
#define c_reference (ctx->csys.imui_base + imui_reference) #define c_reference (ctx->csys.imui_base + imui_reference)
#define t_passage_glyphs (ctx->csys.text_base + text_passage_glyphs)
#define c_passage_glyphs (ctx->csys.base + canvas_passage_glyphs)
#define c_glyphs (ctx->csys.base + canvas_glyphs) #define c_glyphs (ctx->csys.base + canvas_glyphs)
#define c_passage_glyphs (ctx->csys.text_base + text_passage_glyphs)
#define c_color (ctx->tsys.text_base + text_color) #define c_color (ctx->tsys.text_base + text_color)
#define c_fill (ctx->csys.base + canvas_fill) #define c_fill (ctx->csys.base + canvas_fill)
@ -304,9 +305,28 @@ IMUI_NewContext (canvas_system_t canvas_sys, const char *font, float fontsize)
return ctx; return ctx;
} }
static void
clear_items (imui_ctx_t *ctx)
{
uint32_t root_ent = ctx->root_view.id;
// delete the root view (but not the root entity)
Ent_RemoveComponent (root_ent, ctx->root_view.comp, ctx->root_view.reg);
for (uint32_t i = 0; i < ctx->windows.size; i++) {
auto window = View_FromEntity (ctx->vsys, ctx->windows.a[i]->entity);
View_Delete (window);
}
DARRAY_RESIZE (&ctx->parent_stack, 0);
DARRAY_RESIZE (&ctx->windows, 0);
DARRAY_RESIZE (&ctx->links, 0);
DARRAY_RESIZE (&ctx->style_stack, 0);
}
void void
IMUI_DestroyContext (imui_ctx_t *ctx) IMUI_DestroyContext (imui_ctx_t *ctx)
{ {
clear_items (ctx);
for (auto s = ctx->states; s; s = s->next) { for (auto s = ctx->states; s; s = s->next) {
free (s->label); free (s->label);
} }
@ -415,8 +435,7 @@ IMUI_BeginFrame (imui_ctx_t *ctx)
uint32_t root_ent = ctx->root_view.id; uint32_t root_ent = ctx->root_view.id;
auto root_size = View_GetLen (ctx->root_view); auto root_size = View_GetLen (ctx->root_view);
// delete and recreate the root view (but not the root entity) clear_items (ctx);
Ent_RemoveComponent (root_ent, ctx->root_view.comp, ctx->root_view.reg);
ctx->root_view = View_AddToEntity (root_ent, ctx->vsys, nullview, true); ctx->root_view = View_AddToEntity (root_ent, ctx->vsys, nullview, true);
set_hierarchy_tree_mode (ctx, View_GetRef (ctx->root_view), true); set_hierarchy_tree_mode (ctx, View_GetRef (ctx->root_view), true);
View_SetLen (ctx->root_view, root_size.x, root_size.y); View_SetLen (ctx->root_view, root_size.x, root_size.y);
@ -424,15 +443,7 @@ IMUI_BeginFrame (imui_ctx_t *ctx)
ctx->frame_start = Sys_LongTime (); ctx->frame_start = Sys_LongTime ();
ctx->frame_count++; ctx->frame_count++;
ctx->current_parent = ctx->root_view; ctx->current_parent = ctx->root_view;
for (uint32_t i = 0; i < ctx->windows.size; i++) {
auto window = View_FromEntity (ctx->vsys, ctx->windows.a[i]->entity);
View_Delete (window);
}
ctx->draw_order = imui_draw_order (ctx->windows.size); ctx->draw_order = imui_draw_order (ctx->windows.size);
DARRAY_RESIZE (&ctx->parent_stack, 0);
DARRAY_RESIZE (&ctx->windows, 0);
DARRAY_RESIZE (&ctx->links, 0);
DARRAY_RESIZE (&ctx->style_stack, 0);
ctx->current_menu = 0; ctx->current_menu = 0;
} }
@ -493,11 +504,15 @@ dump_tree (hierref_t href, int level, imui_ctx_t *ctx)
auto reg = ctx->csys.reg; auto reg = ctx->csys.reg;
uint32_t ind = href.index; uint32_t ind = href.index;
hierarchy_t *h = Ent_GetComponent (href.id, ecs_hierarchy, reg); hierarchy_t *h = Ent_GetComponent (href.id, ecs_hierarchy, reg);
view_pos_t *abs = h->components[view_abs];
view_pos_t *len = h->components[view_len]; view_pos_t *len = h->components[view_len];
auto c = ((viewcont_t *)h->components[view_control])[ind]; auto c = ((viewcont_t *)h->components[view_control])[ind];
uint32_t e = h->ent[ind]; uint32_t e = h->ent[ind];
printf ("%2d: %*s[%s%d %s%d"DFL"] %c %s%d %s%d"DFL, ind, printf ("%3d:%08x %*s[%s%d %s%d"DFL"] [%s%d %s%d"DFL"] %c %s%d %s%d"DFL,
ind, e,
level * 3, "", level * 3, "",
view_color (h, ind, ctx, false), abs[ind].x,
view_color (h, ind, ctx, true), abs[ind].y,
view_color (h, ind, ctx, false), len[ind].x, view_color (h, ind, ctx, false), len[ind].x,
view_color (h, ind, ctx, true), len[ind].y, view_color (h, ind, ctx, true), len[ind].y,
c.vertical ? 'v' : 'h', c.vertical ? 'v' : 'h',
@ -516,14 +531,14 @@ dump_tree (hierref_t href, int level, imui_ctx_t *ctx)
printf (DFL"\n"); printf (DFL"\n");
if (c.is_link) { if (c.is_link) {
printf (GRN"%2d: %*slink"DFL"\n", ind, level * 3, ""); printf (GRN"%3d: %*slink"DFL"\n", ind, 8 + level * 3, "");
auto reg = ctx->csys.reg; auto reg = ctx->csys.reg;
uint32_t ent = h->ent[ind]; uint32_t ent = h->ent[ind];
imui_reference_t *sub = Ent_GetComponent (ent, c_reference, reg); imui_reference_t *sub = Ent_GetComponent (ent, c_reference, reg);
auto sub_view = View_FromEntity (ctx->vsys, sub->ref_id); auto sub_view = View_FromEntity (ctx->vsys, sub->ref_id);
auto href = View_GetRef (sub_view); auto href = View_GetRef (sub_view);
dump_tree (href, level + 1, ctx); dump_tree (href, level + 1, ctx);
printf (RED"%2d: %*slink"DFL"\n", ind, level * 3, ""); printf (RED"%3d: %*slink"DFL"\n", ind, 8 + level * 3, "");
} }
if (h->childIndex[ind] > ind) { if (h->childIndex[ind] > ind) {
for (uint32_t i = 0; i < h->childCount[ind]; i++) { for (uint32_t i = 0; i < h->childCount[ind]; i++) {
@ -1068,7 +1083,7 @@ add_text (imui_ctx_t *ctx, view_t view, imui_state_t *state, int mode)
View_SetVisible (text, 1); View_SetVisible (text, 1);
Ent_SetComponent (text.id, c_glyphs, reg, Ent_SetComponent (text.id, c_glyphs, reg,
Ent_GetComponent (text.id, c_passage_glyphs, reg)); Ent_GetComponent (text.id, t_passage_glyphs, reg));
len = View_GetLen (text); len = View_GetLen (text);
View_SetLen (view, len.x, len.y); View_SetLen (view, len.x, len.y);
@ -1143,6 +1158,63 @@ IMUI_Labelf (imui_ctx_t *ctx, const char *fmt, ...)
IMUI_Label (ctx, ctx->dstr->str); IMUI_Label (ctx, ctx->dstr->str);
} }
void
IMUI_Passage (imui_ctx_t *ctx, const char *name, struct passage_s *passage)
{
auto anchor_view = View_New (ctx->vsys, ctx->current_parent);
*View_Control (anchor_view) = (viewcont_t) {
.gravity = grav_northwest,
.visible = 1,
.semantic_x = imui_size_expand,
.semantic_y = imui_size_expand,
.vertical = true,
.active = 1,
};
auto reg = ctx->csys.reg;
*(int*) Ent_AddComponent (anchor_view.id, c_percent_x, reg) = 100;
*(int*) Ent_AddComponent (anchor_view.id, c_percent_y, reg) = 100;
auto state = imui_get_state (ctx, name, anchor_view.id);
update_hot_active (ctx, state);
set_fill (ctx, anchor_view, ctx->style.background.normal);
auto psg_view = Text_PassageView (ctx->tsys, nullview,
ctx->font, passage);
Canvas_SetReference (ctx->csys, psg_view.id,
Canvas_Entity (ctx->csys,
View_GetRoot (anchor_view).id));
if (Ent_HasComponent (psg_view.id, c_passage_glyphs, reg)) {
// FIXME this shouldn't be necessary and is a sign of bigger problems
Ent_RemoveComponent (psg_view.id, c_passage_glyphs, reg);
}
Ent_SetComponent (psg_view.id, c_passage_glyphs, reg,
Ent_GetComponent (psg_view.id, t_passage_glyphs, reg));
*View_Control (psg_view) = (viewcont_t) {
.gravity = grav_northwest,
.visible = 1,
.semantic_x = imui_size_expand,
.semantic_y = imui_size_expand,
.free_x = 1,
.free_y = 1,
.vertical = true,
.active = 1,
};
*(int*) Ent_AddComponent (psg_view.id, c_percent_x, ctx->csys.reg) = 100;
*(int*) Ent_AddComponent (psg_view.id, c_percent_y, ctx->csys.reg) = 100;
View_Control (anchor_view)->is_link = 1;
imui_reference_t link = {
.ref_id = psg_view.id,
};
Ent_SetComponent (anchor_view.id, c_reference, anchor_view.reg, &link);
imui_reference_t anchor = {
.ref_id = anchor_view.id,
};
Ent_SetComponent (psg_view.id, c_reference, psg_view.reg, &anchor);
}
bool bool
IMUI_Button (imui_ctx_t *ctx, const char *label) IMUI_Button (imui_ctx_t *ctx, const char *label)
{ {

View file

@ -61,6 +61,7 @@ void IMUI_Style_Fetch (imui_ctx_t ctx, imui_style_t *style);
void IMUI_Label (imui_ctx_t ctx, string label); void IMUI_Label (imui_ctx_t ctx, string label);
void IMUI_Labelf (imui_ctx_t ctx, string fmt, ...); void IMUI_Labelf (imui_ctx_t ctx, string fmt, ...);
void IMUI_Passage (imui_ctx_t ctx, string name, int passage);
int IMUI_Button (imui_ctx_t ctx, string label); int IMUI_Button (imui_ctx_t ctx, string label);
int IMUI_Checkbox (imui_ctx_t ctx, int *flag, string label); int IMUI_Checkbox (imui_ctx_t ctx, int *flag, string label);
void IMUI_Radio (imui_ctx_t ctx, int *curvalue, int value, string label); void IMUI_Radio (imui_ctx_t ctx, int *curvalue, int value, string label);
@ -96,6 +97,9 @@ void IMUI_EndScrollBox (imui_ctx_t ctx);
#define UI_Labelf(fmt...) \ #define UI_Labelf(fmt...) \
IMUI_Labelf(IMUI_context, fmt) IMUI_Labelf(IMUI_context, fmt)
#define UI_Passage(name, psg) \
IMUI_Passage(IMUI_context, name, psg)
#define UI_Button(label) \ #define UI_Button(label) \
IMUI_Button(IMUI_context, label) IMUI_Button(IMUI_context, label)

View file

@ -27,6 +27,7 @@ void IMUI_Style_Fetch (imui_ctx_t ctx, imui_style_t *style) = #0;
void IMUI_Label (imui_ctx_t ctx, string label) = #0; void IMUI_Label (imui_ctx_t ctx, string label) = #0;
void IMUI_Labelf (imui_ctx_t ctx, string fmt, ...) = #0; void IMUI_Labelf (imui_ctx_t ctx, string fmt, ...) = #0;
void IMUI_Passage (imui_ctx_t ctx, string name, int passage) = #0;
int IMUI_Button (imui_ctx_t ctx, string label) = #0; int IMUI_Button (imui_ctx_t ctx, string label) = #0;
int IMUI_Checkbox (imui_ctx_t ctx, int *flag, string label) = #0; int IMUI_Checkbox (imui_ctx_t ctx, int *flag, string label) = #0;
void IMUI_Radio (imui_ctx_t ctx, int *curvalue, int value, string label) = #0; void IMUI_Radio (imui_ctx_t ctx, int *curvalue, int value, string label) = #0;