more fixes for text buffer, add scrolling

This commit is contained in:
Matthew 2025-09-20 15:48:00 +10:00
parent 6503dae769
commit c9617b701b
4 changed files with 204 additions and 144 deletions

View File

@ -13,12 +13,22 @@ struct FlatBuffer
u64 length;
u64 lf_count;
i64 buf_pos;
i64 offset;
i64 rows;
}
struct LineBuffers
{
Arena arena;
u8[][] lines;
LineBuffer* first;
LineBuffer* last;
u64 count;
}
struct LineBuffer
{
u8[] text;
LineBuffer* next;
}
enum WalkDir
@ -102,6 +112,8 @@ Insert(FlatBuffer* buffer, u8[] insert, u64 length, u64 pos)
buffer.length += length;
Reset(&buffer.arena);
AdjustOffset(buffer);
}
void
@ -118,22 +130,34 @@ Insert(FlatBuffer* buffer, u8[] insert, u64 length, I64Vec2 pos)
Insert(buffer, insert, length, VecToPos(buffer, pos));
}
void
GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 length)
{
GetLines(buffer, linebufs, buffer.offset, length);
}
void
GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length)
{
assert(linebufs != null, "GetLines failure: linebufs is null");
u64 line_count = buffer.lf_count + 1;
length = length > line_count ? line_count : length;
Reset(&linebufs.arena);
linebufs.lines = AllocArray!(u8[])(&linebufs.arena, length);
linebufs.first = Alloc!(LineBuffer)(&linebufs.arena);
linebufs.count = 0;
i64 start = -1;
u64 line = 0;
u64 current_line = 0;
if(buffer.length == 0)
{
linebufs.first.text = AllocArray!(u8)(&linebufs.arena, 1);
linebufs.first.text[0] = 0;
}
else with(linebufs)
{
LineBuffer* current = first;
for(u64 i = 0; i < buffer.length; i += 1)
{
if(current_line == length)
if(count == length)
{
break;
}
@ -145,11 +169,19 @@ GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length)
continue;
}
if(line < start_line)
{
continue;
}
if(start < 0 && new_line)
{
linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, 1);
linebufs.lines[current_line][0] = '\n';
current_line += 1;
current.text = AllocArray!(u8)(&arena, 1);
current.text[0] = '\n';
count += 1;
current.next = Alloc!(LineBuffer)(&arena);
current = current.next;
continue;
}
@ -160,17 +192,34 @@ GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length)
if(new_line)
{
linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, (i-start));
linebufs.lines[current_line][0 .. i-start] = buffer.data[start .. i];
current_line += 1;
current.text = AllocArray!(u8)(&arena, i-start);
current.text[0 .. i-start] = buffer.data[start .. i];
count += 1;
start = -1;
current.next = Alloc!(LineBuffer)(&arena);
current = current.next;
continue;
}
if(i == buffer.length-1)
{
linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, (buffer.length-start));
linebufs.lines[current_line][0 .. buffer.length-start] = buffer.data[start .. buffer.length];
current.text = AllocArray!(u8)(&arena, (buffer.length-start));
current.text[0 .. buffer.length-start] = buffer.data[start .. buffer.length];
current.next = Alloc!(LineBuffer)(&arena);
current = current.next;
count += 1;
}
}
if(buffer.length > 0 && buffer.data[buffer.length-1] == '\n')
{
current.text = AllocArray!(u8)(&linebufs.arena, 1);
current.text[0] = 0;
count += 1;
}
}
}
@ -178,6 +227,7 @@ GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length)
void
Move(FlatBuffer* buffer, Input key, Modifier md)
{
Logf("key: %s", key);
if(md & (MD.LeftShift | MD.RightShift))
{
switch(key)
@ -254,6 +304,11 @@ Move(FlatBuffer* buffer, Input key, Modifier md)
break;
}
if(buffer.buf_pos == buffer.length)
{
break;
}
Walk!(WalkDir.Forward)(buffer);
}
}
@ -275,11 +330,9 @@ Move(FlatBuffer* buffer, Input key, Modifier md)
if(buffer.data[buffer.buf_pos] == '\n')
{
Logf("1");
new_l += 1;
if(new_l == 2)
{
Logf("2");
Walk!(WalkDir.Forward)(buffer);
break;
}
@ -300,6 +353,11 @@ Move(FlatBuffer* buffer, Input key, Modifier md)
break;
}
if(buffer.buf_pos == buffer.length)
{
break;
}
Walk!(WalkDir.Forward)(buffer);
}
}
@ -322,10 +380,33 @@ Move(FlatBuffer* buffer, Input key, Modifier md)
}
}
Logf("%s %s", buffer.buf_pos, buffer.pos.v);
AdjustOffset(buffer);
Logf("buf_pos %s pos %s", buffer.buf_pos, buffer.pos.v);
//VerifyPosition(buffer, key, md);
}
void
AdjustOffset(FlatBuffer* buffer)
{
with(buffer)
{
i64 screen_pos = pos.y - offset;
i64 start = 1;
i64 end = rows-1;
if(offset > 0 && screen_pos < start)
{
Logf("rows %s offset %s adjusting by %s - %s", rows, offset, screen_pos, start);
offset += screen_pos - start;
}
else if(screen_pos > end)
{
Logf("rows %s offset %s adjusting by %s - %s", rows, offset, screen_pos, end);
offset += screen_pos - end;
}
}
}
u64
VecToPos(FlatBuffer* buffer, I64Vec2 vec)
{
@ -428,79 +509,9 @@ AdjustLinePos(FlatBuffer* buffer, i64 adj)
}
}
pragma(inline) i64
MoveToPrevLine(FlatBuffer* buffer)
{
i64 adj = 0;
with(buffer)
{
if(pos.y == 0)
{
adj = -pos.x;
pos.x = 0;
buf_pos = 0;
}
else
{
i64 p = buf_pos;
if(buffer.data[p] == '\n')
{
p -= 1;
}
for(; p > 0 && data[p] != '\n'; p -= 1) {}
buf_pos = p;
pos.y -= 1;
Logf("pos in line %s", PosInLine(buffer, p));
pos.x = PosInLine(buffer, p);
}
}
return adj;
}
pragma(inline) i64
MoveToNextLine(FlatBuffer* buffer)
{
i64 adj = 0;
with(buffer)
{
if(pos.y == lf_count)
{
Logf("upper");
adj = length - buf_pos;
pos.x += adj;
buf_pos += adj;
}
else
{
Logf("lower");
i64 p = buf_pos;
u8 prev = 0;
for(; p < length; p += 1)
{
if(p > 0 && data[p-1] == '\n')
{
break;
}
}
pos.x = 0;
pos.y += 1;
buf_pos = p;
}
}
return adj;
}
pragma(inline) void
Walk(alias dir)(FlatBuffer* buffer)
{
Logf("%s", buffer.pos.v);
static if(dir == WalkDir.Backward)
{
buffer.buf_pos -= 1;
@ -514,8 +525,11 @@ Walk(alias dir)(FlatBuffer* buffer)
buffer.pos.x -= 1;
}
assert(buffer.pos.y >= 0);
assert(buffer.pos.x >= 0);
if(buffer.pos.x < 0 || buffer.pos.y < 0)
{
Logf("walked %s buf_pos %s pos %s", dir, buffer.buf_pos, buffer.pos.v);
assert(pos.x >= 0 && pos.y >= 0);
}
}
else static if(dir == WalkDir.Forward)
{
@ -530,7 +544,6 @@ Walk(alias dir)(FlatBuffer* buffer)
buffer.pos.x += 1;
}
}
Logf("%s", buffer.pos.v);
}
pragma(inline) void
@ -554,8 +567,6 @@ VerifyPosition(FlatBuffer* buffer, Input input, Modifier md)
p.x += 1;
}
Logf("%s %s", p.v, pos.v);
assert(p.y <= pos.y);
}
@ -576,16 +587,25 @@ PosInLine(FlatBuffer* buffer, i64 pos)
i64 p = pos;
i64 line_pos = 0;
i64 skip_lf = buffer.data[pos] == '\n';
i64 lf_count = 0;
for(; p > 0; p -= 1, line_pos += 1)
{
if(buffer.data[p] == '\n')
{
p -= 1;
line_pos += 1;
}
for(; p > 0 && buffer.data[p] != '\n'; p -= 1, line_pos += 1)
if(skip_lf)
{
skip_lf = false;
}
else
{
break;
}
}
}
Logf("line_pos %s", line_pos);
return line_pos;
}

