further work on command palette, change debugging from log to in UI

This commit is contained in:
Matthew 2026-01-28 06:15:05 +11:00
parent b45da79331
commit 08fe3c4b81
2 changed files with 213 additions and 92 deletions

View File

@ -43,6 +43,7 @@ struct Ctx
Arena arena;
Arena temp_arena;
Arena[FO] str_arenas;
Inputs* inputs;
u64 frame;
@ -88,6 +89,8 @@ struct Ctx
string[] file_names;
u64 panel_id;
debug bool dbg;
alias rd_ctx this;
}
@ -98,6 +101,7 @@ struct CmdPalette
u8[] buffer;
u32 icount;
i64 selected;
u64 visible_opts;
Command current;
Parameter[] params;
}
@ -144,6 +148,7 @@ struct Command
string desc;
string cmd;
CmdType type;
bool hidden;
union
{
CmdFn fn;
@ -736,11 +741,18 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse
{
if(Shift(node.md))
{
ctx.state = ES.CmdPalette;
ctx.cmd.icount = 0;
ctx.cmd.selected = 0;
ctx.cmd.params = [];
taken = true;
ctx.state = ES.CmdPalette;
ctx.cmd.icount = 0;
ctx.cmd.selected = 0;
ctx.cmd.params = [];
ctx.cmd.visible_opts = CMD_LIST.length;
static foreach(i; 0 .. CMD_LIST.length)
{
CMD_LIST[i].hidden = false;
}
taken = true;
}
} break;
case v:
@ -766,6 +778,16 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse
taken = true;
}
} break;
case g:
{
debug
{
if(Shift(md))
{
ctx.dbg = !ctx.dbg;
}
}
} break;
default:
{
taken = MoveCursor(ed, node);
@ -923,12 +945,6 @@ Lower(u8 ch)
return ch;
}
bool
StrContains(bool begins_with)(u8[] str, u8[] match)
{
return StrContains!(begins_with)(Str(str), match);
}
bool
StrContains(bool begins_with, T, U)(T str_param, U match_param) if(StringType!(T) && StringType!(U))
{
@ -950,6 +966,12 @@ StrContains(bool begins_with, T, U)(T str_param, U match_param) if(StringType!(T
string match = match_param;
}
return StrContains!(begins_with)(str, match);
}
bool
StrContains(bool begins_with)(string str, string match)
{
u64 count;
for(u64 i = 0; i < str.length; i += 1)
{
@ -983,86 +1005,135 @@ HandleCmdMode(Ctx* ctx)
Editor* ed = panel.ed;
CmdPalette* cmd = &ctx.cmd;
for(InputEvent* ev = ctx.inputs.first; ev && ctx.state == ES.CmdPalette; ev = ev.next)
bool buffer_changed;
for(UIInput* ev = ctx.events.first; ev && ctx.state == ES.CmdPalette; ev = ev.next)
{
bool taken;
if(!ev.pressed) continue;
switch(ev.key) with(Input)
switch(ev.type)
{
case Enter:
case UIE.Press:
{
if(cmd.current.type != CT.None)
switch(ev.key) with(Input)
{
cmd.current = CMD_LIST[cmd.selected];
case Enter:
{
if(cmd.current.type != CT.None)
{
cmd.current = CMD_LIST[cmd.selected];
switch(cmd.current.type) with(CmdType)
{
case Config:
switch(cmd.current.type) with(CmdType)
{
case Config:
{
// TODO: implement
} break;
case Hotkey:
{
// TODO: implement
} break;
case Callback:
{
assert(cmd.current.fn, "Callback type doesn't have a function pointer set");
ctx.state = ES.RunCmd;
} break;
default: break;
}
}
} break;
case Backspace:
{
if(cmd.icount > 0)
{
// TODO: implement
} break;
case Hotkey:
cmd.icount -= 1;
if(cmd.icount == cmd.current.name.length)
{
cmd.current = cast(Command)NO_CMD;
}
buffer_changed = true;
}
} break;
case Up, Down:
{
i32 incr = ev.key == Up ? -1 : +1;
i64 selected = cmd.selected;
for(i64 i = selected+incr; true; i += incr)
{
// TODO: implement
} break;
case Callback:
if(i < 0 || i >= CMD_LIST.length)
{
break;
}
if(!CMD_LIST[i].hidden)
{
selected = i;
break;
}
}
cmd.selected = selected;
} break;
case Escape:
{
ResetCtx();
} break;
default:
{
if(ev.text.length)
{
assert(cmd.current.fn, "Callback type doesn't have a function pointer set");
ctx.state = ES.RunCmd;
} break;
default: break;
}
}
} break;
case Backspace:
{
if(cmd.icount > 0)
{
cmd.icount -= 1;
if(cmd.icount == cmd.current.name.length)
{
cmd.current = cast(Command)NO_CMD;
}
}
} break;
case Space:
{
Check(cmd, 1);
cmd.buffer[cmd.icount++] = ' ';
} goto case Tab;
case Tab:
{
if(cmd.current.type == CT.None)
{
cmd.current = CMD_LIST[cmd.selected];
cmd.buffer[0 .. cmd.current.name.length] = Arr!(u8)(cmd.current.name[0 .. $]);
cmd.icount = cast(u32)cmd.current.name.length;
cmd.buffer[cmd.icount++] = ' ';
}
} break;
case Up, Down:
{
i32 incr = ev.key == Up ? -1 : +1;
cmd.selected = clamp(cmd.selected+incr, 0, CMD_LIST.length-1);
} break;
case Escape:
{
ResetCtx();
} break;
default:
{
if(ev.text.length)
{
cmd.buffer[cmd.icount .. cmd.icount+ev.text.length] = cast(u8[])ev.text[0 .. $];
cmd.icount += ev.text.length;
Check(cmd, ev.text.length);
cmd.buffer[cmd.icount .. cmd.icount+ev.text.length] = cast(u8[])ev.text[0 .. $];
cmd.icount += ev.text.length;
buffer_changed = true;
}
} break;
}
} break;
default: break;
}
if(taken)
{
DLLRemove(ctx.inputs, ev, null);
DLLRemove(&ctx.events, ev, null);
}
}
if(buffer_changed)
{
if(cmd.icount)
{
cmd.visible_opts = 0;
string buffer_text = Str(cmd.buffer[0 .. cmd.icount]);
static foreach(i; 0 .. CMD_LIST.length)
{
CMD_LIST[i].hidden = !(StrContains!(false)(CMD_LIST[i].cmd, buffer_text) || StrContains!(false)(CMD_LIST[i].name, buffer_text));
cmd.visible_opts += !CMD_LIST[i].hidden;
}
if(CMD_LIST[cmd.selected].hidden)
{
i64 selected = 0;
foreach(i; 0 .. CMD_LIST.length)
{
if(!CMD_LIST[i].hidden)
{
selected = i;
break;
}
}
cmd.selected = selected;
}
}
else
{
static foreach(i; 0 .. CMD_LIST.length)
{
CMD_LIST[i].hidden = false;
}
cmd.visible_opts = CMD_LIST.length;
}
}
}

