more work on ui layout
This commit is contained in:
parent
e30d8f6689
commit
1bbf142039
2
src/dlib
2
src/dlib
@ -1 +1 @@
|
|||||||
Subproject commit 263cd8435ddd7a1cf67b39c2933e606a891bfe7b
|
Subproject commit a7d571bd5a1bdbe7aa15e5cacfba8795f2e5979b
|
||||||
@ -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);
|
||||||
|
|||||||
197
src/editor/ui.d
197
src/editor/ui.d
@ -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
19
src/editor/widgets.d
Normal 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;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user