View File

@ -35,6 +35,7 @@ struct Editor
FlatBuffer buf;
Tokenizer tk;
LineBuffers linebufs;
i64 offset;
Vec2 cursor_pos;
Vec2 select_start;
@ -276,6 +277,11 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs)
case Input.Left:
case Input.Right:
{
UIPanel* p = GetFocusedPanel();
if(!Nil(p))
{
Move(&p.ed.buf, key, node.value.md);
}
} break;
default: break;
}

View File

@ -1131,28 +1131,43 @@ DrawLine(UIItem* item)
f32 x = item.rect.x0;
FontAtlas* atlas = &ctx.atlas_buf.atlas;
UIPanel* panel = GetFocusedPanel();
bool active = panel.id == item.parent.key.text;
bool edit_mode = EditModeActive();
Vertex* v;
if(item.highlighted_char >= 0 && active)
{
v = ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count;
AddUIIndices(ctx);
}
for(u64 i = 0; i < item.key.text.length && item.key.text[i] != '\0'; i += 1)
{
u8 ch = item.key.text.ptr[i];
if(ch < 128)
{
DrawGlyph(item, &atlas.glyphs[ch], atlas.size/ctx.text_size, &x, y, i == item.highlighted_char);
DrawGlyph(item, &atlas.glyphs[ch], atlas.size/ctx.text_size, &x, y, !edit_mode && i == item.highlighted_char);
}
}
if(item.highlighted_char >= 0)
if(v)
{
y = item.rect.y0 + 2;
x = item.rect.x0;
UIPanel* panel = GetFocusedPanel();
bool text_in_focus = panel.id == item.parent.key.text;
f32 adv = atlas.glyphs[' '].advance;
Vertex* v = ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count;
for(u64 i = 0; i < item.highlighted_char; i += 1)
{
if(item.key.text[i] == '\t')
{
x += adv*2;
}
else
{
x += adv;
}
}
v.dst_start.x = x;
v.dst_start.y = y;
@ -1160,7 +1175,7 @@ DrawLine(UIItem* item)
v.dst_end.y = y + ctx.text_size - 2;
v.cols = Vec4(1.0);
if(text_in_focus)
if(edit_mode)
{
v.dst_end.x = v.dst_start.x + 2;
}
@ -1175,7 +1190,6 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32 scale, f32* x_pos, f32 y, bool highlig
UICtx* ctx = GetCtx();
Vertex* bg_v = null, v = null;
f32 h;
bool text_in_focus = false;
if(glyph.ch == '\t')
{
@ -1203,6 +1217,11 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32 scale, f32* x_pos, f32 y, bool highlig
v.src_end.y = glyph.atlas_bottom;
}
if(highlight)
{
col = Vec4(Vec3(1.0)-col.xyz, 1.0);
}
v.cols = col;
v.texture = 1;

View File

@ -5,7 +5,7 @@ import ui : Nil;
import ui;
import editor;
import std.format : sformat;
import std.math.rounding : ceil;
import std.math.rounding : ceil, floor;
const UIPanel g_ui_nil_panel;
UIPanel* g_UI_NIL_PANEL;
@ -42,6 +42,7 @@ struct TextPart
{
UIItem* item;
TextPart* next;
u32 count;
}
UIItem*
@ -175,26 +176,38 @@ EditorView(UIPanel* panel)
{
UICtx* ctx = GetCtx();
UIItem* item = Panel(panel, UIF.Clickable);
Editor* ed = panel.ed;
bool focused = panel == GetFocusedPanel();
u64 rows = cast(u64)ceil(item.size.y/16.0);
GetLines(&panel.ed.buf, &panel.ed.linebufs, 0, rows);
for(u64 i = 0; i < panel.ed.linebufs.lines.length; i += 1)
f32 text_size = 16.0;
f32 height = 0.0;
i64 rows = cast(i64)ceil(item.size.y/text_size);
if(ed.buf.rows != rows)
{
u8[] line = panel.ed.linebufs.lines[i];
if(line.length > 0)
{
if(panel.ed.buf.pos.y == i && focused)
{
SetHighlightedChar(panel.ed.buf.pos.x);
Logf("editor height %s text_size %s rows %s", item.size.y, text_size, rows);
ed.buf.rows = rows;
}
TextPart* tp = WrappedTextLine(line, panel.id, 16.0, i);
GetLines(&ed.buf, &ed.linebufs, rows);
u64 i = 0;
for(LineBuffer* buf = ed.linebufs.first; buf != null; buf = buf.next, i += 1)
{
if(buf.text.length > 0)
{
i64 line_no = i+ed.buf.offset;
if(ed.buf.pos.y == line_no && focused)
{
SetHighlightedChar(ed.buf.pos.x);
}
TextPart* tp = WrappedTextLine(buf.text, panel.id, text_size, line_no);
height += (text_size * tp.count);
if(TextClicked(tp))
{
SetFocusedPanel(panel);
}
}
SetHighlightedChar(-1);
@ -242,6 +255,8 @@ WrappedTextLine(u8[] text, u8[] parent_id, f32 text_size, u64 line_no)
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)
{
part.count += 1;
tp.item = Get(line.value);
tp.next = ScratchAlloc!(TextPart)();
tp.next.item = g_UI_NIL;