begin rebuilding UI framework

This commit is contained in:
Matthew 2025-12-06 17:17:03 +11:00
parent d69b5b5993
commit 2a3be6ad58
5 changed files with 804 additions and 614 deletions

@ -1 +1 @@
Subproject commit b05d0553837233818f1cbdb1dc3a3981eac1a0a3 Subproject commit 589b2191babf009bef097d1272fac4a05a4c280d

View File

@ -948,8 +948,9 @@ unittest
// FlatBuffer Insert/Delete/Replace // FlatBuffer Insert/Delete/Replace
{ {
/*
u8[] data = StringToU8("This is a test string for testing the FlatBuffer struct."); u8[] data = StringToU8("This is a test string for testing the FlatBuffer struct.");
FlatBuffer buf = CreateFlatBuffer(data); FlatBuffer buf = CreateFlatBuffer(data, "file");
u8[] insert = StringToU8("This is a string inserted into the beginning of the buffer. "); u8[] insert = StringToU8("This is a string inserted into the beginning of the buffer. ");
Insert(&buf, insert, insert.length, 0); Insert(&buf, insert, insert.length, 0);
@ -977,5 +978,6 @@ unittest
{ {
assert(buf.data[i] == ch, "FlatBuffer Replace failure: buffers do not match"); assert(buf.data[i] == ch, "FlatBuffer Replace failure: buffers do not match");
} }
*/
} }
} }

View File

