clean up, editor position/offset/etc within a buffer now tracked per editor per buffer
This commit is contained in:
parent
117b5eb51e
commit
5261118dd0
2
dub.json
2
dub.json
@ -16,7 +16,7 @@
|
||||
"versions": ["VULKAN_DEBUG", "ENABLE_RENDERER", "DLIB"],
|
||||
"preGenerateCommands-linux": ["./build.sh"],
|
||||
"preGenerateCommands-windows": [],
|
||||
"dflags": ["-P-I/usr/include/freetype2", "-Jbuild", "-Jassets", "-P-DBUILD_VULKAN"],
|
||||
"dflags": ["-P-I/usr/include/freetype2", "-Jbuild", "-Jassets", "-P-DBUILD_VULKAN", "-verrors=100"],
|
||||
"dflags-ldc2": ["-link-debuglib", "--Xcc=-DBUILD_VULKAN"],
|
||||
"dflags-dmd": ["-Xcc=-DBUILD_VULKAN"]
|
||||
},
|
||||
|
||||
2
src/dlib
2
src/dlib
@ -1 +1 @@
|
||||
Subproject commit 53eb211a1e227d1cf3d8036a0e8ecfb79f514eed
|
||||
Subproject commit f3d1f551ccfa37de73d626479252bada0fc17cb2
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,6 @@
|
||||
import dlib;
|
||||
import dlib.util : Str;
|
||||
import dlib.util : Str;
|
||||
import dlib.alloc : Reset;
|
||||
|
||||
import vulkan;
|
||||
import std.format : sformat;
|
||||
@ -16,8 +17,12 @@ import std.file;
|
||||
import std.string;
|
||||
import core.stdc.stdio;
|
||||
|
||||
const u64 ARRAY_COUNT_INCREMENT = 32;
|
||||
|
||||
f32 g_delta = 0.0;
|
||||
|
||||
alias UIHashTable = HashTable!(UIHash, UIItem*);
|
||||
|
||||
struct RenderCtx
|
||||
{
|
||||
PlatformWindow* window;
|
||||
@ -25,7 +30,6 @@ struct RenderCtx
|
||||
Descriptor default_tex;
|
||||
Descriptor sampler;
|
||||
Pipeline pipeline;
|
||||
Pipeline slug_pipeline;
|
||||
DescSetLayout desc_set_layout;
|
||||
DescSet[FO] desc_sets;
|
||||
PipelineLayout pipeline_layout;
|
||||
@ -34,70 +38,73 @@ struct RenderCtx
|
||||
|
||||
struct Ctx
|
||||
{
|
||||
RenderCtx rd_ctx;
|
||||
RenderCtx rd_ctx;
|
||||
|
||||
HashTable!(UIHash, UIItem*) items;
|
||||
UIItem* free_items;
|
||||
UIItem* last_item;
|
||||
UIHashTable items;
|
||||
UIItem* free_items;
|
||||
UIItem* last_item;
|
||||
|
||||
Arena arena;
|
||||
Arena temp_arena;
|
||||
Arena[FO] str_arenas;
|
||||
Arena arena;
|
||||
Arena temp_arena;
|
||||
Arena[FO] str_arenas;
|
||||
|
||||
Inputs* inputs;
|
||||
u64 frame;
|
||||
u64 f_idx;
|
||||
Inputs* inputs;
|
||||
u64 frame;
|
||||
u64 frame_index;
|
||||
|
||||
Notification* active_notifications;
|
||||
Notification* free_notifications;
|
||||
Notification* active_notifications;
|
||||
Notification* free_notifications;
|
||||
|
||||
LinkedList!(UIInput) events;
|
||||
IVec2 mouse_pos;
|
||||
LinkedList!(UIInput) events;
|
||||
IVec2 mouse_pos;
|
||||
|
||||
SlugFont slug_font;
|
||||
FontFace font;
|
||||
FontSet[FS] font_sets;
|
||||
u32 font_sets_used;
|
||||
bool[FO] fonts_to_load;
|
||||
bool prev_has_tex;
|
||||
u32 prev_atlas_index;
|
||||
FontFace font;
|
||||
FontSet[FS] font_sets;
|
||||
u32 font_sets_used;
|
||||
bool[FO] fonts_to_load;
|
||||
bool prev_has_tex;
|
||||
u32 prev_atlas_index;
|
||||
|
||||
UIBuffer[FO] buffers;
|
||||
|
||||
SlugBuffer[FO] slug_buffers;
|
||||
MappedBuffer!(SlugVertex)[FO] slug_vertex_buffers;
|
||||
MappedBuffer!(u32)[FO] slug_index_buffers;
|
||||
UIBuffer[FO] buffers;
|
||||
|
||||
u32 tab_width;
|
||||
Vec4[TS.max][UISH.max] syntax_colors;
|
||||
u32 tab_width;
|
||||
Vec4[TS.max][UISH.max] syntax_colors;
|
||||
|
||||
UIKey drag_key;
|
||||
UIKey hover_key;
|
||||
UIKey focus_key;
|
||||
UIKey drag_key;
|
||||
UIKey hover_key;
|
||||
UIKey focus_key;
|
||||
|
||||
UIPanel* base_panel;
|
||||
UIPanel* focused_panel;
|
||||
UIPanel* free_panels;
|
||||
UIPanel* base_panel;
|
||||
UIPanel* focused_panel;
|
||||
UIPanel* free_panels;
|
||||
|
||||
u64 last_hover_frame;
|
||||
u64 last_hover_frame;
|
||||
|
||||
f32 pos_rate;
|
||||
f32 scroll_rate;
|
||||
f32 animation_rate;
|
||||
f32 fade_rate;
|
||||
f32 pos_rate;
|
||||
f32 scroll_rate;
|
||||
f32 animation_rate;
|
||||
f32 fade_rate;
|
||||
|
||||
ConfigValue[CO.max] config_values;
|
||||
ConfigValue[CO.max] config_values;
|
||||
|
||||
EditState state;
|
||||
u8[128] input_buf;
|
||||
u32 icount;
|
||||
u64 editor_id_incr;
|
||||
Timer timer;
|
||||
CmdPalette cmd;
|
||||
string[] file_names;
|
||||
u64 panel_id;
|
||||
EditState state;
|
||||
u8[128] input_buf;
|
||||
u32 icount;
|
||||
u64 editor_id_incr;
|
||||
Timer timer;
|
||||
CmdPalette cmd;
|
||||
string[] file_names;
|
||||
u64 panel_id;
|
||||
Editor[] editors;
|
||||
u64 editor_count;
|
||||
Editor* free_editors;
|
||||
FlatBuffer[] text_buffers;
|
||||
u64 text_buffer_count;
|
||||
FlatBuffer* free_text_buffers;
|
||||
|
||||
debug bool dbg;
|
||||
@property ref DescSet desc_set() => this.rd_ctx.desc_sets[this.frame_index];
|
||||
|
||||
debug bool dbg;
|
||||
|
||||
alias rd_ctx this;
|
||||
}
|
||||
@ -131,21 +138,17 @@ struct CmdPalette
|
||||
|
||||
struct Editor
|
||||
{
|
||||
Arena arena;
|
||||
u64 editor_id;
|
||||
|
||||
FlatBuffer buf;
|
||||
Tokenizer tk;
|
||||
alias BufferViewTable = HashTable!(string, BufferViewInfo);
|
||||
|
||||
I64Vec2 cursor_pos;
|
||||
Vec2 select_start;
|
||||
Vec2 select_end;
|
||||
i64 line_offset;
|
||||
i64 line_height;
|
||||
BufferViewInfo view_info_default;
|
||||
FlatBuffer* buffer;
|
||||
Editor* list_next;
|
||||
BufferViewInfo* view_info;
|
||||
u64 editor_id;
|
||||
i64 line_height;
|
||||
BufferViewTable view_info_table;
|
||||
|
||||
Editor* free_next;
|
||||
|
||||
alias buf this;
|
||||
alias buffer this;
|
||||
}
|
||||
|
||||
struct ChangeStacks
|
||||
@ -165,7 +168,7 @@ struct EditorChange
|
||||
EditorChange* next;
|
||||
}
|
||||
|
||||
alias CmdFn = bool function(Ctx* ctx); // return true when completed
|
||||
alias CmdFn = bool function(ref Ctx ctx); // return true when completed
|
||||
|
||||
struct Command
|
||||
{
|
||||
@ -235,17 +238,19 @@ enum EditState
|
||||
SetPanelFocus, // if moving left/right move up parent tree until one is found with a2d.x, same thing for up/down a2d.y
|
||||
} alias ES = EditState;
|
||||
|
||||
__gshared Ctx g_ctx;
|
||||
__gshared const Editor g_nil_ed;
|
||||
__gshared Editor* g_NIL_ED;
|
||||
__gshared const UIItem g_ui_nil_item;
|
||||
__gshared UIItem* g_UI_NIL;
|
||||
__gshared const UIInput g_ui_nil_input;
|
||||
__gshared UIInput* g_UI_NIL_INPUT;
|
||||
__gshared const UIPanel g_nil_panel;
|
||||
__gshared UIPanel* g_NIL_PANEL;
|
||||
__gshared const Notification g_nil_notif;
|
||||
__gshared Notification* g_NIL_NOTIF;
|
||||
__gshared Ctx g_ctx;
|
||||
|
||||
__gshared Editor g_nil_ed;
|
||||
__gshared UIItem g_ui_nil_item;
|
||||
__gshared UIInput g_ui_nil_input;
|
||||
__gshared UIPanel g_nil_panel;
|
||||
__gshared Notification g_nil_notif;
|
||||
|
||||
__gshared Editor* g_NIL_ED = &g_nil_ed;
|
||||
__gshared UIItem* g_UI_NIL_ITEM = &g_ui_nil_item;
|
||||
__gshared UIInput* g_UI_NIL_INPUT = &g_ui_nil_input;
|
||||
__gshared UIPanel* g_NIL_PANEL = &g_nil_panel;
|
||||
__gshared Notification* g_NIL_NOTIF = &g_nil_notif;
|
||||
|
||||
const Command NO_CMD = {
|
||||
name: [],
|
||||
@ -402,10 +407,24 @@ Command[21] CMD_LIST = [
|
||||
},
|
||||
];
|
||||
|
||||
ref Ctx GetCtx() => g_ctx;
|
||||
|
||||
bool
|
||||
ClosePanelCmd(Ctx* ctx)
|
||||
ClosePanelCmd(ref Ctx ctx)
|
||||
{
|
||||
Clear(ctx.focused_panel.ed);
|
||||
Editor* editor = ctx.focused_panel.ed;
|
||||
ctx.focused_panel.ed = null;
|
||||
if(editor.file_name.length == 0 && editor.length == 0)
|
||||
{
|
||||
editor.buffer.list_next = ctx.free_text_buffers;
|
||||
ctx.free_text_buffers = editor.buffer;
|
||||
}
|
||||
|
||||
FreeHashTable(editor.view_info_table);
|
||||
memset(editor, 0, Editor.sizeof);
|
||||
editor.list_next = ctx.free_editors;
|
||||
ctx.free_editors = editor;
|
||||
|
||||
if(ctx.focused_panel != ctx.base_panel)
|
||||
{
|
||||
DLLRemove(ctx.focused_panel.parent, ctx.focused_panel, g_NIL_PANEL);
|
||||
@ -456,38 +475,27 @@ ClosePanelCmd(Ctx* ctx)
|
||||
}
|
||||
|
||||
bool
|
||||
SplitVertically(Ctx* ctx)
|
||||
SplitVertically(ref Ctx ctx)
|
||||
{
|
||||
AddPanel(ctx.focused_panel, A2D.X);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SplitHorizontally(Ctx* ctx)
|
||||
SplitHorizontally(ref Ctx ctx)
|
||||
{
|
||||
AddPanel(ctx.focused_panel, A2D.Y);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NotImplementedCallback(Ctx* ctx)
|
||||
NotImplementedCallback(ref Ctx ctx)
|
||||
{
|
||||
Logf("Not yet implemented!");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CmdModeActive()
|
||||
{
|
||||
return g_ctx.state == ES.CmdPalette;
|
||||
}
|
||||
|
||||
bool
|
||||
Active(EditState state)
|
||||
{
|
||||
return g_ctx.state == state;
|
||||
}
|
||||
bool Active(EditState state) => g_ctx.state == state;
|
||||
|
||||
UIPanel*
|
||||
MakePanel(UIPanel* parent = g_NIL_PANEL)
|
||||
@ -511,7 +519,7 @@ Cycle(Inputs* inputs)
|
||||
|
||||
BeginUI(inputs);
|
||||
|
||||
Ctx* ctx = GetCtx();
|
||||
ref Ctx ctx = GetCtx();
|
||||
|
||||
Panel(ctx, ctx.base_panel);
|
||||
|
||||
@ -538,12 +546,7 @@ Focus(UIPanel* panel)
|
||||
void
|
||||
InitCtx(PlatformWindow* window)
|
||||
{
|
||||
Ctx* ctx = &g_ctx;
|
||||
|
||||
g_NIL_ED = cast(Editor*)&g_nil_ed;
|
||||
g_UI_NIL = cast(UIItem*)&g_ui_nil_item;
|
||||
g_UI_NIL_INPUT = cast(UIInput*)&g_ui_nil_input;
|
||||
g_NIL_PANEL = cast(UIPanel*)&g_nil_panel;
|
||||
ref Ctx ctx = GetCtx();
|
||||
|
||||
ctx.window = window;
|
||||
ctx.arena = CreateArena(MB(2));
|
||||
@ -552,6 +555,8 @@ InitCtx(PlatformWindow* window)
|
||||
ctx.cmd.exec_cmd_arena = CreateArena(MB(1));
|
||||
ctx.timer = CreateTimer();
|
||||
ctx.free_panels = g_NIL_PANEL;
|
||||
ctx.text_buffers = Alloc!(FlatBuffer)(ARRAY_COUNT_INCREMENT);
|
||||
ctx.editors = Alloc!(Editor)(ARRAY_COUNT_INCREMENT);
|
||||
|
||||
InitUI(ctx);
|
||||
|
||||
@ -569,7 +574,7 @@ InitCtx(PlatformWindow* window)
|
||||
if(indexOf(e.name, ".git") != -1 || e.isDir) continue;
|
||||
|
||||
u64 start = indexOf(e.name, "./") == 0 ? 2 : 0;
|
||||
count += 1;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
ctx.file_names = Alloc!(string)(&ctx.arena, count);
|
||||
@ -579,7 +584,7 @@ InitCtx(PlatformWindow* window)
|
||||
{
|
||||
if(indexOf(e.name, ".git") != -1 || e.isDir) continue;
|
||||
|
||||
u64 start = indexOf(e.name, "./") == 0 ? 2 : 0;
|
||||
u64 start = indexOf(e.name, "./") == 0 ? 2 : 0;
|
||||
ctx.file_names[count++] = Alloc(&ctx.arena, e.name);
|
||||
}
|
||||
}
|
||||
@ -590,86 +595,36 @@ InitCtx(PlatformWindow* window)
|
||||
}
|
||||
}
|
||||
|
||||
Ctx*
|
||||
GetCtx()
|
||||
{
|
||||
return &g_ctx;
|
||||
}
|
||||
|
||||
char[]
|
||||
ToAbsolutePath(string file_name)
|
||||
{
|
||||
import core.stdc.string : strlen;
|
||||
|
||||
char[1024] name_buf = '\0';
|
||||
char[1024] wd_buf = '\0';
|
||||
version(linux)
|
||||
{
|
||||
import core.sys.posix.unistd;
|
||||
getcwd(wd_buf.ptr, wd_buf.length);
|
||||
}
|
||||
|
||||
version(Windows)
|
||||
{
|
||||
import core.sys.windows.direct;
|
||||
_getcwd(wd_buf.ptr, wd_buf.length);
|
||||
}
|
||||
|
||||
char[] wd = wd_buf[0 .. strlen(wd_buf.ptr)];
|
||||
|
||||
version(linux)
|
||||
{
|
||||
if(file_name[0] != '/')
|
||||
{
|
||||
name_buf.sformat("%s/%s", wd, cast(char[])file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
name_buf.sformat("%s", cast(char[])file_name);
|
||||
}
|
||||
}
|
||||
|
||||
version(Windows)
|
||||
{
|
||||
name_buf.sformat("%s/%s", wd, cast(char[])file_name);
|
||||
}
|
||||
|
||||
char[] path_buf = ScratchAlloc!(char)(strlen(name_buf.ptr)+1);
|
||||
path_buf[0 .. $] = name_buf[0 .. path_buf.length];
|
||||
|
||||
return path_buf;
|
||||
}
|
||||
|
||||
void
|
||||
SaveFile(Editor* ed, string file_name)
|
||||
{
|
||||
import core.stdc.stdio;
|
||||
|
||||
file_name = file_name.length == 0 ? Str(ed.buf.file_name) : file_name;
|
||||
file_name = file_name.length == 0 ? Str(ed.file_name) : file_name;
|
||||
|
||||
if(file_name.length > 0)
|
||||
{
|
||||
char[] file_path = ToAbsolutePath(file_name);
|
||||
string file_path = AbsolutePath(file_name);
|
||||
auto f = fopen(cast(char*)file_path.ptr, "wb");
|
||||
if(f != null)
|
||||
{
|
||||
u64 tab_count;
|
||||
for(u64 i = 0; i < ed.buf.length; i += 1)
|
||||
for(u64 i = 0; i < ed.length; i += 1)
|
||||
{
|
||||
if(ed.buf.data[i] == '\t')
|
||||
if(ed.data[i] == '\t')
|
||||
{
|
||||
tab_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
u64 tab_width = GetCtx().tab_width;
|
||||
u64 buf_size = ed.buf.length + ((tab_width-1) * tab_count);
|
||||
u64 buf_size = ed.length + ((tab_width-1) * tab_count);
|
||||
u8[] temp_buf = ScratchAlloc!(u8)(buf_size);
|
||||
|
||||
u64 buf_pos;
|
||||
for(u64 i = 0; i < ed.buf.length; i += 1)
|
||||
for(u64 i = 0; i < ed.length; i += 1)
|
||||
{
|
||||
if(ed.buf.data[i] == '\t')
|
||||
if(ed.data[i] == '\t')
|
||||
{
|
||||
for(u64 j = 0; j < tab_width; j += 1)
|
||||
{
|
||||
@ -678,7 +633,7 @@ SaveFile(Editor* ed, string file_name)
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_buf[buf_pos++] = ed.buf.data[i];
|
||||
temp_buf[buf_pos++] = ed.data[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -689,40 +644,6 @@ SaveFile(Editor* ed, string file_name)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenFile(Editor* ed, string file_name)
|
||||
{
|
||||
import core.stdc.stdio;
|
||||
import std.file;
|
||||
import std.conv;
|
||||
|
||||
if(file_name.length > 0)
|
||||
{
|
||||
char[] file_path = ToAbsolutePath(file_name);
|
||||
auto f = fopen(file_path.ptr, "rb");
|
||||
if(f != null)
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
i64 len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if(len > 0)
|
||||
{
|
||||
u8[] buf = ScratchAlloc!(u8)(len);
|
||||
fread(buf.ptr, u8.sizeof, len, f);
|
||||
Change(&ed.buf, buf, file_name);
|
||||
ed.buf.file_name = file_name;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("[Error] Unable to open file");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
Str(TextInputBuffer text_buffer)
|
||||
{
|
||||
@ -732,20 +653,48 @@ Str(TextInputBuffer text_buffer)
|
||||
Editor*
|
||||
CreateEditor()
|
||||
{
|
||||
Editor* ed = Alloc!(Editor)(&g_ctx.arena);
|
||||
ed.arena = CreateArena(MB(4));
|
||||
ed.buf = CreateFlatBuffer([], []);
|
||||
ed.editor_id = g_ctx.editor_id_incr++;
|
||||
ref Ctx ctx = GetCtx();
|
||||
|
||||
if(ctx.editor_count == ctx.editors.length)
|
||||
{
|
||||
ctx.editors = Realloc(ctx.editors, ctx.editors.length+ARRAY_COUNT_INCREMENT);
|
||||
}
|
||||
|
||||
Editor* editor = ctx.free_editors;
|
||||
if(editor)
|
||||
{
|
||||
ctx.free_editors = editor.list_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
editor = &ctx.editors[ctx.editor_count++];
|
||||
}
|
||||
|
||||
editor.view_info_table = CreateHashTable!(string, BufferViewInfo)(4);
|
||||
ResetViewInfo(&editor.view_info_default);
|
||||
editor.view_info = &editor.view_info_default;
|
||||
|
||||
editor.buffer = ctx.free_text_buffers;
|
||||
if(editor.buffer)
|
||||
{
|
||||
ctx.free_text_buffers = editor.buffer.list_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
editor.buffer = CreateFlatBuffer(ctx);
|
||||
}
|
||||
|
||||
editor.editor_id = g_ctx.editor_id_incr++;
|
||||
|
||||
return ed;
|
||||
return editor;
|
||||
}
|
||||
|
||||
pragma(inline) void
|
||||
InsertInputToBuf(Ctx* ctx, Editor* ed)
|
||||
InsertInputToBuf(ref Ctx ctx, Editor* ed)
|
||||
{
|
||||
if(ctx.icount > 0)
|
||||
{
|
||||
Insert(&ed.buf, ctx.input_buf, ctx.icount);
|
||||
Insert(ed, ctx.input_buf, ctx.icount);
|
||||
ctx.icount = 0;
|
||||
}
|
||||
}
|
||||
@ -753,12 +702,12 @@ InsertInputToBuf(Ctx* ctx, Editor* ed)
|
||||
void
|
||||
ResetCtx(Editor* ed)
|
||||
{
|
||||
InsertInputToBuf(&g_ctx, ed);
|
||||
InsertInputToBuf(GetCtx(), ed);
|
||||
ResetCtx();
|
||||
}
|
||||
|
||||
void
|
||||
ResetCmd(Ctx* ctx)
|
||||
ResetCmd(ref Ctx ctx)
|
||||
{
|
||||
ctx.cmd.text_input.length = 0;
|
||||
ctx.cmd.selected = 0;
|
||||
@ -836,9 +785,8 @@ bool
|
||||
HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focused)
|
||||
{
|
||||
Editor* ed = p.ed;
|
||||
Ctx* ctx = &g_ctx;
|
||||
FlatBuffer* fb = &ed.buf;
|
||||
u64 initial_len = p.ed.buf.length;
|
||||
ref Ctx ctx = GetCtx();
|
||||
u64 initial_len = p.ed.length;
|
||||
u8[] cb_text;
|
||||
|
||||
for(auto node = inputs.first; node != null; node = node.next)
|
||||
@ -896,17 +844,17 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse
|
||||
{
|
||||
case a, i:
|
||||
{
|
||||
if(key == a && Shift(md) && fb)
|
||||
if(key == a && Shift(md))
|
||||
{
|
||||
MoveToEOL(fb);
|
||||
MoveToEOL(ed);
|
||||
}
|
||||
else if(key == a)
|
||||
{
|
||||
Move(fb, Right, MD.None);
|
||||
Move(ed, Right, MD.None);
|
||||
}
|
||||
else if(key == i && Shift(md))
|
||||
{
|
||||
MoveToSOL(fb);
|
||||
MoveToSOL(ed);
|
||||
}
|
||||
|
||||
ctx.state = ES.InputMode;
|
||||
@ -916,7 +864,7 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse
|
||||
{
|
||||
if(Shift(node.md))
|
||||
{
|
||||
ctx.state = ES.CmdPalette;
|
||||
ctx.state = ES.CmdPalette;
|
||||
ResetCmd(ctx);
|
||||
|
||||
taken = true;
|
||||
@ -930,11 +878,11 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse
|
||||
}
|
||||
if(Shift(md))
|
||||
{
|
||||
ToggleSelection(fb, SM.Line);
|
||||
ToggleSelection(ed, SM.Line);
|
||||
}
|
||||
else
|
||||
{
|
||||
ToggleSelection(fb, SM.Normal);
|
||||
ToggleSelection(ed, SM.Normal);
|
||||
}
|
||||
} break;
|
||||
case c:
|
||||
@ -984,22 +932,22 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse
|
||||
|
||||
if(cb_text.length > 0)
|
||||
{
|
||||
Insert(fb, cb_text, cb_text.length);
|
||||
Insert(ed, cb_text, cb_text.length);
|
||||
}
|
||||
|
||||
return initial_len != p.ed.buf.length;
|
||||
return initial_len != p.ed.length;
|
||||
}
|
||||
|
||||
void
|
||||
SetOffset(Editor* ed, i64 adjust)
|
||||
{
|
||||
i64 max_offset = ed.buf.line_count-ed.line_height;
|
||||
i64 max_offset = ed.line_count-ed.line_height;
|
||||
if(max_offset < 0)
|
||||
{
|
||||
max_offset = 0;
|
||||
}
|
||||
|
||||
ed.line_offset = clamp(ed.line_offset+adjust, 0, max_offset);
|
||||
ed.view_info.line_offset = clamp(ed.view_info.line_offset+adjust, 0, max_offset);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1009,15 +957,15 @@ MoveCursor(Editor* ed, UIInput* ev)
|
||||
|
||||
switch(ev.key) with(Input)
|
||||
{
|
||||
case Up, Down, Left, Right: taken = Move(&ed.buf, ev.key, ev.md); break;
|
||||
case Up, Down, Left, Right: taken = Move(ed, ev.key, ev.md); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(taken)
|
||||
{
|
||||
I64Vec2 pos = VecPos(&ed.buf);
|
||||
i64 min = ed.line_offset+2;
|
||||
i64 max = clamp(ed.line_offset+ed.line_height-3, 0, ed.buf.line_count);
|
||||
I64Vec2 pos = VecPos(ed);
|
||||
i64 min = ed.view_info.line_offset+2;
|
||||
i64 max = clamp(ed.view_info.line_offset+ed.line_height-3, 0, ed.line_count);
|
||||
if(pos.y > max)
|
||||
{
|
||||
SetOffset(ed, pos.y-max);
|
||||
@ -1032,7 +980,7 @@ MoveCursor(Editor* ed, UIInput* ev)
|
||||
}
|
||||
|
||||
pragma(inline) void
|
||||
InsertChar(Ctx* ctx, Input input, bool modified)
|
||||
InsertChar(ref Ctx ctx, Input input, bool modified)
|
||||
{
|
||||
ctx.input_buf[ctx.icount++] = InputToChar(input, modified);
|
||||
}
|
||||
@ -1055,7 +1003,7 @@ CharCases()
|
||||
}
|
||||
|
||||
bool
|
||||
HandleInputMode(Ctx* ctx, UIPanel* p, UIInput* ev)
|
||||
HandleInputMode(ref Ctx ctx, UIPanel* p, UIInput* ev)
|
||||
{
|
||||
bool taken;
|
||||
|
||||
@ -1064,7 +1012,7 @@ HandleInputMode(Ctx* ctx, UIPanel* p, UIInput* ev)
|
||||
mixin(CharCases());
|
||||
case Input.Backspace:
|
||||
{
|
||||
Backspace(&p.ed.buf);
|
||||
Backspace(p.ed);
|
||||
taken = true;
|
||||
} break;
|
||||
case Input.Escape:
|
||||
@ -1168,7 +1116,7 @@ StrContains(bool begins_with)(string str, string match)
|
||||
}
|
||||
|
||||
void
|
||||
HandleCmdMode(Ctx* ctx, bool* enter_hit, bool* buffer_changed, bool* selection_changed)
|
||||
HandleCmdMode(ref Ctx ctx, bool* enter_hit, bool* buffer_changed, bool* selection_changed)
|
||||
{
|
||||
UIPanel* panel = ctx.focused_panel;
|
||||
Editor* ed = panel.ed;
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import dlib;
|
||||
|
||||
import dlib.alloc : Reset;
|
||||
|
||||
import editor;
|
||||
import buffer;
|
||||
|
||||
enum TokenStyle : u8
|
||||
@ -399,28 +402,22 @@ struct Tokenizer
|
||||
}
|
||||
|
||||
bool
|
||||
Nil(Token* tk)
|
||||
Nil(Token* token)
|
||||
{
|
||||
return tk == g_NIL_TOKEN || tk == null;
|
||||
}
|
||||
|
||||
void
|
||||
SetBuffers(Tokenizer* tk, TokenStyle[] tokens)
|
||||
{
|
||||
tk.tokens = tokens;
|
||||
return token == g_NIL_TOKEN || token == null;
|
||||
}
|
||||
|
||||
Tokenizer
|
||||
CreateTokenizer(FlatBuffer* fb)
|
||||
CreateTokenizer(FlatBuffer* buffer)
|
||||
{
|
||||
Tokenizer tk = {
|
||||
Tokenizer tokenizer = {
|
||||
arena: CreateArena(MB(4)),
|
||||
};
|
||||
|
||||
SetBuffers(&tk, Alloc!(TS)(fb.data.length));
|
||||
tokenizer.tokens = Alloc!(TS)(buffer.data.length);
|
||||
|
||||
g_NIL_TOKEN = cast(Token*)&g_nil_tk;
|
||||
tk.first = tk.last = g_NIL_TOKEN;
|
||||
tokenizer.first = tokenizer.last = g_NIL_TOKEN;
|
||||
|
||||
for(u64 i = 0; i < D_KEYWORDS.length; i += 1)
|
||||
{
|
||||
@ -438,132 +435,133 @@ CreateTokenizer(FlatBuffer* fb)
|
||||
}
|
||||
}
|
||||
|
||||
return tk;
|
||||
return tokenizer;
|
||||
}
|
||||
|
||||
void
|
||||
ResetTokenizer(Tokenizer* tk, u64 len)
|
||||
ResetTokenizer(Tokenizer* tokenizer, u64 length)
|
||||
{
|
||||
Reset(&tk.arena);
|
||||
Free(tk.tokens);
|
||||
Reset(&tokenizer.arena);
|
||||
Free(tokenizer.tokens);
|
||||
|
||||
SetBuffers(tk, Alloc!(TS)(len));
|
||||
tk.pos = 0;
|
||||
tk.first = tk.last = g_NIL_TOKEN;
|
||||
tokenizer.tokens = Alloc!(TS)(length);
|
||||
tokenizer.pos = 0;
|
||||
tokenizer.first = tokenizer.last = g_NIL_TOKEN;
|
||||
}
|
||||
|
||||
Token*
|
||||
MakeToken(Tokenizer* tk, TokenType type, u64 start, u64 end)
|
||||
MakeToken(Tokenizer* tokenizer, TokenType type, u64 length)
|
||||
{
|
||||
Token* t = Alloc!(Token)(&tk.arena);
|
||||
Token* token = Alloc!(Token)(&tokenizer.arena);
|
||||
|
||||
t.type = type;
|
||||
t.start = start;
|
||||
t.end = end;
|
||||
token.type = type;
|
||||
token.start = tokenizer.pos;
|
||||
token.end = tokenizer.pos+length;
|
||||
|
||||
DLLPush(tk, t, g_NIL_TOKEN);
|
||||
DLLPush(tokenizer, token, g_NIL_TOKEN);
|
||||
|
||||
return t;
|
||||
return token;
|
||||
}
|
||||
|
||||
u8
|
||||
Peek(FlatBuffer* fb)
|
||||
Peek(T)(T* buffer) if(is(T == Editor) || is(T == FlatBuffer))
|
||||
{
|
||||
return fb.tk.pos+1 < fb.length ? fb.data[fb.tk.pos+1] : 0;
|
||||
return buffer.tokenizer.pos+1 < buffer.length ? buffer.data[buffer.tokenizer.pos+1] : 0;
|
||||
}
|
||||
|
||||
void
|
||||
TokenizeD(FlatBuffer* fb)
|
||||
TokenizeD(T)(T* buffer)
|
||||
if(is(T == Editor) || is(T == FlatBuffer))
|
||||
{
|
||||
Tokenizer* tk = &fb.tk;
|
||||
Tokenizer* tokenizer = &buffer.tokenizer;
|
||||
|
||||
Reset(&tk.arena);
|
||||
tk.pos = 0;
|
||||
tk.first = tk.last = g_NIL_TOKEN;
|
||||
Reset(&tokenizer.arena);
|
||||
tokenizer.pos = 0;
|
||||
tokenizer.first = tokenizer.last = g_NIL_TOKEN;
|
||||
|
||||
for(; tk.pos < fb.length;)
|
||||
for(; tokenizer.pos < buffer.length;)
|
||||
{
|
||||
u8 ch = fb.data[tk.pos];
|
||||
u8 ch = buffer.data[tokenizer.pos];
|
||||
bool alpha = (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
|
||||
|
||||
if(ch == ' ' || ch == '\t')
|
||||
{
|
||||
Token* t = MakeToken(tk, TT.Whitespace, tk.pos, tk.pos+1);
|
||||
Token* token = MakeToken(tokenizer, TT.Whitespace, 1);
|
||||
|
||||
for(tk.pos += 1; tk.pos < fb.length; tk.pos += 1)
|
||||
for(tokenizer.pos += 1; tokenizer.pos < buffer.length; tokenizer.pos += 1)
|
||||
{
|
||||
if(fb.data[tk.pos] != ' ' && fb.data[tk.pos] != '\t')
|
||||
if(buffer.data[tokenizer.pos] != ' ' && buffer.data[tokenizer.pos] != '\t')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
t.end = tk.pos;
|
||||
token.end = tokenizer.pos;
|
||||
}
|
||||
else if(ch == '\n')
|
||||
{
|
||||
Token* t = MakeToken(tk, TT.NewLine, tk.pos, tk.pos+1);
|
||||
tk.pos += 1;
|
||||
Token* token = MakeToken(tokenizer, TT.NewLine, 1);
|
||||
tokenizer.pos += 1;
|
||||
}
|
||||
else if(ch == 'r')
|
||||
{
|
||||
u8 next = Peek(fb);
|
||||
u8 next = Peek(buffer);
|
||||
if(next == '"')
|
||||
{
|
||||
tk.pos += 1;
|
||||
ParseStr!('"')(fb);
|
||||
tokenizer.pos += 1;
|
||||
ParseStr!('"')(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseId(fb);
|
||||
ParseId(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
else if(ch >= '0' && ch <= '9')
|
||||
{
|
||||
ParseNum(fb);
|
||||
ParseNum(buffer);
|
||||
}
|
||||
|
||||
else if(ch == 'P' || ch == 'E' || ch == 'e' || ch == 'p')
|
||||
{
|
||||
u8 next = Peek(fb);
|
||||
u8 next = Peek(buffer);
|
||||
if(next == '-' || next == '+' || (next >= '0' && next <= '9'))
|
||||
{
|
||||
ParseNum(fb);
|
||||
ParseNum(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseId(fb);
|
||||
ParseId(buffer);
|
||||
}
|
||||
}
|
||||
else if(alpha || ch == '_')
|
||||
{
|
||||
ParseId(fb);
|
||||
ParseId(buffer);
|
||||
}
|
||||
else if(ch < 128 && D_STD_TOKEN[ch] != TT.None)
|
||||
{
|
||||
Token* t = MakeToken(tk, D_STD_TOKEN[ch], tk.pos, tk.pos+1);
|
||||
tk.pos += 1;
|
||||
Token* token = MakeToken(tokenizer, D_STD_TOKEN[ch], 1);
|
||||
tokenizer.pos += 1;
|
||||
}
|
||||
else if(ch < 128 && D_OP_TOKEN[ch] != TT.None)
|
||||
{
|
||||
Token* t = MakeToken(tk, D_OP_TOKEN[ch], tk.pos, tk.pos+1);
|
||||
tk.pos += 1;
|
||||
FixOpAssign(fb, t);
|
||||
Token* token = MakeToken(tokenizer, D_OP_TOKEN[ch], 1);
|
||||
tokenizer.pos += 1;
|
||||
FixOpAssign(buffer, token);
|
||||
}
|
||||
else if(ch < 128 && D_STR_TOKEN[ch] != TT.None)
|
||||
{
|
||||
if(ch == '"')
|
||||
{
|
||||
ParseStr!('"')(fb);
|
||||
ParseStr!('"')(buffer);
|
||||
}
|
||||
else if(ch == '`')
|
||||
{
|
||||
ParseStr!('`')(fb);
|
||||
ParseStr!('`')(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseStr!('\'')(fb);
|
||||
ParseStr!('\'')(buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -572,108 +570,108 @@ TokenizeD(FlatBuffer* fb)
|
||||
{
|
||||
case '@':
|
||||
{
|
||||
Token* t = MakeToken(tk, TT.At, tk.pos, tk.pos+1);
|
||||
tk.pos += 1;
|
||||
Token* token = MakeToken(tokenizer, TT.At, 1);
|
||||
tokenizer.pos += 1;
|
||||
|
||||
for(; tk.pos < fb.length; tk.pos += 1)
|
||||
for(; tokenizer.pos < buffer.length; tokenizer.pos += 1)
|
||||
{
|
||||
u8 c = fb.data[tk.pos];
|
||||
u8 c = buffer.data[tokenizer.pos];
|
||||
|
||||
if(CheckWhiteSpace(c)) break;
|
||||
if(!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z')) break;
|
||||
}
|
||||
|
||||
t.end = tk.pos;
|
||||
token.end = tokenizer.pos;
|
||||
} break;
|
||||
case '.':
|
||||
{
|
||||
Token* t = MakeToken(tk, TT.Dot, tk.pos, tk.pos+1);
|
||||
Token* token = MakeToken(tokenizer, TT.Dot, 1);
|
||||
|
||||
for(; tk.pos < fb.length; tk.pos += 1)
|
||||
for(; tokenizer.pos < buffer.length; tokenizer.pos += 1)
|
||||
{
|
||||
if(fb.data[tk.pos] != '.') break;
|
||||
if(buffer.data[tokenizer.pos] != '.') break;
|
||||
}
|
||||
|
||||
t.end = tk.pos;
|
||||
token.end = tokenizer.pos;
|
||||
} break;
|
||||
case '#':
|
||||
{
|
||||
Token* t = MakeToken(tk, TT.Import, tk.pos, tk.pos+1);
|
||||
Token* token = MakeToken(tokenizer, TT.Import, 1);
|
||||
|
||||
for(; tk.pos < fb.length; tk.pos += 1)
|
||||
for(; tokenizer.pos < buffer.length; tokenizer.pos += 1)
|
||||
{
|
||||
if(CheckWhiteSpace(fb.data[tk.pos])) break;
|
||||
if(CheckWhiteSpace(buffer.data[tokenizer.pos])) break;
|
||||
}
|
||||
|
||||
t.end = tk.pos;
|
||||
token.end = tokenizer.pos;
|
||||
} break;
|
||||
case '/':
|
||||
{
|
||||
Token* t = MakeToken(tk, TT.Slash, tk.pos, tk.pos+1);
|
||||
Token* token = MakeToken(tokenizer, TT.Slash, 1);
|
||||
|
||||
u8 next = Peek(fb);
|
||||
u8 next = Peek(buffer);
|
||||
if(next == '/')
|
||||
{
|
||||
tk.pos += 1;
|
||||
t.type = TT.Comment;
|
||||
tokenizer.pos += 1;
|
||||
token.type = TT.Comment;
|
||||
|
||||
for(; tk.pos < fb.length; tk.pos += 1)
|
||||
for(; tokenizer.pos < buffer.length; tokenizer.pos += 1)
|
||||
{
|
||||
if(CheckEOL(fb.data[tk.pos]))
|
||||
if(CheckEOL(buffer.data[tokenizer.pos]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
t.end = tk.pos+1;
|
||||
token.end = tokenizer.pos+1;
|
||||
}
|
||||
else if(next == '*')
|
||||
{
|
||||
tk.pos += 1;
|
||||
t.type = TT.Comment;
|
||||
tokenizer.pos += 1;
|
||||
token.type = TT.Comment;
|
||||
|
||||
for(; tk.pos < fb.length; tk.pos += 1)
|
||||
for(; tokenizer.pos < buffer.length; tokenizer.pos += 1)
|
||||
{
|
||||
if(fb.data[tk.pos] == '/' && fb.data[tk.pos-1] == '*')
|
||||
if(buffer.data[tokenizer.pos] == '/' && buffer.data[tokenizer.pos-1] == '*')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tk.pos += 1;
|
||||
t.end = tk.pos;
|
||||
tokenizer.pos += 1;
|
||||
token.end = tokenizer.pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
tk.pos += 1;
|
||||
FixOpAssign(fb, t);
|
||||
tokenizer.pos += 1;
|
||||
FixOpAssign(buffer, token);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
Token* t = MakeToken(tk, TT.None, tk.pos, tk.pos+1);
|
||||
Token* token = MakeToken(tokenizer, TT.None, 1);
|
||||
|
||||
for(; tk.pos < fb.length; tk.pos += 1)
|
||||
for(; tokenizer.pos < buffer.length; tokenizer.pos += 1)
|
||||
{
|
||||
if(CheckWhiteSpace(fb.data[tk.pos]))
|
||||
if(CheckWhiteSpace(buffer.data[tokenizer.pos]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
t.end = tk.pos;
|
||||
tk.pos += 1;
|
||||
token.end = tokenizer.pos;
|
||||
tokenizer.pos += 1;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto n = tk.first; !Nil(n); n = Next(n))
|
||||
for(auto n = tokenizer.first; !Nil(n); n = Next(n))
|
||||
{
|
||||
Token* prev = Prev(n);
|
||||
Token* next = Next(n);
|
||||
|
||||
if(CheckFuncOrTemplateSig(fb, n))
|
||||
if(CheckFuncOrTemplateSig(n))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -688,7 +686,7 @@ TokenizeD(FlatBuffer* fb)
|
||||
else if(prev.type == TT.TypeKeyword && n.type == TT.Identifier)
|
||||
{
|
||||
n.type = TT.Type;
|
||||
CheckTypeDeclaration(fb, n);
|
||||
CheckTypeDeclaration(n);
|
||||
continue;
|
||||
}
|
||||
else if(prev.type == TT.EnumKeyword && n.type == TT.Identifier)
|
||||
@ -715,9 +713,9 @@ TokenizeD(FlatBuffer* fb)
|
||||
CheckVarDeclaration(n);
|
||||
}
|
||||
|
||||
for(auto token = tk.first; !Nil(token); token = token.next)
|
||||
for(auto token = tokenizer.first; !Nil(token); token = token.next)
|
||||
{
|
||||
tk.tokens[token.start .. token.end] = TOKEN_STYLES[token.type];
|
||||
tokenizer.tokens[token.start .. token.end] = TOKEN_STYLES[token.type];
|
||||
}
|
||||
}
|
||||
|
||||
@ -767,20 +765,20 @@ CheckVarDeclaration(Token* token)
|
||||
}
|
||||
|
||||
void
|
||||
CheckTypeDeclaration(FlatBuffer* fb, Token* token)
|
||||
CheckTypeDeclaration(Token* token)
|
||||
{
|
||||
for(Token* tk = Next(token); !Nil(tk) && tk.type != TT.RightBrace; tk = Next(tk))
|
||||
for(Token* next_token = Next(token); !Nil(next_token) && next_token.type != TT.RightBrace; next_token = Next(next_token))
|
||||
{
|
||||
Token* prev = Prev(tk);
|
||||
Token* prev = Prev(next_token);
|
||||
if(prev.type == TT.LeftBrace || prev.type == TT.Semicolon)
|
||||
{
|
||||
tk.type = TT.Type;
|
||||
next_token.type = TT.Type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CheckFuncOrTemplateSig(FlatBuffer* fb, Token* token)
|
||||
CheckFuncOrTemplateSig(Token* token)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
@ -825,18 +823,18 @@ CheckFuncOrTemplateSig(FlatBuffer* fb, Token* token)
|
||||
}
|
||||
|
||||
u8[]
|
||||
TokenStr(FlatBuffer* fb, Token* t)
|
||||
TokenStr(Editor* editor, Token* token)
|
||||
{
|
||||
return fb.data[t.start .. t.end];
|
||||
return editor.data[token.start .. token.end];
|
||||
}
|
||||
|
||||
Token*
|
||||
Prev(types...)(Token* t)
|
||||
Prev(types...)(Token* token)
|
||||
{
|
||||
Token* res = g_NIL_TOKEN;
|
||||
|
||||
PrevMain:
|
||||
for(auto p = t.prev; !Nil(p); p = p.prev)
|
||||
for(auto p = token.prev; !Nil(p); p = p.prev)
|
||||
{
|
||||
if(p.type == TT.NewLine || p.type == TT.Whitespace || p.type == TT.Comment)
|
||||
{
|
||||
@ -865,12 +863,12 @@ PrevMain:
|
||||
alias PrevFnToken = Prev!(TT.Identifier, TT.LeftParen, TT.RightParen, TT.Comma, TT.Keyword, TT.Dot, TT.Exclamation, TT.Type);
|
||||
|
||||
Token*
|
||||
Next(types...)(Token* t)
|
||||
Next(types...)(Token* token)
|
||||
{
|
||||
Token* res = g_NIL_TOKEN;
|
||||
|
||||
NextMain:
|
||||
for(auto n = t.next; !Nil(n); n = n.next)
|
||||
for(auto n = token.next; !Nil(n); n = n.next)
|
||||
{
|
||||
if(n.type == TT.NewLine || n.type == TT.Whitespace || n.type == TT.Comment)
|
||||
{
|
||||
@ -899,20 +897,20 @@ NextMain:
|
||||
alias NextFnToken = Next!(TT.Identifier, TT.LeftParen, TT.RightParen, TT.Comma, TT.Keyword, TT.Dot, TT.Exclamation, TT.Type);
|
||||
|
||||
void
|
||||
ParseNum(FlatBuffer* fb)
|
||||
ParseNum(T)(T* buffer) if(is(T == Editor) || is(T == FlatBuffer))
|
||||
{
|
||||
Tokenizer* tk = &fb.tk;
|
||||
Tokenizer* tokenizer = &buffer.tokenizer;
|
||||
|
||||
Token* t = Alloc!(Token)(&tk.arena);
|
||||
t.type = TT.Number;
|
||||
t.start = tk.pos;
|
||||
Token* token = Alloc!(Token)(&tokenizer.arena);
|
||||
token.type = TT.Number;
|
||||
token.start = tokenizer.pos;
|
||||
|
||||
bool first = true;
|
||||
while (tk.pos < fb.length)
|
||||
while (tokenizer.pos < buffer.length)
|
||||
{
|
||||
tk.pos += 1;
|
||||
tokenizer.pos += 1;
|
||||
|
||||
u8 ch = fb.data[tk.pos];
|
||||
u8 ch = buffer.data[tokenizer.pos];
|
||||
|
||||
if(ch != '_' && ch != '.' && !(ch >= '0' && ch <= '9') && ch != 'x' && ch != 'X' && !((ch == '-' || ch == '+') && first))
|
||||
{
|
||||
@ -922,76 +920,76 @@ ParseNum(FlatBuffer* fb)
|
||||
first = false;
|
||||
}
|
||||
|
||||
while (tk.pos < fb.length)
|
||||
while (tokenizer.pos < buffer.length)
|
||||
{
|
||||
u8 ch = fb.data[tk.pos];
|
||||
u8 ch = buffer.data[tokenizer.pos];
|
||||
if(ch != 'l' && ch != 'u' && ch != 'U' && ch != 'L' && ch != 'f' && ch != 'F')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
tk.pos += 1;
|
||||
tokenizer.pos += 1;
|
||||
}
|
||||
|
||||
t.end = tk.pos;
|
||||
token.end = tokenizer.pos;
|
||||
|
||||
DLLPush(tk, t, g_NIL_TOKEN);
|
||||
DLLPush(tokenizer, token, g_NIL_TOKEN);
|
||||
}
|
||||
|
||||
void
|
||||
ParseStr(u8 str_ch)(FlatBuffer* fb)
|
||||
ParseStr(u8 str_ch, T)(T* buffer) if(is(T == Editor) || is(T == FlatBuffer))
|
||||
{
|
||||
static assert(str_ch == '`' || str_ch == '\'' || str_ch == '"');
|
||||
|
||||
Tokenizer* tk = &fb.tk;
|
||||
Tokenizer* tokenizer = &buffer.tokenizer;
|
||||
|
||||
Token* t = Alloc!(Token)(&tk.arena);
|
||||
Token* token = Alloc!(Token)(&tokenizer.arena);
|
||||
|
||||
t.type = D_STR_TOKEN[str_ch];
|
||||
t.start = tk.pos;
|
||||
token.type = D_STR_TOKEN[str_ch];
|
||||
token.start = tokenizer.pos;
|
||||
|
||||
static if(str_ch == '`') tk.pos += 1;
|
||||
static if(str_ch == '`') tokenizer.pos += 1;
|
||||
|
||||
bool ignore = str_ch != '`';
|
||||
for(; (fb.data[tk.pos] != str_ch || ignore) && tk.pos < fb.length; tk.pos += 1)
|
||||
for(; (buffer.data[tokenizer.pos] != str_ch || ignore) && tokenizer.pos < buffer.length; tokenizer.pos += 1)
|
||||
{
|
||||
static if(str_ch != '`') ignore = fb.data[tk.pos] == '\\';
|
||||
static if(str_ch != '`') ignore = buffer.data[tokenizer.pos] == '\\';
|
||||
}
|
||||
|
||||
tk.pos += 1;
|
||||
t.end = tk.pos;
|
||||
tokenizer.pos += 1;
|
||||
token.end = tokenizer.pos;
|
||||
|
||||
DLLPush(tk, t, g_NIL_TOKEN);
|
||||
DLLPush(tokenizer, token, g_NIL_TOKEN);
|
||||
}
|
||||
|
||||
void
|
||||
ParseId(FlatBuffer* fb)
|
||||
ParseId(T)(T* buffer) if(is(T == Editor) || is(T == FlatBuffer))
|
||||
{
|
||||
Tokenizer* tk = &fb.tk;
|
||||
Token* t = MakeToken(tk, TT.Identifier, tk.pos, tk.pos+1);
|
||||
Tokenizer* tokenizer = &buffer.tokenizer;
|
||||
Token* token = MakeToken(tokenizer, TT.Identifier, 1);
|
||||
|
||||
for(; tk.pos < fb.length; tk.pos += 1)
|
||||
for(; tokenizer.pos < buffer.length; tokenizer.pos += 1)
|
||||
{
|
||||
u8 ch = fb.data[tk.pos];
|
||||
u8 ch = buffer.data[tokenizer.pos];
|
||||
|
||||
if(!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && ch != '.' && ch != '_' && !(ch >= '0' && ch <= '9'))
|
||||
{
|
||||
t.end = tk.pos;
|
||||
token.end = tokenizer.pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u8 ch = fb.data[t.start];
|
||||
u8 ch = buffer.data[token.start];
|
||||
if(ch < D_KEYWORDS.length && D_KEYWORDS[ch] != null && D_KEYWORDS[ch].length > 0)
|
||||
{
|
||||
bool found = false;
|
||||
u8[] id = fb.data[t.start .. t.end];
|
||||
u8[] id = buffer.data[token.start .. token.end];
|
||||
|
||||
foreach(ref k; D_TYPES[ch])
|
||||
{
|
||||
if(id == k)
|
||||
{
|
||||
t.type = TT.Type;
|
||||
token.type = TT.Type;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@ -1005,19 +1003,19 @@ ParseId(FlatBuffer* fb)
|
||||
{
|
||||
if(k == r"import")
|
||||
{
|
||||
t.type = TT.Import;
|
||||
token.type = TT.Import;
|
||||
}
|
||||
else if(k == r"class" || k == r"struct")
|
||||
{
|
||||
t.type = TT.TypeKeyword;
|
||||
token.type = TT.TypeKeyword;
|
||||
}
|
||||
else if(k == r"enum")
|
||||
{
|
||||
t.type = TT.EnumKeyword;
|
||||
token.type = TT.EnumKeyword;
|
||||
}
|
||||
else
|
||||
{
|
||||
t.type = TT.Keyword;
|
||||
token.type = TT.Keyword;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1025,15 +1023,15 @@ ParseId(FlatBuffer* fb)
|
||||
}
|
||||
}
|
||||
|
||||
assert(t.start < t.end, "ParseId failure: start is lower or equal to end");
|
||||
assert(token.start < token.end, "ParseId failure: start is lower or equal to end");
|
||||
}
|
||||
|
||||
void
|
||||
FixOpAssign(FlatBuffer* fb, Token* t)
|
||||
FixOpAssign(T)(T* buffer, Token* token) if(is(T == Editor) || is(T == FlatBuffer))
|
||||
{
|
||||
if(t.end+1 < fb.length)
|
||||
if(token.end+1 < buffer.length)
|
||||
{
|
||||
u8[] str = fb.data[t.start .. t.end+1];
|
||||
u8[] str = buffer.data[token.start .. token.end+1];
|
||||
if(
|
||||
str == "/=" ||
|
||||
str == "+=" ||
|
||||
@ -1044,8 +1042,8 @@ FixOpAssign(FlatBuffer* fb, Token* t)
|
||||
str == "!="
|
||||
)
|
||||
{
|
||||
fb.tk.pos += 1;
|
||||
t.end += 1;
|
||||
buffer.tokenizer.pos += 1;
|
||||
token.end += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1072,11 +1070,11 @@ CheckWhiteSpace(u8 ch)
|
||||
}
|
||||
|
||||
void
|
||||
SkipWhiteSpace(FlatBuffer* fb)
|
||||
SkipWhiteSpace(Editor* editor)
|
||||
{
|
||||
while (fb.tk.pos < fb.length)
|
||||
while (editor.tokenizer.pos < editor.length)
|
||||
{
|
||||
u8 ch = fb.data[fb.tk.pos];
|
||||
u8 ch = editor.data[editor.tokenizer.pos];
|
||||
|
||||
bool white_space = CheckWhiteSpace(ch);
|
||||
|
||||
@ -1085,7 +1083,7 @@ SkipWhiteSpace(FlatBuffer* fb)
|
||||
break;
|
||||
}
|
||||
|
||||
fb.tk.pos += 1;
|
||||
editor.tokenizer.pos += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
320
src/editor/ui.d
320
src/editor/ui.d
@ -1,6 +1,7 @@
|
||||
import dlib;
|
||||
import dlib.util : HTPush = Push;
|
||||
import dlib.math : Clamp;
|
||||
import dlib.alloc : Reset;
|
||||
|
||||
import vulkan;
|
||||
import vulkan : RendererGetExtent = GetExtent;
|
||||
@ -64,8 +65,8 @@ u8[] FONT_BYTES = cast(u8[])import("jetbrains-mono/JetBrainsMono-Regula
|
||||
u8[] VERTEX_BYTES = cast(u8[])import("gui.vert.spv");
|
||||
u8[] FRAGMENT_BYTES = cast(u8[])import("gui.frag.spv");
|
||||
|
||||
const SEP_FLAGS = UIF.Drag|UIF.Priority|UIF.TargetLeniency;
|
||||
const PANEL_FLAGS = UIF.Click|UIF.Drag;
|
||||
const SEP_FLAGS = UIF.Drag | UIF.Priority | UIF.TargetLeniency;
|
||||
const PANEL_FLAGS = UIF.Click | UIF.Drag;
|
||||
|
||||
const UI_COUNT = 5000;
|
||||
|
||||
@ -322,10 +323,27 @@ Attribute[10] attributes = [
|
||||
{ binding: 0, location: 9, format: FMT.R_U32, offset: Vertex.has_texture.offsetof },
|
||||
];
|
||||
|
||||
union Rect
|
||||
struct Rect
|
||||
{
|
||||
Vec2[2] v;
|
||||
struct { Vec2 p0, p1; alias p0 pos; };
|
||||
union
|
||||
{
|
||||
Vec2[2] v;
|
||||
struct
|
||||
{
|
||||
Vec2 p0, p1;
|
||||
alias p0 pos;
|
||||
};
|
||||
};
|
||||
|
||||
ref Vec2 opIndex(usize index)
|
||||
{
|
||||
return this.v[index];
|
||||
}
|
||||
|
||||
ref Vec2 opIndexAssign(usize index, Vec2 value)
|
||||
{
|
||||
return this.v[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
alias UIHash = u64;
|
||||
@ -341,53 +359,11 @@ struct UIKey
|
||||
bool opCast(T)() if(is(T == bool)) => this.hash != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
"atlas": {
|
||||
"type": "mtsdf",
|
||||
"distanceRange": 2,
|
||||
"distanceRangeMiddle": 0,
|
||||
"size": 32.5,
|
||||
"width": 216,
|
||||
"height": 216,
|
||||
"yOrigin": "bottom"
|
||||
},
|
||||
"metrics": {
|
||||
"emSize": 1,
|
||||
"lineHeight": 1.3200000000000001,
|
||||
"ascender": 1.02,
|
||||
"descender": -0.29999999999999999,
|
||||
"underlineY": -0.17999999999999999,
|
||||
"underlineThickness": 0.050000000000000003
|
||||
},
|
||||
"glyphs": [
|
||||
{
|
||||
"unicode": 32,
|
||||
"advance": 0.59999999999999998
|
||||
},
|
||||
{
|
||||
"unicode": 33,
|
||||
"advance": 0.59999999999999998,
|
||||
"planeBounds": {
|
||||
"left": 0.19230769230769232,
|
||||
"bottom": -0.046153846153846149,
|
||||
"right": 0.40769230769230769,
|
||||
"top": 0.78461538461538449
|
||||
},
|
||||
"atlasBounds": {
|
||||
"left": 19.5,
|
||||
"bottom": 151.5,
|
||||
"right": 26.5,
|
||||
"top": 178.5
|
||||
}
|
||||
},
|
||||
|
||||
*/
|
||||
|
||||
enum bool KeyType(T) = (StringType!(T) || is(T == UIKey) || is(T == const(UIKey)));
|
||||
enum bool ItemAndKeyType(T) = (KeyType!(T) || is(T == UIItem*));
|
||||
|
||||
void
|
||||
InitUI(Ctx* ctx)
|
||||
InitUI(ref Ctx ctx)
|
||||
{
|
||||
version(ENABLE_RENDERER)
|
||||
{
|
||||
@ -438,18 +414,13 @@ InitUI(Ctx* ctx)
|
||||
|
||||
for(u64 i = 0; i < FRAME_OVERLAP; i += 1)
|
||||
{
|
||||
ctx.buffers[i].m_vtx = CreateMappedBuffer!(Vertex)(BT.Vertex, VERTEX_MAX_COUNT);
|
||||
ctx.buffers[i].m_idx = CreateMappedBuffer!(u32)(BT.Index, 6);
|
||||
ctx.buffers[i].vtx = ctx.buffers[i].m_vtx.data;
|
||||
ctx.buffers[i].idx = ctx.buffers[i].m_idx.data;
|
||||
ctx.buffers[i].m_vtx = CreateMappedBuffer!(Vertex)(BT.Vertex, VERTEX_MAX_COUNT);
|
||||
ctx.buffers[i].m_idx = CreateMappedBuffer!(u32)(BT.Index, 6);
|
||||
ctx.buffers[i].vtx = ctx.buffers[i].m_vtx.data;
|
||||
ctx.buffers[i].idx = ctx.buffers[i].m_idx.data;
|
||||
ctx.buffers[i].idx[0 .. $] = [0, 1, 2, 2, 1, 3];
|
||||
ctx.desc_sets[i] = AllocDescSet(ctx.desc_set_layout);
|
||||
ctx.str_arenas[i] = CreateArena(MB(1));
|
||||
|
||||
ctx.slug_vertex_buffers[i] = CreateMappedBuffer!(SlugVertex)(BT.Vertex, 1000);
|
||||
ctx.slug_index_buffers[i] = CreateMappedBuffer!(u32)(BT.Index, 1000);
|
||||
ctx.slug_buffers[i].vertices = ctx.slug_vertex_buffers[i].data;
|
||||
ctx.slug_buffers[i].indices = ctx.slug_index_buffers[i].data;
|
||||
ctx.desc_sets[i] = AllocDescSet(ctx.desc_set_layout);
|
||||
ctx.str_arenas[i] = CreateArena(MB(1));
|
||||
}
|
||||
|
||||
GfxPipelineInfo ui_info = {
|
||||
@ -550,16 +521,16 @@ PushFree(string next_member = "free_next", T)(T** top, T* node)
|
||||
*top = node;
|
||||
}
|
||||
|
||||
f32
|
||||
GetLineHeight(u32 size)
|
||||
{
|
||||
return GetFontSet(size).line_height;
|
||||
}
|
||||
f32
|
||||
GetLineHeight(u32 size) => GetFontSet(size).line_height;
|
||||
|
||||
FontSet*
|
||||
GetFontSet(T)(T font_set) if(is(T == FontSet*)) => font_set;
|
||||
|
||||
FontSet*
|
||||
GetFontSet(u32 size)
|
||||
GetFontSet(T)(T size) if(is(T: u32))
|
||||
{
|
||||
Ctx* ctx = GetCtx();
|
||||
ref Ctx ctx = GetCtx();
|
||||
|
||||
FontSet* fs = null;
|
||||
for(u64 i = 0; i < ctx.font_sets_used; i += 1)
|
||||
@ -570,7 +541,7 @@ GetFontSet(u32 size)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!fs)
|
||||
{
|
||||
fs = &ctx.font_sets[ctx.font_sets_used++];
|
||||
@ -590,30 +561,30 @@ GetFontSet(u32 size)
|
||||
void
|
||||
LoadFontSet()
|
||||
{
|
||||
Ctx* ctx = GetCtx();
|
||||
u64 fi = ctx.f_idx;
|
||||
ref Ctx ctx = GetCtx();
|
||||
|
||||
for(u64 i = 0; i < ctx.font_sets_used; i += 1)
|
||||
{
|
||||
FontSet* fs = ctx.font_sets.ptr + i;
|
||||
FontSet* fs = ctx.font_sets.ptr + i;
|
||||
ref bool descriptor_written = fs.descriptor_written[ctx.frame_index];
|
||||
if(!fs.texture_loaded)
|
||||
{
|
||||
Transfer!(true)(&ctx.font_descs[i], fs.atlas.data);
|
||||
fs.texture_loaded = true;
|
||||
}
|
||||
|
||||
if(!fs.descriptor_written[fi])
|
||||
if(!descriptor_written)
|
||||
{
|
||||
Write(ctx.desc_sets[fi], ctx.font_descs);
|
||||
fs.descriptor_written[fi] = true;
|
||||
Write(ctx.desc_set, ctx.font_descs);
|
||||
descriptor_written = true;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.fonts_to_load[fi] = false;
|
||||
ctx.fonts_to_load[ctx.frame_index] = false;
|
||||
}
|
||||
|
||||
void
|
||||
Scissor(Ctx* ctx, Rect rect, Style* style)
|
||||
Scissor(ref Ctx ctx, Rect rect, Style* style)
|
||||
{
|
||||
DrawUI(ctx);
|
||||
|
||||
@ -630,14 +601,14 @@ Scissor(Ctx* ctx, Rect rect, Style* style)
|
||||
}
|
||||
|
||||
void
|
||||
EndScissor(Ctx* ctx)
|
||||
EndScissor(ref Ctx ctx)
|
||||
{
|
||||
DrawUI(ctx);
|
||||
ResetScissor();
|
||||
}
|
||||
|
||||
void
|
||||
Panel(Ctx* ctx, UIPanel* panel)
|
||||
Panel(ref Ctx ctx, UIPanel* panel)
|
||||
{
|
||||
panel.item = MakeItem!(PANEL_FLAGS)("###panel_%s", panel.id);
|
||||
Axis2D p_axis = Nil(panel.parent) ? A2D.X : panel.parent.axis;
|
||||
@ -682,16 +653,16 @@ Panel(Ctx* ctx, UIPanel* panel)
|
||||
panel.move_text_with_cursor = false;
|
||||
}
|
||||
|
||||
panel.scroll_target.y = cast(f32)(panel.ed.line_offset)*fs.line_height;
|
||||
panel.scroll_target.y = cast(f32)(panel.ed.view_info.line_offset)*fs.line_height;
|
||||
|
||||
f32 max_px = panel.ed.buf.line_count*fs.line_height;
|
||||
f32 max_px = panel.ed.line_count*fs.line_height;
|
||||
f32 offset = -(panel.item.scroll_offset.y%fs.line_height);
|
||||
u64 start_ln = cast(u64)(floor(panel.scroll_offset.y/fs.line_height));
|
||||
const f32 PAD = 4.0f;
|
||||
|
||||
// Line counter
|
||||
|
||||
u64 lc_chars = panel.ed.buf.line_count.toChars().length;
|
||||
u64 lc_chars = panel.ed.line_count.toChars().length;
|
||||
f32 lc_width = PAD*2.0 + cast(f32)(lc_chars)*fs.max_advance;
|
||||
|
||||
Style style = PANEL_STYLE;
|
||||
@ -709,7 +680,7 @@ Panel(Ctx* ctx, UIPanel* panel)
|
||||
|
||||
f32 panel_height = Size!(A2D.Y)(line_count_rect);
|
||||
panel.ed.line_height = cast(i64)ceil(panel_height/fs.line_height);
|
||||
u64 max_ln = Min(panel.ed.line_height + start_ln, panel.ed.buf.line_count);
|
||||
u64 max_ln = Min(panel.ed.line_height + start_ln, panel.ed.line_count);
|
||||
|
||||
for(u64 i = start_ln; i < max_ln; i += 1)
|
||||
{
|
||||
@ -729,12 +700,12 @@ Panel(Ctx* ctx, UIPanel* panel)
|
||||
|
||||
text_rect = Pad(text_view_rect, PAD);
|
||||
|
||||
I64Vec2 cursor_coords = VecPos(&panel.ed.buf);
|
||||
LineBuffer* current_lbuf = GetLine(&panel.ed.buf, cursor_coords.y);
|
||||
I64Vec2 cursor_coords = VecPos(panel.ed);
|
||||
LineBuffer* current_lbuf = GetLine(panel.ed, cursor_coords.y);
|
||||
UIItem* cursor = MakeItem("###cursor_%s", panel.id);
|
||||
if(ctx.focused_panel == panel)
|
||||
{
|
||||
i64 y_pos = cursor_coords.y - panel.ed.line_offset;
|
||||
i64 y_pos = cursor_coords.y - panel.ed.view_info.line_offset;
|
||||
|
||||
cursor.size.x = Active(ES.InputMode) ? 2.0 : fs.max_advance;
|
||||
cursor.size.y = fs.line_height;
|
||||
@ -760,7 +731,7 @@ Panel(Ctx* ctx, UIPanel* panel)
|
||||
{
|
||||
if(Active(ES.InputMode) && panel.move_text_with_cursor)
|
||||
{
|
||||
for(LineBuffer* lbuf = GetLine(&panel.ed.buf, i); i < max_ln && !CheckNil(g_NIL_LINE_BUF, lbuf); lbuf = GetLine(&panel.ed.buf, ++i))
|
||||
for(LineBuffer* lbuf = GetLine(panel.ed, i); i < max_ln && !CheckNil(g_NIL_LINE_BUF, lbuf); lbuf = GetLine(panel.ed, ++i))
|
||||
{
|
||||
if(i == cursor_coords.y)
|
||||
{
|
||||
@ -799,7 +770,7 @@ Panel(Ctx* ctx, UIPanel* panel)
|
||||
DrawLines(ctx, panel, start_ln, max_ln, text_rect, fs);
|
||||
}
|
||||
|
||||
ResetBuffer(&panel.ed.buf);
|
||||
ResetBuffer(panel.ed);
|
||||
|
||||
EndScissor(ctx);
|
||||
DrawBorder(ctx, text_view_rect, &style);
|
||||
@ -844,10 +815,10 @@ Panel(Ctx* ctx, UIPanel* panel)
|
||||
}
|
||||
|
||||
void
|
||||
DrawLines(bool hl = false)(Ctx* ctx, UIPanel* panel, u64 start_line, u64 end_line, Rect text_rect, FontSet* fs, I64Vec2 cursor_coords = I64Vec2(-1))
|
||||
DrawLines(bool hl = false)(ref Ctx ctx, UIPanel* panel, u64 start_line, u64 end_line, Rect text_rect, FontSet* fs, I64Vec2 cursor_coords = I64Vec2(-1))
|
||||
{
|
||||
u64 i = start_line;
|
||||
for(LineBuffer* lbuf = GetLine(&panel.ed.buf, i); i < end_line && !CheckNil(g_NIL_LINE_BUF, lbuf); lbuf = GetLine(&panel.ed.buf, ++i))
|
||||
for(LineBuffer* lbuf = GetLine(panel.ed, i); i < end_line && !CheckNil(g_NIL_LINE_BUF, lbuf); lbuf = GetLine(panel.ed, ++i))
|
||||
{
|
||||
static if(hl)
|
||||
{
|
||||
@ -873,7 +844,7 @@ struct SearchWindowCtx(T)
|
||||
void
|
||||
SearchInputWindow(T)(string hash_text, SearchWindowCtx!(T)* window_ctx, bool ready_cond) if(is(T == Command) || is(T == string))
|
||||
{
|
||||
Ctx* ctx = GetCtx();
|
||||
ref Ctx ctx = GetCtx();
|
||||
Vec2 extent = GetExtent();
|
||||
f32 x = extent.x * 0.1;
|
||||
f32 y = extent.y * 0.2;
|
||||
@ -955,7 +926,7 @@ SearchInputWindow(T)(string hash_text, SearchWindowCtx!(T)* window_ctx, bool rea
|
||||
Rect opt_rect = inner_rect;
|
||||
opt_rect.p0.y -= opt_start_offset;
|
||||
|
||||
UIItem* selected_opt_item = g_UI_NIL;
|
||||
UIItem* selected_opt_item = g_UI_NIL_ITEM;
|
||||
if(start_opt_index < options.length) foreach(i; start_opt_index .. options.length)
|
||||
{
|
||||
Rect[2] opt_rects = Split(opt_rect, full_opt_height, A2D.Y);
|
||||
@ -1058,9 +1029,9 @@ SearchInputWindow(T)(string hash_text, SearchWindowCtx!(T)* window_ctx, bool rea
|
||||
}
|
||||
|
||||
bool
|
||||
SaveFileWindow(Ctx* ctx)
|
||||
SaveFileWindow(ref Ctx ctx)
|
||||
{
|
||||
bool exit;
|
||||
bool exit;
|
||||
Editor* ed = ctx.focused_panel.ed;
|
||||
|
||||
static bool init = false;
|
||||
@ -1068,7 +1039,6 @@ SaveFileWindow(Ctx* ctx)
|
||||
{
|
||||
ctx.cmd.exec_cmd_input.data[0 .. ed.file_name.length] = Arr!(u8)(ed.file_name[0 .. $]);
|
||||
ctx.cmd.exec_cmd_input.length = ed.file_name.length;
|
||||
init = true;
|
||||
}
|
||||
|
||||
const PAD = 4.0f;
|
||||
@ -1133,19 +1103,16 @@ SaveFileWindow(Ctx* ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if(exit)
|
||||
{
|
||||
init = false;
|
||||
}
|
||||
init = !exit;
|
||||
|
||||
return exit;
|
||||
}
|
||||
|
||||
bool
|
||||
OpenFileWindow(Ctx* ctx)
|
||||
OpenFileWindow(ref Ctx ctx)
|
||||
{
|
||||
bool exit;
|
||||
CmdPalette* cmd = &ctx.cmd;
|
||||
bool exit;
|
||||
ref CmdPalette cmd = ctx.cmd;
|
||||
|
||||
if(!cmd.exec_cmd_opts.length && !cmd.exec_cmd_input.length)
|
||||
{
|
||||
@ -1218,9 +1185,9 @@ OpenFileWindow(Ctx* ctx)
|
||||
}
|
||||
|
||||
void
|
||||
CommandPalette(Ctx* ctx)
|
||||
CommandPalette(ref Ctx ctx)
|
||||
{
|
||||
CmdPalette* cmd = &ctx.cmd;
|
||||
ref CmdPalette cmd = ctx.cmd;
|
||||
|
||||
bool enter_hit, buffer_changed, selection_changed;
|
||||
if(ctx.state == ES.CmdPalette)
|
||||
@ -1416,15 +1383,9 @@ CreatePanel(Editor* ed = null)
|
||||
else
|
||||
{
|
||||
bool allocated;
|
||||
p = GetOrAlloc(&g_ctx.arena, &g_ctx.free_panels, g_NIL_PANEL, &allocated);
|
||||
if(allocated)
|
||||
{
|
||||
p.id = panel_id++;
|
||||
}
|
||||
if(!p.ed)
|
||||
{
|
||||
p.ed = CreateEditor();
|
||||
}
|
||||
p = GetOrAlloc(&g_ctx.arena, &g_ctx.free_panels, g_NIL_PANEL, &allocated);
|
||||
p.id = panel_id++;
|
||||
p.ed = CreateEditor();
|
||||
}
|
||||
|
||||
p.item = MakeItem!(PANEL_FLAGS)("###panel_%s", p.id);
|
||||
@ -1500,7 +1461,7 @@ Hovered(bool current_frame, T, U)(T param, U* ptr, U index)
|
||||
bool
|
||||
Hovered(bool current_frame, T)(T param)
|
||||
{
|
||||
Ctx* ctx = GetCtx();
|
||||
ref Ctx ctx = GetCtx();
|
||||
bool result;
|
||||
|
||||
UIKey key = mixin(AssignKey!(T, param));
|
||||
@ -1521,7 +1482,7 @@ Hovered(bool current_frame, T)(T param)
|
||||
}
|
||||
|
||||
void
|
||||
PushUIEvent(Ctx* ctx, UIInput input)
|
||||
PushUIEvent(ref Ctx ctx, UIInput input)
|
||||
{
|
||||
UIInput* ev = Alloc!(UIInput)(&ctx.temp_arena);
|
||||
*ev = input;
|
||||
@ -1530,7 +1491,7 @@ PushUIEvent(Ctx* ctx, UIInput input)
|
||||
}
|
||||
|
||||
void
|
||||
DrawUI(Ctx* ctx, u32 atlas_index)
|
||||
DrawUI(ref Ctx ctx, u32 atlas_index)
|
||||
{
|
||||
if(ctx.pc.atlas_index != atlas_index)
|
||||
{
|
||||
@ -1541,33 +1502,17 @@ DrawUI(Ctx* ctx, u32 atlas_index)
|
||||
}
|
||||
|
||||
void
|
||||
DrawSlug(Ctx* ctx)
|
||||
DrawUI(ref Ctx ctx)
|
||||
{
|
||||
version(ENABLE_RENDERER)
|
||||
{
|
||||
// TODO: fix this
|
||||
SlugBuffer* buffer = ctx.slug_buffers.ptr + ctx.f_idx;
|
||||
|
||||
auto vertex_buffer = ctx.slug_vertex_buffers.ptr + ctx.f_idx;
|
||||
auto index_buffer = ctx.slug_index_buffers.ptr + ctx.f_idx;
|
||||
|
||||
BindBuffers(index_buffer, vertex_buffer);
|
||||
DrawIndexed(buffer.quad_offset*6, 1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawUI(Ctx* ctx)
|
||||
{
|
||||
version(ENABLE_RENDERER)
|
||||
{
|
||||
UIBuffer* b = ctx.buffers.ptr + ctx.f_idx;
|
||||
if(b.vtx_offset != b.count)
|
||||
ref UIBuffer buffer = ctx.buffers[ctx.frame_index];
|
||||
if(buffer.vtx_offset != buffer.count)
|
||||
{
|
||||
u32 count = b.count - b.vtx_offset;
|
||||
BindBuffers(&b.m_idx, &b.m_vtx);
|
||||
DrawIndexed(6, count, 0, 0, b.vtx_offset);
|
||||
b.vtx_offset += count;
|
||||
u32 count = buffer.count - buffer.vtx_offset;
|
||||
BindBuffers(&buffer.m_idx, &buffer.m_vtx);
|
||||
DrawIndexed(6, count, 0, 0, buffer.vtx_offset);
|
||||
buffer.vtx_offset += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1575,10 +1520,10 @@ DrawUI(Ctx* ctx)
|
||||
void
|
||||
BeginUI(Inputs* inputs)
|
||||
{
|
||||
Ctx* ctx = GetCtx();
|
||||
Arena* a = &ctx.temp_arena;
|
||||
ref Ctx ctx = GetCtx();
|
||||
ref Arena arena = ctx.temp_arena;
|
||||
|
||||
Reset(a);
|
||||
Reset(&arena);
|
||||
|
||||
// Convert Inputs
|
||||
ctx.events.first = ctx.events.last = null;
|
||||
@ -1687,11 +1632,11 @@ BeginUI(Inputs* inputs)
|
||||
|
||||
// Ctx state
|
||||
ctx.frame = next_frame;
|
||||
ctx.f_idx = ctx.frame%FRAME_OVERLAP;
|
||||
ctx.frame_index = ctx.frame%FRAME_OVERLAP;
|
||||
ctx.inputs = inputs;
|
||||
ctx.last_item = g_UI_NIL;
|
||||
ctx.last_item = g_UI_NIL_ITEM;
|
||||
|
||||
Reset(&ctx.str_arenas[ctx.f_idx]);
|
||||
Reset(&ctx.str_arenas[ctx.frame_index]);
|
||||
|
||||
assert(!mouse_moved || ZeroKey(ctx.hover_key) || (ctx.frame == ctx.last_hover_frame));
|
||||
|
||||
@ -1704,7 +1649,7 @@ BeginUI(Inputs* inputs)
|
||||
{
|
||||
BeginFrame();
|
||||
|
||||
if(ctx.fonts_to_load[ctx.f_idx])
|
||||
if(ctx.fonts_to_load[ctx.frame_index])
|
||||
{
|
||||
LoadFontSet();
|
||||
}
|
||||
@ -1714,22 +1659,19 @@ BeginUI(Inputs* inputs)
|
||||
SetStencilTest(false);
|
||||
|
||||
PushConstants(ctx.pipeline, &ctx.pc);
|
||||
Bind(ctx.pipeline, ctx.desc_sets[ctx.f_idx]);
|
||||
Bind(ctx.pipeline, ctx.desc_sets[ctx.frame_index]);
|
||||
}
|
||||
|
||||
UIBuffer* buffer = ctx.buffers.ptr + ctx.f_idx;
|
||||
SlugBuffer* slug_buffer = ctx.slug_buffers.ptr + ctx.f_idx;
|
||||
UIBuffer* buffer = ctx.buffers.ptr + ctx.frame_index;
|
||||
|
||||
memset(buffer.vtx.ptr, 0, Vertex.sizeof * buffer.count);
|
||||
memset(slug_buffer.vertices.ptr, 0, SlugVertex.sizeof * slug_buffer.quad_offset);
|
||||
memset(buffer.vtx.ptr, 0, Vertex.sizeof * buffer.count);
|
||||
|
||||
buffer.count = 0;
|
||||
buffer.vtx_offset = 0;
|
||||
slug_buffer.quad_offset = 0;
|
||||
}
|
||||
|
||||
UIKey
|
||||
FindHoverKey(bool priority)(Ctx* ctx)
|
||||
FindHoverKey(bool priority)(ref Ctx ctx)
|
||||
{
|
||||
UIKey hovered;
|
||||
|
||||
@ -1762,11 +1704,11 @@ FindHoverKey(bool priority)(Ctx* ctx)
|
||||
void
|
||||
EndUI()
|
||||
{
|
||||
Ctx* ctx = GetCtx();
|
||||
ref Ctx ctx = GetCtx();
|
||||
|
||||
if(ctx.dbg)
|
||||
debug if(ctx.dbg)
|
||||
{
|
||||
const PAD = 4.0f;
|
||||
const f32 PAD = 4.0f;
|
||||
static FontSet* fs;
|
||||
if(!fs)
|
||||
{
|
||||
@ -1780,7 +1722,7 @@ EndUI()
|
||||
|
||||
Rect debug_rect;
|
||||
|
||||
debug_rect.p0.x = ext.x - text_width - PAD*2.0f;
|
||||
debug_rect.p0.x = ext.x - text_width - PAD*2.0f;
|
||||
debug_rect.p0.y = ext.y - fs.line_height - PAD*2.0f;
|
||||
debug_rect.p1 = ext;
|
||||
|
||||
@ -1814,7 +1756,7 @@ SetNil(Args...)(Args args)
|
||||
{
|
||||
static if(is(typeof(Args[i]) == UIItem**))
|
||||
{
|
||||
*args[i] = g_UI_NIL;
|
||||
*args[i] = g_UI_NIL_ITEM;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1824,7 +1766,7 @@ SetNil(Args...)(Args args)
|
||||
}
|
||||
|
||||
void
|
||||
Clamp(Ctx* ctx, Vertex* v)
|
||||
Clamp(ref Ctx ctx, Vertex* v)
|
||||
{
|
||||
v.dst_start = Clamp(v.dst_start, Vec2(0.0), cast(Vec2)ctx.pc.resolution);
|
||||
v.dst_end = Clamp(v.dst_end, Vec2(0.0), cast(Vec2)ctx.pc.resolution);
|
||||
@ -1853,7 +1795,7 @@ UpdateState(f32* v, bool cond)
|
||||
}
|
||||
|
||||
void
|
||||
UpdateState(ISF flags)(Ctx* ctx, UIItem* item)
|
||||
UpdateState(ISF flags)(ref Ctx ctx, UIItem* item)
|
||||
{
|
||||
static if(flags & ISF.Hot) UpdateState(&item.hot_t, cast(bool)(flags & ISF.SetHot) || Hovered!(true)(item));
|
||||
static if(flags & ISF.Ready) UpdateState(&item.ready_t, cast(bool)(flags & ISF.SetReady));
|
||||
@ -1892,7 +1834,7 @@ AnimateReady(Args...)(f32 ready, Args cols)
|
||||
}
|
||||
|
||||
void
|
||||
DrawDropShadow(Ctx* ctx, Rect rect, f32 ready_t = 1.0)
|
||||
DrawDropShadow(ref Ctx ctx, Rect rect, f32 ready_t = 1.0)
|
||||
{
|
||||
Vec2 size = Vec2(rect.p1.x-rect.p0.x, rect.p1.y-rect.p0.y);
|
||||
|
||||
@ -1911,7 +1853,7 @@ DrawDropShadow(Ctx* ctx, Rect rect, f32 ready_t = 1.0)
|
||||
}
|
||||
|
||||
void
|
||||
DrawBorder(Ctx* ctx, Rect rect, Style* style, f32 hot_t = 0.0, f32 ready_t = 1.0)
|
||||
DrawBorder(ref Ctx ctx, Rect rect, Style* style, f32 hot_t = 0.0, f32 ready_t = 1.0)
|
||||
{
|
||||
Vec4 col = style.border_col;
|
||||
AnimateHot(hot_t, style.border_hl_col, &col);
|
||||
@ -1929,7 +1871,7 @@ DrawBorder(Ctx* ctx, Rect rect, Style* style, f32 hot_t = 0.0, f32 ready_t = 1.0
|
||||
}
|
||||
|
||||
void
|
||||
DrawRect(Ctx* ctx, Rect rect, Style* style, f32 hot_t = 0.0f, f32 ready_t = 1.0f)
|
||||
DrawRect(ref Ctx ctx, Rect rect, Style* style, f32 hot_t = 0.0f, f32 ready_t = 1.0f)
|
||||
{
|
||||
Vec4 col = style.col;
|
||||
AnimateHot(hot_t, style.hl_col, &col);
|
||||
@ -1955,19 +1897,11 @@ enum TextAlign
|
||||
} alias TA = TextAlign;
|
||||
|
||||
void
|
||||
DrawText(T, U, V)(Ctx* ctx, T text_param, U col_param, V text_size_param, Rect rect, TextAlign text_align, i64 hl_char = -1, f32 ready = 1.0)
|
||||
DrawText(T, U, V)(ref Ctx ctx, T text_param, U col_param, V text_size_param, Rect rect, TextAlign text_align, i64 hl_char = -1, f32 ready = 1.0)
|
||||
if(is(V: u32) || is(V == FontSet*))
|
||||
{
|
||||
static if(is(V == FontSet*))
|
||||
{
|
||||
FontSet* fs = text_size_param;
|
||||
}
|
||||
else if(is(V == u32))
|
||||
{
|
||||
FontSet* fs = GetFontSet(text_size_param);
|
||||
}
|
||||
else static assert(false, "invalid input parameter, V must be FontSet* or u32");
|
||||
|
||||
string text = Str(text_param);
|
||||
FontSet* fs = GetFontSet(text_size_param);
|
||||
string text = Str(text_param);
|
||||
|
||||
DrawUI(ctx, fs.index);
|
||||
|
||||
@ -2031,7 +1965,7 @@ InvertCol(Vec4 col)
|
||||
}
|
||||
|
||||
void
|
||||
BeginScissor(Ctx* ctx, UIItem* item, bool scissor_x = true, bool scissor_y = true)
|
||||
BeginScissor(ref Ctx ctx, UIItem* item, bool scissor_x = true, bool scissor_y = true)
|
||||
{
|
||||
DrawUI(ctx);
|
||||
|
||||
@ -2050,7 +1984,10 @@ BeginScissor(Ctx* ctx, UIItem* item, bool scissor_x = true, bool scissor_y = tru
|
||||
Vec2
|
||||
GetExtent()
|
||||
{
|
||||
version(ENABLE_RENDERER) return Vec2(RendererGetExtent()); else return Vec2(1280, 720);
|
||||
version(ENABLE_RENDERER)
|
||||
return Vec2(RendererGetExtent());
|
||||
else
|
||||
return Vec2(1280, 720);
|
||||
}
|
||||
|
||||
template
|
||||
@ -2187,10 +2124,10 @@ ZeroKey(T)(T param) if(is(T == UIItem*) || is(T == UIKey))
|
||||
}
|
||||
|
||||
UIItem*
|
||||
NewItem(Ctx* ctx)
|
||||
NewItem(ref Ctx ctx)
|
||||
{
|
||||
bool allocated;
|
||||
return GetOrAlloc(&ctx.arena, &ctx.free_items, g_UI_NIL, &allocated);
|
||||
return GetOrAlloc(&ctx.arena, &ctx.free_items, g_UI_NIL_ITEM, &allocated);
|
||||
}
|
||||
|
||||
UIItem*
|
||||
@ -2205,7 +2142,7 @@ MakeItem(UIFlags flags = UIF.None, Args...)(string str, Args args)
|
||||
}
|
||||
}
|
||||
|
||||
char[] key = sformat(Alloc!(char)(&g_ctx.str_arenas[g_ctx.f_idx], len), str, args);
|
||||
char[] key = sformat(Alloc!(char)(&g_ctx.str_arenas[g_ctx.frame_index], len), str, args);
|
||||
return MakeItem(key, flags);
|
||||
}
|
||||
|
||||
@ -2213,7 +2150,7 @@ pragma(inline) UIItem*
|
||||
MakeItem(T)(T k, UIFlags flags = UIF.None) if(KeyType!(T))
|
||||
{
|
||||
UIKey key = mixin(AssignKey!(T, k));
|
||||
Ctx* ctx = GetCtx();
|
||||
ref Ctx ctx = GetCtx();
|
||||
UIItem* item;
|
||||
|
||||
Result!(UIItem*) res = ctx.items[key.hash];
|
||||
@ -2309,14 +2246,7 @@ SetHot(UIItem* item, bool hot)
|
||||
f32
|
||||
CalcTextWidth(T, U)(T text, U param) if((is(T == string) || StringType!T) && (is(U: u32) || is(U == FontSet*) ))
|
||||
{
|
||||
static if(is(T == string))
|
||||
{
|
||||
string str = text;
|
||||
}
|
||||
else
|
||||
{
|
||||
string str = Str(text);
|
||||
}
|
||||
string str = Str(text);
|
||||
|
||||
static if(is(U: u32))
|
||||
{
|
||||
@ -2349,7 +2279,7 @@ DrawGlyph(Rect rect, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, u32 size,
|
||||
{
|
||||
if(glyph)
|
||||
{
|
||||
Ctx* ctx = GetCtx();
|
||||
ref Ctx ctx = GetCtx();
|
||||
Vertex* v = null;
|
||||
f32 advance = glyph.advance;
|
||||
|
||||
@ -2412,24 +2342,24 @@ DrawGlyph(Rect rect, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, u32 size,
|
||||
}
|
||||
|
||||
pragma(inline) Vertex*
|
||||
GetVertex(Ctx* ctx)
|
||||
GetVertex(ref Ctx ctx)
|
||||
{
|
||||
assert(ctx.buffers[ctx.f_idx].count < VERTEX_MAX_COUNT);
|
||||
return ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count++;
|
||||
assert(ctx.buffers[ctx.frame_index].count < VERTEX_MAX_COUNT);
|
||||
return ctx.buffers[ctx.frame_index].vtx.ptr + ctx.buffers[ctx.frame_index].count++;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Nil(T)(T item)
|
||||
{
|
||||
static if(is(T == UIItem*)) return item == null || item == g_UI_NIL;
|
||||
static if(is(T == UIItem*)) return item == null || item == g_UI_NIL_ITEM;
|
||||
else static if(is(T == UIInput*)) return item == null || item == g_UI_NIL_INPUT;
|
||||
else static if(is(T == UIPanel*)) return item == null || item == g_NIL_PANEL;
|
||||
else static assert(false, "Invalid nil type checked");
|
||||
}
|
||||
|
||||
bool
|
||||
Dragged(Ctx* ctx, UIItem* item, IVec2* dragged)
|
||||
Dragged(ref Ctx ctx, UIItem* item, IVec2* dragged)
|
||||
{
|
||||
if(item.key == ctx.drag_key || (!ctx.drag_key && item.key == ctx.hover_key))
|
||||
{
|
||||
@ -2459,7 +2389,7 @@ Dragged(Ctx* ctx, UIItem* item, IVec2* dragged)
|
||||
}
|
||||
|
||||
bool
|
||||
Clicked(Ctx* ctx, UIItem* item)
|
||||
Clicked(ref Ctx ctx, UIItem* item)
|
||||
{
|
||||
bool result;
|
||||
|
||||
@ -2550,7 +2480,7 @@ OklabToSRGB(Vec4 v)
|
||||
string
|
||||
EdScratchf(Args...)(string fmt, Args args)
|
||||
{
|
||||
char[] buf = Alloc!(char)(&g_ctx.str_arenas[g_ctx.f_idx], fmt.length < 16 ? 32 : 128);
|
||||
char[] buf = Alloc!(char)(&g_ctx.str_arenas[g_ctx.frame_index], fmt.length < 16 ? 32 : 128);
|
||||
return Str(sformat(buf, fmt, args));
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user