input handling added, panels now resizeable, panels now have persistent state

This commit is contained in:
Matthew 2025-09-10 06:18:53 +10:00
parent 55247980c1
commit de90479aa7
4 changed files with 257 additions and 54 deletions

@ -1 +1 @@
Subproject commit b2b6fef26c0b0e15575ee431eea60235d4565c34 Subproject commit f30edc3bbe9fdfda5eb429a214fdf050a0012af0

View File

@ -182,40 +182,107 @@ Cycle(Editor* ed, Inputs* inputs)
BeginBuild(inputs); BeginBuild(inputs);
Panel("##panel_1", 1.0, 0.3, A2D.X, Vec4(0.2, 0.5, 0.8, 1.0)); static UIPanel[11] panels = [
{ {
Panel("##sub_panel_1", 0.125, 1.0, A2D.X, Vec4(0.2, 0.4, 0.5, 1.0)); id: CastStr!(u8)("##panel_1"),
pct: 0.3,
axis: A2D.X,
color: Vec4(0.2, 0.5, 0.8, 1.0),
},
{
id: CastStr!(u8)("##sub_panel_1"),
pct: 0.125,
axis: A2D.X,
color: Vec4(0.2, 0.4, 0.5, 1.0),
},
{
id: CastStr!(u8)("##sub_panel_2"),
pct: 0.675,
axis: A2D.X,
color: Vec4(0.9, 0.6, 0.5, 1.0),
},
{
id: CastStr!(u8)("##sub_panel_3"),
pct: 0.2,
axis: A2D.X,
color: Vec4(1.0, 0.4, 0.5, 1.0),
},
{
id: CastStr!(u8)("##panel_2"),
pct: 0.3,
axis: A2D.X,
color: Vec4(0.5, 0.2, 0.45, 1.0),
},
{
id: CastStr!(u8)("##panel_3"),
pct: 0.4,
axis: A2D.X,
color: Vec4(0.3, 0.7, 0.6, 1.0),
},
{
id: CastStr!(u8)("##sub_panel_4"),
pct: 0.25,
axis: A2D.Y,
color: Vec4(0.33, 0.4, 0.8, 1.0),
},
{
id: CastStr!(u8)("##sub_sub_panel_1"),
pct: 0.4,
axis: A2D.X,
color: Vec4(1.0, 0.0, 0.0, 1.0),
},
{
id: CastStr!(u8)("##sub_sub_panel_2"),
pct: 0.6,
axis: A2D.X,
color: Vec4(1.0, 1.0, 0.0, 1.0),
},
{
id: CastStr!(u8)("##sub_panel_5"),
pct: 0.55,
axis: A2D.X,
color: Vec4(0.9, 0.2, 0.3, 1.0),
},
{
id: CastStr!(u8)("##sub_panel_6"),
pct: 0.2,
axis: A2D.X,
color: Vec4(0.2, 0.76, 0.5, 1.0),
},
];
Panel(&panels[0]);
{
Panel(&panels[1]);
EndPanel(); EndPanel();
Panel("##sub_panel_2", 0.675, 1.0, A2D.X, Vec4(0.9, 0.6, 0.5, 1.0)); Panel(&panels[2]);
EndPanel(); EndPanel();
Panel("##sub_panel_3", 0.2, 1.0, A2D.X, Vec4(1.0, 0.4, 0.5, 1.0)); Panel(&panels[3]);
EndPanel(); EndPanel();
} }
EndPanel(); EndPanel();
Panel("##panel_2", 1.0, 0.3, A2D.X, Vec4(0.5, 0.2, 0.45, 1.0)); Panel(&panels[4]);
{
}
EndPanel(); EndPanel();
Panel("##panel_3", 1.0, 0.4, A2D.X, Vec4(0.3, 0.7, 0.6, 1.0)); Panel(&panels[5]);
{ {
Panel("##sub_panel_6", 0.25, 1.0, A2D.Y, Vec4(0.33, 0.4, 0.8, 1.0)); Panel(&panels[6]);
{ {
Panel("##sub_sub_panel_1", 1.0, 0.4, A2D.X, Vec4(1.0, 0.0, 0.0, 1.0)); Panel(&panels[7]);
EndPanel(); EndPanel();
Panel("##sub_sub_panel_2", 1.0, 0.6, A2D.X, Vec4(1.0, 1.0, 0.0, 1.0));
Panel(&panels[8]);
EndPanel(); EndPanel();
} }
EndPanel(); EndPanel();
Panel("##sub_panel_7", 0.55, 1.0, A2D.X, Vec4(0.9, 0.2, 0.3, 1.0)); Panel(&panels[9]);
EndPanel(); EndPanel();
Panel("##sub_panel_8", 0.2, 1.0, A2D.X, Vec4(0.2, 0.76, 0.5, 1.0)); Panel(&panels[10]);
EndPanel(); EndPanel();
} }
EndPanel(); EndPanel();

