more work on UI, starting to replace existing UI code
This commit is contained in:
parent
ad3ababe97
commit
8acbeee072
10
dub.json
10
dub.json
@ -16,8 +16,9 @@
|
|||||||
"versions": ["VULKAN_DEBUG", "ENABLE_RENDERER"],
|
"versions": ["VULKAN_DEBUG", "ENABLE_RENDERER"],
|
||||||
"preGenerateCommands-linux": ["./build.sh"],
|
"preGenerateCommands-linux": ["./build.sh"],
|
||||||
"preGenerateCommands-windows": [],
|
"preGenerateCommands-windows": [],
|
||||||
"dflags": ["-Xcc=-mno-sse", "-P-I/usr/include/freetype2", "-Jbuild", "-Jassets", "-link-debuglib"],
|
"dflags": ["-P-I/usr/include/freetype2", "-Jbuild", "-Jassets"],
|
||||||
"dflags-dmd": ["-P=-DSTBI_NO_SIMD"]
|
"dflags-ldc2": ["-link-debuglib"],
|
||||||
|
"dflags-dmd": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "editor-test",
|
"name": "editor-test",
|
||||||
@ -33,8 +34,9 @@
|
|||||||
"versions": ["VULKAN_DEBUG"],
|
"versions": ["VULKAN_DEBUG"],
|
||||||
"preGenerateCommands-linux": ["./build.sh"],
|
"preGenerateCommands-linux": ["./build.sh"],
|
||||||
"preGenerateCommands-windows": [],
|
"preGenerateCommands-windows": [],
|
||||||
"dflags": ["-Xcc=-mno-sse", "-P-I/usr/include/freetype2", "-Jbuild", "-Jassets", "-link-debuglib", "-unittest"],
|
"dflags": ["-P-I/usr/include/freetype2", "-Jbuild", "-Jassets", "-unittest"],
|
||||||
"dflags-dmd": ["-P=-DSTBI_NO_SIMD"]
|
"dflags-ldc2": ["-link-debuglib"],
|
||||||
|
"dflags-dmd": []
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
2
src/dlib
2
src/dlib
@ -1 +1 @@
|
|||||||
Subproject commit e5f91cae6d90c40e458e1208c2ab8f8eb917c99a
|
Subproject commit 617e03f917911f6f9898086720a6539756f79758
|
||||||
@ -141,6 +141,29 @@ Cycle(EditorCtx* ctx, Inputs* inputs)
|
|||||||
|
|
||||||
BeginUI(inputs);
|
BeginUI(inputs);
|
||||||
|
|
||||||
|
UICtx* ui_ctx = GetCtx();
|
||||||
|
|
||||||
|
Vec4[4] col0 = Vec4(0.2, 0.4, 0.8, 1.0);
|
||||||
|
Vec4[4] col1 = Vec4(0.8, 0.4, 0.2, 1.0);
|
||||||
|
Vec4[4] col_sep = Vec4(0.2, 0.8, 0.1, 1.0);
|
||||||
|
|
||||||
|
Push!("size_info")(ui_ctx, MakeUISizeX(ST.Percentage, 0.5));
|
||||||
|
|
||||||
|
Push!("bg_col", true)(ui_ctx, col0);
|
||||||
|
UIItem* p0 = MakeItem("###p0", UIF.DrawBackground|UIF.Resizeable);
|
||||||
|
|
||||||
|
Logf("%s", *ui_ctx.size_info.top);
|
||||||
|
Push!("size_info", true)(ui_ctx, MakeUISizeX(ST.Pixels, 2.0));
|
||||||
|
Logf("%s", *ui_ctx.size_info.top);
|
||||||
|
Push!("bg_col", true)(ui_ctx, col_sep);
|
||||||
|
UIItem* sep = MakeItem("###sep", UIF.Draggable|UIF.DrawBackground|UIF.ResizeAdjacent);
|
||||||
|
Logf("%s", *ui_ctx.size_info.top);
|
||||||
|
|
||||||
|
|
||||||
|
Push!("bg_col", true)(ui_ctx, col1);
|
||||||
|
UIItem* p1 = MakeItem("###p1", UIF.DrawBackground|UIF.Resizeable);
|
||||||
|
|
||||||
|
/*
|
||||||
UIPanel* root = ctx.base_panel;
|
UIPanel* root = ctx.base_panel;
|
||||||
|
|
||||||
root.size.x = g_ui_ctx.res.x;
|
root.size.x = g_ui_ctx.res.x;
|
||||||
@ -150,7 +173,7 @@ Cycle(EditorCtx* ctx, Inputs* inputs)
|
|||||||
|
|
||||||
static foreach(axis; A2D.min .. A2D.max)
|
static foreach(axis; A2D.min .. A2D.max)
|
||||||
{
|
{
|
||||||
for(UIPanel* p = root; !Nil(p); p = Recurse(p, root, g_UI_NIL_PANEL))
|
for(UIPanel* p = root; !Nil(p); p = Recurse(p, g_UI_NIL_PANEL))
|
||||||
{
|
{
|
||||||
f32 pos = p.rect.p0.v[axis];
|
f32 pos = p.rect.p0.v[axis];
|
||||||
for(UIPanel* c = p.first; !Nil(c); c = c.next)
|
for(UIPanel* c = p.first; !Nil(c); c = c.next)
|
||||||
@ -167,7 +190,7 @@ Cycle(EditorCtx* ctx, Inputs* inputs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto p = ctx.base_panel; !Nil(p); p = Recurse(p, ctx.base_panel, g_UI_NIL_PANEL))
|
for(auto p = ctx.base_panel; !Nil(p); p = Recurse(p, g_UI_NIL_PANEL))
|
||||||
{
|
{
|
||||||
Panel(p);
|
Panel(p);
|
||||||
}
|
}
|
||||||
@ -181,6 +204,7 @@ Cycle(EditorCtx* ctx, Inputs* inputs)
|
|||||||
|
|
||||||
CommandPalette(&ctx.cmd);
|
CommandPalette(&ctx.cmd);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
EndUI();
|
EndUI();
|
||||||
}
|
}
|
||||||
|
|||||||
300
src/editor/ui.d
300
src/editor/ui.d
@ -14,6 +14,7 @@ import std.math.traits : isNaN;
|
|||||||
import std.math.rounding : ceil, floor;
|
import std.math.rounding : ceil, floor;
|
||||||
import std.math.exponential : pow;
|
import std.math.exponential : pow;
|
||||||
import std.math.remainder : fmod;
|
import std.math.remainder : fmod;
|
||||||
|
import std.algorithm.comparison : clamp;
|
||||||
import std.format : sformat;
|
import std.format : sformat;
|
||||||
import core.stdc.string : memset;
|
import core.stdc.string : memset;
|
||||||
import core.stdc.math : fabsf;
|
import core.stdc.math : fabsf;
|
||||||
@ -102,12 +103,17 @@ enum UIFlags
|
|||||||
ScrollY = 1<<6,
|
ScrollY = 1<<6,
|
||||||
ClampX = 1<<7,
|
ClampX = 1<<7,
|
||||||
ClampY = 1<<8,
|
ClampY = 1<<8,
|
||||||
|
Resizeable = 1<<9,
|
||||||
|
ResizeAdjacent = 1<<10,
|
||||||
|
FloatingWindow = 1<<11,
|
||||||
|
CenteredWindow = 1<<12,
|
||||||
|
TextInput = 1<<13,
|
||||||
|
|
||||||
Clamp = UIFlags.ClampX | UIFlags.ClampY,
|
Clamp = UIFlags.ClampX | UIFlags.ClampY,
|
||||||
}
|
}
|
||||||
alias UIF = UIFlags;
|
alias UIF = UIFlags;
|
||||||
|
|
||||||
|
const UIFlags AUTO_FLAGS = UIF.ResizeAdjacent;
|
||||||
|
|
||||||
enum UISignal
|
enum UISignal
|
||||||
{
|
{
|
||||||
@ -159,35 +165,27 @@ UICtxParameter(T, string name)
|
|||||||
|
|
||||||
template CtxMemberInfo(int i)
|
template CtxMemberInfo(int i)
|
||||||
{
|
{
|
||||||
import std.string : endsWith;
|
import std.string : endsWith, startsWith;
|
||||||
import std.traits : isInstanceOf, isPointer;
|
import std.traits : isInstanceOf, isPointer;
|
||||||
|
|
||||||
struct MemberInfo
|
struct MemberInfo
|
||||||
{
|
{
|
||||||
string id;
|
string id;
|
||||||
bool is_stack, is_top, is_stack_top;
|
bool is_stack, is_top;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum string id = __traits(identifier, UICtx.tupleof[i]);
|
enum string id = __traits(identifier, UICtx.tupleof[i]);
|
||||||
enum bool is_ptr = isPointer!(typeof(UICtx.tupleof[i]));
|
|
||||||
enum bool is_top = endsWith(id, "_top");
|
enum bool is_top = endsWith(id, "_top");
|
||||||
enum bool is_stack_top = isInstanceOf!(StackTop, typeof(UICtx.tupleof[i]));
|
enum bool is_stack = startsWith(typeof(UICtx.tupleof[i]).stringof, "StackTop!");
|
||||||
|
|
||||||
static if(is_ptr)
|
enum MemberInfo CtxMemberInfo = MemberInfo(id: id, is_stack: is_stack, is_top: is_top);
|
||||||
{
|
|
||||||
enum bool is_stack = isInstanceOf!(Stack, typeof(*UICtx.tupleof[i]));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
enum bool is_stack = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum MemberInfo CtxMemberInfo = MemberInfo(id: id, is_stack: is_ptr && is_stack, is_top: is_top, is_stack_top: is_stack_top);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UICtx
|
struct UICtx
|
||||||
{
|
{
|
||||||
HashTable!(UIHash, UIItem*) items;
|
HashTable!(UIHash, UIItem*) items;
|
||||||
|
UIItem* free_items;
|
||||||
|
|
||||||
Arena arena;
|
Arena arena;
|
||||||
Arena temp_arena;
|
Arena temp_arena;
|
||||||
Inputs* inputs;
|
Inputs* inputs;
|
||||||
@ -219,6 +217,7 @@ struct UICtx
|
|||||||
u32 tab_width;
|
u32 tab_width;
|
||||||
f32 text_size;
|
f32 text_size;
|
||||||
|
|
||||||
|
UIItem* window_root;
|
||||||
UIItem* root;
|
UIItem* root;
|
||||||
UIItem* drag_item;
|
UIItem* drag_item;
|
||||||
UIPanel* parent_panel;
|
UIPanel* parent_panel;
|
||||||
@ -245,13 +244,13 @@ struct Stack(T)
|
|||||||
{
|
{
|
||||||
Stack!(T)* next;
|
Stack!(T)* next;
|
||||||
T value;
|
T value;
|
||||||
|
bool auto_pop;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StackTop(T)
|
struct StackTop(T)
|
||||||
{
|
{
|
||||||
Stack!(T)* top;
|
Stack!(T)* top;
|
||||||
Stack!(T)* free;
|
Stack!(T)* free;
|
||||||
bool auto_pop;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin template UIItemParameters()
|
mixin template UIItemParameters()
|
||||||
@ -264,7 +263,7 @@ mixin template UIItemParameters()
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
enum info = CtxMemberInfo!(i);
|
enum info = CtxMemberInfo!(i);
|
||||||
static if(info.is_stack_top)
|
static if(info.is_stack)
|
||||||
{
|
{
|
||||||
fields ~= typeof(UICtx.tupleof[i].top.value).stringof ~ " " ~ info.id ~ ";\n";
|
fields ~= typeof(UICtx.tupleof[i].top.value).stringof ~ " " ~ info.id ~ ";\n";
|
||||||
}
|
}
|
||||||
@ -279,17 +278,20 @@ mixin template UIItemParameters()
|
|||||||
|
|
||||||
struct UIItem
|
struct UIItem
|
||||||
{
|
{
|
||||||
UIKey key;
|
IVec2 dragged;
|
||||||
UIFlags flags;
|
UIKey key;
|
||||||
u64 last_frame;
|
|
||||||
IVec2 dragged;
|
|
||||||
|
|
||||||
UIItem* next, prev, first, last; // parent in mixin
|
u64 last_frame;
|
||||||
|
UISignal signal;
|
||||||
|
UIFlags flags;
|
||||||
|
|
||||||
Rect rect;
|
UIItem* next, prev, first, last; // parent in mixin
|
||||||
Vec2 size;
|
|
||||||
|
|
||||||
u8[] display_string;
|
Rect rect;
|
||||||
|
Vec2 size;
|
||||||
|
|
||||||
|
f32 resize_pct;
|
||||||
|
u8[] display_string;
|
||||||
|
|
||||||
mixin UIItemParameters!();
|
mixin UIItemParameters!();
|
||||||
}
|
}
|
||||||
@ -417,6 +419,7 @@ InitUICtx(PlatformWindow* window)
|
|||||||
|
|
||||||
UICtx ctx = {
|
UICtx ctx = {
|
||||||
items: CreateHashTable!(UIHash, UIItem*)(12),
|
items: CreateHashTable!(UIHash, UIItem*)(12),
|
||||||
|
free_items: Alloc!(UIItem)(&arena),
|
||||||
arena: arena,
|
arena: arena,
|
||||||
temp_arena: CreateArena(MB(1)),
|
temp_arena: CreateArena(MB(1)),
|
||||||
drag_item: g_UI_NIL,
|
drag_item: g_UI_NIL,
|
||||||
@ -426,6 +429,9 @@ InitUICtx(PlatformWindow* window)
|
|||||||
tab_width: 2,
|
tab_width: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UIItem* fi = ctx.free_items;
|
||||||
|
fi.first = fi.last = fi.next = fi.prev = fi.parent = g_UI_NIL;
|
||||||
|
|
||||||
ctx.atlas_buf = CreateAtlas(&arena, ctx.font, 16.0, 256);
|
ctx.atlas_buf = CreateAtlas(&arena, ctx.font, 16.0, 256);
|
||||||
|
|
||||||
version(ENABLE_RENDERER)
|
version(ENABLE_RENDERER)
|
||||||
@ -435,9 +441,10 @@ InitUICtx(PlatformWindow* window)
|
|||||||
for(u64 i = 0; i < FRAME_OVERLAP; i += 1)
|
for(u64 i = 0; i < FRAME_OVERLAP; i += 1)
|
||||||
{
|
{
|
||||||
ctx.buffers[i].m_vtx = CreateMappedBuffer!(Vertex)(&ctx.rd, BT.Vertex, VERTEX_MAX_COUNT);
|
ctx.buffers[i].m_vtx = CreateMappedBuffer!(Vertex)(&ctx.rd, BT.Vertex, VERTEX_MAX_COUNT);
|
||||||
ctx.buffers[i].m_idx = CreateMappedBuffer!(u32)(&ctx.rd, BT.Index, cast(u64)(ceil(VERTEX_MAX_COUNT*1.5)));
|
ctx.buffers[i].m_idx = CreateMappedBuffer!(u32)(&ctx.rd, BT.Index, 6);
|
||||||
ctx.buffers[i].vtx = ctx.buffers[i].m_vtx.data;
|
ctx.buffers[i].vtx = ctx.buffers[i].m_vtx.data;
|
||||||
ctx.buffers[i].idx = ctx.buffers[i].m_idx.data;
|
ctx.buffers[i].idx = ctx.buffers[i].m_idx.data;
|
||||||
|
ctx.buffers[i].idx[0 .. $] = [0, 1, 2, 2, 1, 3];
|
||||||
}
|
}
|
||||||
|
|
||||||
DescLayoutBinding[2] layout_bindings = [
|
DescLayoutBinding[2] layout_bindings = [
|
||||||
@ -513,33 +520,54 @@ Set(UIItem* item, UICtx* ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
UIItem*
|
UIItem*
|
||||||
MakeItem(T)(T k) if(is(T: UIKey) || StringType!T)
|
MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T)
|
||||||
{
|
{
|
||||||
UICtx* ctx = GetCtx();
|
UICtx* ctx = GetCtx();
|
||||||
UIItem* item = Get(k);
|
UIItem* item = Get(k);
|
||||||
|
item.flags = flags;
|
||||||
|
|
||||||
Set(item, ctx);
|
Set(item, ctx);
|
||||||
if(!Nil(item.parent))
|
if(item.flags & (UIF.CenteredWindow | UIF.FloatingWindow))
|
||||||
|
{
|
||||||
|
item.parent = ctx.window_root;
|
||||||
|
DLLPush(item.parent, item, g_UI_NIL);
|
||||||
|
}
|
||||||
|
else if(!Nil(item.parent))
|
||||||
{
|
{
|
||||||
DLLPush(item.parent, item, g_UI_NIL);
|
DLLPush(item.parent, item, g_UI_NIL);
|
||||||
}
|
}
|
||||||
AutoPopStacks(ctx);
|
AutoPopStacks(ctx);
|
||||||
|
|
||||||
|
if(item.last_frame != ctx.frame-1 && item.flags & UIF.Resizeable)
|
||||||
|
{
|
||||||
|
if(item.size_info[item.parent.layout_axis].type != ST.Percentage)
|
||||||
|
{
|
||||||
|
Logf("Warning: Resizing not percentage SizeType item, disabling flag");
|
||||||
|
item.flags &= ~UIF.Resizeable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.resize_pct = item.size_info[item.layout_axis].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item.last_frame = ctx.frame;
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
UISignal
|
void
|
||||||
Signal(UIItem* item)
|
Signal(UIItem* item)
|
||||||
{
|
{
|
||||||
UISignal signal;
|
UICtx* ctx = GetCtx();
|
||||||
UICtx* ctx = GetCtx();
|
i32 x = ctx.mouse_pos.x;
|
||||||
|
i32 y = ctx.mouse_pos.y;
|
||||||
|
|
||||||
i32 x = ctx.mouse_pos.x;
|
item.signal = UIS.None;
|
||||||
i32 y = ctx.mouse_pos.y;
|
|
||||||
|
|
||||||
if(x >= item.rect.p0.x && x <= item.rect.p1.x && y >= item.rect.p0.y && y <= item.rect.p1.y)
|
if(x >= item.rect.p0.x && x <= item.rect.p1.x && y >= item.rect.p0.y && y <= item.rect.p1.y)
|
||||||
{
|
{
|
||||||
signal |= UIS.Hovered;
|
item.signal |= UIS.Hovered;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.dragged = 0;
|
item.dragged = 0;
|
||||||
@ -548,21 +576,27 @@ Signal(UIItem* item)
|
|||||||
{
|
{
|
||||||
bool taken;
|
bool taken;
|
||||||
|
|
||||||
|
Logf("%s", i.type);
|
||||||
|
|
||||||
if(item.flags & UIF.Clickable && i.type == UIE.Click && InBounds(ctx.mouse_pos, &item.rect))
|
if(item.flags & UIF.Clickable && i.type == UIE.Click && InBounds(ctx.mouse_pos, &item.rect))
|
||||||
{
|
{
|
||||||
signal |= UIS.Clicked;
|
Logf("clicked");
|
||||||
taken = true;
|
item.signal |= UIS.Clicked;
|
||||||
|
taken = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Nil(ctx.drag_item) && item.flags & UIF.Draggable && i.type == UIE.DragStart && InBounds(i.pos, &item.rect))
|
if(Nil(ctx.drag_item) && item.flags & UIF.Draggable && i.type == UIE.DragStart && InBounds(i.pos, &item.rect))
|
||||||
{
|
{
|
||||||
signal |= UIS.Dragged;
|
Logf("dragged");
|
||||||
|
item.signal |= UIS.Dragged;
|
||||||
ctx.drag_item = item;
|
ctx.drag_item = item;
|
||||||
taken = true;
|
taken = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ctx.drag_item == item && i.type == UIE.Drag)
|
if(ctx.drag_item == item && i.type == UIE.Drag)
|
||||||
{
|
{
|
||||||
|
Logf("dragged");
|
||||||
|
item.signal |= UIS.Dragged;
|
||||||
item.dragged += i.rel;
|
item.dragged += i.rel;
|
||||||
taken = true;
|
taken = true;
|
||||||
}
|
}
|
||||||
@ -572,8 +606,6 @@ Signal(UIItem* item)
|
|||||||
DLLRemove(&ctx.events, i, g_UI_NIL_INPUT);
|
DLLRemove(&ctx.events, i, g_UI_NIL_INPUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return signal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -593,8 +625,8 @@ BeginUI(Inputs* inputs)
|
|||||||
|
|
||||||
Reset(a);
|
Reset(a);
|
||||||
|
|
||||||
|
// Convert Inputs
|
||||||
ctx.events.first = ctx.events.last = null;
|
ctx.events.first = ctx.events.last = null;
|
||||||
|
|
||||||
static bool dragging;
|
static bool dragging;
|
||||||
static bool mouse_down;
|
static bool mouse_down;
|
||||||
for(auto i = inputs.first; i; i = i.next)
|
for(auto i = inputs.first; i; i = i.next)
|
||||||
@ -633,6 +665,21 @@ BeginUI(Inputs* inputs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up items
|
||||||
|
KVPair!(UIHash, UIItem*)*[] items = GetAllNodes(&ctx.temp_arena, &ctx.items);
|
||||||
|
foreach(i; 0 .. items.length)
|
||||||
|
{
|
||||||
|
UIItem* item = items[i].value;
|
||||||
|
if(item.last_frame != ctx.frame)
|
||||||
|
{
|
||||||
|
Logf("discarding %s", cast(char[])item.key.hash_text);
|
||||||
|
item.first = item.last = item.parent = item.prev = item.next = g_UI_NIL;
|
||||||
|
DLLPush(ctx.free_items, item, g_UI_NIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.frame += 1;
|
||||||
|
|
||||||
// Ctx state
|
// Ctx state
|
||||||
ctx.f_idx = ctx.frame%FRAME_OVERLAP;
|
ctx.f_idx = ctx.frame%FRAME_OVERLAP;
|
||||||
ctx.inputs = inputs;
|
ctx.inputs = inputs;
|
||||||
@ -660,13 +707,16 @@ BeginUI(Inputs* inputs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(ctx.buffers[ctx.f_idx].vtx.ptr, 0, Vertex.sizeof * ctx.buffers[ctx.f_idx].count);
|
memset(ctx.buffers[ctx.f_idx].vtx.ptr, 0, Vertex.sizeof * ctx.buffers[ctx.f_idx].count);
|
||||||
memset(ctx.buffers[ctx.f_idx].idx.ptr, 0, u32.sizeof * ctx.buffers[ctx.f_idx].count);
|
|
||||||
ctx.buffers[ctx.f_idx].count = 0;
|
ctx.buffers[ctx.f_idx].count = 0;
|
||||||
|
|
||||||
// Root Item
|
// Root Item
|
||||||
UISize[2] sizes = [UISize(ST.Pixels, ctx.res.x), UISize(ST.Pixels, ctx.res.y)];
|
UISize[2] sizes = [UISize(ST.Pixels, ctx.res.x), UISize(ST.Pixels, ctx.res.y)];
|
||||||
Push!("size_info", true)(ctx, sizes);
|
Push!("size_info")(ctx, sizes);
|
||||||
ctx.root = MakeItem("###root");
|
|
||||||
|
ctx.root = MakeItem("###root");
|
||||||
|
ctx.window_root = MakeItem("###window_root");
|
||||||
|
|
||||||
|
Pop!("size_info")(ctx);
|
||||||
Push!("parent")(ctx, ctx.root);
|
Push!("parent")(ctx, ctx.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -675,9 +725,45 @@ EndUI()
|
|||||||
{
|
{
|
||||||
UICtx* ctx = GetCtx();
|
UICtx* ctx = GetCtx();
|
||||||
|
|
||||||
|
// Automatic signals
|
||||||
|
for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(true)(item, g_UI_NIL))
|
||||||
|
{
|
||||||
|
if(item.flags & AUTO_FLAGS)
|
||||||
|
{
|
||||||
|
Signal(item);
|
||||||
|
|
||||||
|
if(item.signal & UIS.Dragged)
|
||||||
|
{
|
||||||
|
Logf("1");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(item.flags & UIF.ResizeAdjacent && item.dragged != IVec2(0))
|
||||||
|
{
|
||||||
|
UIItem* prev = !Nil(item.prev) ? item.prev : g_UI_NIL;
|
||||||
|
UIItem* next = !Nil(item.next) ? item.next : g_UI_NIL;
|
||||||
|
|
||||||
|
if(prev.flags & UIF.Resizeable && next.flags & UIF.Resizeable)
|
||||||
|
{
|
||||||
|
Axis2D axis = item.parent.layout_axis;
|
||||||
|
f32 mov_pct = Remap(item.dragged.v[axis], 0.0, item.parent.size.v[axis], 0.0, 1.0);
|
||||||
|
if(prev.resize_pct > 0.0 && prev.resize_pct < 1.0 && next.resize_pct > 0.0 && next.resize_pct < 1.0)
|
||||||
|
{
|
||||||
|
prev.resize_pct -= mov_pct;
|
||||||
|
next.resize_pct += mov_pct;
|
||||||
|
|
||||||
|
prev.resize_pct = clamp(prev.resize_pct, 0.0, 1.0);
|
||||||
|
next.resize_pct = clamp(next.resize_pct, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate item properties
|
||||||
static foreach(axis; A2D.min .. A2D.max)
|
static foreach(axis; A2D.min .. A2D.max)
|
||||||
{
|
{
|
||||||
for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(true)(item, ctx.root, g_UI_NIL))
|
// Pixel sizes
|
||||||
|
for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(true)(item, g_UI_NIL))
|
||||||
{
|
{
|
||||||
if(item.size_info[axis].type == ST.Pixels)
|
if(item.size_info[axis].type == ST.Pixels)
|
||||||
{
|
{
|
||||||
@ -685,10 +771,16 @@ EndUI()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(true)(item, ctx.root, g_UI_NIL))
|
// Percentage sizes
|
||||||
|
for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(true)(item, g_UI_NIL))
|
||||||
{
|
{
|
||||||
if(item.size_info[axis].type == ST.Percentage)
|
if(item.size_info[axis].type == ST.Percentage)
|
||||||
{
|
{
|
||||||
|
if(item.layout_axis == axis && item.flags & UIF.Resizeable)
|
||||||
|
{
|
||||||
|
item.size_info[axis].value = item.resize_pct;
|
||||||
|
}
|
||||||
|
|
||||||
for(UIItem* p = item.parent; !Nil(p); p = p.parent)
|
for(UIItem* p = item.parent; !Nil(p); p = p.parent)
|
||||||
{
|
{
|
||||||
if(p.size_info[axis].type == ST.Pixels)
|
if(p.size_info[axis].type == ST.Pixels)
|
||||||
@ -700,7 +792,8 @@ EndUI()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(false)(item, ctx.root, g_UI_NIL))
|
// Sum of children sizes
|
||||||
|
for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(false)(item, g_UI_NIL))
|
||||||
{
|
{
|
||||||
if(item.size_info[axis].type == ST.ChildrenSum)
|
if(item.size_info[axis].type == ST.ChildrenSum)
|
||||||
{
|
{
|
||||||
@ -712,7 +805,8 @@ EndUI()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(true)(item, ctx.root, g_UI_NIL))
|
// Violations
|
||||||
|
for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(true)(item, g_UI_NIL))
|
||||||
{
|
{
|
||||||
if(axis == item.layout_axis)
|
if(axis == item.layout_axis)
|
||||||
{
|
{
|
||||||
@ -724,7 +818,6 @@ EndUI()
|
|||||||
|
|
||||||
if(children_size > item.size[axis])
|
if(children_size > item.size[axis])
|
||||||
{
|
{
|
||||||
Logf("%s %s %s %s", axis, cast(char[])item.key.hash_text, children_size, item.size[axis]);
|
|
||||||
u64 child_count;
|
u64 child_count;
|
||||||
for(UIItem* c = item.first; !Nil(c); c = c.next)
|
for(UIItem* c = item.first; !Nil(c); c = c.next)
|
||||||
{
|
{
|
||||||
@ -766,6 +859,7 @@ EndUI()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate final sizes
|
||||||
{
|
{
|
||||||
f32 pos = 0.0;
|
f32 pos = 0.0;
|
||||||
for(UIItem* item = ctx.root; !Nil(item);)
|
for(UIItem* item = ctx.root; !Nil(item);)
|
||||||
@ -809,6 +903,11 @@ EndUI()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Render Items
|
||||||
|
RenderItems(ctx.root);
|
||||||
|
RenderItems(ctx.window_root);
|
||||||
|
|
||||||
version(ENABLE_RENDERER) with(ctx)
|
version(ENABLE_RENDERER) with(ctx)
|
||||||
{
|
{
|
||||||
BindBuffers(&rd, &buffers[f_idx].m_idx, &buffers[f_idx].m_vtx);
|
BindBuffers(&rd, &buffers[f_idx].m_idx, &buffers[f_idx].m_vtx);
|
||||||
@ -817,8 +916,39 @@ EndUI()
|
|||||||
FinishRendering(&rd);
|
FinishRendering(&rd);
|
||||||
SubmitAndPresent(&rd);
|
SubmitAndPresent(&rd);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx.frame += 1;
|
void
|
||||||
|
RenderItems(UIItem* root)
|
||||||
|
{
|
||||||
|
UICtx* ctx = GetCtx();
|
||||||
|
for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(true)(item, g_UI_NIL))
|
||||||
|
{
|
||||||
|
if(item.flags & UIF.DrawBackground)
|
||||||
|
{
|
||||||
|
// DrawRect
|
||||||
|
Vertex* v = GetVertex(ctx);
|
||||||
|
v.dst_start = item.rect.p0 + item.border_thickness;
|
||||||
|
v.dst_end = item.rect.p1 - item.border_thickness;
|
||||||
|
v.cols = item.bg_col;
|
||||||
|
v.corner_radius = item.corner_radius;
|
||||||
|
|
||||||
|
AddVertexCount(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(item.flags & UIF.DrawBorder)
|
||||||
|
{
|
||||||
|
Vertex* v = GetVertex(ctx);
|
||||||
|
v.dst_start = item.rect.p0;
|
||||||
|
v.dst_end = item.rect.p1;
|
||||||
|
v.cols = item.border_col;
|
||||||
|
v.corner_radius = item.corner_radius;
|
||||||
|
v.border_thickness = item.border_thickness;
|
||||||
|
v.edge_softness = item.edge_softness;
|
||||||
|
|
||||||
|
AddVertexCount(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32[2]
|
u32[2]
|
||||||
@ -862,11 +992,11 @@ Push(string stack_str, bool auto_pop = false, T)(UICtx* ctx, T value)
|
|||||||
node = Alloc!(Stack!(T))(&ctx.temp_arena);
|
node = Alloc!(Stack!(T))(&ctx.temp_arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
node.next = stack.top;
|
node.next = stack.top;
|
||||||
node.value = value;
|
node.value = value;
|
||||||
|
node.auto_pop = auto_pop;
|
||||||
|
|
||||||
stack.top = node;
|
stack.top = node;
|
||||||
stack.auto_pop = auto_pop;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto
|
auto
|
||||||
@ -902,12 +1032,12 @@ AutoPopStacks(UICtx* ctx)
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
enum member_info = CtxMemberInfo!(i);
|
enum member_info = CtxMemberInfo!(i);
|
||||||
static if(member_info.is_stack && !member_info.is_top)
|
static if(member_info.is_stack)
|
||||||
{
|
{
|
||||||
if(ctx.tupleof[i].auto_pop)
|
if(ctx.tupleof[i].top.auto_pop)
|
||||||
{
|
{
|
||||||
|
ctx.tupleof[i].top.auto_pop = false;
|
||||||
Pop!(member_info.id)(ctx);
|
Pop!(member_info.id)(ctx);
|
||||||
ctx.tupleof[i].auto_pop = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -924,7 +1054,7 @@ InitStacks(UICtx* ctx)
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
enum member_info = CtxMemberInfo!(i);
|
enum member_info = CtxMemberInfo!(i);
|
||||||
static if(member_info.is_stack && member_info.is_top)
|
static if(member_info.is_top)
|
||||||
{
|
{
|
||||||
enum global_default = replace("g_@_default", "@", chomp(member_info.id, "_top"));
|
enum global_default = replace("g_@_default", "@", chomp(member_info.id, "_top"));
|
||||||
|
|
||||||
@ -946,11 +1076,10 @@ ResetStacks(UICtx* ctx)
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
enum member_info = CtxMemberInfo!(i);
|
enum member_info = CtxMemberInfo!(i);
|
||||||
static if(member_info.is_stack_top)
|
static if(member_info.is_stack)
|
||||||
{
|
{
|
||||||
enum top = replace("ctx.@_top", "@", member_info.id);
|
enum top = replace("ctx.@_top", "@", member_info.id);
|
||||||
ctx.tupleof[i].top = mixin(top);
|
ctx.tupleof[i].top = mixin(top);
|
||||||
ctx.tupleof[i].auto_pop = false;
|
|
||||||
ctx.tupleof[i].free = null;
|
ctx.tupleof[i].free = null;
|
||||||
|
|
||||||
assert(ctx.tupleof[i].top.next == null, "Top stack node next isn't null");
|
assert(ctx.tupleof[i].top.next == null, "Top stack node next isn't null");
|
||||||
@ -960,18 +1089,21 @@ ResetStacks(UICtx* ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
T*
|
T*
|
||||||
Recurse(bool pre = true, T)(T* panel, T* root, T* nil)
|
Recurse(bool pre = true, T)(T* node, T* nil)
|
||||||
{
|
{
|
||||||
|
T* child = pre ? node.first : node.last;
|
||||||
|
T* sibling = pre ? node.next : node.prev;
|
||||||
|
|
||||||
T* result = nil;
|
T* result = nil;
|
||||||
if(!Nil(panel.first))
|
if(!Nil(child))
|
||||||
{
|
{
|
||||||
result = pre ? panel.first : panel.last;
|
result = child;
|
||||||
}
|
}
|
||||||
else for(T* p = panel; !Nil(p) && p != root; p = p.parent)
|
else for(T* p = node; !Nil(p); p = p.parent)
|
||||||
{
|
{
|
||||||
if(!Nil(pre ? p.next : p.prev))
|
if(!Nil(sibling))
|
||||||
{
|
{
|
||||||
result = pre ? p.next : p.prev;
|
result = sibling;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1115,16 +1247,26 @@ Get(T)(T k) if(is(T: UIKey) || StringType!T)
|
|||||||
UIKey key = MakeKey(k);
|
UIKey key = MakeKey(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result!(UIItem*) result = g_ui_ctx.items[key.hash];
|
Result!(UIItem*) res = g_ui_ctx.items[key.hash];
|
||||||
if(!result.ok)
|
if(!res.ok)
|
||||||
{
|
{
|
||||||
result.value = Alloc!(UIItem)(&g_ui_ctx.arena);
|
if(!Nil(g_ui_ctx.free_items.first))
|
||||||
HTPush(&g_ui_ctx.items, key.hash, result.value);
|
{
|
||||||
|
res.value = DLLPop(g_ui_ctx.free_items, g_UI_NIL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res.value = Alloc!(UIItem)(&g_ui_ctx.arena);
|
||||||
|
HTPush(&g_ui_ctx.items, key.hash, res.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.value.last_frame = g_ui_ctx.frame-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.value.key = key;
|
res.value.key = key;
|
||||||
|
res.value.next = res.value.prev = res.value.first = res.value.last = res.value.parent = g_UI_NIL;
|
||||||
|
|
||||||
return result.value;
|
return res.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
f32
|
f32
|
||||||
@ -1283,7 +1425,7 @@ DrawGlyph(Glyph* glyph, f32 scale, f32* x_pos, f32 y)
|
|||||||
v.src_end.y = gb.atlas_b;
|
v.src_end.y = gb.atlas_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddUIIndices(ctx);
|
AddVertexCount(ctx);
|
||||||
|
|
||||||
*x_pos += glyph.advance * scale;
|
*x_pos += glyph.advance * scale;
|
||||||
|
|
||||||
@ -1382,7 +1524,7 @@ DrawRect(f32 x, f32 y, f32 w, f32 h, f32 corner_radius, f32 border, Vec4[4] cols
|
|||||||
v.dst_end -= border;
|
v.dst_end -= border;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddUIIndices(ctx);
|
AddVertexCount(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1399,21 +1541,13 @@ DrawBorder(Vec2 pos, Vec2 size, f32 border, f32 radius, f32 softness, Vec4[4] co
|
|||||||
v.edge_softness = softness;
|
v.edge_softness = softness;
|
||||||
v.raised = 0.0;
|
v.raised = 0.0;
|
||||||
|
|
||||||
AddUIIndices(ctx);
|
AddVertexCount(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma(inline) void
|
pragma(inline) void
|
||||||
AddUIIndices(UICtx* ctx)
|
AddVertexCount(UICtx* ctx)
|
||||||
{
|
{
|
||||||
ctx.buffers[ctx.f_idx].idx[0] = 0;
|
|
||||||
ctx.buffers[ctx.f_idx].idx[1] = 1;
|
|
||||||
ctx.buffers[ctx.f_idx].idx[2] = 2;
|
|
||||||
ctx.buffers[ctx.f_idx].idx[3] = 2;
|
|
||||||
ctx.buffers[ctx.f_idx].idx[4] = 1;
|
|
||||||
ctx.buffers[ctx.f_idx].idx[5] = 3;
|
|
||||||
|
|
||||||
ctx.buffers[ctx.f_idx].count += 1;
|
ctx.buffers[ctx.f_idx].count += 1;
|
||||||
|
|
||||||
assert(ctx.buffers[ctx.f_idx].count < VERTEX_MAX_COUNT);
|
assert(ctx.buffers[ctx.f_idx].count < VERTEX_MAX_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user