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.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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user