From 97d9996160b7c1c0bf6619e2a2b439b09826a6ce Mon Sep 17 00:00:00 2001 From: Matthew Date: Sun, 7 Sep 2025 15:09:50 +1000 Subject: [PATCH] rework imgui, new auto layout system --- src/dlib | 2 +- src/editor/editor.d | 76 ++--- src/editor/ui.d | 667 ++++++++++++++++++------------------------- src/editor/widgets.d | 210 +------------- 4 files changed, 300 insertions(+), 655 deletions(-) diff --git a/src/dlib b/src/dlib index c7f7752..421f903 160000 --- a/src/dlib +++ b/src/dlib @@ -1 +1 @@ -Subproject commit c7f77523c4b7c86b625149ef7fde76257f6fcf51 +Subproject commit 421f903cffaa22c7d7f9115ae49daa45576adfa8 diff --git a/src/editor/editor.d b/src/editor/editor.d index 4cf18ff..553a62d 100644 --- a/src/editor/editor.d +++ b/src/editor/editor.d @@ -48,8 +48,6 @@ struct Editor FontFace font; FontAtlasBuf atlas_buf; - Stack!(UIPanel*) panel_stack; - UVec2 res; } @@ -164,8 +162,7 @@ CreateEditor(PlatformWindow* window, u8[] buffer_data, u8[] buffer_name) assert(CreateGraphicsPipeline(&editor.rd, &editor.pipeline, &ui_info), "Unable to build UI pipeline"); - InitUIContext(&editor.rd); - SetProp!(CtxP.FontAtlas)(editor.atlas_buf.atlas); + InitUICtx(&editor.rd, editor.atlas_buf.atlas); CreateImageView(&editor.rd, &editor.font_atlas, editor.atlas_buf.atlas.width, editor.atlas_buf.atlas.height, 4, editor.atlas_buf.data); @@ -182,66 +179,27 @@ void Cycle(Editor* ed, Inputs* inputs) { Reset(&ed.temp_arena); - UIBeginBuild(); - /* - f32 pos = 0.0; - f32 h = ed.atlas_buf.atlas.size; - DrawBuffer(ed, 0.0, 0.0, h, ed.active_buffer); - */ + BeginBuild(); - u32 count = 0; - static bool init = false; - static Timer timer; - static u32 box_count = 1; + Panel("##panel_1", 1.0, 0.33, A2D.X, Vec4(0.2, 0.5, 0.8, 1.0)); - if (!init) - { - timer = CreateTimer(); - init = true; - } + Panel("##sub_panel_1", 0.125, 1.0, A2D.X, Vec4(0.2, 0.4, 0.5, 1.0)); + EndPanel(); - u32 prev_box_count = box_count; - g_delta = DeltaTime(&timer); - for(auto ev = inputs.list.first; ev != null; ev = ev.next) - { - count += 1; - switch(ev.value.key) - { - case KBI.One: box_count = 1; break; - case KBI.Two: box_count = 2; break; - case KBI.Three: box_count = 3; break; - case KBI.Four: box_count = 4; break; - case KBI.Five: box_count = 5; break; - case KBI.Six: box_count = 6; break; - case KBI.Seven: box_count = 7; break; - case KBI.Eight: box_count = 8; break; - case KBI.Nine: box_count = 9; break; - default: break; - } - } + Panel("##sub_panel_2", 0.675, 1.0, A2D.X, Vec4(0.9, 0.6, 0.5, 1.0)); + EndPanel(); - PanelStart("##Base", Vec3(0.5)); + Panel("##sub_panel_3", 0.2, 1.0, A2D.X, Vec4(1.0, 0.4, 0.5, 1.0)); + EndPanel(); - PanelStart("##horizontal1", Vec3(0.2, 0.3, 0.7)); + EndPanel(); + + Panel("##panel_2", 1.0, 0.33, A2D.X, Vec4(0.5, 0.2, 0.45, 1.0)); + EndPanel(); - PanelStart("##horizontal2", Vec3(0.2, 0.3, 0.7)); - - char[128] buf; - f32 x_pct = 1.0/box_count; - foreach(i; 0 .. box_count) - { - buf.sformat("##%s", i); - PanelStart(cast(u8[])buf, Vec3(x_pct * i)); - PanelEnd(); - } - - PanelEnd(); - - PanelStart("##horizontal3", Vec3(0.2, 0.5, 0.9)); - PanelEnd(); - - PanelEnd(); + Panel("##panel_3", 1.0, 0.33, A2D.X, Vec4(0.3, 0.7, 0.6, 1.0)); + EndPanel(); BeginFrame(&ed.rd); @@ -258,9 +216,7 @@ Cycle(Editor* ed, Inputs* inputs) Bind(&ed.rd, ed.pipeline, ed.desc_set); - UIFinishBuild(); - - DrawUI(); + EndBuild(); FinishRendering(&ed.rd); diff --git a/src/editor/ui.d b/src/editor/ui.d index e9b8a80..e5bfd90 100644 --- a/src/editor/ui.d +++ b/src/editor/ui.d @@ -10,9 +10,37 @@ import std.stdio; import editor; UIContext g_ui_ctx; + const UIItem g_ui_nil_item; UIItem* g_UI_NIL; +enum Axis2D +{ + X, + Y, + Max +} + +alias A2D = Axis2D; + +enum UIFlags +{ + None, + DrawBackground, + DragX, + DragY, +} + +alias UIF = UIFlags; + +enum SizeType +{ + Pixels, + Percentage, +} + +alias ST = SizeType; + struct UIContext { HashTable!(UIHash, UIItem*) items; @@ -22,18 +50,42 @@ struct UIContext UIBuffer buffer; UIItem* root; + UIItem* top_parent; - // UI builder state FontAtlas atlas; - Vec4[4] bg_cols; - Vec4[4] border_cols; - UISize[A2D.max] size_axes; - Rect padding; - u32 tab_width; - f32 text_scale; - UIItem* parent_stack; + Vec4[4] color; + Vec4[4] border_color; + Vec4 text_color; Axis2D layout_axis; - Vec2 position; +} + +struct UIItem +{ + UIFlags flags; + UIKey key; + + UIItem* next; + UIItem* prev; + UIItem* first; // first child + UIItem* last; // last child + UIItem* parent; + + UIItem* stack_next; + + // Build Parameters + Axis2D layout_axis; + UISize[2] size_info; + + // Calculated Parameters + Vec2 size; + Rect rect; + Vec4[4] color; +} + +struct UISize +{ + SizeType type; + f32 value; } struct UIBuffer @@ -45,67 +97,6 @@ struct UIBuffer u32 count; } -enum CtxProperty -{ - None, - BGColor, - BorderColor, - SizeKind, - SizeValue, - SizeStrictness, - FontAtlas, - AxisX, - AxisY, - Padding, - TextScale, - TabWidth, - LayoutAxis, - Position, -} - -alias CtxP = CtxProperty; - -enum Axis2D -{ - X, - Y, - Max, -} - -alias A2D = Axis2D; - -enum UIRecurse -{ - PostOrder, - PreOrder, -} - -alias UIR = UIRecurse; - -enum UIProperties : u64 -{ - Clickable = (1<<0), - ViewScroll = (1<<1), - DrawText = (1<<2), - DrawBackground = (1<<3), - DrawBorder = (1<<4), - Resizeable = (1<<5), - Draggable = (1<<6), -} - -alias UIP = UIProperties; - -enum SizeKind : u64 -{ - None, - Pixels, - TextContent, - PercentOfParent, - ChildrenSum, -} - -alias SK = SizeKind; - union Rect { Vec2[2] v; @@ -127,55 +118,218 @@ alias UIHash = u64; alias UIPair = KVPair!(UIHash, UIItem*); -struct UISize -{ - SizeKind kind; - f32 value; - f32 strictness; -} - -struct UIItemRec -{ - UIItem* next; - i32 push_count; - i32 pop_count; -} - -struct UIItem -{ - UIProperties flags; - UIKey key; - - UIItem* first; - UIItem* last; - UIItem* next; - UIItem* prev; - UIItem* parent; - - UIItem* list_next; - UIItem* list_prev; - - debug { u8[] debug_id; } - - UISize[A2D.max] size; - Vec4[4] bg_color; - Vec4[4] border_color; - Rect padding; - f32[A2D.max] computed_size; - f32[A2D.max] fixed_position; - Rect rect; - f32 text_scale; - Axis2D layout_axis; - f32 hot_t; - f32 active_t; -} - struct UIKey { u8[] text; u64 hash; } +void +InitUICtx(Renderer* rd, FontAtlas atlas) +{ + g_UI_NIL = cast(UIItem*)&g_ui_nil_item; + + Arena arena = CreateArena(MB(4)); + + MappedBuffer!(Vertex) m_vtx = CreateMappedBuffer!(Vertex)(rd, BT.Vertex, 5000); + MappedBuffer!(u32) m_idx = CreateMappedBuffer!(u32)(rd, BT.Index, 15000); + + UIContext ctx = { + rd: rd, + items: CreateHashTable!(UIHash, UIItem*)(12), + arena: CreateArena(MB(4)), + atlas: atlas, + root: g_UI_NIL, + top_parent: g_UI_NIL, + buffer: { + mapped_vtx: m_vtx, + mapped_idx: m_idx, + vtx: m_vtx.data, + idx: m_idx.data, + }, + }; + + g_ui_ctx = ctx; +} + +UIItem* +PopParent() +{ + UIContext* ctx = GetCtx(); + UIItem* parent = ctx.top_parent; + ctx.top_parent = ctx.top_parent.stack_next; + return parent; +} + +void +PushParent(UIItem* parent) +{ + UIContext* ctx = GetCtx(); + parent.stack_next = ctx.top_parent; + ctx.top_parent = parent; +} + +void +SetColor(Vec4 col) +{ + SetColor(col, col, col, col); +} + +void +SetColor(Vec4 col0, Vec4 col1, Vec4 col2, Vec4 col3) +{ + UIContext* ctx = GetCtx(); + ctx.color[0] = col0; + ctx.color[1] = col1; + ctx.color[2] = col2; + ctx.color[3] = col3; +} + +void +SetLayoutAxis(Axis2D axis) +{ + UIContext* ctx = GetCtx(); + ctx.layout_axis = axis; +} + +void +BeginBuild() +{ + UIContext* ctx = GetCtx(); + + ctx.buffer.count = 0; + + ctx.root = Root(); + PushParent(ctx.root); +} + +void +EndBuild() +{ + UIContext* ctx = GetCtx(); + + PopParent(); + + assert(Nil(ctx.top_parent)); + + CalcFixedSizes(ctx.root); + CalcPercentageSizes(ctx.root); + static foreach(axis; A2D.min .. A2D.max) + { + CalcPositions!(axis)(ctx.root); + } + DrawUI(ctx, ctx.root); + + BindBuffers(g_ui_ctx.rd, &g_ui_ctx.buffer.mapped_idx, &g_ui_ctx.buffer.mapped_vtx); + DrawIndexed(g_ui_ctx.rd, 6, g_ui_ctx.buffer.count, 0); +} + +void +CalcFixedSizes(UIItem* item) +{ + if (!Nil(item)) + { + static foreach(axis; A2D.min .. A2D.max) + { + if (item.size_info[axis].type == ST.Pixels) + { + item.size.v[axis] = item.size_info[axis].value; + } + } + + CalcFixedSizes(item.first); + CalcFixedSizes(item.next); + } +} + +void +CalcPercentageSizes(UIItem* item) +{ + if (!Nil(item)) + { + CalcPercentageSizes(item.first); + CalcPercentageSizes(item.next); + + static foreach(axis; A2D.min .. A2D.max) + { + if (item.size_info[axis].type == ST.Percentage) + { + UIItem* parent; + for(UIItem* p = item.parent; !Nil(p); p = p.parent) + { + if (p.size_info[axis].type == ST.Pixels) + { + parent = p; + break; + } + } + + item.size.v[axis] = parent.size_info[axis].value * item.size_info[axis].value; + } + } + } +} + +void +CalcPositions(alias axis)(UIItem* item, f32 pos = 0.0) +{ + if (!Nil(item)) + { + f32 end_pos = pos + item.size.v[axis]; + item.rect.vec0.v[axis] = pos; + item.rect.vec1.v[axis] = end_pos; + + f32 next_pos = item.parent.layout_axis == axis ? end_pos : pos; + + CalcPositions!(axis)(item.first, pos); + CalcPositions!(axis)(item.next, next_pos); + } +} + +void +DrawUI(UIContext* ctx, UIItem* item) +{ + if (!Nil(item)) + { + DrawRect(ctx, item); + + DrawUI(ctx, item.first); + DrawUI(ctx, item.next); + } +} + +UIItem* +BuildItem(string id, UISize size_x, UISize size_y, UIFlags properties) +{ + u8[] u8_id = CastStr!(u8)(id); + return BuildItem(u8_id, size_x, size_y, properties); +} + +UIItem* +BuildItem(u8[] id, UISize size_x, UISize size_y, UIFlags properties) +{ + UIContext* ctx = GetCtx(); + UIKey key = MakeKey(id); + + UIItem* item = Get(key); + item.first = item.last = item.next = item.prev = g_UI_NIL; + + item.key = key; + item.flags = properties; + item.size_info[A2D.X] = size_x; + item.size_info[A2D.Y] = size_y; + item.color = ctx.color; + item.layout_axis = ctx.layout_axis; + + item.parent = ctx.top_parent; + if (!Nil(item.parent)) + { + DLLPush(item.parent, item, g_UI_NIL); + } + + return item; +} + UIContext* GetCtx() { @@ -189,249 +343,6 @@ RootSize() return size; } -void -UIBeginBuild() -{ - UIContext* ui = GetCtx(); - - ui.buffer.count = 0; - - ClearParentStack(); - - ui.root = RootItem(); -} - -void -UIFinishBuild() -{ - UIContext* ui = GetCtx(); - - - // 1. Pixel/Text sizes (any order) - for(UIItem* item = ui.root; !Nil(item); item = Recurse!(UIR.PreOrder)(item, ui.root).next) - { - foreach(i, ref s; item.size) - { - if (s.kind == SK.Pixels) - { - item.computed_size[i] = s.value; - } - else if (s.kind == SK.TextContent) - { - // Text size + padding - } - } - } - - // 2. PercentOfParent (Upward dependant) size (pre-order) (Ignore downward dependant sizes) - foreach(axis; A2D.min .. A2D.max) - { - for(UIItem* item = ui.root; !Nil(item); item = Recurse!(UIR.PreOrder)(item, ui.root).next) - { - for(UIItem* child = item.first; !Nil(child); child = child.next) - { - if (child.size[axis].kind == SK.PercentOfParent) - { - UIItem* fixed_parent = g_UI_NIL; - for(UIItem* p = child.parent; !Nil(p); p = p.parent) - { - if (p.size[axis].kind == SK.Pixels || p.size[axis].kind == SK.TextContent) - { - fixed_parent = p; - break; - } - } - - child.computed_size[axis] = fixed_parent.computed_size[axis] * child.size[axis].value; - } - } - } - } - - // 3. ChildrenSum (Downward dependant) (post-order) - { - UIItemRec rec; - foreach(axis; A2D.min .. A2D.max) - { - for(UIItem* item = ui.root; !Nil(item); item = rec.next) - { - rec = Recurse!(UIR.PreOrder)(item, ui.root); - i32 pop_index = 0; - for(UIItem* i = item; !Nil(item) && pop_index <= rec.pop_count; i = i.parent, pop_index += 1) - { - if (i.size[axis].kind == SK.ChildrenSum) - { - f32 sum = 0.0; - for(UIItem* child = i.first; !Nil(child); child = child.next) - { - sum = axis == child.layout_axis ? sum + child.computed_size[axis] : Max(sum, child.computed_size[axis]); - } - i.computed_size[axis] = sum; - } - } - } - } - } - // 4. Solve violations e.g. extending past boundaries of parent (pre-order) - foreach(axis; A2D.min .. A2D.max) - { - for(UIItem* item = ui.root; !Nil(item); item = Recurse!(UIR.PreOrder)(item, ui.root).next) - { - if (!Nil(item.parent)) - { - if (item.parent.computed_size[axis] < item.computed_size[axis]) - { - item.computed_size[axis] = item.parent.computed_size[axis]; - } - } - } - } - - // 5. Compute relative positions of each widgets (pre-order) - foreach(axis; A2D.min .. A2D.max) - { - for(UIItem* item = ui.root; !Nil(item); item = Recurse!(UIR.PreOrder)(item, ui.root).next) - { - f32 layout_position = 0.0; - for(UIItem* child = item.first; !Nil(child); child = child.next) - { - child.fixed_position[axis] = layout_position; - - child.rect.vec0.v[axis] = item.rect.vec0.v[axis] + child.fixed_position[axis]; - child.rect.vec1.v[axis] = child.rect.vec0.v[axis] + child.computed_size[axis]; - - if (axis == item.layout_axis) - { - layout_position += child.computed_size[axis]; - } - } - } - } - - u32 count = 0; - for(UIItem* item = ui.root; !Nil(item); item = Recurse!(UIR.PreOrder)(item, ui.root).next) - { - if (item.flags & UIP.DrawBackground) - { - DrawRect(ui, item); - } - } - - WidgetsComplete(); -} - -void -PrintTree(UIItem* item, u32 count = 0, string prefix = "", bool is_left = false) -{ - if (!Nil(item)) - { - writeln(is_left ? "f" : "l", count, prefix, is_left ? "├──" : "└──", item.debug_id); - - prefix ~= is_left ? "│ " : " "; - PrintTree(item.first, count + 1, prefix, true); - PrintTree(item.next, count + 1, prefix, false); - } -} - -void -PushParent(UIItem* parent) -{ - auto ctx = GetCtx(); - parent.list_next = ctx.parent_stack; - ctx.parent_stack = parent; -} - -UIItem* -PopParent() -{ - auto ctx = GetCtx(); - UIItem* parent = ctx.parent_stack; - ctx.parent_stack = parent.list_next; - return parent; -} - -UIItem* -BuildItem(UIKey key, UIProperties flags) -{ - UIContext* ui = GetCtx(); - - UIItem* item = Get(key); - item.first = item.last = item.next = item.prev = item.parent = item.list_next = item.list_prev = g_UI_NIL; - item.computed_size = 0; - - item.flags = flags; - item.size = ui.size_axes; - item.padding = ui.padding; - item.layout_axis = ui.layout_axis; - - if (item.flags & UIP.DrawBackground) - { - item.bg_color = ui.bg_cols; - } - if (item.flags & UIP.DrawBorder) - { - item.border_color = ui.border_cols; - } - if (item.flags & UIP.DrawText) - { - item.text_scale = ui.text_scale; - } - - item.parent = ui.parent_stack; - if (!Nil(item.parent)) - { - DLLPush(item.parent, item, g_UI_NIL); - } - - debug - { - item.debug_id = key.text; - } - - return item; -} - -void -ClearParentStack() -{ - auto ctx = GetCtx(); - ctx.parent_stack = g_UI_NIL; -} - -void -DrawUI() -{ - BindBuffers(g_ui_ctx.rd, &g_ui_ctx.buffer.mapped_idx, &g_ui_ctx.buffer.mapped_vtx); - DrawIndexed(g_ui_ctx.rd, 6, g_ui_ctx.buffer.count, 0); -} - -void -InitUIContext(Renderer* rd) -{ - g_UI_NIL = cast(UIItem*)&g_ui_nil_item; - - auto vtx = CreateMappedBuffer!(Vertex)(rd, BT.Vertex, Vertex.sizeof * UI_COUNT); - auto idx = CreateMappedBuffer!(u32)(rd, BT.Index, u32.sizeof * UI_COUNT); - - g_ui_ctx.root = g_UI_NIL; - g_ui_ctx.items = CreateHashTable!(UIHash, UIItem*)(16); - g_ui_ctx.arena = CreateArena(MB(8)); - g_ui_ctx.rd = rd; - g_ui_ctx.buffer.mapped_vtx = vtx; - g_ui_ctx.buffer.mapped_idx = idx; - g_ui_ctx.buffer.vtx = vtx.data; - g_ui_ctx.buffer.idx = idx.data; - - InitWidgetContext(); -} - -UIKey -MakeKey(string str) -{ - u8[] id = (cast(u8*)str)[0 .. str.length]; - return MakeKey(id); -} - UIKey MakeKey(u8[] id) { @@ -497,7 +408,7 @@ Get(UIKey key) f32 CalcTextWidth(u8[] str) { - u32 tab_width = g_ui_ctx.tab_width; + u32 tab_width = 2; //g_ui_ctx.tab_width; Glyph* space = g_ui_ctx.atlas.glyphs.ptr + ' '; f32 width; @@ -515,7 +426,7 @@ CalcTextWidth(u8[] str) } } - return width * g_ui_ctx.text_scale; + return width; // * g_ui_ctx.text_scale; } pragma(inline) void @@ -561,7 +472,7 @@ DrawRect(UIContext* ctx, UIItem* item) Vertex* v = ctx.buffer.vtx.ptr + ctx.buffer.count; v.dst_start = item.rect.vec0; v.dst_end = item.rect.vec1; - v.cols = item.bg_color; + v.cols = item.color; v.border_thickness = 0.0; v.corner_radius = 0.0; v.edge_softness = 0.0; @@ -589,42 +500,7 @@ Nil(UIItem* item) return item == null || item == g_UI_NIL; } -UIItemRec -Recurse(alias mode)(UIItem* item, UIItem* root) -{ - UIItem* sibling, child; - UIItemRec result = UIItemRec(next: g_UI_NIL); - - static if (mode == UIR.PostOrder) child = item.last; else child = item.first; - - if (!Nil(child)) - { - result.next = child; - result.push_count = 1; - } - else for(UIItem* i = item; !Nil(i) && i != root; i = i.parent) - { - static if (mode == UIR.PostOrder) - { - sibling = i.prev; - } - else - { - sibling = i.next; - } - - if (!Nil(sibling)) - { - result.next = sibling; - break; - } - - result.pop_count += 1; - } - - return result; -} - +/* // Setter function in case I need to change to using a mutex pragma(inline) void SetProp(alias P, T)(T value) @@ -683,6 +559,7 @@ SetProp(alias P, T)(T value) } else static assert(false, "Unknown Type"); } +*/ unittest { diff --git a/src/editor/widgets.d b/src/editor/widgets.d index af8ad50..79bc4b7 100644 --- a/src/editor/widgets.d +++ b/src/editor/widgets.d @@ -1,219 +1,31 @@ import dlib; -import editor; import ui; -struct WidgetAnimation +UIItem* +Root() { - f32 start; - f32 end; - f32 time_start; - f32 time_remaining; -} + Vec2 d = RootSize(); + SetLayoutAxis(A2D.Y); + UIItem* root = BuildItem("##root_item", UISize(ST.Pixels, d.x), UISize(ST.Pixels, d.y), UIF.DrawBackground); -WidgetContext g_widget_ctx; -const UIPanel g_ui_panel; -UIPanel* g_PANEL_NIL; - -struct WidgetContext -{ - u64 frame; - Arena arena; - HashTable!(UIHash, UIPanel*) panels; - UIPanel* parent_panel; -} - -struct UIPanel -{ - Axis2D split_axis; - f32 percent; - - UIPanel* first; - UIPanel* last; - UIPanel* prev; - UIPanel* next; - UIPanel* parent; - - UIPanel* list_next; - - u64 last_frame; - bool new_children; - u32 child_count; - - WidgetAnimation anim; -} - -void -InitWidgetContext() -{ - g_PANEL_NIL = cast(UIPanel*)&g_ui_panel; - - g_widget_ctx.arena = CreateArena(MB(1)); - g_widget_ctx.parent_panel = g_PANEL_NIL; - g_widget_ctx.panels = CreateHashTable!(UIHash, UIPanel*)(6); -} - -void -WidgetsComplete() -{ - g_widget_ctx.frame += 1; -} - -bool -Nil(UIPanel* panel) -{ - return panel == g_PANEL_NIL || panel == null; + return root; } UIItem* -RootItem() +Panel(string id, f32 x_pct, f32 y_pct, Axis2D layout_axis, Vec4 color) { - Vec2 size = RootSize(); - - UIKey key = MakeKey("##root_key"); - - SetProp!(CtxP.AxisX)(UISize(SK.Pixels, size.x, 1.0)); - SetProp!(CtxP.AxisY)(UISize(SK.Pixels, size.y, 1.0)); - SetProp!(CtxP.BGColor)(Vec4(0.2, 0.5, 0.85, 1.0)); - SetProp!(CtxP.LayoutAxis)(A2D.X); - - UIItem* item = BuildItem(key, UIP.DrawBackground); - - UIContext* ui = GetCtx(); - - PushParent(ui.root); - - assert(g_widget_ctx.parent_panel == g_PANEL_NIL); - - return item; -} - -UIItem* -PanelStart(string str, Vec3 col) -{ - u8[] u8_str = (cast(u8*)str.ptr)[0 .. str.length]; - return PanelStart(u8_str, col); -} - -UIPanel* -GetPanel(UIKey key) -{ - UIPanel* panel; - Result!(UIPanel*) result = g_widget_ctx.panels[key.hash]; - if (result.ok) - { - panel = result.value; - } - else - { - panel = Alloc!(UIPanel)(&g_widget_ctx.arena); - panel.last_frame = u64.max; - g_widget_ctx.panels[key.hash] = panel; - } - - return panel; -} - -UIItem* -PanelStart(u8[] str, Vec3 col) -{ - UIKey key = MakeKey(str); - UIPanel* panel = GetPanel(key); - - panel.first = panel.last = panel.next = panel.list_next = g_PANEL_NIL; - panel.child_count = 0; - - if (panel.anim.time_remaining > 0.0) - { - f32 r = panel.anim.time_remaining; - - r -= g_delta; - if (r < 0.0) - { - r = 0.0; - } - Logf("%f", r); - - f32 t = Remap(r, 0.0, panel.anim.time_start, 1.0, 0.0); - panel.percent = Lerp(panel.anim.start, panel.anim.end, t); - - panel.anim.time_remaining = r; - if (r == 0.0) - { - panel.anim.start = panel.anim.end = panel.anim.time_start = 0.0; - } - } - - panel.parent = g_widget_ctx.parent_panel; - panel.list_next = g_widget_ctx.parent_panel; - g_widget_ctx.parent_panel = panel; - - f32 x_pct = 1.0, y_pct = 1.0; - if (!Nil(panel.parent)) - { - if (panel.parent.split_axis == A2D.X) - { - x_pct = panel.percent; - } - else - { - y_pct = panel.percent; - } - - if (panel.last_frame != g_widget_ctx.frame) - { - Logf("new"); - panel.parent.new_children = true; - panel.anim.start = panel.anim.end = panel.anim.time_start = panel.anim.time_remaining = 0.0; - } - - panel.child_count += 1; - DLLPush(panel.parent, panel, g_PANEL_NIL); - } - - SetProp!(CtxP.LayoutAxis)(panel.split_axis); - SetProp!(CtxP.AxisX)(UISize(SK.PercentOfParent, x_pct, 1.0)); - SetProp!(CtxP.AxisY)(UISize(SK.PercentOfParent, y_pct, 1.0)); - SetProp!(CtxP.BGColor)(Vec4(col, 1.0)); - - UIItem* item = BuildItem(key, UIP.DrawBackground); + SetColor(color); + SetLayoutAxis(layout_axis); + UIItem* item = BuildItem(id, UISize(ST.Percentage, x_pct), UISize(ST.Percentage, y_pct), UIF.DrawBackground); PushParent(item); - panel.last_frame = g_widget_ctx.frame + 1; - return item; } void -PanelEnd() +EndPanel() { - UIPanel* parent = g_widget_ctx.parent_panel; - if (parent.new_children) - { - f32 new_percent = 1.0/cast(f32)(parent.child_count); - for(UIPanel* child = parent.first; !Nil(child); child = child.next) - { - f32 percent = child.percent; - if (percent > 0.0) - { - percent -= new_percent/cast(f32)(parent.child_count-1); - } - else - { - percent = new_percent; - } - - child.anim.start = child.percent; - child.anim.end = new_percent; - child.anim.time_start = 0.2; - child.anim.time_remaining = 0.2; - child.percent = percent; - } - - parent.new_children = false; - } - - g_widget_ctx.parent_panel = g_widget_ctx.parent_panel.list_next; PopParent(); }