start work on text input

This commit is contained in:
Matthew 2025-09-17 06:28:01 +10:00
parent 13aedaacff
commit d233c65304
5 changed files with 266 additions and 134 deletions

@ -1 +1 @@
Subproject commit 6757559089314da06956460c32ff632db7d10f88
Subproject commit ff94c5cb5e4b3c581521452a2a50b363a09cd8d6

View File

@ -1,25 +1,18 @@
import dlib.aliases;
import dlib.math;
import dlib.alloc;
import dlib.util;
import dlib;
import core.stdc.stdio : EOF;
import parsing;
import std.format : sformat;
import std.math.algebraic : abs;
struct FlatBuffer
{
Tokenizer tk;
Arena arena;
U64Vec2 pos;
u8[] data;
u64 length;
u64 line_count;
Range pos;
}
struct Range
{
u32 x;
u32 y;
u64 buf_pos;
}
struct LineBuffers
@ -31,7 +24,7 @@ struct LineBuffers
FlatBuffer
CreateFlatBuffer(u8[] data)
{
u64 capacity = RoundUp(cast(u64)(data.length) * 2, KB(4));
u64 capacity = data.length > 0 ? RoundUp(cast(u64)(data.length) * 2, KB(4)) : KB(4);
u8[] buf = MAllocArray!(u8)(capacity);
buf[0 .. data.length] = data[0 .. data.length];
@ -70,6 +63,7 @@ CreateLineBuffers(u64 arena_size)
void
Insert(FlatBuffer* buffer, u8[] insert, u64 length, u64 pos)
{
Logf("%s %s %s", buffer.length, length, buffer.data.length);
if(buffer.length + length > buffer.data.length)
{
FlatBuffer new_buf = CreateFlatBuffer(buffer.data);
@ -99,11 +93,11 @@ Insert(FlatBuffer* buffer, u8[] insert, u64 length, u64 pos)
}
void
Insert(FlatBuffer* buffer, u8[] insert, u64 length, Range pos)
Insert(FlatBuffer* buffer, u8[] insert, u64 length, UVec2 pos)
{
assert(pos.y <= buffer.line_count, "Insert failure: y provided is greater than line_count");
Insert(buffer, insert, length, RangeToPos(buffer, pos));
Insert(buffer, insert, length, VecToPos(buffer, pos));
}
// TODO: handle case for when lines are longer than line buffer
@ -164,30 +158,131 @@ GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length)
}
}
u64
RangeToPos(FlatBuffer* buffer, Range range)
void
Move(FlatBuffer* buffer, Input key, Modifier md)
{
u64 buffer_pos;
if(md & (MD.LeftShift | MD.RightShift))
{
switch(key)
{
case Input.Up:
{
} break;
case Input.Down:
{
} break;
case Input.Left:
{
} break;
case Input.Right:
{
} break;
default: break;
}
}
else if(md & (MD.LeftCtrl | MD.RightCtrl))
{
switch(key)
{
case Input.Up:
{
} break;
case Input.Down:
{
} break;
case Input.Left:
{
} break;
case Input.Right:
{
} break;
default: break;
}
}
else
{
switch(key)
{
case Input.Down:
case Input.Up:
{
if((Input.Up && buffer.pos.y > 0) || (Input.Down && buffer.pos.y < buffer.line_count))
{
u32 x = buffer.pos.x;
buffer.pos.x = 0;
buffer.pos.y += key == Input.Down ? 1 : -1;
u64 pos = VecToPos(buffer, buffer.pos);
u64 i = pos;
for(; i < pos+x && buffer.data[i] != '\n'; i += 1) {}
buffer.pos.x = cast(u32)(i - pos);
buffer.buf_pos = i;
}
} break;
case Input.Left:
case Input.Right:
{
if((Input.Left && buffer.buf_pos > 0) || (Input.Right && buffer.buf_pos < buffer.length))
{
u64 move = key == Input.Left ? -1 : +1;
buffer.buf_pos += move;
if(buffer.data[buffer.buf_pos] == '\n')
{
u64 x = buffer.pos.x;
buffer.pos.y += move;
buffer.pos.x = 0;
if(key == Input.Left)
{
u64 pos = VecToPos(buffer, buffer.pos);
u64 i = pos;
for(; i < pos+x && buffer.data[i] != '\n'; i += 1) {}
buffer.pos.x = cast(u32)(i - pos);
buffer.buf_pos = i;
}
}
else
{
buffer.pos.x += move;
}
}
} break;
default: break;
}
}
Logf("%s %s", buffer.buf_pos, buffer.pos.v);
}
u64
RelVecToPos(FlatBuffer* buffer, U64Vec2 vec)
{
u64 pos = 0;
bool closer_to_start = abs(buffer.pos.y - vec.x) > vec.x;
if(closer_to_start)
{
u32 line, col;
for(u64 i = 0; i < buffer.length; i += 1)
for(; i < buffer.length; pos += 1)
{
if(range.y == line)
{
buffer_pos = i;
break;
}
if(buffer.data.ptr[i] == '\n')
if(buffer.data.ptr[pos] == '\n')
{
line += 1;
}
}
for(u64 i = buffer_pos; i < buffer.length; i += 1)
for(; buffer_pos < buffer.length; pos += 1)
{
if(col == range.x)
{
buffer_pos = i;
break;
}
@ -195,6 +290,18 @@ RangeToPos(FlatBuffer* buffer, Range range)
assert(buffer.data.ptr[i] != '\n', "Insert FlatBuffer Range failure: x position not in range of line");
}
}
else
{
u64 move = buffer.pos.y < vec.y || (buffer.pos.y == vec.y && buffer.pos.x < vec.pos.x) ? -1 : +1;
}
return pos;
}
u64
VecToPos(FlatBuffer* buffer, U64Vec2 vec)
{
return buffer_pos;
}

