start work on text input
This commit is contained in:
parent
13aedaacff
commit
d233c65304
2
src/dlib
2
src/dlib
@ -1 +1 @@
|
|||||||
Subproject commit 6757559089314da06956460c32ff632db7d10f88
|
Subproject commit ff94c5cb5e4b3c581521452a2a50b363a09cd8d6
|
||||||
@ -1,25 +1,18 @@
|
|||||||
import dlib.aliases;
|
import dlib;
|
||||||
import dlib.math;
|
|
||||||
import dlib.alloc;
|
|
||||||
import dlib.util;
|
|
||||||
import core.stdc.stdio : EOF;
|
import core.stdc.stdio : EOF;
|
||||||
import parsing;
|
import parsing;
|
||||||
import std.format : sformat;
|
import std.format : sformat;
|
||||||
|
import std.math.algebraic : abs;
|
||||||
|
|
||||||
struct FlatBuffer
|
struct FlatBuffer
|
||||||
{
|
{
|
||||||
Tokenizer tk;
|
Tokenizer tk;
|
||||||
Arena arena;
|
Arena arena;
|
||||||
|
U64Vec2 pos;
|
||||||
u8[] data;
|
u8[] data;
|
||||||
u64 length;
|
u64 length;
|
||||||
u64 line_count;
|
u64 line_count;
|
||||||
Range pos;
|
u64 buf_pos;
|
||||||
}
|
|
||||||
|
|
||||||
struct Range
|
|
||||||
{
|
|
||||||
u32 x;
|
|
||||||
u32 y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LineBuffers
|
struct LineBuffers
|
||||||
@ -31,7 +24,7 @@ struct LineBuffers
|
|||||||
FlatBuffer
|
FlatBuffer
|
||||||
CreateFlatBuffer(u8[] data)
|
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);
|
u8[] buf = MAllocArray!(u8)(capacity);
|
||||||
buf[0 .. data.length] = data[0 .. data.length];
|
buf[0 .. data.length] = data[0 .. data.length];
|
||||||
@ -70,6 +63,7 @@ CreateLineBuffers(u64 arena_size)
|
|||||||
void
|
void
|
||||||
Insert(FlatBuffer* buffer, u8[] insert, u64 length, u64 pos)
|
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)
|
if(buffer.length + length > buffer.data.length)
|
||||||
{
|
{
|
||||||
FlatBuffer new_buf = CreateFlatBuffer(buffer.data);
|
FlatBuffer new_buf = CreateFlatBuffer(buffer.data);
|
||||||
@ -99,11 +93,11 @@ Insert(FlatBuffer* buffer, u8[] insert, u64 length, u64 pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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");
|
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
|
// 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
|
void
|
||||||
RangeToPos(FlatBuffer* buffer, Range range)
|
Move(FlatBuffer* buffer, Input key, Modifier md)
|
||||||
|
{
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
u64 buffer_pos;
|
|
||||||
u32 line, col;
|
u32 line, col;
|
||||||
for(u64 i = 0; i < buffer.length; i += 1)
|
for(; i < buffer.length; pos += 1)
|
||||||
{
|
{
|
||||||
if(range.y == line)
|
if(range.y == line)
|
||||||
{
|
{
|
||||||
buffer_pos = i;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(buffer.data.ptr[i] == '\n')
|
if(buffer.data.ptr[pos] == '\n')
|
||||||
{
|
{
|
||||||
line += 1;
|
line += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(u64 i = buffer_pos; i < buffer.length; i += 1)
|
for(; buffer_pos < buffer.length; pos += 1)
|
||||||
{
|
{
|
||||||
if(col == range.x)
|
if(col == range.x)
|
||||||
{
|
{
|
||||||
buffer_pos = i;
|
|
||||||
break;
|
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");
|
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;
|
return buffer_pos;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import ui;
|
|||||||
import widgets : Nil;
|
import widgets : Nil;
|
||||||
import widgets;
|
import widgets;
|
||||||
|
|
||||||
|
import std.format;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.exception;
|
import std.exception;
|
||||||
|
|
||||||
@ -22,6 +23,8 @@ struct EditorCtx
|
|||||||
UIPanel* base_panel;
|
UIPanel* base_panel;
|
||||||
u64 panel_id;
|
u64 panel_id;
|
||||||
EditState state;
|
EditState state;
|
||||||
|
u8[128] input_buf;
|
||||||
|
u32 icount;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Editor
|
struct Editor
|
||||||
@ -108,6 +111,8 @@ CreateEditor(EditorCtx* ctx)
|
|||||||
Editor* ed = Alloc!(Editor)(&ctx.arena);
|
Editor* ed = Alloc!(Editor)(&ctx.arena);
|
||||||
|
|
||||||
ed.arena = CreateArena(MB(4));
|
ed.arena = CreateArena(MB(4));
|
||||||
|
ed.buf = CreateFlatBuffer([]);
|
||||||
|
ed.linebufs = CreateLineBuffers(MB(1));
|
||||||
|
|
||||||
return ed;
|
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
|
void
|
||||||
HandleInputs(EditorCtx* ctx, Inputs* inputs)
|
HandleInputs(EditorCtx* ctx, Inputs* inputs)
|
||||||
{
|
{
|
||||||
@ -201,120 +220,117 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs)
|
|||||||
bool pressed = node.value.pressed;
|
bool pressed = node.value.pressed;
|
||||||
|
|
||||||
if (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)
|
switch(key)
|
||||||
{
|
{
|
||||||
case Input.i:
|
case Input.i:
|
||||||
{
|
|
||||||
if(ctx.state == ES.NormalMode)
|
|
||||||
{
|
{
|
||||||
ctx.state = ES.InputMode;
|
ctx.state = ES.InputMode;
|
||||||
taken = true;
|
taken = true;
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case Input.Esc:
|
|
||||||
{
|
|
||||||
if(ctx.state == ES.InputMode || ctx.state == ES.CmdOpen)
|
|
||||||
{
|
|
||||||
ctx.state = ES.NormalMode;
|
|
||||||
taken = true;
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
case Input.Semicolon:
|
case Input.Semicolon:
|
||||||
{
|
{
|
||||||
if(node.value.md & (MD.LeftShift | MD.RightShift))
|
if(node.value.md & (MD.LeftShift | MD.RightShift))
|
||||||
{
|
|
||||||
if(ctx.state != ES.NormalMode)
|
|
||||||
{
|
{
|
||||||
ctx.state = ES.CmdOpen;
|
ctx.state = ES.CmdOpen;
|
||||||
taken = true;
|
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;
|
} break;
|
||||||
case Input.v:
|
case Input.v:
|
||||||
{
|
|
||||||
if(ctx.state == ES.NormalMode)
|
|
||||||
{
|
{
|
||||||
AddEditor(ctx, GetFocusedPanel(), A2D.X);
|
AddEditor(ctx, GetFocusedPanel(), A2D.X);
|
||||||
}
|
taken = true;
|
||||||
} break;
|
} break;
|
||||||
case Input.c:
|
case Input.c:
|
||||||
{
|
|
||||||
if(ctx.state == ES.NormalMode)
|
|
||||||
{
|
{
|
||||||
AddEditor(ctx, GetFocusedPanel(), A2D.Y);
|
AddEditor(ctx, GetFocusedPanel(), A2D.Y);
|
||||||
}
|
taken = true;
|
||||||
} break;
|
} break;
|
||||||
case Input.d:
|
case Input.d:
|
||||||
{
|
{
|
||||||
if(node.value.md & (MD.LeftShift | MD.RightShift))
|
|
||||||
{
|
|
||||||
static dbg = false;
|
|
||||||
dbg = !dbg;
|
|
||||||
SetDebug(dbg);
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
case Input.Up:
|
case Input.Up:
|
||||||
case Input.Down:
|
case Input.Down:
|
||||||
case Input.Left:
|
case Input.Left:
|
||||||
case Input.Right:
|
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;
|
} break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(taken)
|
if(taken)
|
||||||
{
|
{
|
||||||
DLLRemove(&inputs.list, node, null);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -149,6 +149,8 @@ const const(u8[])[]['z'-95] D_KEYWORDS = [
|
|||||||
void
|
void
|
||||||
Tokenize(FlatBuffer* fb)
|
Tokenize(FlatBuffer* fb)
|
||||||
{
|
{
|
||||||
|
if(fb.data.length == 0) return;
|
||||||
|
|
||||||
Tokenizer* tk = &fb.tk;
|
Tokenizer* tk = &fb.tk;
|
||||||
|
|
||||||
u64 semi_count;
|
u64 semi_count;
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import ui : Nil;
|
|||||||
import ui;
|
import ui;
|
||||||
import editor;
|
import editor;
|
||||||
import std.format : sformat;
|
import std.format : sformat;
|
||||||
|
import std.math.rounding : ceil;
|
||||||
|
|
||||||
const UIPanel g_ui_nil_panel;
|
const UIPanel g_ui_nil_panel;
|
||||||
UIPanel* g_UI_NIL_PANEL;
|
UIPanel* g_UI_NIL_PANEL;
|
||||||
@ -175,14 +176,20 @@ EditorView(UIPanel* panel)
|
|||||||
UICtx* ctx = GetCtx();
|
UICtx* ctx = GetCtx();
|
||||||
UIItem* item = Panel(panel, UIF.Clickable);
|
UIItem* item = Panel(panel, UIF.Clickable);
|
||||||
|
|
||||||
TextPart* tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 16.0, 0);
|
u64 rows = cast(u64)ceil(item.size.y/16.0);
|
||||||
if(TextClicked(tp)) SetFocusedPanel(panel);
|
GetLines(&panel.ed.buf, &panel.ed.linebufs, 0, rows);
|
||||||
tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 16.0, 1);
|
for(u64 i = 0; i < panel.ed.linebufs.lines.length; i += 1)
|
||||||
if(TextClicked(tp)) SetFocusedPanel(panel);
|
{
|
||||||
tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 16.0, 2);
|
u8[] line = panel.ed.linebufs.lines[i];
|
||||||
if(TextClicked(tp)) SetFocusedPanel(panel);
|
if(line.length > 0)
|
||||||
tp = WrappedTextLine(CastStr!(u8)("Test 1234"), panel.id, 16.0, 3);
|
{
|
||||||
if(TextClicked(tp)) SetFocusedPanel(panel);
|
TextPart* tp = WrappedTextLine(line, panel.id, 16.0, i);
|
||||||
|
if(TextClicked(tp))
|
||||||
|
{
|
||||||
|
SetFocusedPanel(panel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Signal(item);
|
Signal(item);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user