more work on ui layout

This commit is contained in:
Matthew 2025-09-01 06:56:08 +10:00
parent e30d8f6689
commit 1bbf142039
4 changed files with 195 additions and 37 deletions

@ -1 +1 @@
Subproject commit 263cd8435ddd7a1cf67b39c2933e606a891bfe7b Subproject commit a7d571bd5a1bdbe7aa15e5cacfba8795f2e5979b

View File

@ -16,7 +16,9 @@ const u8[] FONT_BYTES = import("pc-9800.ttf");
const u8[] VERTEX_BYTES = import("gui.vert.spv"); const u8[] VERTEX_BYTES = import("gui.vert.spv");
const u8[] FRAGMENT_BYTES = import("gui.frag.spv"); const u8[] FRAGMENT_BYTES = import("gui.frag.spv");
const UI_COUNT = 50000; const UI_COUNT = 5000;
Editor* g_editor;
struct Editor struct Editor
{ {
@ -175,11 +177,15 @@ void
Cycle(Editor* ed) Cycle(Editor* ed)
{ {
Reset(&ed.temp_arena); Reset(&ed.temp_arena);
UIBeginFrame(); Logf("begin");
UIBeginBuild();
Logf("end");
/*
f32 pos = 0.0; f32 pos = 0.0;
f32 h = ed.atlas_buf.atlas.size; f32 h = ed.atlas_buf.atlas.size;
DrawBuffer(ed, 0.0, 0.0, h, ed.active_buffer); DrawBuffer(ed, 0.0, 0.0, h, ed.active_buffer);
*/
BeginFrame(&ed.rd); BeginFrame(&ed.rd);
@ -196,6 +202,10 @@ Cycle(Editor* ed)
Bind(&ed.rd, ed.pipeline, ed.desc_set); Bind(&ed.rd, ed.pipeline, ed.desc_set);
UIFinishBuild();
DrawUI();
FinishRendering(&ed.rd); FinishRendering(&ed.rd);
SubmitAndPresent(&ed.rd); SubmitAndPresent(&ed.rd);

View File

@ -4,6 +4,7 @@ import dlib.util;
import dlib.alloc; import dlib.alloc;
import dlib.fonts; import dlib.fonts;
import vulkan; import vulkan;
import widgets;
import editor; import editor;
@ -29,6 +30,12 @@ struct UIContext
Rect padding; Rect padding;
u32 tab_width; u32 tab_width;
f32 text_scale; f32 text_scale;
Stack!(UIItem) parent_stack;
}
struct Stack(T)
{
T* first;
} }
struct UIBuffer struct UIBuffer
@ -43,7 +50,7 @@ struct UIBuffer
enum CtxProperty enum CtxProperty
{ {
None, None,
BackgroundColor, BGColor,
BorderColor, BorderColor,
SizeKind, SizeKind,
SizeValue, SizeValue,
@ -129,6 +136,7 @@ struct UISize
struct UIItem struct UIItem
{ {
UIProperties flags; UIProperties flags;
UIKey key;
UIItem* first; UIItem* first;
UIItem* last; UIItem* last;
@ -137,9 +145,12 @@ struct UIItem
UIItem* parent; UIItem* parent;
UISize[A2D.max] size; UISize[A2D.max] size;
Vec4[4] bg_color;
Vec4[4] border_color;
Rect padding; Rect padding;
f32[A2D.max] computed_rel_pos; f32[A2D.max] computed_rel_pos;
f32[A2D.max] computed_size; f32[A2D.max] computed_size;
f32[A2D.max] fixed_position;
Rect rect; Rect rect;
f32 text_scale; f32 text_scale;
} }
@ -150,14 +161,130 @@ struct UIKey
u64 hash; u64 hash;
} }
void UIContext*
UIBeginFrame() GetCtx()
{ {
g_ui_ctx.buffer.count = 0; return &g_ui_ctx;
}
Vec2
RootSize()
{
Vec2 size = GetExtent(GetCtx().rd);
return size;
} }
void void
UIFrameSubmit() UIBeginBuild()
{
UIContext* ui = GetCtx();
ui.buffer.count = 0;
ClearStack(&g_ui_ctx.parent_stack, g_UI_NIL);
ui.root = RootItem();
PushParent(ui.root);
}
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))
{
foreach(i, ref s; item.size)
{
if (s.kind == SK.Pixels)
{
item.computed_size[i] = s.value;
}
}
}
// 2. PercentOfParent (Upward dependant) size (pre-order) (Ignore downward dependant sizes)
// 3. ChildrenSum (Downward dependant) (post-order)
// 4. Solve violations e.g. extending past boundaries of parent (pre-order)
// 5. Compute relative positions of each widgets (pre-order)
for(UIItem* item = ui.root; !Nil(item); item = Recurse!(UIR.PreOrder)(item, ui.root))
{
if (Nil(item.parent))
{
item.computed_rel_pos = item.fixed_position;
item.rect.x0 = item.computed_rel_pos[A2D.X];
item.rect.y0 = item.computed_rel_pos[A2D.Y];
item.rect.x1 = item.computed_size[A2D.X];
item.rect.y1 = item.computed_size[A2D.Y];
}
}
for(UIItem* item = ui.root; !Nil(item); item = Recurse!(UIR.PreOrder)(item, ui.root))
{
if (!Nil(item))
{
if (item.flags & UIP.DrawBackground)
{
DrawRect(ui, item);
}
}
}
}
UIItem*
BuildItem(UIKey key, UIProperties flags)
{
UIContext* ui = GetCtx();
UIItem* item = Get(key);
item.first = item.last = item.next = item.prev = item.parent = g_UI_NIL;
item.computed_rel_pos = item.computed_size = 0;
item.flags = flags;
item.size = ui.size_axes;
item.padding = ui.padding;
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;
}
return item;
}
void
ClearStack(T)(Stack!(T)* stack, T* nil)
{
while(SPop(stack, nil) != nil) {}
}
void
PushParent(UIItem* parent)
{
SPush(&g_ui_ctx.parent_stack, parent, g_UI_NIL);
}
UIItem*
PopParent()
{
return SPop(&g_ui_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); 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); DrawIndexed(g_ui_ctx.rd, 6, g_ui_ctx.buffer.count, 0);
@ -179,6 +306,14 @@ InitUIContext(Renderer* rd)
g_ui_ctx.buffer.mapped_idx = idx; g_ui_ctx.buffer.mapped_idx = idx;
g_ui_ctx.buffer.vtx = vtx.data; g_ui_ctx.buffer.vtx = vtx.data;
g_ui_ctx.buffer.idx = idx.data; g_ui_ctx.buffer.idx = idx.data;
g_ui_ctx.parent_stack.first = g_UI_NIL;
}
UIKey
MakeKey(string str)
{
u8[] id = (cast(u8*)str)[0 .. str.length];
return MakeKey(id);
} }
UIKey UIKey
@ -231,27 +366,18 @@ MakeKey(u8[] id)
} }
UIItem* UIItem*
Find(u8[] id) Get(UIKey key)
{ {
u64 hash = Hash(id); Result!(UIItem*) result = g_ui_ctx.items[key.hash];
Result!(UIItem*) result = g_ui_ctx.items[hash];
if (!result.ok) if (!result.ok)
{ {
result.value = Alloc!(UIItem)(&g_ui_ctx.arena); result.value = Alloc!(UIItem)(&g_ui_ctx.arena);
Push(&g_ui_ctx.items, hash, result.value); Push(&g_ui_ctx.items, key.hash, result.value);
} }
return result.value; return result.value;
} }
bool
UIWindow(Rect rect, f32 border_px, u8[] text)
{
UIItem* item = Find(text);
return false;
}
f32 f32
CalcTextWidth(u8[] str) CalcTextWidth(u8[] str)
{ {
@ -312,25 +438,21 @@ DrawGlyph(Glyph* glyph, f32 scale, f32* x_pos, f32 y, Vec4 col = Vec4(1.0))
*x_pos += glyph.advance * scale; *x_pos += glyph.advance * scale;
} }
/*
pragma(inline) void pragma(inline) void
DrawRect(UIContext* ctx, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, f32 border, f32 corner, f32 softness, f32 raised, Vec4[4] cols) DrawRect(UIContext* ctx, UIItem* item)
{ {
// Y reversed // Y reversed
Vertex* v = g_ui_ctx.buffer.vtx.ptr + g_ui_ctx.buffer.count; Vertex* v = ctx.buffer.vtx.ptr + ctx.buffer.count;
v.dst_start.x = p0_x; v.dst_start = item.rect.vec0;
v.dst_start.y = p0_y; v.dst_end = item.rect.vec1;
v.dst_end.x = p1_x; v.cols = item.bg_color;
v.dst_end.y = p1_y; v.border_thickness = 0.0;
v.cols = cols; v.corner_radius = 0.0;
v.border_thickness = border; v.edge_softness = 0.0;
v.corner_radius = corner; v.raised = 0.0;
v.edge_softness = softness;
v.raised = raised;
AddUIIndices(ctx); AddUIIndices();
} }
*/
void void
AddUIIndices() AddUIIndices()
@ -381,11 +503,18 @@ Recurse(alias mode)(UIItem* item, UIItem* root)
pragma(inline) void pragma(inline) void
SetProp(alias P, T)(T value) SetProp(alias P, T)(T value)
{ {
static if (is(T: Vec4[4])) static if (is(T: Vec4))
{ {
static if (0) {} static if (0) {}
else static if (P == CtxP.BackgroundColor) { g_ui_ctx.bg_cols = value; } else static if (P == CtxP.BGColor) g_ui_ctx.bg_cols = [value, value, value, value];
else static if (P == CtxP.BorderColor) g_ui_ctx.border_cols = value; else static if (P == CtxP.BorderColor) g_ui_ctx.border_cols = [value, value, value, value];
else static assert(false, "Unknown Property for type Vec4");
}
else static if (is(T: Vec4[4]))
{
static if (0) {}
else static if (P == CtxP.BGColor) g_ui_ctx.bg_cols = value;
else static if (P == CtxP.BorderColor) g_ui_ctx.border_cols = value;
else static assert(false, "Unknown Property for type Vec4[4]"); else static assert(false, "Unknown Property for type Vec4[4]");
} }
else static if (is(T: SizeKind) && P == CtxP.SizeKind) else static if (is(T: SizeKind) && P == CtxP.SizeKind)

19
src/editor/widgets.d Normal file
View File

@ -0,0 +1,19 @@
import dlib;
import ui;
UIItem*
RootItem()
{
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));
UIItem* item = BuildItem(key, UIP.DrawBackground);
return item;
}