View File

@ -11,6 +11,7 @@ import ui;
import widgets : Nil;
import widgets;
import std.format;
import std.stdio;
import std.exception;
@ -22,6 +23,8 @@ struct EditorCtx
UIPanel* base_panel;
u64 panel_id;
EditState state;
u8[128] input_buf;
u32 icount;
}
struct Editor
@ -108,6 +111,8 @@ CreateEditor(EditorCtx* ctx)
Editor* ed = Alloc!(Editor)(&ctx.arena);
ed.arena = CreateArena(MB(4));
ed.buf = CreateFlatBuffer([]);
ed.linebufs = CreateLineBuffers(MB(1));
return ed;
}
@ -190,6 +195,20 @@ AddEditor(EditorCtx* ctx, UIPanel* target, Axis2D axis)
}
}
pragma(inline) void
InsertInputToBuf(EditorCtx* ctx)
{
if(ctx.icount > 0)
{
UIPanel* p = GetFocusedPanel();
if(!Nil(p))
{
Insert(&p.ed.buf, ctx.input_buf, ctx.icount, 0);
ctx.icount = 0;
}
}
}
void
HandleInputs(EditorCtx* ctx, Inputs* inputs)
{
@ -201,120 +220,117 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs)
bool pressed = node.value.pressed;
if (pressed)
{
if(key == Input.Escape)
{
ctx.state = ES.NormalMode;
InsertInputToBuf(ctx);
taken = true;
}
else if(ctx.state == ES.InputMode)
{
taken = HandleInputMode(ctx, node.value);
}
else
{
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);
}
taken = true;
} break;
case Input.c:
{
if(ctx.state == ES.NormalMode)
{
AddEditor(ctx, GetFocusedPanel(), A2D.Y);
}
taken = true;
} break;
case Input.d:
{
if(node.value.md & (MD.LeftShift | MD.RightShift))
{
static dbg = false;
dbg = !dbg;
SetDebug(dbg);
}
} 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);
}
}
InsertInputToBuf(ctx);
}
pragma(inline) void
InsertChar(EditorCtx* ctx, Input input, bool modified)
{
ctx.input_buf[ctx.icount++] = InputToChar(input, modified);
}
static string
CharCases()
{
import std.traits;
string result = "";
foreach(input; EnumMembers!Input)
{
u8 ch = InputToChar(input);
if(ch > 0)
{
result ~= format("case Input.%s: InsertChar(ctx, Input.%s, cast(bool)(ev.md & (MD.LeftShift | MD.RightShift))); taken = true; break;\n", input, input);
}
}
return result;
}
bool
HandleInputMode(EditorCtx* ctx, InputEvent ev)
{
bool taken = false;
switch(ev.key)
{
mixin(CharCases());
case Input.Escape:
{
ctx.state = ES.NormalMode;
} break;
case Input.Up:
case Input.Down:
case Input.Left:
case Input.Right:
{
UIPanel* p = GetFocusedPanel();
if(!Nil(p))
{
Move(&p.ed.buf, ev.key, ev.md);
}
} break;
default: break;
}
return taken;
}
/*

View File

@ -149,6 +149,8 @@ const const(u8[])[]['z'-95] D_KEYWORDS = [
void
Tokenize(FlatBuffer* fb)
{
if(fb.data.length == 0) return;
Tokenizer* tk = &fb.tk;
u64 semi_count;

View File

@ -5,6 +5,7 @@ import ui : Nil;
import ui;
import editor;
import std.format : sformat;
import std.math.rounding : ceil;
const UIPanel g_ui_nil_panel;
UIPanel* g_UI_NIL_PANEL;
@ -175,14 +176,20 @@ EditorView(UIPanel* panel)
UICtx* ctx = GetCtx();
UIItem* item = Panel(panel, UIF.Clickable);
TextPart* tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 16.0, 0);
if(TextClicked(tp)) SetFocusedPanel(panel);
tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 16.0, 1);
if(TextClicked(tp)) SetFocusedPanel(panel);
tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 16.0, 2);
if(TextClicked(tp)) SetFocusedPanel(panel);
tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 16.0, 3);
if(TextClicked(tp)) SetFocusedPanel(panel);
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)
{
u8[] line = panel.ed.linebufs.lines[i];
if(line.length > 0)
{
TextPart* tp = WrappedTextLine(line, panel.id, 16.0, i);
if(TextClicked(tp))
{
SetFocusedPanel(panel);
}
}
}
Signal(item);