@ -6,6 +6,7 @@ import buffer;
import ui : Nil; import ui : Nil;
import ui; import ui;
import parsing; import parsing;
import views;
import std.format; import std.format;
import std.stdio; import std.stdio;
@ -657,9 +658,7 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs)
} break; } break;
debug case d: debug case d:
{ {
static bool dbg = false; g_ui_ctx.dbg = !g_ui_ctx.dbg;
dbg = !dbg;
SetDebug(dbg);
} break; } break;
debug case g: debug case g:
{ {

File diff suppressed because it is too large Load Diff

330
src/editor/views.d Normal file
View File

@ -0,0 +1,330 @@
import dlib;
import ui;
import editor;
import parsing;
import buffer;
import std.format;
import std.conv;
void
Panel(UIPanel* panel)
{
UICtx* ctx = GetCtx();
UIItem* item = Get(panel.id);
Editor* ed = panel.ed;
bool focused = GetFocusedPanel() == panel;
UIPanel* parent = panel.parent;
UIPanel* prev = panel.prev;
Axis2D pax = parent.axis;
Vec2 adj = Vec2(
parent.axis == A2D.X ? 10 : 0,
parent.axis == A2D.Y ? 10 : 0
);
Vec2 p0 = panel.rect.vec0+adj;
Vec2 p1 = panel.rect.vec1-adj;
if(!Nil(prev)) with(panel)
{
Vec2 d0 = rect.vec0-adj;
Vec2 d1 = Vec2(
pax == A2D.X ? rect.vec0.x+adj.x : rect.vec1.x,
pax == A2D.Y ? rect.vec0.y+adj.y : rect.vec1.y
);
if(Dragged(item, d0, d1) && item.dragged.v[pax] != 0.0)
{
f32 mov_pct = Remap(item.dragged.v[pax], 0.0, panel.parent.size.v[pax], 0.0, 1.0);
if(CheckPanelBounds(pct + mov_pct) && CheckPanelBounds(panel.prev.pct - mov_pct))
{
pct += mov_pct;
panel.prev.pct -= mov_pct;
}
}
}
if(panel.ed != null)
{
if(Clicked(item, p0, p1))
{
SetFocusedPanel(panel);
}
Vec2 inner = InnerSize(panel);
SetScrollOffset(panel);
panel.start_ln = cast(u64)(floor(panel.scroll_offset/TEXT_SIZE));
panel.end_ln = panel.start_ln + cast(u64)(ceil(inner.y/TEXT_SIZE));
panel.vis_lines = panel.end_ln - panel.start_ln;
char[64] ch_buf = '\0';
char[] fmt = ch_buf.sformat("%%0%ss", u64(panel.end_ln.toChars().length));
f32 lc_w = panel.end_ln.toChars().length*ctx.char_width + LINE_COUNT_PADDING*2.0;
f32 code_view_width = inner.x-lc_w;
StartLineBuffer(&panel.ed.buf, code_view_width);
U64Vec2 pos = VecPos(&ed.buf);
DrawPanel(panel, lc_w, focused);
f32 y_rem = fmod(panel.scroll_offset, TEXT_SIZE);
f32 x = panel.rect.x0;
f32 y = panel.rect.y0 + TEXT_SIZE - fmod(panel.scroll_offset, TEXT_SIZE);
u64 i = panel.start_ln;
for(auto buf = GetLine(&ed.buf, i); !CheckNil(g_NIL_LINE_BUF, buf) && i < panel.end_ln; i += 1, buf = GetLine(&ed.buf, i))
{
f32 x_pos = x + LINE_COUNT_PADDING;
DrawLineCount(fmt, &x_pos, y, i);
u64 ch_offset;
auto parts = MakeMultiline(buf.text, code_view_width, buf.style);
if(parts == null)
{
if(pos.y == i)
{
DrawCursor([], 0, x+lc_w, y, ch_offset);
}
}
else for(auto n = parts; n != null; n = n.next)
{
auto l = &n.value;
if(pos.y == i)
{
DrawCursor(l.text, pos.x, x+lc_w, y, ch_offset);
}
foreach(j; 0 .. l.text.length)
{
bool hl = pos.y == i && !EditModeActive() && j == pos.x-ch_offset;
DrawChar(l.text[j], &x_pos, y, hl ? Vec4(Vec3(0.0), 1.0) : SYNTAX_COLORS[l.style[j]]);
}
y += TEXT_SIZE;
x_pos = x + lc_w + LINE_COUNT_PADDING*2.0;
ch_offset += l.text.length;
}
}
}
}
void
CommandPalette(CmdPalette* cmd)
{
UICtx* ctx = GetCtx();
u8[] text = cmd.buffer[0 .. cmd.icount];
u8[][] options = cmd.opt_strs;
Vec2 size = RootSize();
f32 x = size.x*0.15;
f32 y = size.y*0.1;
f32 w = size.x*0.7;
f32 h = 40.0;
DrawCmdRect(Vec2(x, y), Vec2(w, h), false);
f32 y_off = h*0.5 + 6;
f32 ch_x = x + 6.0;
f32 ch_y = y + y_off;
foreach(i; 0 .. text.length)
{
DrawChar(text[i], &ch_x, ch_y, Vec4(1.0));
}
for(u64 i = 0; i < options.length; i += 1)
{
y += h;
ch_x = x + 6.0;
ch_y = y + y_off;
DrawCmdRect(Vec2(x, y), Vec2(w, h), cmd.selected == i);
foreach(j; 0 .. options[i].length)
{
DrawChar(options[i][j], &ch_x, ch_y, Vec4(1.0));
}
if(y+h > size.y+h) break;
}
}
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)
{
return pct >= 0.0 && pct <= 1.0;
}
void
PushPanel(UIPanel* parent, UIPanel* panel)
{
DLLPush(parent, panel, g_UI_NIL_PANEL);
panel.parent = parent;
}
void
InsertPanel(UIPanel* parent, UIPanel* prev, UIPanel* panel)
{
DLLInsert(parent, panel, prev, g_UI_NIL_PANEL);
panel.parent = prev.parent;
}
void
SetFocusedPanel(UIPanel* panel)
{
if(!CheckNil(g_UI_NIL_PANEL, panel))
{
g_ui_ctx.focused_panel = panel;
}
}
UIPanel*
GetFocusedPanel()
{
return Nil(g_ui_ctx.focused_panel) ? g_UI_NIL_PANEL : g_ui_ctx.focused_panel;
}
bool
Nil(UIPanel* panel)
{
return panel == null || panel == g_UI_NIL_PANEL;
}
Node!(TextBuffer)*
MakeMultiline(u8[] text, f32 width, TS[] style = [])
{
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));
Node!(TextBuffer)* node = null;
if(line_count > 0)
{
f32 w = 0.0;
u64 line = 0;
u64 start = 0;
const u64 extra_buf = 20;
for(u64 i = 0; i < text.length; i += 1)
{
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[] str = ScratchAlloc!(u8)(text, start, len);
TS[] stl = [];
if(style.length > 0)
{
stl = ScratchAlloc!(TS)(style, start, len);
}
Node!(TextBuffer)* n = node;
for(;;)
{
if(node == null)
{
node = ScratchAlloc!(Node!(TextBuffer))();
node.value.text = str;
node.value.style = stl;
node.next = null;
break;
}
if(n.next == null)
{
n.next = ScratchAlloc!(Node!(TextBuffer))();
n.next.value.text = str;
n.next.value.style = stl;
n.next.next = null;
break;
}
n = n.next;
}
line += 1;
start = i;
w = 0.0;
}
w += ch_w;
}
}
return node;
}
pragma(inline) void
DrawCursor(u8[] text, u64 ch_x, f32 x, f32 y, u64 offset)
{
Glyph* g = GetGlyph(' ');
foreach(j; 0 .. text.length)
{
bool hl = j == ch_x-offset;
if(hl)
{
break;
}
g = j == text.length-1 ? GetGlyph(' ') : GetGlyph(text[j]);
x += GlyphWidth(g);
}
DrawRect(x, y, cast(u8)g.ch, Vec4(1.0), EditModeActive());
}
pragma(inline) void
DrawLineCount(char[] fmt, f32* x_pos, f32 y, u64 line)
{
char[32] line_buf = '\0';
char[] line_str = sformat(line_buf, fmt, line+1);
foreach(j; 0 .. line_str.length)
{
DrawChar(line_str[j], x_pos, y, Vec4(1.0));
}
*x_pos += LINE_COUNT_PADDING;
}