View File

@ -96,7 +96,7 @@ __gshared Style CMD_STYLE = {
border_col: CMD_BORDER_COL,
border_hl_col: BORDER_HL_COL,
corner_radius: Vec4(CORNER_RADIUS),
border_thickness: 1.0,
border_thickness: 1.5,
edge_softness: 1.0,
};
@ -405,6 +405,7 @@ InitUI(Ctx* ctx)
ctx.buffers[i].idx = ctx.buffers[i].m_idx.data;
ctx.buffers[i].idx[0 .. $] = [0, 1, 2, 2, 1, 3];
ctx.desc_sets[i] = AllocDescSet(&ctx.rd, ctx.desc_set_layout);
ctx.str_arenas[i] = CreateArena(MB(1));
}
GfxPipelineInfo ui_info = {
@ -581,9 +582,16 @@ Panel(Ctx* ctx, UIPanel* panel)
FontAtlasBuf* abuf = &fg.abuf;
// Inputs
bool hovered = ctx.hover_key == panel.key;
bool focused = ctx.focus_key == panel.key && ctx.focused_panel == panel;
panel.move_text_with_cursor |= HandleInputs(panel, &ctx.events, hovered, focused);
if(ctx.state == ES.NormalMode || ctx.state == ES.InputMode)
{
bool hovered = ctx.hover_key == panel.key;
bool focused = ctx.focus_key == panel.key && ctx.focused_panel == panel;
panel.move_text_with_cursor |= HandleInputs(panel, &ctx.events, hovered, focused);
}
else
{
panel.move_text_with_cursor = false;
}
f32 lheight = abuf.atlas.line_height;
panel.scroll_target.y = cast(f32)(panel.ed.line_offset)*lheight;
@ -615,7 +623,7 @@ Panel(Ctx* ctx, UIPanel* panel)
for(u64 i = start_ln; i < max_ln; i += 1)
{
string line_num = Scratchf("%s", i+1);
string line_num = EdScratchf("%s", i+1);
DrawText(ctx, line_num, Vec4(1.0), fg, text_rect, TA.Right);
text_rect.p0.y += lheight;
}
@ -751,9 +759,9 @@ CommandPalette(Ctx* ctx)
Vec2 extent = GetExtent();
CmdPalette* cmd = &ctx.cmd;
f32 x = extent.x * 0.3;
f32 x = extent.x * 0.1;
f32 y = extent.y * 0.2;
f32 w = extent.x * 0.4;
f32 w = extent.x * 0.8;
f32 h = extent.y * 0.6;
UIItem* cmd_item = MakeItem("###cmd_palette");
@ -774,31 +782,42 @@ CommandPalette(Ctx* ctx)
Style style = CMD_STYLE;
Rect[2] rects = Split(cmd_item.rect, lheight+PAD*2.0, A2D.Y);
Rect[2] rects = Split(cmd_item.rect, lheight+PAD*4.0, A2D.Y);
style.corner_radius.zw = 0.0;
DrawRect(ctx, rects[0], &style, 0.0, cmd_item.ready_t);
DrawBorder(ctx, rects[0], &style, 0.0, cmd_item.ready_t);
style.corner_radius.zw = 1.0;
Rect text_input_rect = rects[0];
text_input_rect.p0.y += PAD*2.0f;
text_input_rect.p0.x += PAD*4.0f;
string input_str = cmd.icount ? Str(cmd.buffer[0 .. cmd.icount]) : "Type to search...";
Vec4 input_col = cmd.icount ? WHITE : GREY;
DrawText(ctx, input_str, input_col, fg, text_input_rect, TA.Left, -1, cmd_item.ready_t);
style.corner_radius.zw = CORNER_RADIUS;
style.corner_radius.xy = 0.0;
DrawRect(ctx, rects[1], &style, 0.0, cmd_item.ready_t);
Rect border_rect = rects[1];
rects[1].p0 += style.border_thickness;
rects[1].p1 -= style.border_thickness;
Rect opt_rect = rects[1];
Rect opt_rect = rects[1];
foreach(i; 0 .. CMD_LIST.length)
{
if(CMD_LIST[i].hidden) continue;
Rect[2] opt_rects = Split(opt_rect, lheight+sub_lheight+PAD*3.0f, A2D.Y);
if(opt_rects[0].p0.y == opt_rects[0].p1.y)
{
break;
}
UIItem* opt_item = MakeItem!(UIF.Click|UIF.Priority)("###opt_%s", i);
f32 opt_height = opt_rects[0].p1.y-opt_rects[1].p0.y;
@ -812,7 +831,8 @@ CommandPalette(Ctx* ctx)
if(opt_rects[0].p1.y - opt_rects[0].p0.y > PAD)
{
opt_rects[0].p0 += PAD;
opt_rects[0].p0.y += PAD;
opt_rects[0].p0.x += PAD*2.0f;
DrawText(ctx, CMD_LIST[i].name, WHITE, fg, opt_rects[0], TA.Left, -1, cmd_item.ready_t);
opt_rects[0].p0.y += lheight+PAD;
@ -823,7 +843,7 @@ CommandPalette(Ctx* ctx)
opt_rect = opt_rects[1];
}
DrawBorder(ctx, rects[1], &style, 0.0, cmd_item.ready_t);
DrawBorder(ctx, border_rect, &style, 0.0, cmd_item.ready_t);
HandleCmdMode(ctx);
}
@ -1068,7 +1088,7 @@ void
BeginUI(Inputs* inputs)
{
Ctx* ctx = GetCtx();
Arena* a = &ctx.temp_arena;
Arena* a = &ctx.temp_arena;
Reset(a);
@ -1146,8 +1166,6 @@ BeginUI(Inputs* inputs)
{
ctx.hover_key = ZeroKey();
}
Logf("hover key %s", ctx.hover_key.hash_text);
}
// Clean up items
@ -1170,6 +1188,8 @@ BeginUI(Inputs* inputs)
ctx.inputs = inputs;
ctx.last_item = g_UI_NIL;
Reset(&ctx.str_arenas[ctx.f_idx]);
assert(!mouse_moved || ZeroKey(ctx.hover_key) || (ctx.frame == ctx.last_hover_frame));
ctx.animation_rate = 1.0 - pow(2.0, (-30.0f * g_delta));
@ -1250,6 +1270,29 @@ EndUI()
{
Ctx* ctx = GetCtx();
if(ctx.dbg)
{
const PAD = 4.0f;
static FontGlyphs* fg;
if(!fg)
{
fg = GetFontGlyphs(12);
}
string debug_hover_key = Scratchf("Hover Key: %s", ctx.hover_key.hash_text.length ? ctx.hover_key.hash_text : "None");
Vec2 ext = GetExtent();
f32 text_width = CalcTextWidth(debug_hover_key, &fg.abuf);
Rect debug_rect;
debug_rect.p0.x = ext.x - text_width - PAD*2.0f;
debug_rect.p0.y = ext.y - fg.abuf.atlas.line_height - PAD*2.0f;
debug_rect.p1 = ext;
DrawText(ctx, debug_hover_key, WHITE, fg, debug_rect, TA.Left);
}
version(ENABLE_RENDERER)
{
DrawUI(ctx);
@ -1664,7 +1707,7 @@ NewItem(Ctx* ctx)
UIItem*
MakeItem(UIFlags flags = UIF.None, Args...)(string str, Args args)
{
char[] key = sformat(ScratchAlloc!(char)(cast(u64)(str.length*1.5)), str, args);
char[] key = sformat(Alloc!(char)(&g_ctx.str_arenas[g_ctx.f_idx], cast(u64)(str.length*1.5)), str, args);
return MakeItem(key, flags);
}
@ -2004,6 +2047,13 @@ OklabToSRGB(Vec4 v)
);
}
string
EdScratchf(Args...)(string fmt, Args args)
{
char[] buf = Alloc!(char)(&g_ctx.str_arenas[g_ctx.f_idx], fmt.length < 16 ? 32 : 128);
return Str(sformat(buf, fmt, args));
}
unittest
{
{ // UI Key