View File

@ -10,7 +10,7 @@ import std.stdio;
import editor; import editor;
UIContext g_ui_ctx; UICtx g_ui_ctx;
const UIItem g_ui_nil_item; const UIItem g_ui_nil_item;
UIItem* g_UI_NIL; UIItem* g_UI_NIL;
@ -54,7 +54,7 @@ enum SizeType
alias ST = SizeType; alias ST = SizeType;
struct UIContext struct UICtx
{ {
HashTable!(UIHash, UIItem*) items; HashTable!(UIHash, UIItem*) items;
Arena arena; Arena arena;
@ -104,6 +104,7 @@ struct UIItem
UIItem* parent; UIItem* parent;
u32 level; u32 level;
Vec2 dragged;
// Build Parameters // Build Parameters
Axis2D layout_axis; Axis2D layout_axis;
@ -169,7 +170,7 @@ InitUICtx(Renderer* rd, FontAtlas atlas)
MappedBuffer!(Vertex) m_vtx = CreateMappedBuffer!(Vertex)(rd, BT.Vertex, 5000); MappedBuffer!(Vertex) m_vtx = CreateMappedBuffer!(Vertex)(rd, BT.Vertex, 5000);
MappedBuffer!(u32) m_idx = CreateMappedBuffer!(u32)(rd, BT.Index, 15000); MappedBuffer!(u32) m_idx = CreateMappedBuffer!(u32)(rd, BT.Index, 15000);
UIContext ctx = { UICtx ctx = {
rd: rd, rd: rd,
items: CreateHashTable!(UIHash, UIItem*)(12), items: CreateHashTable!(UIHash, UIItem*)(12),
arena: CreateArena(MB(4)), arena: CreateArena(MB(4)),
@ -187,12 +188,14 @@ InitUICtx(Renderer* rd, FontAtlas atlas)
}; };
g_ui_ctx = ctx; g_ui_ctx = ctx;
InitWidgets();
} }
UIItemNode* UIItemNode*
PopItemNode() PopItemNode()
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
UIItemNode* node; UIItemNode* node;
if (!CheckNil(g_UI_NIL_NODE, ctx.stack_free_list.first)) if (!CheckNil(g_UI_NIL_NODE, ctx.stack_free_list.first))
@ -213,14 +216,14 @@ PopItemNode()
void void
PushItemNode(UIItemNode* node) PushItemNode(UIItemNode* node)
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
SLLPushFront(&ctx.stack_free_list, node, g_UI_NIL_NODE); SLLPushFront(&ctx.stack_free_list, node, g_UI_NIL_NODE);
} }
void void
PushSiblingPanel(UIItem* panel) PushSiblingPanel(UIItem* panel)
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
UIItemNode* node = PopItemNode(); UIItemNode* node = PopItemNode();
node.item = panel; node.item = panel;
@ -231,7 +234,7 @@ PushSiblingPanel(UIItem* panel)
UIItem* UIItem*
PopSiblingPanel() PopSiblingPanel()
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
UIItem* panel = g_UI_NIL; UIItem* panel = g_UI_NIL;
UIItemNode* node = ctx.prev_sibling; UIItemNode* node = ctx.prev_sibling;
@ -264,7 +267,7 @@ PeekSiblingPanel()
UIItem* UIItem*
PrevSiblingPanel(UIItem* panel) PrevSiblingPanel(UIItem* panel)
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
UIItem* result = g_UI_NIL; UIItem* result = g_UI_NIL;
UIItemNode* prev = ctx.prev_sibling; UIItemNode* prev = ctx.prev_sibling;
for(;;) for(;;)
@ -305,7 +308,7 @@ PeekParent()
UIItem* UIItem*
PopParent() PopParent()
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
UIItemNode* node = ctx.top_parent; UIItemNode* node = ctx.top_parent;
UIItem* item = node.item; UIItem* item = node.item;
@ -320,7 +323,7 @@ PopParent()
void void
PushParent(UIItem* parent) PushParent(UIItem* parent)
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
UIItemNode* node = PopItemNode(); UIItemNode* node = PopItemNode();
node.item = parent; node.item = parent;
@ -344,7 +347,7 @@ SetColor(Vec4 col)
void void
SetColor(Vec4 col0, Vec4 col1, Vec4 col2, Vec4 col3) SetColor(Vec4 col0, Vec4 col1, Vec4 col2, Vec4 col3)
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
ctx.color[0] = col0; ctx.color[0] = col0;
ctx.color[1] = col1; ctx.color[1] = col1;
ctx.color[2] = col2; ctx.color[2] = col2;
@ -354,14 +357,14 @@ SetColor(Vec4 col0, Vec4 col1, Vec4 col2, Vec4 col3)
void void
SetLayoutAxis(Axis2D axis) SetLayoutAxis(Axis2D axis)
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
ctx.layout_axis = axis; ctx.layout_axis = axis;
} }
void void
BeginBuild(Inputs* inputs) BeginBuild(Inputs* inputs)
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
ctx.inputs = inputs; ctx.inputs = inputs;
ctx.buffer.count = 0; ctx.buffer.count = 0;
@ -374,7 +377,7 @@ BeginBuild(Inputs* inputs)
void void
EndBuild() EndBuild()
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
PopParent(); PopParent();
PopSiblingPanels(); PopSiblingPanels();
@ -390,10 +393,29 @@ EndBuild()
} }
DrawUI(ctx, ctx.root); DrawUI(ctx, ctx.root);
static bool first = false;
if (!first)
{
DrawNodes(ctx.root);
first = true;
}
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);
} }
void
DrawNodes(UIItem* item)
{
if (!Nil(item))
{
Logf("x0 %s x1 %s y0 %s y1 %s", item.rect.x0, item.rect.x1, item.rect.y0, item.rect.y1);
DrawNodes(item.first);
DrawNodes(item.next);
}
}
void void
CalcFixedSizes(UIItem* item) CalcFixedSizes(UIItem* item)
{ {
@ -447,7 +469,7 @@ CalcPositions(alias axis)(UIItem* item, f32 pos = 0.0)
} }
void void
DrawUI(UIContext* ctx, UIItem* item) DrawUI(UICtx* ctx, UIItem* item)
{ {
if (!Nil(item)) if (!Nil(item))
{ {
@ -461,7 +483,7 @@ DrawUI(UIContext* ctx, UIItem* item)
void void
BuildItem(UIItem* item, UISize size_x, UISize size_y, UIFlags properties) BuildItem(UIItem* item, UISize size_x, UISize size_y, UIFlags properties)
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
item.first = item.last = item.next = item.prev = g_UI_NIL; item.first = item.last = item.next = item.prev = g_UI_NIL;
@ -486,28 +508,53 @@ BuildItem(UIItem* item, UISize size_x, UISize size_y, UIFlags properties)
void void
Signal(UIItem* item) Signal(UIItem* item)
{ {
UIContext* ctx = GetCtx(); UICtx* ctx = GetCtx();
item.signal = UIS.None; item.signal = UIS.None;
item.dragged = 0.0;
for(DNode!(InputEvent)* n = ctx.inputs.list.first; !CheckNil(null, n); n = n.next) for(DNode!(InputEvent)* n = ctx.inputs.list.first; !CheckNil(null, n); n = n.next)
{ {
bool taken = false;
if (item.flags & UIF.Clickable && Clicked(item, n)) if (item.flags & UIF.Clickable && Clicked(item, n))
{ {
Logf("Clicked"); Logf("Clicked");
DLLRemove(&ctx.inputs.list, n, null); item.signal |= UIS.Clicked;
taken = true;
} }
if (item.flags & UIF.Draggable && Clicked(item, n)) if (item.flags & UIF.Draggable && Clicked(item, n) && Nil(ctx.drag_item))
{ {
Logf("Dragged"); Logf("Dragged");
item.signal |= UIS.Dragged;
ctx.drag_item = item;
taken = true;
}
if (ctx.drag_item == item && n.value.key == Input.LeftClick && !n.value.pressed)
{
Logf("Released");
ctx.drag_item = g_UI_NIL;
taken = true;
}
if (ctx.drag_item == item && n.value.key == Input.MouseMotion)
{
item.signal |= UIS.Dragged;
item.dragged.x += cast(f32)n.value.rel_x;
item.dragged.y += cast(f32)n.value.rel_y;
taken = true;
}
if (taken)
{
DLLRemove(&ctx.inputs.list, n, null); DLLRemove(&ctx.inputs.list, n, null);
} }
} }
} }
UIContext* UICtx*
GetCtx() GetCtx()
{ {
return &g_ui_ctx; return &g_ui_ctx;
@ -653,7 +700,7 @@ DrawGlyph(Glyph* glyph, f32 scale, f32* x_pos, f32 y, Vec4 col = Vec4(1.0))
} }
pragma(inline) void pragma(inline) void
DrawRect(UIContext* ctx, UIItem* item) DrawRect(UICtx* ctx, UIItem* item)
{ {
// Y reversed // Y reversed
Vertex* v = ctx.buffer.vtx.ptr + ctx.buffer.count; Vertex* v = ctx.buffer.vtx.ptr + ctx.buffer.count;

View File

@ -3,6 +3,58 @@ import dlib;
import ui; import ui;
import std.format : sformat; import std.format : sformat;
const UIPanel g_ui_nil_panel;
UIPanel* g_UI_NIL_PANEL;
UIPanel g_root_panel;
WidgetCtx g_widget_ctx;
struct WidgetCtx
{
UIPanel* parent;
}
struct UIPanel
{
u8[] id;
UIPanel* parent;
UIPanel* next;
UIPanel* prev;
UIPanel* first;
UIPanel* last;
UIPanel* list_next;
Axis2D axis;
f32 pct;
Vec4 color;
}
void
PushPanel(UIPanel* parent)
{
parent.list_next = g_widget_ctx.parent;
g_widget_ctx.parent = parent;
}
UIPanel*
PopPanel()
{
UIPanel* parent = g_widget_ctx.parent;
g_widget_ctx.parent = parent.list_next;
parent.list_next = g_UI_NIL_PANEL;
return parent;
}
void
InitWidgets()
{
g_UI_NIL_PANEL = cast(UIPanel*)&g_ui_nil_panel;
g_widget_ctx.parent = g_UI_NIL_PANEL;
}
UIItem* UIItem*
Root() Root()
{ {
@ -11,47 +63,81 @@ Root()
UIItem* root = Get("##root_item"); UIItem* root = Get("##root_item");
BuildItem(root, UISize(ST.Pixels, d.x), UISize(ST.Pixels, d.y), UIF.DrawBackground); BuildItem(root, UISize(ST.Pixels, d.x), UISize(ST.Pixels, d.y), UIF.DrawBackground);
g_root_panel.pct = 1.0;
g_root_panel.axis = A2D.Y;
g_root_panel.color = Vec4(Vec3(0.0), 1.0);
g_root_panel.list_next = g_root_panel.parent = g_root_panel.next = g_root_panel.prev = g_root_panel.first = g_root_panel.last = g_UI_NIL_PANEL;
g_widget_ctx.parent = &g_root_panel;
return root; return root;
} }
UIItem* UIItem*
Panel(string id, f32 x_pct, f32 y_pct, Axis2D layout_axis, Vec4 color) Panel(UIPanel* panel)
{ {
UIItem* item = Get(id); UIItem* item = Get(panel.id);
UIItem* separator = g_UI_NIL; UIItem* separator = g_UI_NIL;
UIItem* prev_panel = PeekSiblingPanel(); UIItem* prev_panel = PeekSiblingPanel();
UIItem* parent = PeekParent(); UIItem* parent = PeekParent();
UIPanel* parent_pn = g_widget_ctx.parent;
DLLPush(parent_pn, panel, g_UI_NIL_PANEL);
f32 x_pct = 1.0, y_pct = 1.0;
if (parent_pn != g_UI_NIL_PANEL)
{
x_pct = parent_pn.axis == A2D.X ? panel.pct : 1.0;
y_pct = parent_pn.axis == A2D.Y ? panel.pct : 1.0;
}
Signal(item); Signal(item);
f32 adj_x = 0.0, adj_y = 0.0; f32 adj_x = 0.0, adj_y = 0.0;
if (!Nil(prev_panel) && parent != prev_panel) if (!Nil(prev_panel) && parent != prev_panel)
{ {
f32 sep_y = 1.0, sep_x = 1.0; f32 sep_y = 1.0, sep_x = 1.0, parent_start = 0.0, parent_end = 0.0;
if (parent.layout_axis == A2D.X) if (parent.layout_axis == A2D.X)
{ {
sep_x = 5.0; sep_x = 5.0;
adj_x = -5.0; adj_x = -5.0;
parent_start = parent.rect.vec0.x;
parent_end = parent.rect.vec1.x;
} }
else else
{ {
sep_y = 5.0; sep_y = 5.0;
adj_y = -5.0; adj_y = -5.0;
parent_start = parent.rect.vec0.y;
parent_end = parent.rect.vec1.y;
} }
u8[128] buf = 0; u8[128] buf = 0;
(cast(char[])buf).sformat("sep_%s", id); (cast(char[])buf).sformat("sep_%s", cast(char[])panel.id);
separator = Get(buf); separator = Get(buf);
Separator(separator, sep_x, sep_y, parent.layout_axis); Separator(separator, sep_x, sep_y, parent.layout_axis);
Signal(separator); Signal(separator);
f32 pos = separator.dragged.v[parent.layout_axis];
if (separator.signal & UIS.Dragged && pos != 0.0)
{
f32 pct = Remap(pos, 0.0, parent_start-parent_end, 0.0, 1.0);
panel.pct -= pct;
panel.prev.pct += pct;
Logf("%f", pct);
Logf("%s %f %s %f", cast(char[])panel.id, panel.pct, cast(char[])panel.prev.id, panel.prev.pct);
}
} }
SetColor(color); SetColor(panel.color);
SetLayoutAxis(layout_axis); SetLayoutAxis(panel.axis);
BuildItem(item, UISize(ST.Percentage, x_pct), UISize(ST.Percentage, y_pct), UIF.DrawBackground); BuildItem(item, UISize(ST.Percentage, x_pct), UISize(ST.Percentage, y_pct), UIF.DrawBackground);
@ -60,6 +146,8 @@ Panel(string id, f32 x_pct, f32 y_pct, Axis2D layout_axis, Vec4 color)
PushSiblingPanel(item); PushSiblingPanel(item);
PushParent(item); PushParent(item);
PushPanel(panel);
return item; return item;
} }
@ -78,4 +166,5 @@ void
EndPanel() EndPanel()
{ {
PopParent(); PopParent();
PopPanel();
} }