start work on command palette

This commit is contained in:
Matthew 2025-09-26 19:17:55 +10:00
parent 822dd5ea71
commit 1becb705be
5 changed files with 290 additions and 114 deletions

@ -1 +1 @@
Subproject commit 27d62beb4195c08bd25bffaa0d9c72b523d971f4 Subproject commit cadb2b5f853a22aa870dc1d986e73330c9136bb5

View File

@ -14,8 +14,11 @@ import widgets;
import std.format; import std.format;
import std.stdio; import std.stdio;
import std.exception; import std.exception;
import std.file;
f32 g_delta = 0.0; f32 g_delta = 0.0;
debug bool g_frame_step = false;
debug bool g_frame_continue = false;
struct EditorCtx struct EditorCtx
{ {
@ -25,6 +28,8 @@ struct EditorCtx
EditState state; EditState state;
u8[128] input_buf; u8[128] input_buf;
u32 icount; u32 icount;
u8[] cmd_buffer;
u32 cmd_count;
Timer timer; Timer timer;
} }
@ -64,23 +69,32 @@ Cycle(EditorCtx* ctx, Inputs* inputs)
g_delta = DeltaTime(&ctx.timer); g_delta = DeltaTime(&ctx.timer);
debug if(g_frame_step)
{
g_delta = 0.01;
}
assert(Nil(ctx.base_panel.next)); assert(Nil(ctx.base_panel.next));
HandleInputs(ctx, inputs); HandleInputs(ctx, inputs);
debug if(g_frame_step && !g_frame_continue) return;
debug g_frame_continue = false;
g_input_mode = ctx.state == ES.InputMode; g_input_mode = ctx.state == ES.InputMode;
// UI Functions After This Point
BeginBuild(inputs); BeginBuild(inputs);
if(ctx.state == ES.CmdOpen) if(ctx.state == ES.CmdOpen)
{ {
CommandPalette(); CommandPalette(ctx.cmd_buffer[0 .. ctx.cmd_count]);
} }
DrawPanels(ctx.base_panel); DrawPanels(ctx.base_panel);
EndBuild(); EndBuild();
// UI Functions Before This Point
} }
EditorCtx EditorCtx
@ -97,6 +111,7 @@ InitEditorCtx(PlatformWindow* window)
ctx.base_panel = CreatePanel(&ctx); ctx.base_panel = CreatePanel(&ctx);
ctx.base_panel.ed = CreateEditor(&ctx); ctx.base_panel.ed = CreateEditor(&ctx);
ctx.timer = CreateTimer(); ctx.timer = CreateTimer();
ctx.cmd_buffer = MAllocArray!(u8)(1024);
SetFocusedPanel(ctx.base_panel); SetFocusedPanel(ctx.base_panel);
return ctx; return ctx;
@ -123,6 +138,12 @@ EditModeActive()
return g_input_mode; return g_input_mode;
} }
void
ScanFiles(EditorCtx* ctx)
{
}
// Load all files then move things into editor after being created when selected // Load all files then move things into editor after being created when selected
Editor* Editor*
@ -251,6 +272,10 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs)
{ {
taken = HandleInputMode(ctx, node.value); taken = HandleInputMode(ctx, node.value);
} }
else if(ctx.state == ES.CmdOpen)
{
taken = HandleCmdMode(ctx, node.value);
}
else else
{ {
switch(key) with(Input) switch(key) with(Input)
@ -276,11 +301,25 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs)
} break; } break;
case c: case c:
{ {
//AddEditor(ctx, GetFocusedPanel(), A2D.Y); AddEditor(ctx, GetFocusedPanel(), A2D.Y);
//taken = true; taken = true;
} break; } break;
case d: case d:
{ {
static bool dbg = false;
dbg = !dbg;
SetDebug(dbg);
} break;
case g:
{
debug
{
g_frame_step = !g_frame_step;
}
} break;
debug case s:
{
g_frame_continue = true;
} break; } break;
case Up: case Up:
case Down: case Down:
@ -367,6 +406,64 @@ HandleInputMode(EditorCtx* ctx, InputEvent ev)
return taken; return taken;
} }
static string
TextLineCharCases()
{
import std.traits;
string result = "";
foreach(input; EnumMembers!Input)
{
u8 ch = InputToChar(input);
if(ch > 0 && ch != '\n')
{
if(ch == '\'' || ch == '\\')
{
result ~= format("case %s: result = '\\%s'; taken = true; break;\n", input, cast(char)ch);
}
else
{
result ~= format("case %s: result = '%s'; taken = true; break;\n", input, cast(char)ch);
}
}
}
return result;
}
bool
HandleCmdMode(EditorCtx* ctx, InputEvent ev)
{
u8 result = 0;
bool taken = false;
switch(ev.key) with(Input)
{
mixin(TextLineCharCases());
case Backspace:
{
if(ctx.cmd_count > 0)
{
ctx.cmd_count -= 1;
}
} break;
case Escape:
{
ctx.cmd_count = 0;
ctx.state = ES.NormalMode;
} break;
default: break;
}
if(result != 0)
{
Logf("test");
ctx.cmd_buffer[ctx.cmd_count++] = result;
}
return taken;
}
/* /*
void void
DrawBuffer(Editor* ed, f32 x, f32 y, f32 px, FlatBuffer* fb) DrawBuffer(Editor* ed, f32 x, f32 y, f32 px, FlatBuffer* fb)

View File

@ -195,6 +195,20 @@ struct PushConst
Mat4 projection; Mat4 projection;
} }
struct GlyphBounds
{
f32 r = 0.0;
f32 l = 0.0;
f32 t = 0.0;
f32 b = 0.0;
f32 w = 0.0;
f32 h = 0.0;
f32 atlas_r = 0.0;
f32 atlas_l = 0.0;
f32 atlas_t = 0.0;
f32 atlas_b = 0.0;
}
struct Vertex struct Vertex
{ {
Vec4[4] cols; Vec4[4] cols;
@ -234,6 +248,7 @@ alias UIPair = KVPair!(UIHash, UIItem*);
struct UIKey struct UIKey
{ {
u8[] text; u8[] text;
u8[] hash_text;
u64 hash; u64 hash;
} }
@ -655,7 +670,7 @@ EndBuild()
DrawUI(ctx, ctx.root); DrawUI(ctx, ctx.root);
if(ctx.dbg) debug if(ctx.dbg)
{ {
DrawDebugUI(ctx, ctx.root); DrawDebugUI(ctx, ctx.root);
} }
@ -674,7 +689,8 @@ EndBuild()
static u32 prev_count = 0; static u32 prev_count = 0;
if(prev_count != ctx.item_count) if(prev_count != ctx.item_count)
{ {
PrintNodes(ctx.root); //Logf("New node count, printing node debug info: ");
//PrintNodes(ctx.root);
prev_count = ctx.item_count; prev_count = ctx.item_count;
} }
} }
@ -714,13 +730,9 @@ void
PrintNodes(UIItem* item) PrintNodes(UIItem* item)
{ {
if(!Nil(item)) if(!Nil(item))
{
if(item.culling.vec0 != Vec2(0.0) || item.culling.vec1 != Vec2(0.0))
{ {
Logf("%s:", cast(char[])item.key.text); Logf("%s:", cast(char[])item.key.text);
Logf("x0 %s x1 %s y0 %s y1 %s", item.rect.x0, item.rect.x1, item.rect.y0, item.rect.y1); Logf("x0 %s x1 %s y0 %s y1 %s", item.rect.x0, item.rect.x1, item.rect.y0, item.rect.y1);
Logf("cull x0 %s x1 %s y0 %s y1 %s\n", item.culling.x0, item.culling.x1, item.culling.y0, item.culling.y1);
}
PrintNodes(item.first); PrintNodes(item.first);
PrintNodes(item.next); PrintNodes(item.next);
@ -791,15 +803,24 @@ CalcPositions(alias axis)(UIItem* item)
f32 end_pos = 0.0, next_pos = 0.0; f32 end_pos = 0.0, next_pos = 0.0;
if(i.flags & UIF.Window) if(i.flags & UIF.Window)
{ {
end_pos = i.size.v[axis] + i.offset.v[axis]; end_pos = i.offset.v[axis] + i.size.v[axis];
i.rect.vec0.v[axis] = i.offset.v[axis]; i.rect.vec0.v[axis] = i.offset.v[axis];
i.rect.vec1.v[axis] = end_pos; i.rect.vec1.v[axis] = end_pos;
pos = i.rect.vec0.v[axis];
} }
else else
{ {
pos += i.offset.v[axis];
end_pos = pos + i.size.v[axis]; end_pos = pos + i.size.v[axis];
i.rect.vec0.v[axis] = pos + i.offset.v[axis]; i.rect.vec0.v[axis] = pos;
i.rect.vec1.v[axis] = end_pos + i.offset.v[axis]; i.rect.vec1.v[axis] = end_pos;
if(item.parent.key.text == r"###cmd_palette_input_cntr")
{
Logf("pos %s end_pos %s", pos, end_pos);
}
assert(!isNaN(i.rect.vec0.v[axis])); assert(!isNaN(i.rect.vec0.v[axis]));
assert(!isNaN(i.rect.vec1.v[axis])); assert(!isNaN(i.rect.vec1.v[axis]));
@ -1032,18 +1053,6 @@ RootSize()
return size; return size;
} }
UIKey
MakeKey(u8[] text, u8[] hash)
{
UIKey key;
key.text = text;
key.hash = Hash(text, hash);
return key;
}
UIKey UIKey
MakeKey(u8[] id) MakeKey(u8[] id)
{ {
@ -1079,17 +1088,20 @@ MakeKey(u8[] id)
if(hash_count < 2 || hash_only) if(hash_count < 2 || hash_only)
{ {
key.text = id; key.text = hash_only ? [] : id;
key.hash_text = hash_only ? id : [];
key.hash = Hash(id); key.hash = Hash(id);
} }
else if(hash_count == 2) else if(hash_count == 2)
{ {
key.text = id.ptr[0 .. pos]; key.text = id[0 .. pos];
key.hash_text = id[pos .. $];
key.hash = Hash(id); key.hash = Hash(id);
} }
else if(hash_count == 3) else if(hash_count == 3)
{ {
key.text = id.ptr[0 .. pos]; key.text = id[0 .. pos];
key.hash_text = id[pos .. $];
key.hash = Hash(id[pos+hash_count .. $]); key.hash = Hash(id[pos+hash_count .. $]);
} }
@ -1306,6 +1318,58 @@ DrawLine(UIItem* item)
} }
} }
pragma(inline) bool
CullText(UIItem* item, GlyphBounds* gb)
{
bool skip = false;
if(item.culling.x0 != 0.0 || item.culling.x1 != 0.0)
{
if(gb.w <= item.culling.x0+item.culling.x1)
{
skip = true;
}
else
{
f32 start_pct = 1.0-((gb.w-item.culling.x0)/gb.w);
f32 end_pct = 1.0-((gb.w-item.culling.x1)/gb.w);
f32 atlas_len = gb.atlas_r - gb.atlas_l;
gb.atlas_l += atlas_len * start_pct;
gb.atlas_r -= atlas_len * end_pct;
gb.l += item.culling.x0;
gb.r -= item.culling.x1;
gb.w = gb.r-gb.l;
}
}
if(!skip && (item.culling.y0 != 0.0 || item.culling.y1 != 0.0))
{
if(gb.h <= item.culling.y0+item.culling.y1)
{
skip = true;
}
else
{
f32 start_pct = 1.0-((gb.h-item.culling.y0)/gb.h);
f32 end_pct = 1.0-((gb.h-item.culling.y1)/gb.h);
f32 atlas_len = gb.atlas_b-gb.atlas_t;
gb.atlas_t += atlas_len * start_pct;
gb.atlas_b -= atlas_len * end_pct;
gb.t += item.culling.y0;
gb.b -= item.culling.y1;
gb.h = gb.b-gb.t;
}
}
return skip;
}
pragma(inline) void pragma(inline) void
DrawGlyph(UIItem* item, Glyph* glyph, f32 scale, f32* x_pos, f32 y, bool highlight = false, Vec4 col = Vec4(1.0)) DrawGlyph(UIItem* item, Glyph* glyph, f32 scale, f32* x_pos, f32 y, bool highlight = false, Vec4 col = Vec4(1.0))
{ {
@ -1321,58 +1385,22 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32 scale, f32* x_pos, f32 y, bool highlig
f32 l = glyph.plane_left * scale; f32 l = glyph.plane_left * scale;
f32 t = glyph.plane_top * scale; f32 t = glyph.plane_top * scale;
f32 b = glyph.plane_bottom * scale; f32 b = glyph.plane_bottom * scale;
f32 w = r - l;
f32 h = b - t;
f32 atlas_r = glyph.atlas_right; GlyphBounds gb = {
f32 atlas_l = glyph.atlas_left; r: r,
f32 atlas_t = glyph.atlas_top; l: l,
f32 atlas_b = glyph.atlas_bottom; t: t,
b: b,
w: r - l,
h: b - t,
atlas_r: glyph.atlas_right,
atlas_l: glyph.atlas_left,
atlas_t: glyph.atlas_top,
atlas_b: glyph.atlas_bottom,
};
bool skip = false; //bool skip = false;
if(item.culling.x0 != 0.0 || item.culling.x1 != 0.0) bool skip = CullText(item, &gb);
{
if(w <= item.culling.x0+item.culling.x1)
{
skip = true;
}
else
{
f32 start_pct = 1.0-((w-item.culling.x0)/w);
f32 end_pct = 1.0-((w-item.culling.x1)/w);
f32 atlas_len = atlas_r - atlas_l;
atlas_l += atlas_len * start_pct;
atlas_r -= atlas_len * end_pct;
l += item.culling.x0;
r -= item.culling.x1;
w = r-l;
}
}
if(!skip && (item.culling.y0 != 0.0 || item.culling.y1 != 0.0))
{
if(h <= item.culling.y0+item.culling.y1)
{
skip = true;
}
else
{
f32 start_pct = 1.0-((h-item.culling.y0)/h);
f32 end_pct = 1.0-((h-item.culling.y1)/h);
f32 atlas_len = atlas_b-atlas_t;
atlas_t += atlas_len * start_pct;
atlas_b -= atlas_len * end_pct;
t += item.culling.y0;
b -= item.culling.y1;
h = b-t;
}
}
if(!skip) if(!skip)
{ {
@ -1380,17 +1408,17 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32 scale, f32* x_pos, f32 y, bool highlig
v = ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count; v = ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count;
v.dst_start.x = *x_pos + l; v.dst_start.x = *x_pos + gb.l;
v.dst_start.y = y - y_pos; v.dst_start.y = y - y_pos;
v.dst_end.x = *x_pos + w + l; v.dst_end.x = *x_pos + gb.w + gb.l;
v.dst_end.y = y + h - y_pos; v.dst_end.y = y + gb.h - y_pos;
if(glyph.ch != '\t' && glyph.ch != '\n') if(glyph.ch != '\t' && glyph.ch != '\n')
{ {
v.src_start.x = glyph.atlas_left; v.src_start.x = gb.atlas_l;
v.src_start.y = glyph.atlas_top; v.src_start.y = gb.atlas_t;
v.src_end.x = glyph.atlas_right; v.src_end.x = gb.atlas_r;
v.src_end.y = glyph.atlas_bottom; v.src_end.y = gb.atlas_b;
} }
if(highlight) if(highlight)
@ -1417,7 +1445,7 @@ DrawRect(UICtx* ctx, UIItem* item)
v.dst_end = item.rect.vec1; v.dst_end = item.rect.vec1;
v.cols = item.color; v.cols = item.color;
v.border_thickness = 0.0; v.border_thickness = 0.0;
v.corner_radius = 0.0; v.corner_radius = item.corner_radius;
v.edge_softness = 0.0; v.edge_softness = 0.0;
v.raised = 0.0; v.raised = 0.0;
@ -1501,16 +1529,20 @@ Clicked(UIItem* item, DNode!(InputEvent)* n)
return result; return result;
} }
u8[]
ScratchName(u8[] base, u8[] append)
{
u8[] id = ScratchAlloc!(u8)(base.length+append.length);
id[0 .. base.length] = base[0 .. $];
id[base.length .. $] = append[0 .. $];
return id;
}
u8[] u8[]
ScratchName(u8[] base, string append) ScratchName(u8[] base, string append)
{ {
u8[] u8_append = CastStr!(u8)(append); u8[] u8_append = CastStr!(u8)(append);
return ScratchName(base, u8_append);
u8[] id = ScratchAlloc!(u8)(base.length+append.length);
id[0 .. base.length] = base[0 .. $];
id[base.length .. $] = u8_append[0 .. $];
return id;
} }
void void

View File

@ -13,9 +13,9 @@ import core.stdc.stdio : sprintf;
const Vec4[4] DEFAULT_COL = [ const Vec4[4] DEFAULT_COL = [
Vec4(0.3, 0.65, 0.86, 1.0), Vec4(0.3, 0.65, 0.86, 1.0),
Vec4(0.25, 0.60, 0.81, 1.0), Vec4(0.28, 0.63, 0.83, 1.0),
Vec4(0.25, 0.60, 0.81, 1.0), Vec4(0.26, 0.62, 0.82, 1.0),
Vec4(0.3, 0.65, 0.86, 1.0), Vec4(0.25, 0.61, 0.80, 1.0),
]; ];
const UIPanel g_ui_nil_panel; const UIPanel g_ui_nil_panel;
@ -137,7 +137,6 @@ UIItem*
LineCounter(u8[] parent_id, FlatBuffer* buf, f32 offset, i64 start_row, i64 end_row) LineCounter(u8[] parent_id, FlatBuffer* buf, f32 offset, i64 start_row, i64 end_row)
{ {
Push!("padding")(Vec2(4.0, 0.0)); Push!("padding")(Vec2(4.0, 0.0));
Push!("offset")(Vec2(0.0, offset));
Push!("color")(Vec4(0.2, 0.5, 0.65, 1.0)); Push!("color")(Vec4(0.2, 0.5, 0.65, 1.0));
u8[] id = ScratchName(parent_id, "linec"); u8[] id = ScratchName(parent_id, "linec");
@ -169,17 +168,18 @@ LineCounter(u8[] parent_id, FlatBuffer* buf, f32 offset, i64 start_row, i64 end_
{ {
UIItem* inner = Container(ScratchName(parent_id, "lcinner"), s_x, s_y, A2D.Y, UIF.None); UIItem* inner = Container(ScratchName(parent_id, "lcinner"), s_x, s_y, A2D.Y, UIF.None);
{ {
Push!("offset")(Vec2(0.0, offset));
for(u64 i = 0; i < line_counts.length; i += 1) for(u64 i = 0; i < line_counts.length; i += 1)
{ {
UIItem* line = Text(line_counts[i]); UIItem* line = Text(line_counts[i]);
} }
Pop!("offset")();
} }
EndContainer(); EndContainer();
} }
EndContainer(); EndContainer();
Pop!("padding")(); Pop!("padding")();
Pop!("offset")();
Pop!("color")(); Pop!("color")();
return item; return item;
@ -364,11 +364,9 @@ EditorView(UIPanel* panel)
LineCounter(panel.id, &panel.ed.buf, offset, line_offset, line_offset+line_rows); LineCounter(panel.id, &panel.ed.buf, offset, line_offset, line_offset+line_rows);
Push!("offset")(Vec2(0.0, offset));
scope(exit) Pop!("offset")();
Container(ScratchName(panel.id, "lines"), UISize(ST.Percentage, 1.0), UISize(ST.Percentage, 1.0), A2D.Y); Container(ScratchName(panel.id, "lines"), UISize(ST.Percentage, 1.0), UISize(ST.Percentage, 1.0), A2D.Y);
{ {
Push!("offset")(Vec2(0.0, offset));
U64Vec2 pos = VecPos(&ed.buf); U64Vec2 pos = VecPos(&ed.buf);
u64 i = 0; u64 i = 0;
for(LineBuffer* buf = ed.linebufs.first; buf != null; buf = buf.next, i += 1) for(LineBuffer* buf = ed.linebufs.first; buf != null; buf = buf.next, i += 1)
@ -404,6 +402,8 @@ EditorView(UIPanel* panel)
{ {
SetFocusedPanel(panel); SetFocusedPanel(panel);
} }
Pop!("offset");
} }
bool bool
@ -455,27 +455,67 @@ WrappedTextLine(u8[] text, u8[] parent_id, f32 text_size, u64 line_no)
BuildItem(tp.item, UISize(ST.Percentage, 1.0), UISize(ST.Pixels, text_size), UIF.DrawText|UIF.Clickable|UIF.Draggable); BuildItem(tp.item, UISize(ST.Percentage, 1.0), UISize(ST.Pixels, text_size), UIF.DrawText|UIF.Clickable|UIF.Draggable);
} }
Pop!("color")(); Pop!("color");
return part; return part;
} }
UIItem* UIItem*
CommandPalette() TextInput(u8[] text, u8[] hash, f32 x, f32 y, f32 w_pct, f32 text_size, Vec4 bg_col)
{
UIItem* input = Get(ScratchName(text, hash));
//Logf("%s %s %s", input.rect.vec0.v, input.rect.vec1.v, cast(char[])input.key.text);
Push!("offset")(Vec2(x, y));
Push!("padding")(Vec2(2.0));
Push!("color")(bg_col);
Container(ScratchName(hash, "_cntr"), UISize(ST.Percentage, w_pct), UISize(ST.Pixels, text_size), A2D.Y, UIF.DrawBackground);
Pop!("color");
Pop!("offset");
Push!("color")(Vec4(1.0));
Push!("text_size")(text_size);
BuildItem(input, UISize(ST.Percentage, 1.0), UISize(ST.Pixels, text_size), UIF.DrawText);
EndContainer();
Pop!("color");
Pop!("padding");
return input;
}
void
CommandPalette(u8[] text)
{ {
Vec2 size = RootSize(); Vec2 size = RootSize();
f32 x = size.x*0.3; f32 x = size.x*0.3;
f32 y = size.y*0.2; f32 y = size.y*0.2;
f32 w = size.x*0.4; f32 w = size.x*0.4;
f32 h = size.y*0.3; f32 h = size.y*0.3;
Logf("%s %s %s %s %s", size.v, x, y, w, h); Push!("border_thickness")(2.0);
Push!("color")(Vec4(0.2, 0.5, 0.65, 1.0));
Push!("border_color")(Vec4(0.08, 0.3, 0.40, 1.0));
Push!("corner_radius")(4.0);
Push!("edge_softness")(0.08);
UIItem* window = Window(CastStr!(u8)("##cmd_palette"), x, y, w, h); UIItem* window = Window(CastStr!(u8)("##cmd_palette"), x, y, w, h);
return window; UIItem* text_box = TextInput(text, CastStr!(u8)("###cmd_palette_input"), w*0.1, y*0.2, 0.8, 16.0, Vec4(Vec3(0.0), 1.0));
EndWindow();
Pop!("border_thickness");
Pop!("border_color");
Pop!("corner_radius");
Pop!("edge_softness");
Pop!("color");
} }
UIItem* UIItem*
@ -487,11 +527,19 @@ Window(u8[] id, f32 x, f32 y, f32 w, f32 h)
BuildItem(item, UISize(ST.Pixels, x), UISize(ST.Pixels, y), UIF.Window|UIF.DrawBackground|UIF.DrawBorder); BuildItem(item, UISize(ST.Pixels, x), UISize(ST.Pixels, y), UIF.Window|UIF.DrawBackground|UIF.DrawBorder);
Pop!("offset")(); Pop!("offset");
PushParent(item);
return item; return item;
} }
void
EndWindow()
{
PopParent();
}
void void
EndPanel() EndPanel()
{ {

View File

@ -75,7 +75,6 @@ void main()
if(in_has_texture != 0) if(in_has_texture != 0)
{ {
tex_color = texture(sampler2D(SpriteAtlas, SamplerNearest), FD.uv); tex_color = texture(sampler2D(SpriteAtlas, SamplerNearest), FD.uv);
//tex_color = pow(tex_color, gamma);
} }
vec4 color = ToLinear(FD.color); vec4 color = ToLinear(FD.color);