ui panels mostly working
This commit is contained in:
parent
1358683331
commit
988223b675
@ -1 +1 @@
|
||||
Subproject commit 65ac576cb0f37e797030365ef25d11a771468654
|
||||
Subproject commit 7a77505fc100da21a5bf804e415be8eb1f36ba19
|
||||
2
src/dlib
2
src/dlib
@ -1 +1 @@
|
||||
Subproject commit 5ff3cd91d73464e88bff3daef94a0a3bea2c3cb7
|
||||
Subproject commit 6757559089314da06956460c32ff632db7d10f88
|
||||
@ -8,6 +8,7 @@ import std.format : sformat;
|
||||
import dlib.alloc;
|
||||
import buffer;
|
||||
import ui;
|
||||
import widgets : Nil;
|
||||
import widgets;
|
||||
|
||||
import std.stdio;
|
||||
@ -15,12 +16,12 @@ import std.exception;
|
||||
|
||||
f32 g_delta = 0.0;
|
||||
|
||||
EditorCtx g_ed_ctx;
|
||||
|
||||
struct EditorCtx
|
||||
{
|
||||
Arena arena;
|
||||
UIPanel* base_panel;
|
||||
u64 panel_id;
|
||||
EditState state;
|
||||
}
|
||||
|
||||
struct Editor
|
||||
@ -40,26 +41,33 @@ struct Editor
|
||||
u64 line_offset;
|
||||
}
|
||||
|
||||
enum EditState
|
||||
{
|
||||
NormalMode,
|
||||
InputMode,
|
||||
CmdOpen,
|
||||
SetPanelFocus,
|
||||
}
|
||||
|
||||
alias ES = EditState;
|
||||
|
||||
void
|
||||
Cycle(Inputs* inputs)
|
||||
Cycle(EditorCtx* ctx, Inputs* inputs)
|
||||
{
|
||||
ResetScratch(MB(4));
|
||||
|
||||
assert(Nil(ctx.base_panel.next));
|
||||
|
||||
HandleInputs(ctx, inputs);
|
||||
|
||||
BeginBuild(inputs);
|
||||
|
||||
static UIPanel panel = {
|
||||
id: CastStr!(u8)("##base"),
|
||||
axis: A2D.Y,
|
||||
pct: 1.0,
|
||||
};
|
||||
|
||||
Panel(&panel);
|
||||
EndPanel();
|
||||
DrawPanels(ctx.base_panel);
|
||||
|
||||
EndBuild();
|
||||
}
|
||||
|
||||
void
|
||||
EditorCtx
|
||||
InitEditorCtx(PlatformWindow* window)
|
||||
{
|
||||
InitFreeType();
|
||||
@ -70,7 +78,197 @@ InitEditorCtx(PlatformWindow* window)
|
||||
arena: CreateArena(MB(2)),
|
||||
};
|
||||
|
||||
g_ed_ctx = ctx;
|
||||
ctx.base_panel = CreatePanel(&ctx);
|
||||
ctx.base_panel.ed = CreateEditor(&ctx);
|
||||
SetFocusedPanel(ctx.base_panel);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
UIPanel*
|
||||
CreatePanel(EditorCtx* ctx)
|
||||
{
|
||||
UIPanel* p = Alloc!(UIPanel)(&ctx.arena);
|
||||
p.axis = A2D.Y;
|
||||
p.id = AllocArray!(u8)(&ctx.arena, 10);
|
||||
p.pct = 1.0;
|
||||
(cast(char[])p.id).sformat("##%08s", ctx.panel_id);
|
||||
p.parent = p.first = p.last = p.next = p.prev = g_UI_NIL_PANEL;
|
||||
|
||||
ctx.panel_id += 1;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// Load all files then move things into editor after being created when selected
|
||||
|
||||
Editor*
|
||||
CreateEditor(EditorCtx* ctx)
|
||||
{
|
||||
Editor* ed = Alloc!(Editor)(&ctx.arena);
|
||||
|
||||
ed.arena = CreateArena(MB(4));
|
||||
|
||||
return ed;
|
||||
}
|
||||
|
||||
void
|
||||
AddEditor(EditorCtx* ctx, UIPanel* target, Axis2D axis)
|
||||
{
|
||||
if(Nil(target.parent) || target.parent.axis != axis)
|
||||
{
|
||||
UIPanel* first = CreatePanel(ctx);
|
||||
UIPanel* second = CreatePanel(ctx);
|
||||
|
||||
first.ed = target.ed;
|
||||
second.ed = CreateEditor(ctx);
|
||||
|
||||
first.pct = second.pct = 0.5;
|
||||
|
||||
target.axis = axis;
|
||||
target.ed = null;
|
||||
|
||||
PushPanel(target, first);
|
||||
PushPanel(target, second);
|
||||
|
||||
SetFocusedPanel(second);
|
||||
}
|
||||
else if(target.parent.axis == axis)
|
||||
{
|
||||
UIPanel* panel = CreatePanel(ctx);
|
||||
panel.ed = CreateEditor(ctx);
|
||||
|
||||
InsertPanel(target.parent, target, panel);
|
||||
|
||||
u64 count = 0;
|
||||
for(UIPanel* p = target.parent.first; !Nil(p); p = p.next, count += 1) {}
|
||||
|
||||
f32 pct = 1.0/count;
|
||||
for(UIPanel* p = target.parent.first; !Nil(p); p = p.next)
|
||||
{
|
||||
p.pct = pct;
|
||||
}
|
||||
|
||||
SetFocusedPanel(panel);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HandleInputs(EditorCtx* ctx, Inputs* inputs)
|
||||
{
|
||||
for(auto node = inputs.list.first; node != null; node = node.next)
|
||||
{
|
||||
bool taken = false;
|
||||
|
||||
Input key = node.value.key;
|
||||
bool pressed = node.value.pressed;
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
case Input.i:
|
||||
{
|
||||
if(ctx.state == ES.NormalMode)
|
||||
{
|
||||
ctx.state = ES.InputMode;
|
||||
taken = true;
|
||||
}
|
||||
} break;
|
||||
case Input.Esc:
|
||||
{
|
||||
if(ctx.state == ES.InputMode || ctx.state == ES.CmdOpen)
|
||||
{
|
||||
ctx.state = ES.NormalMode;
|
||||
taken = true;
|
||||
}
|
||||
} break;
|
||||
case Input.Semicolon:
|
||||
{
|
||||
if(node.value.md & (MD.LeftShift | MD.RightShift))
|
||||
{
|
||||
if(ctx.state != ES.NormalMode)
|
||||
{
|
||||
ctx.state = ES.CmdOpen;
|
||||
taken = true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Input.w:
|
||||
{
|
||||
if(ctx.state == ES.NormalMode && node.value.md & (MD.LeftCtrl | MD.RightCtrl))
|
||||
{
|
||||
ctx.state = ES.SetPanelFocus;
|
||||
taken = true;
|
||||
}
|
||||
} break;
|
||||
case Input.v:
|
||||
{
|
||||
if(ctx.state == ES.NormalMode)
|
||||
{
|
||||
AddEditor(ctx, GetFocusedPanel(), A2D.X);
|
||||
}
|
||||
} break;
|
||||
case Input.c:
|
||||
{
|
||||
if(ctx.state == ES.NormalMode)
|
||||
{
|
||||
AddEditor(ctx, GetFocusedPanel(), A2D.Y);
|
||||
}
|
||||
} break;
|
||||
case Input.Up:
|
||||
case Input.Down:
|
||||
case Input.Left:
|
||||
case Input.Right:
|
||||
{
|
||||
if(false)
|
||||
{
|
||||
UIPanel* panel = GetFocusedPanel();
|
||||
UIPanel* focused = g_UI_NIL_PANEL;
|
||||
for(UIPanel* p = panel; !Nil(p); p = p.parent)
|
||||
{
|
||||
if(p.parent.axis == A2D.X)
|
||||
{
|
||||
if(key == Input.Left && !Nil(p.prev) && p.prev.ed != null)
|
||||
{
|
||||
focused = p.prev;
|
||||
break;
|
||||
}
|
||||
|
||||
if(key == Input.Right && !Nil(p.next) && p.next.ed != null)
|
||||
{
|
||||
focused = p.next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(key == Input.Up && !Nil(p.prev) && p.prev.ed != null)
|
||||
{
|
||||
focused = p.prev;
|
||||
break;
|
||||
}
|
||||
|
||||
if(key == Input.Down && !Nil(p.next) && p.next.ed != null)
|
||||
{
|
||||
focused = p.next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetFocusedPanel(focused);
|
||||
}
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if(taken)
|
||||
{
|
||||
DLLRemove(&inputs.list, node, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -21,7 +21,7 @@ void main(string[] argv)
|
||||
PlatformWindow window = CreateWindow("Editor", 1920, 1080);
|
||||
StartPlatformThread(&window);
|
||||
|
||||
InitEditorCtx(&window);
|
||||
EditorCtx ctx = InitEditorCtx(&window);
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -31,6 +31,6 @@ void main(string[] argv)
|
||||
break;
|
||||
}
|
||||
|
||||
Cycle(inputs);
|
||||
Cycle(&ctx, inputs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import dlib.fonts;
|
||||
import vulkan;
|
||||
import widgets;
|
||||
import std.stdio;
|
||||
import std.math.traits : isNaN;
|
||||
import std.math.rounding : ceil;
|
||||
import std.format : sformat;
|
||||
import core.stdc.string : memset;
|
||||
@ -44,6 +45,7 @@ enum UIFlags
|
||||
DrawBorder = 0x04,
|
||||
Clickable = 0x08,
|
||||
Draggable = 0x10,
|
||||
TextInput = 0x20,
|
||||
}
|
||||
|
||||
alias UIF = UIFlags;
|
||||
@ -69,6 +71,7 @@ struct UICtx
|
||||
{
|
||||
HashTable!(UIHash, UIItem*) items;
|
||||
Arena arena;
|
||||
Arena temp_arena;
|
||||
Inputs* inputs;
|
||||
u64 frame;
|
||||
u64 f_idx;
|
||||
@ -94,10 +97,10 @@ struct UICtx
|
||||
UIItemNode* prev_sibling;
|
||||
u32 panel_level;
|
||||
UIItem* drag_item;
|
||||
UIItem* focused;
|
||||
|
||||
UIItemStackList stack_free_list;
|
||||
|
||||
FontAtlas atlas;
|
||||
Vec4[4] color;
|
||||
Vec4[4] border_color;
|
||||
Vec4 text_color;
|
||||
@ -108,6 +111,9 @@ struct UICtx
|
||||
f32 border_thickness;
|
||||
f32 corner_radius;
|
||||
f32 edge_softness;
|
||||
|
||||
debug u32 item_count;
|
||||
debug u32 final_count;
|
||||
}
|
||||
|
||||
struct UIItemStackList
|
||||
@ -134,6 +140,7 @@ struct UIItem
|
||||
UIItem* last; // last child
|
||||
UIItem* parent;
|
||||
|
||||
u64 last_frame;
|
||||
u32 level;
|
||||
Vec2 dragged;
|
||||
|
||||
@ -246,11 +253,13 @@ InitUICtx(PlatformWindow* window)
|
||||
rd: InitRenderer(handles, MB(16), MB(8)),
|
||||
items: CreateHashTable!(UIHash, UIItem*)(12),
|
||||
arena: arena,
|
||||
temp_arena: CreateArena(MB(1)),
|
||||
root: g_UI_NIL,
|
||||
top_parent: g_UI_NIL_NODE,
|
||||
prev_sibling: g_UI_NIL_NODE,
|
||||
drag_item: g_UI_NIL,
|
||||
text_size: 14.0,
|
||||
focused: g_UI_NIL,
|
||||
text_size: 16.0,
|
||||
tab_width: 2,
|
||||
border_thickness: 0.0,
|
||||
corner_radius: 0.0,
|
||||
@ -260,6 +269,7 @@ InitUICtx(PlatformWindow* window)
|
||||
atlas_buf: atlas_buf,
|
||||
font: font,
|
||||
font_data: cast(u8[])FONT_BYTES,
|
||||
adjustment: 0.0,
|
||||
};
|
||||
|
||||
u64 vertex_size = 10000;
|
||||
@ -538,6 +548,21 @@ BeginBuild(Inputs* inputs)
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
|
||||
debug ctx.item_count = 0;
|
||||
debug ctx.final_count = 0;
|
||||
|
||||
Reset(&ctx.temp_arena);
|
||||
|
||||
KVPair!(u64, UIItem*)*[] items = GetAllNodes(&ctx.temp_arena, &ctx.items);
|
||||
for(u64 i = 0; i < items.length; i += 1)
|
||||
{
|
||||
UIItem* item = items[i].value;
|
||||
if(item.last_frame != ctx.frame-1)
|
||||
{
|
||||
Delete(&ctx.items, items[i].key);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.f_idx = ctx.frame%FRAME_OVERLAP;
|
||||
|
||||
ctx.inputs = inputs;
|
||||
@ -573,6 +598,8 @@ EndBuild()
|
||||
|
||||
DrawUI(ctx, ctx.root);
|
||||
|
||||
debug assert(ctx.item_count == ctx.final_count);
|
||||
|
||||
BindBuffers(&ctx.rd, &ctx.buffers[ctx.f_idx].m_idx, &ctx.buffers[ctx.f_idx].m_vtx);
|
||||
DrawIndexed(&ctx.rd, 6, ctx.buffers[ctx.f_idx].count, 0);
|
||||
|
||||
@ -582,11 +609,11 @@ EndBuild()
|
||||
|
||||
debug
|
||||
{
|
||||
static bool first = false;
|
||||
if (!first)
|
||||
static u32 prev_count = 0;
|
||||
if(prev_count != ctx.item_count)
|
||||
{
|
||||
PrintNodes(ctx.root);
|
||||
first = true;
|
||||
//PrintNodes(ctx.root);
|
||||
prev_count = ctx.item_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -639,6 +666,7 @@ CalcFixedSizes(UIItem* item)
|
||||
if(i.size_info[axis].type == ST.Pixels)
|
||||
{
|
||||
i.size.v[axis] = i.size_info[axis].value + i.adjustment.v[axis];
|
||||
assert(!isNaN(i.size.v[axis]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -654,6 +682,7 @@ CalcPercentageSizes(UIItem* item)
|
||||
if(i.size_info[axis].type == ST.Percentage)
|
||||
{
|
||||
i.size.v[axis] = (i.parent.size.v[axis]*i.size_info[axis].value) + i.adjustment.v[axis];
|
||||
assert(!isNaN(i.size.v[axis]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -669,6 +698,9 @@ CalcPositions(alias axis)(UIItem* item)
|
||||
i.rect.vec0.v[axis] = pos;
|
||||
i.rect.vec1.v[axis] = end_pos;
|
||||
|
||||
assert(!isNaN(i.rect.vec0.v[axis]));
|
||||
assert(!isNaN(i.rect.vec1.v[axis]));
|
||||
|
||||
f32 next_pos = i.parent.layout_axis == axis ? end_pos : pos;
|
||||
|
||||
if(!Nil(i.first))
|
||||
@ -711,6 +743,8 @@ DrawUI(UICtx* ctx, UIItem* item)
|
||||
{
|
||||
DrawLine(i);
|
||||
}
|
||||
|
||||
debug ctx.final_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -726,9 +760,13 @@ Recurse(UIItem* item)
|
||||
{
|
||||
result = item.next;
|
||||
}
|
||||
else if (!Nil(item.parent.next))
|
||||
else for(UIItem* i = item.parent; !Nil(i); i = i.parent)
|
||||
{
|
||||
result = item.parent.next;
|
||||
if(!Nil(i.next))
|
||||
{
|
||||
result = i.next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -752,6 +790,7 @@ BuildItem(UIItem* item, UISize size_x, UISize size_y, UIFlags properties)
|
||||
item.border_thickness = ctx.border_thickness;
|
||||
item.corner_radius = ctx.corner_radius;
|
||||
item.edge_softness = ctx.edge_softness;
|
||||
item.last_frame = ctx.frame;
|
||||
|
||||
item.parent = ctx.top_parent == g_UI_NIL_NODE ? g_UI_NIL : ctx.top_parent.item;
|
||||
if(!Nil(item.parent))
|
||||
@ -761,6 +800,8 @@ BuildItem(UIItem* item, UISize size_x, UISize size_y, UIFlags properties)
|
||||
|
||||
// Reset any once off values here
|
||||
ctx.adjustment = Vec2(0.0);
|
||||
|
||||
debug ctx.item_count += 1;
|
||||
}
|
||||
|
||||
void
|
||||
@ -917,12 +958,12 @@ f32
|
||||
CalcTextWidth(u8[] str)
|
||||
{
|
||||
u32 tab_width = g_ui_ctx.tab_width;
|
||||
Glyph* space = g_ui_ctx.atlas.glyphs.ptr + ' ';
|
||||
Glyph* space = g_ui_ctx.atlas_buf.atlas.glyphs.ptr + ' ';
|
||||
|
||||
f32 width = 0.0;
|
||||
for(u64 i = 0; i < str.length; i += 1)
|
||||
{
|
||||
width += GlyphWidth(g_ui_ctx.atlas.glyphs.ptr + str.ptr[i]);
|
||||
width += GlyphWidth(g_ui_ctx.atlas_buf.atlas.glyphs.ptr + str.ptr[i]);
|
||||
}
|
||||
|
||||
return width;
|
||||
@ -934,7 +975,7 @@ GlyphWidth(Glyph* g)
|
||||
f32 width = 0.0;
|
||||
if(g.ch == '\t')
|
||||
{
|
||||
width += g_ui_ctx.atlas.glyphs[' '].advance * cast(f32)(g_ui_ctx.tab_width);
|
||||
width += g_ui_ctx.atlas_buf.atlas.glyphs[' '].advance * cast(f32)(g_ui_ctx.tab_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -945,9 +986,9 @@ GlyphWidth(Glyph* g)
|
||||
}
|
||||
|
||||
Node!(u8[])*
|
||||
MakeMultiline(u8[] text, f32 width, u64 line_no)
|
||||
MakeMultiline(u8[] text, f32 width, u8[] parent_id, u64 line_no)
|
||||
{
|
||||
f32 scaled_width = width * (g_ui_ctx.atlas.size/g_ui_ctx.text_size);
|
||||
f32 scaled_width = width * (g_ui_ctx.atlas_buf.atlas.size/g_ui_ctx.text_size);
|
||||
f32 text_width = CalcTextWidth(text);
|
||||
|
||||
u64 line_count = cast(u64)(ceil(text_width/scaled_width));
|
||||
@ -957,16 +998,16 @@ MakeMultiline(u8[] text, f32 width, u64 line_no)
|
||||
f32 w = 0.0;
|
||||
u64 line = 0;
|
||||
u64 start = 0;
|
||||
const u64 extra_buf = 10;
|
||||
const u64 extra_buf = 20;
|
||||
for(u64 i = 0; i < text.length; i += 1)
|
||||
{
|
||||
f32 ch_w = GlyphWidth(g_ui_ctx.atlas.glyphs.ptr + text[i]);
|
||||
f32 ch_w = GlyphWidth(g_ui_ctx.atlas_buf.atlas.glyphs.ptr + text[i]);
|
||||
|
||||
if(ch_w + w > scaled_width || i == text.length-1)
|
||||
{
|
||||
u64 len = i-start+1;
|
||||
u8[10] buf = 0;
|
||||
(cast(char[])buf).sformat("##%04s%04s", line_no, line);
|
||||
u8[extra_buf] buf = 0;
|
||||
(cast(char[])buf).sformat("%s%05s%05s", cast(char[])parent_id, line_no, line);
|
||||
|
||||
u8[] str = ScratchAlloc!(u8)(len+extra_buf);
|
||||
str[0 .. len] = text[start .. start+len];
|
||||
@ -1013,7 +1054,7 @@ DrawLine(UIItem* item)
|
||||
UICtx* ctx = GetCtx();
|
||||
f32 y = item.rect.y0 + ctx.text_size;
|
||||
f32 x = item.rect.x0;
|
||||
FontAtlas* atlas = &ctx.atlas;
|
||||
FontAtlas* atlas = &ctx.atlas_buf.atlas;
|
||||
|
||||
for(u64 i = 0; i < item.key.text.length && item.key.text[i] != '\0'; i += 1)
|
||||
{
|
||||
@ -1139,9 +1180,9 @@ ClickedCharIndex(UIItem* item)
|
||||
for(u64 i = 0; i < item.key.text.length; i += 1)
|
||||
{
|
||||
u8 ch = item.key.text[i];
|
||||
if (ch < ctx.atlas.glyphs.length)
|
||||
if(ch < ctx.atlas_buf.atlas.glyphs.length)
|
||||
{
|
||||
f32 ch_w = GlyphWidth(ctx.atlas.glyphs.ptr + ch);
|
||||
f32 ch_w = GlyphWidth(ctx.atlas_buf.atlas.glyphs.ptr + ch);
|
||||
if(ch_w + w > item.last_click_pos.x)
|
||||
{
|
||||
Logf("char clicked");
|
||||
@ -1174,6 +1215,11 @@ Clicked(UIItem* item, DNode!(InputEvent)* n)
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
SetFocus(UIItem* item)
|
||||
{
|
||||
g_ui_ctx.focused = item;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import dlib;
|
||||
|
||||
import buffer;
|
||||
import ui : Nil;
|
||||
import ui;
|
||||
import editor;
|
||||
import std.format : sformat;
|
||||
@ -15,11 +16,13 @@ WidgetCtx g_widget_ctx;
|
||||
struct WidgetCtx
|
||||
{
|
||||
UIPanel* parent;
|
||||
UIPanel* focused_panel;
|
||||
}
|
||||
|
||||
struct UIPanel
|
||||
{
|
||||
u8[] id;
|
||||
Editor* ed;
|
||||
|
||||
UIPanel* parent;
|
||||
UIPanel* next;
|
||||
@ -34,34 +37,25 @@ struct UIPanel
|
||||
Vec4 color;
|
||||
}
|
||||
|
||||
void
|
||||
PushPanel(UIPanel* parent)
|
||||
struct TextPart
|
||||
{
|
||||
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* item;
|
||||
TextPart* next;
|
||||
}
|
||||
|
||||
UIItem*
|
||||
Root()
|
||||
{
|
||||
Vec2 d = RootSize();
|
||||
|
||||
SetColor(
|
||||
Vec4(0.3, 0.65, 0.86, 1.0),
|
||||
Vec4(0.25, 0.60, 0.81, 1.0),
|
||||
Vec4(0.25, 0.60, 0.81, 1.0),
|
||||
Vec4(0.3, 0.65, 0.86, 1.0),
|
||||
);
|
||||
SetLayoutAxis(A2D.Y);
|
||||
|
||||
UIItem* root = Get("##root_item");
|
||||
BuildItem(root, UISize(ST.Pixels, d.x), UISize(ST.Pixels, d.y), UIF.DrawBackground);
|
||||
|
||||
@ -81,60 +75,28 @@ Panel(UIPanel* panel)
|
||||
UIItem* item = Get(panel.id);
|
||||
UIItem* separator = g_UI_NIL;
|
||||
|
||||
UIItem* prev_panel = PeekSiblingPanel();
|
||||
UIItem* parent = PeekParent();
|
||||
UIPanel* parent_pn = panel.parent;
|
||||
|
||||
UIPanel* parent_pn = g_widget_ctx.parent;
|
||||
|
||||
DLLPush(parent_pn, panel, g_UI_NIL_PANEL);
|
||||
UIItem* prev_panel = !Nil(panel.prev) ? Get(panel.prev.id) : g_UI_NIL;
|
||||
UIItem* parent = !Nil(parent_pn) ? Get(parent_pn.id) : PeekParent();
|
||||
|
||||
f32 x_pct = 1.0, y_pct = 1.0;
|
||||
if (parent_pn != g_UI_NIL_PANEL)
|
||||
if(!Nil(parent_pn))
|
||||
{
|
||||
x_pct = parent_pn.axis == A2D.X ? panel.pct : 1.0;
|
||||
y_pct = parent_pn.axis == A2D.Y ? panel.pct : 1.0;
|
||||
}
|
||||
|
||||
Signal(item);
|
||||
if(item.signal & UIS.Clicked)
|
||||
{
|
||||
Logf("%s clicked", cast(char[])panel.id);
|
||||
SetFocusedPanel(panel);
|
||||
}
|
||||
|
||||
f32 adj_x = 0.0, adj_y = 0.0;
|
||||
if (!Nil(prev_panel) && parent != prev_panel)
|
||||
if(!Nil(prev_panel))
|
||||
{
|
||||
f32 sep_y = 1.0, sep_x = 1.0, parent_start = 0.0, parent_end = 0.0;
|
||||
if (parent.layout_axis == A2D.X)
|
||||
{
|
||||
sep_x = 5.0;
|
||||
adj_x = -5.0;
|
||||
parent_start = parent.rect.vec0.x;
|
||||
parent_end = parent.rect.vec1.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
sep_y = 5.0;
|
||||
adj_y = -5.0;
|
||||
parent_start = parent.rect.vec0.y;
|
||||
parent_end = parent.rect.vec1.y;
|
||||
}
|
||||
|
||||
u8[] buf = ScratchAlloc!(u8)(panel.id.length + 5);
|
||||
(cast(char[])buf).sformat("%s_sep", cast(char[])panel.id);
|
||||
|
||||
separator = Get(buf);
|
||||
|
||||
Separator(separator, sep_x, sep_y, parent.layout_axis);
|
||||
|
||||
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);
|
||||
if (CheckPanelBounds(panel.pct - pct) && CheckPanelBounds(panel.prev.pct + pct))
|
||||
{
|
||||
panel.pct -= pct;
|
||||
panel.prev.pct += pct;
|
||||
}
|
||||
}
|
||||
Separator(panel, parent, &adj_x, &adj_y);
|
||||
}
|
||||
|
||||
SetColor(
|
||||
@ -145,18 +107,216 @@ Panel(UIPanel* panel)
|
||||
);
|
||||
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|UIF.Clickable);
|
||||
|
||||
UIItem* sibling = PrevSiblingPanel(item);
|
||||
|
||||
PushSiblingPanel(item);
|
||||
PushParent(item);
|
||||
|
||||
PushPanel(panel);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void
|
||||
Separator(UIPanel* panel, UIItem* parent, f32* adj_x, f32* adj_y)
|
||||
{
|
||||
Axis2D axis = parent.layout_axis;
|
||||
|
||||
f32 sep_y = 1.0, sep_x = 1.0, parent_start = 0.0, parent_end = 0.0;
|
||||
if(axis == A2D.X)
|
||||
{
|
||||
sep_x = 5.0;
|
||||
*adj_x = -5.0;
|
||||
parent_start = parent.rect.vec0.x;
|
||||
parent_end = parent.rect.vec1.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
sep_y = 5.0;
|
||||
*adj_y = -5.0;
|
||||
parent_start = parent.rect.vec0.y;
|
||||
parent_end = parent.rect.vec1.y;
|
||||
}
|
||||
|
||||
u8[] buf = ScratchAlloc!(u8)(panel.id.length + 5);
|
||||
(cast(char[])buf).sformat("%s_sep", cast(char[])panel.id);
|
||||
|
||||
SetColor(Vec4(0.1, 0.2, 0.6, 1.0));
|
||||
|
||||
SizeType x_t = axis == A2D.X ? ST.Pixels : ST.Percentage;
|
||||
SizeType y_t = axis == A2D.Y ? ST.Pixels : ST.Percentage;
|
||||
|
||||
UIItem* item = Get(buf);
|
||||
|
||||
BuildItem(item, UISize(x_t, sep_x), UISize(y_t, sep_y), UIF.DrawBackground|UIF.Draggable);
|
||||
|
||||
Signal(item);
|
||||
|
||||
f32 pos = item.dragged.v[parent.layout_axis];
|
||||
if(item.signal & UIS.Dragged && pos != 0.0)
|
||||
{
|
||||
f32 pct = Remap(pos, 0.0, parent_start-parent_end, 0.0, 1.0);
|
||||
if(CheckPanelBounds(panel.pct - pct) && CheckPanelBounds(panel.prev.pct + pct))
|
||||
{
|
||||
panel.pct -= pct;
|
||||
panel.prev.pct += pct;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextLine(u8[] text)
|
||||
{
|
||||
UIItem* parent = PeekParent();
|
||||
|
||||
UIItem* item = Get(text);
|
||||
}
|
||||
|
||||
void
|
||||
EditorView(UIPanel* panel)
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
UIItem* item = Panel(panel);
|
||||
|
||||
TextPart* tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 14.0, 0);
|
||||
if(TextClicked(tp)) SetFocusedPanel(panel);
|
||||
tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 14.0, 1);
|
||||
if(TextClicked(tp)) SetFocusedPanel(panel);
|
||||
tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 14.0, 2);
|
||||
if(TextClicked(tp)) SetFocusedPanel(panel);
|
||||
tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 14.0, 3);
|
||||
if(TextClicked(tp)) SetFocusedPanel(panel);
|
||||
|
||||
Signal(item);
|
||||
|
||||
if(item.signal & UIS.Clicked)
|
||||
{
|
||||
SetFocusedPanel(panel);
|
||||
}
|
||||
|
||||
EndPanel();
|
||||
}
|
||||
|
||||
bool
|
||||
TextClicked(TextPart* text_part)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
for(TextPart* tp = text_part; !Nil(tp.item); tp = tp.next)
|
||||
{
|
||||
if(tp.item.signal & UIS.Clicked)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TextPart*
|
||||
WrappedTextLine(u8[] text, u8[] parent_id, f32 text_size, u64 line_no)
|
||||
{
|
||||
UIItem* parent = PeekParent();
|
||||
TextPart* part = ScratchAlloc!(TextPart)();
|
||||
part.item = g_UI_NIL;
|
||||
|
||||
SetColor(Vec4(1.0));
|
||||
SetTextSize(text_size);
|
||||
|
||||
TextPart* tp = part;
|
||||
Node!(u8[])* lines = MakeMultiline(text, parent.size.x, parent_id, line_no);
|
||||
for(Node!(u8[])* line = lines; line != null; line = line.next, tp = tp.next)
|
||||
{
|
||||
tp.item = Get(line.value);
|
||||
tp.next = ScratchAlloc!(TextPart)();
|
||||
tp.next.item = g_UI_NIL;
|
||||
|
||||
Signal(tp.item);
|
||||
|
||||
if(tp.item.signal & UIS.Clicked)
|
||||
{
|
||||
ClickedCharIndex(tp.item);
|
||||
}
|
||||
|
||||
BuildItem(tp.item, UISize(ST.Percentage, 1.0), UISize(ST.Pixels, text_size), UIF.DrawText|UIF.Clickable|UIF.Draggable);
|
||||
}
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
void
|
||||
EndPanel()
|
||||
{
|
||||
PopParent();
|
||||
}
|
||||
|
||||
void
|
||||
DrawPanels(UIPanel* panel)
|
||||
{
|
||||
if(!Nil(panel))
|
||||
{
|
||||
debug
|
||||
{
|
||||
import core.stdc.math : fabsf;
|
||||
|
||||
if(!Nil(panel.first))
|
||||
{
|
||||
f32 total = 1.0;
|
||||
for(UIPanel* child = panel.first; !Nil(child); child = child.next)
|
||||
{
|
||||
total -= child.pct;
|
||||
}
|
||||
|
||||
if(total > 0.00009)
|
||||
{
|
||||
Logf("%s failed with %f", cast(char[])panel.id, total);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(panel.ed)
|
||||
{
|
||||
EditorView(panel);
|
||||
}
|
||||
else
|
||||
{
|
||||
Panel(panel);
|
||||
}
|
||||
|
||||
DrawPanels(panel.first);
|
||||
|
||||
if(panel.ed == null)
|
||||
{
|
||||
EndPanel();
|
||||
}
|
||||
|
||||
DrawPanels(panel.next);
|
||||
}
|
||||
}
|
||||
|
||||
UIPanel*
|
||||
Recurse(UIPanel* panel)
|
||||
{
|
||||
UIPanel* result = g_UI_NIL_PANEL;
|
||||
if(!Nil(panel.first))
|
||||
{
|
||||
result = panel.first;
|
||||
}
|
||||
else if(!Nil(panel.next))
|
||||
{
|
||||
result = panel.next;
|
||||
}
|
||||
else for(UIPanel* p = panel.parent; !Nil(p); p = p.parent)
|
||||
{
|
||||
if(!Nil(p.next))
|
||||
{
|
||||
result = p.next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
CheckPanelBounds(f32 pct)
|
||||
{
|
||||
@ -164,58 +324,44 @@ CheckPanelBounds(f32 pct)
|
||||
}
|
||||
|
||||
void
|
||||
Separator(UIItem* item, f32 x_size, f32 y_size, Axis2D axis)
|
||||
PushPanel(UIPanel* parent, UIPanel* panel)
|
||||
{
|
||||
SetColor(Vec4(0.1, 0.2, 0.6, 1.0));
|
||||
|
||||
SizeType x_t = axis == A2D.X ? ST.Pixels : ST.Percentage;
|
||||
SizeType y_t = axis == A2D.Y ? ST.Pixels : ST.Percentage;
|
||||
|
||||
BuildItem(item, UISize(x_t, x_size), UISize(y_t, y_size), UIF.DrawBackground|UIF.Draggable);
|
||||
DLLPush(parent, panel, g_UI_NIL_PANEL);
|
||||
panel.parent = parent;
|
||||
}
|
||||
|
||||
void
|
||||
EditorView(Editor* ed)
|
||||
InsertPanel(UIPanel* parent, UIPanel* prev, UIPanel* panel)
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
UIItem* parent = PeekParent();
|
||||
|
||||
if (ed.buf.length > 0)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
UIItem*
|
||||
TextLine(u8[] text, f32 text_size, u64 line_no)
|
||||
{
|
||||
UIItem* item = g_UI_NIL;
|
||||
UIItem* parent = PeekParent();
|
||||
|
||||
SetColor(Vec4(1.0));
|
||||
SetTextSize(text_size);
|
||||
|
||||
Node!(u8[])* lines = MakeMultiline(text, parent.size.x, line_no);
|
||||
for(Node!(u8[])* line = lines; line != null; line = line.next)
|
||||
{
|
||||
item = Get(line.value);
|
||||
|
||||
Signal(item);
|
||||
|
||||
if (item.signal & UIS.Clicked)
|
||||
{
|
||||
ClickedCharIndex(item);
|
||||
}
|
||||
|
||||
BuildItem(item, UISize(ST.Percentage, 1.0), UISize(ST.Pixels, text_size), UIF.DrawText|UIF.Clickable|UIF.Draggable);
|
||||
}
|
||||
|
||||
return item;
|
||||
DLLInsert(parent, panel, prev, g_UI_NIL_PANEL);
|
||||
panel.parent = prev.parent;
|
||||
}
|
||||
|
||||
void
|
||||
EndPanel()
|
||||
InitWidgets()
|
||||
{
|
||||
PopParent();
|
||||
PopPanel();
|
||||
g_UI_NIL_PANEL = cast(UIPanel*)&g_ui_nil_panel;
|
||||
g_widget_ctx.parent = g_UI_NIL_PANEL;
|
||||
}
|
||||
|
||||
void
|
||||
SetFocusedPanel(UIPanel* panel)
|
||||
{
|
||||
if(!CheckNil(g_UI_NIL_PANEL, panel))
|
||||
{
|
||||
g_widget_ctx.focused_panel = panel;
|
||||
SetFocus(panel.ed != null ? Get(panel.ed.filename) : Get(panel.id));
|
||||
}
|
||||
}
|
||||
|
||||
UIPanel*
|
||||
GetFocusedPanel()
|
||||
{
|
||||
return Nil(g_widget_ctx.focused_panel) ? g_UI_NIL_PANEL : g_widget_ctx.focused_panel;
|
||||
}
|
||||
|
||||
bool
|
||||
Nil(UIPanel* panel)
|
||||
{
|
||||
return panel == null || panel == g_UI_NIL_PANEL;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user