clean up, editor position/offset/etc within a buffer now tracked per editor per buffer

This commit is contained in:
Matthew 2026-06-26 08:32:22 +10:00
parent 117b5eb51e
commit 5261118dd0
6 changed files with 856 additions and 931 deletions

View File

@ -16,7 +16,7 @@
"versions": ["VULKAN_DEBUG", "ENABLE_RENDERER", "DLIB"], "versions": ["VULKAN_DEBUG", "ENABLE_RENDERER", "DLIB"],
"preGenerateCommands-linux": ["./build.sh"], "preGenerateCommands-linux": ["./build.sh"],
"preGenerateCommands-windows": [], "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-ldc2": ["-link-debuglib", "--Xcc=-DBUILD_VULKAN"],
"dflags-dmd": ["-Xcc=-DBUILD_VULKAN"] "dflags-dmd": ["-Xcc=-DBUILD_VULKAN"]
}, },

@ -1 +1 @@
Subproject commit 53eb211a1e227d1cf3d8036a0e8ecfb79f514eed Subproject commit f3d1f551ccfa37de73d626479252bada0fc17cb2

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
import dlib; import dlib;
import dlib.util : Str; import dlib.util : Str;
import dlib.alloc : Reset;
import vulkan; import vulkan;
import std.format : sformat; import std.format : sformat;
@ -16,8 +17,12 @@ import std.file;
import std.string; import std.string;
import core.stdc.stdio; import core.stdc.stdio;
const u64 ARRAY_COUNT_INCREMENT = 32;
f32 g_delta = 0.0; f32 g_delta = 0.0;
alias UIHashTable = HashTable!(UIHash, UIItem*);
struct RenderCtx struct RenderCtx
{ {
PlatformWindow* window; PlatformWindow* window;
@ -25,7 +30,6 @@ struct RenderCtx
Descriptor default_tex; Descriptor default_tex;
Descriptor sampler; Descriptor sampler;
Pipeline pipeline; Pipeline pipeline;
Pipeline slug_pipeline;
DescSetLayout desc_set_layout; DescSetLayout desc_set_layout;
DescSet[FO] desc_sets; DescSet[FO] desc_sets;
PipelineLayout pipeline_layout; PipelineLayout pipeline_layout;
@ -36,7 +40,7 @@ struct Ctx
{ {
RenderCtx rd_ctx; RenderCtx rd_ctx;
HashTable!(UIHash, UIItem*) items; UIHashTable items;
UIItem* free_items; UIItem* free_items;
UIItem* last_item; UIItem* last_item;
@ -46,7 +50,7 @@ struct Ctx
Inputs* inputs; Inputs* inputs;
u64 frame; u64 frame;
u64 f_idx; u64 frame_index;
Notification* active_notifications; Notification* active_notifications;
Notification* free_notifications; Notification* free_notifications;
@ -54,7 +58,6 @@ struct Ctx
LinkedList!(UIInput) events; LinkedList!(UIInput) events;
IVec2 mouse_pos; IVec2 mouse_pos;
SlugFont slug_font;
FontFace font; FontFace font;
FontSet[FS] font_sets; FontSet[FS] font_sets;
u32 font_sets_used; u32 font_sets_used;
@ -64,10 +67,6 @@ struct Ctx
UIBuffer[FO] buffers; UIBuffer[FO] buffers;
SlugBuffer[FO] slug_buffers;
MappedBuffer!(SlugVertex)[FO] slug_vertex_buffers;
MappedBuffer!(u32)[FO] slug_index_buffers;
u32 tab_width; u32 tab_width;
Vec4[TS.max][UISH.max] syntax_colors; Vec4[TS.max][UISH.max] syntax_colors;
@ -96,6 +95,14 @@ struct Ctx
CmdPalette cmd; CmdPalette cmd;
string[] file_names; string[] file_names;
u64 panel_id; u64 panel_id;
Editor[] editors;
u64 editor_count;
Editor* free_editors;
FlatBuffer[] text_buffers;
u64 text_buffer_count;
FlatBuffer* free_text_buffers;
@property ref DescSet desc_set() => this.rd_ctx.desc_sets[this.frame_index];
debug bool dbg; debug bool dbg;
@ -131,21 +138,17 @@ struct CmdPalette
struct Editor struct Editor
{ {
Arena arena; alias BufferViewTable = HashTable!(string, BufferViewInfo);
BufferViewInfo view_info_default;
FlatBuffer* buffer;
Editor* list_next;
BufferViewInfo* view_info;
u64 editor_id; u64 editor_id;
FlatBuffer buf;
Tokenizer tk;
I64Vec2 cursor_pos;
Vec2 select_start;
Vec2 select_end;
i64 line_offset;
i64 line_height; i64 line_height;
BufferViewTable view_info_table;
Editor* free_next; alias buffer this;
alias buf this;
} }
struct ChangeStacks struct ChangeStacks
@ -165,7 +168,7 @@ struct EditorChange
EditorChange* next; 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 struct Command
{ {
@ -236,16 +239,18 @@ enum EditState
} alias ES = EditState; } alias ES = EditState;
__gshared Ctx g_ctx; __gshared Ctx g_ctx;
__gshared const Editor g_nil_ed;
__gshared Editor* g_NIL_ED; __gshared Editor g_nil_ed;
__gshared const UIItem g_ui_nil_item; __gshared UIItem g_ui_nil_item;
__gshared UIItem* g_UI_NIL; __gshared UIInput g_ui_nil_input;
__gshared const UIInput g_ui_nil_input; __gshared UIPanel g_nil_panel;
__gshared UIInput* g_UI_NIL_INPUT; __gshared Notification g_nil_notif;
__gshared const UIPanel g_nil_panel;
__gshared UIPanel* g_NIL_PANEL; __gshared Editor* g_NIL_ED = &g_nil_ed;
__gshared const Notification g_nil_notif; __gshared UIItem* g_UI_NIL_ITEM = &g_ui_nil_item;
__gshared Notification* g_NIL_NOTIF; __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 = { const Command NO_CMD = {
name: [], name: [],
@ -402,10 +407,24 @@ Command[21] CMD_LIST = [
}, },
]; ];
ref Ctx GetCtx() => g_ctx;
bool 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) if(ctx.focused_panel != ctx.base_panel)
{ {
DLLRemove(ctx.focused_panel.parent, ctx.focused_panel, g_NIL_PANEL); DLLRemove(ctx.focused_panel.parent, ctx.focused_panel, g_NIL_PANEL);
@ -456,38 +475,27 @@ ClosePanelCmd(Ctx* ctx)
} }
bool bool
SplitVertically(Ctx* ctx) SplitVertically(ref Ctx ctx)
{ {
AddPanel(ctx.focused_panel, A2D.X); AddPanel(ctx.focused_panel, A2D.X);
return true; return true;
} }
bool bool
SplitHorizontally(Ctx* ctx) SplitHorizontally(ref Ctx ctx)
{ {
AddPanel(ctx.focused_panel, A2D.Y); AddPanel(ctx.focused_panel, A2D.Y);
return true; return true;
} }
bool bool
NotImplementedCallback(Ctx* ctx) NotImplementedCallback(ref Ctx ctx)
{ {
Logf("Not yet implemented!"); Logf("Not yet implemented!");
return true; return true;
} }
bool bool Active(EditState state) => g_ctx.state == state;
CmdModeActive()
{
return g_ctx.state == ES.CmdPalette;
}
bool
Active(EditState state)
{
return g_ctx.state == state;
}
UIPanel* UIPanel*
MakePanel(UIPanel* parent = g_NIL_PANEL) MakePanel(UIPanel* parent = g_NIL_PANEL)
@ -511,7 +519,7 @@ Cycle(Inputs* inputs)
BeginUI(inputs); BeginUI(inputs);
Ctx* ctx = GetCtx(); ref Ctx ctx = GetCtx();
Panel(ctx, ctx.base_panel); Panel(ctx, ctx.base_panel);
@ -538,12 +546,7 @@ Focus(UIPanel* panel)
void void
InitCtx(PlatformWindow* window) InitCtx(PlatformWindow* window)
{ {
Ctx* ctx = &g_ctx; ref Ctx ctx = GetCtx();
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;
ctx.window = window; ctx.window = window;
ctx.arena = CreateArena(MB(2)); ctx.arena = CreateArena(MB(2));
@ -552,6 +555,8 @@ InitCtx(PlatformWindow* window)
ctx.cmd.exec_cmd_arena = CreateArena(MB(1)); ctx.cmd.exec_cmd_arena = CreateArena(MB(1));
ctx.timer = CreateTimer(); ctx.timer = CreateTimer();
ctx.free_panels = g_NIL_PANEL; ctx.free_panels = g_NIL_PANEL;
ctx.text_buffers = Alloc!(FlatBuffer)(ARRAY_COUNT_INCREMENT);
ctx.editors = Alloc!(Editor)(ARRAY_COUNT_INCREMENT);
InitUI(ctx); InitUI(ctx);
@ -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 void
SaveFile(Editor* ed, string file_name) SaveFile(Editor* ed, string file_name)
{ {
import core.stdc.stdio; 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) 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"); auto f = fopen(cast(char*)file_path.ptr, "wb");
if(f != null) if(f != null)
{ {
u64 tab_count; 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; tab_count += 1;
} }
} }
u64 tab_width = GetCtx().tab_width; 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); u8[] temp_buf = ScratchAlloc!(u8)(buf_size);
u64 buf_pos; 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) for(u64 j = 0; j < tab_width; j += 1)
{ {
@ -678,7 +633,7 @@ SaveFile(Editor* ed, string file_name)
} }
else 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 string
Str(TextInputBuffer text_buffer) Str(TextInputBuffer text_buffer)
{ {
@ -732,20 +653,48 @@ Str(TextInputBuffer text_buffer)
Editor* Editor*
CreateEditor() CreateEditor()
{ {
Editor* ed = Alloc!(Editor)(&g_ctx.arena); ref Ctx ctx = GetCtx();
ed.arena = CreateArena(MB(4));
ed.buf = CreateFlatBuffer([], []);
ed.editor_id = g_ctx.editor_id_incr++;
return ed; 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 editor;
} }
pragma(inline) void pragma(inline) void
InsertInputToBuf(Ctx* ctx, Editor* ed) InsertInputToBuf(ref Ctx ctx, Editor* ed)
{ {
if(ctx.icount > 0) if(ctx.icount > 0)
{ {
Insert(&ed.buf, ctx.input_buf, ctx.icount); Insert(ed, ctx.input_buf, ctx.icount);
ctx.icount = 0; ctx.icount = 0;
} }
} }
@ -753,12 +702,12 @@ InsertInputToBuf(Ctx* ctx, Editor* ed)
void void
ResetCtx(Editor* ed) ResetCtx(Editor* ed)
{ {
InsertInputToBuf(&g_ctx, ed); InsertInputToBuf(GetCtx(), ed);
ResetCtx(); ResetCtx();
} }
void void
ResetCmd(Ctx* ctx) ResetCmd(ref Ctx ctx)
{ {
ctx.cmd.text_input.length = 0; ctx.cmd.text_input.length = 0;
ctx.cmd.selected = 0; ctx.cmd.selected = 0;
@ -836,9 +785,8 @@ bool
HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focused) HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focused)
{ {
Editor* ed = p.ed; Editor* ed = p.ed;
Ctx* ctx = &g_ctx; ref Ctx ctx = GetCtx();
FlatBuffer* fb = &ed.buf; u64 initial_len = p.ed.length;
u64 initial_len = p.ed.buf.length;
u8[] cb_text; u8[] cb_text;
for(auto node = inputs.first; node != null; node = node.next) 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: case a, i:
{ {
if(key == a && Shift(md) && fb) if(key == a && Shift(md))
{ {
MoveToEOL(fb); MoveToEOL(ed);
} }
else if(key == a) else if(key == a)
{ {
Move(fb, Right, MD.None); Move(ed, Right, MD.None);
} }
else if(key == i && Shift(md)) else if(key == i && Shift(md))
{ {
MoveToSOL(fb); MoveToSOL(ed);
} }
ctx.state = ES.InputMode; ctx.state = ES.InputMode;
@ -930,11 +878,11 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse
} }
if(Shift(md)) if(Shift(md))
{ {
ToggleSelection(fb, SM.Line); ToggleSelection(ed, SM.Line);
} }
else else
{ {
ToggleSelection(fb, SM.Normal); ToggleSelection(ed, SM.Normal);
} }
} break; } break;
case c: case c:
@ -984,22 +932,22 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse
if(cb_text.length > 0) 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 void
SetOffset(Editor* ed, i64 adjust) 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) if(max_offset < 0)
{ {
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 bool
@ -1009,15 +957,15 @@ MoveCursor(Editor* ed, UIInput* ev)
switch(ev.key) with(Input) 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; default: break;
} }
if(taken) if(taken)
{ {
I64Vec2 pos = VecPos(&ed.buf); I64Vec2 pos = VecPos(ed);
i64 min = ed.line_offset+2; i64 min = ed.view_info.line_offset+2;
i64 max = clamp(ed.line_offset+ed.line_height-3, 0, ed.buf.line_count); i64 max = clamp(ed.view_info.line_offset+ed.line_height-3, 0, ed.line_count);
if(pos.y > max) if(pos.y > max)
{ {
SetOffset(ed, pos.y-max); SetOffset(ed, pos.y-max);
@ -1032,7 +980,7 @@ MoveCursor(Editor* ed, UIInput* ev)
} }
pragma(inline) void 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); ctx.input_buf[ctx.icount++] = InputToChar(input, modified);
} }
@ -1055,7 +1003,7 @@ CharCases()
} }
bool bool
HandleInputMode(Ctx* ctx, UIPanel* p, UIInput* ev) HandleInputMode(ref Ctx ctx, UIPanel* p, UIInput* ev)
{ {
bool taken; bool taken;
@ -1064,7 +1012,7 @@ HandleInputMode(Ctx* ctx, UIPanel* p, UIInput* ev)
mixin(CharCases()); mixin(CharCases());
case Input.Backspace: case Input.Backspace:
{ {
Backspace(&p.ed.buf); Backspace(p.ed);
taken = true; taken = true;
} break; } break;
case Input.Escape: case Input.Escape:
@ -1168,7 +1116,7 @@ StrContains(bool begins_with)(string str, string match)
} }
void 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; UIPanel* panel = ctx.focused_panel;
Editor* ed = panel.ed; Editor* ed = panel.ed;

View File

@ -1,5 +1,8 @@
import dlib; import dlib;
import dlib.alloc : Reset;
import editor;
import buffer; import buffer;
enum TokenStyle : u8 enum TokenStyle : u8
@ -399,28 +402,22 @@ struct Tokenizer
} }
bool bool
Nil(Token* tk) Nil(Token* token)
{ {
return tk == g_NIL_TOKEN || tk == null; return token == g_NIL_TOKEN || token == null;
}
void
SetBuffers(Tokenizer* tk, TokenStyle[] tokens)
{
tk.tokens = tokens;
} }
Tokenizer Tokenizer
CreateTokenizer(FlatBuffer* fb) CreateTokenizer(FlatBuffer* buffer)
{ {
Tokenizer tk = { Tokenizer tokenizer = {
arena: CreateArena(MB(4)), 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; 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) for(u64 i = 0; i < D_KEYWORDS.length; i += 1)
{ {
@ -438,132 +435,133 @@ CreateTokenizer(FlatBuffer* fb)
} }
} }
return tk; return tokenizer;
} }
void void
ResetTokenizer(Tokenizer* tk, u64 len) ResetTokenizer(Tokenizer* tokenizer, u64 length)
{ {
Reset(&tk.arena); Reset(&tokenizer.arena);
Free(tk.tokens); Free(tokenizer.tokens);
SetBuffers(tk, Alloc!(TS)(len)); tokenizer.tokens = Alloc!(TS)(length);
tk.pos = 0; tokenizer.pos = 0;
tk.first = tk.last = g_NIL_TOKEN; tokenizer.first = tokenizer.last = g_NIL_TOKEN;
} }
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; token.type = type;
t.start = start; token.start = tokenizer.pos;
t.end = end; token.end = tokenizer.pos+length;
DLLPush(tk, t, g_NIL_TOKEN); DLLPush(tokenizer, token, g_NIL_TOKEN);
return t; return token;
} }
u8 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 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); Reset(&tokenizer.arena);
tk.pos = 0; tokenizer.pos = 0;
tk.first = tk.last = g_NIL_TOKEN; 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'); bool alpha = (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
if(ch == ' ' || ch == '\t') 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; break;
} }
} }
t.end = tk.pos; token.end = tokenizer.pos;
} }
else if(ch == '\n') else if(ch == '\n')
{ {
Token* t = MakeToken(tk, TT.NewLine, tk.pos, tk.pos+1); Token* token = MakeToken(tokenizer, TT.NewLine, 1);
tk.pos += 1; tokenizer.pos += 1;
} }
else if(ch == 'r') else if(ch == 'r')
{ {
u8 next = Peek(fb); u8 next = Peek(buffer);
if(next == '"') if(next == '"')
{ {
tk.pos += 1; tokenizer.pos += 1;
ParseStr!('"')(fb); ParseStr!('"')(buffer);
} }
else else
{ {
ParseId(fb); ParseId(buffer);
} }
} }
else if(ch >= '0' && ch <= '9') else if(ch >= '0' && ch <= '9')
{ {
ParseNum(fb); ParseNum(buffer);
} }
else if(ch == 'P' || ch == 'E' || ch == 'e' || ch == 'p') 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')) if(next == '-' || next == '+' || (next >= '0' && next <= '9'))
{ {
ParseNum(fb); ParseNum(buffer);
} }
else else
{ {
ParseId(fb); ParseId(buffer);
} }
} }
else if(alpha || ch == '_') else if(alpha || ch == '_')
{ {
ParseId(fb); ParseId(buffer);
} }
else if(ch < 128 && D_STD_TOKEN[ch] != TT.None) else if(ch < 128 && D_STD_TOKEN[ch] != TT.None)
{ {
Token* t = MakeToken(tk, D_STD_TOKEN[ch], tk.pos, tk.pos+1); Token* token = MakeToken(tokenizer, D_STD_TOKEN[ch], 1);
tk.pos += 1; tokenizer.pos += 1;
} }
else if(ch < 128 && D_OP_TOKEN[ch] != TT.None) else if(ch < 128 && D_OP_TOKEN[ch] != TT.None)
{ {
Token* t = MakeToken(tk, D_OP_TOKEN[ch], tk.pos, tk.pos+1); Token* token = MakeToken(tokenizer, D_OP_TOKEN[ch], 1);
tk.pos += 1; tokenizer.pos += 1;
FixOpAssign(fb, t); FixOpAssign(buffer, token);
} }
else if(ch < 128 && D_STR_TOKEN[ch] != TT.None) else if(ch < 128 && D_STR_TOKEN[ch] != TT.None)
{ {
if(ch == '"') if(ch == '"')
{ {
ParseStr!('"')(fb); ParseStr!('"')(buffer);
} }
else if(ch == '`') else if(ch == '`')
{ {
ParseStr!('`')(fb); ParseStr!('`')(buffer);
} }
else else
{ {
ParseStr!('\'')(fb); ParseStr!('\'')(buffer);
} }
} }
else else
@ -572,108 +570,108 @@ TokenizeD(FlatBuffer* fb)
{ {
case '@': case '@':
{ {
Token* t = MakeToken(tk, TT.At, tk.pos, tk.pos+1); Token* token = MakeToken(tokenizer, TT.At, 1);
tk.pos += 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(CheckWhiteSpace(c)) break;
if(!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z')) break; if(!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z')) break;
} }
t.end = tk.pos; token.end = tokenizer.pos;
} break; } break;
case '.': 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; } break;
case '#': 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; } break;
case '/': 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 == '/') if(next == '/')
{ {
tk.pos += 1; tokenizer.pos += 1;
t.type = TT.Comment; 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; break;
} }
} }
t.end = tk.pos+1; token.end = tokenizer.pos+1;
} }
else if(next == '*') else if(next == '*')
{ {
tk.pos += 1; tokenizer.pos += 1;
t.type = TT.Comment; 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; break;
} }
} }
tk.pos += 1; tokenizer.pos += 1;
t.end = tk.pos; token.end = tokenizer.pos;
} }
else else
{ {
tk.pos += 1; tokenizer.pos += 1;
FixOpAssign(fb, t); FixOpAssign(buffer, token);
} }
} break; } break;
default: 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; break;
} }
} }
t.end = tk.pos; token.end = tokenizer.pos;
tk.pos += 1; tokenizer.pos += 1;
} break; } 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* prev = Prev(n);
Token* next = Next(n); Token* next = Next(n);
if(CheckFuncOrTemplateSig(fb, n)) if(CheckFuncOrTemplateSig(n))
{ {
continue; continue;
} }
@ -688,7 +686,7 @@ TokenizeD(FlatBuffer* fb)
else if(prev.type == TT.TypeKeyword && n.type == TT.Identifier) else if(prev.type == TT.TypeKeyword && n.type == TT.Identifier)
{ {
n.type = TT.Type; n.type = TT.Type;
CheckTypeDeclaration(fb, n); CheckTypeDeclaration(n);
continue; continue;
} }
else if(prev.type == TT.EnumKeyword && n.type == TT.Identifier) else if(prev.type == TT.EnumKeyword && n.type == TT.Identifier)
@ -715,9 +713,9 @@ TokenizeD(FlatBuffer* fb)
CheckVarDeclaration(n); 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 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) if(prev.type == TT.LeftBrace || prev.type == TT.Semicolon)
{ {
tk.type = TT.Type; next_token.type = TT.Type;
} }
} }
} }
bool bool
CheckFuncOrTemplateSig(FlatBuffer* fb, Token* token) CheckFuncOrTemplateSig(Token* token)
{ {
bool found = false; bool found = false;
@ -825,18 +823,18 @@ CheckFuncOrTemplateSig(FlatBuffer* fb, Token* token)
} }
u8[] 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* Token*
Prev(types...)(Token* t) Prev(types...)(Token* token)
{ {
Token* res = g_NIL_TOKEN; Token* res = g_NIL_TOKEN;
PrevMain: 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) 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); alias PrevFnToken = Prev!(TT.Identifier, TT.LeftParen, TT.RightParen, TT.Comma, TT.Keyword, TT.Dot, TT.Exclamation, TT.Type);
Token* Token*
Next(types...)(Token* t) Next(types...)(Token* token)
{ {
Token* res = g_NIL_TOKEN; Token* res = g_NIL_TOKEN;
NextMain: 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) 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); alias NextFnToken = Next!(TT.Identifier, TT.LeftParen, TT.RightParen, TT.Comma, TT.Keyword, TT.Dot, TT.Exclamation, TT.Type);
void 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); Token* token = Alloc!(Token)(&tokenizer.arena);
t.type = TT.Number; token.type = TT.Number;
t.start = tk.pos; token.start = tokenizer.pos;
bool first = true; 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)) if(ch != '_' && ch != '.' && !(ch >= '0' && ch <= '9') && ch != 'x' && ch != 'X' && !((ch == '-' || ch == '+') && first))
{ {
@ -922,76 +920,76 @@ ParseNum(FlatBuffer* fb)
first = false; 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') if(ch != 'l' && ch != 'u' && ch != 'U' && ch != 'L' && ch != 'f' && ch != 'F')
{ {
break; 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 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 == '"'); 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]; token.type = D_STR_TOKEN[str_ch];
t.start = tk.pos; token.start = tokenizer.pos;
static if(str_ch == '`') tk.pos += 1; static if(str_ch == '`') tokenizer.pos += 1;
bool ignore = str_ch != '`'; 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; tokenizer.pos += 1;
t.end = tk.pos; token.end = tokenizer.pos;
DLLPush(tk, t, g_NIL_TOKEN); DLLPush(tokenizer, token, g_NIL_TOKEN);
} }
void void
ParseId(FlatBuffer* fb) ParseId(T)(T* buffer) if(is(T == Editor) || is(T == FlatBuffer))
{ {
Tokenizer* tk = &fb.tk; Tokenizer* tokenizer = &buffer.tokenizer;
Token* t = MakeToken(tk, TT.Identifier, tk.pos, tk.pos+1); 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')) if(!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && ch != '.' && ch != '_' && !(ch >= '0' && ch <= '9'))
{ {
t.end = tk.pos; token.end = tokenizer.pos;
break; 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) if(ch < D_KEYWORDS.length && D_KEYWORDS[ch] != null && D_KEYWORDS[ch].length > 0)
{ {
bool found = false; 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]) foreach(ref k; D_TYPES[ch])
{ {
if(id == k) if(id == k)
{ {
t.type = TT.Type; token.type = TT.Type;
found = true; found = true;
break; break;
} }
@ -1005,19 +1003,19 @@ ParseId(FlatBuffer* fb)
{ {
if(k == r"import") if(k == r"import")
{ {
t.type = TT.Import; token.type = TT.Import;
} }
else if(k == r"class" || k == r"struct") else if(k == r"class" || k == r"struct")
{ {
t.type = TT.TypeKeyword; token.type = TT.TypeKeyword;
} }
else if(k == r"enum") else if(k == r"enum")
{ {
t.type = TT.EnumKeyword; token.type = TT.EnumKeyword;
} }
else else
{ {
t.type = TT.Keyword; token.type = TT.Keyword;
} }
break; 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 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( if(
str == "/=" || str == "/=" ||
str == "+=" || str == "+=" ||
@ -1044,8 +1042,8 @@ FixOpAssign(FlatBuffer* fb, Token* t)
str == "!=" str == "!="
) )
{ {
fb.tk.pos += 1; buffer.tokenizer.pos += 1;
t.end += 1; token.end += 1;
} }
} }
} }
@ -1072,11 +1070,11 @@ CheckWhiteSpace(u8 ch)
} }
void 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); bool white_space = CheckWhiteSpace(ch);
@ -1085,7 +1083,7 @@ SkipWhiteSpace(FlatBuffer* fb)
break; break;
} }
fb.tk.pos += 1; editor.tokenizer.pos += 1;
} }
} }

View File

@ -1,6 +1,7 @@
import dlib; import dlib;
import dlib.util : HTPush = Push; import dlib.util : HTPush = Push;
import dlib.math : Clamp; import dlib.math : Clamp;
import dlib.alloc : Reset;
import vulkan; import vulkan;
import vulkan : RendererGetExtent = GetExtent; 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[] VERTEX_BYTES = cast(u8[])import("gui.vert.spv");
u8[] FRAGMENT_BYTES = cast(u8[])import("gui.frag.spv"); u8[] FRAGMENT_BYTES = cast(u8[])import("gui.frag.spv");
const SEP_FLAGS = UIF.Drag|UIF.Priority|UIF.TargetLeniency; const SEP_FLAGS = UIF.Drag | UIF.Priority | UIF.TargetLeniency;
const PANEL_FLAGS = UIF.Click|UIF.Drag; const PANEL_FLAGS = UIF.Click | UIF.Drag;
const UI_COUNT = 5000; const UI_COUNT = 5000;
@ -322,10 +323,27 @@ Attribute[10] attributes = [
{ binding: 0, location: 9, format: FMT.R_U32, offset: Vertex.has_texture.offsetof }, { binding: 0, location: 9, format: FMT.R_U32, offset: Vertex.has_texture.offsetof },
]; ];
union Rect struct Rect
{ {
union
{
Vec2[2] v; Vec2[2] v;
struct { Vec2 p0, p1; alias p0 pos; }; 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; alias UIHash = u64;
@ -341,53 +359,11 @@ struct UIKey
bool opCast(T)() if(is(T == bool)) => this.hash != 0; 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 KeyType(T) = (StringType!(T) || is(T == UIKey) || is(T == const(UIKey)));
enum bool ItemAndKeyType(T) = (KeyType!(T) || is(T == UIItem*)); enum bool ItemAndKeyType(T) = (KeyType!(T) || is(T == UIItem*));
void void
InitUI(Ctx* ctx) InitUI(ref Ctx ctx)
{ {
version(ENABLE_RENDERER) version(ENABLE_RENDERER)
{ {
@ -445,11 +421,6 @@ InitUI(Ctx* ctx)
ctx.buffers[i].idx[0 .. $] = [0, 1, 2, 2, 1, 3]; ctx.buffers[i].idx[0 .. $] = [0, 1, 2, 2, 1, 3];
ctx.desc_sets[i] = AllocDescSet(ctx.desc_set_layout); ctx.desc_sets[i] = AllocDescSet(ctx.desc_set_layout);
ctx.str_arenas[i] = CreateArena(MB(1)); 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;
} }
GfxPipelineInfo ui_info = { GfxPipelineInfo ui_info = {
@ -551,15 +522,15 @@ PushFree(string next_member = "free_next", T)(T** top, T* node)
} }
f32 f32
GetLineHeight(u32 size) GetLineHeight(u32 size) => GetFontSet(size).line_height;
{
return GetFontSet(size).line_height;
}
FontSet* FontSet*
GetFontSet(u32 size) GetFontSet(T)(T font_set) if(is(T == FontSet*)) => font_set;
FontSet*
GetFontSet(T)(T size) if(is(T: u32))
{ {
Ctx* ctx = GetCtx(); ref Ctx ctx = GetCtx();
FontSet* fs = null; FontSet* fs = null;
for(u64 i = 0; i < ctx.font_sets_used; i += 1) for(u64 i = 0; i < ctx.font_sets_used; i += 1)
@ -590,30 +561,30 @@ GetFontSet(u32 size)
void void
LoadFontSet() LoadFontSet()
{ {
Ctx* ctx = GetCtx(); ref Ctx ctx = GetCtx();
u64 fi = ctx.f_idx;
for(u64 i = 0; i < ctx.font_sets_used; i += 1) 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) if(!fs.texture_loaded)
{ {
Transfer!(true)(&ctx.font_descs[i], fs.atlas.data); Transfer!(true)(&ctx.font_descs[i], fs.atlas.data);
fs.texture_loaded = true; fs.texture_loaded = true;
} }
if(!fs.descriptor_written[fi]) if(!descriptor_written)
{ {
Write(ctx.desc_sets[fi], ctx.font_descs); Write(ctx.desc_set, ctx.font_descs);
fs.descriptor_written[fi] = true; descriptor_written = true;
} }
} }
ctx.fonts_to_load[fi] = false; ctx.fonts_to_load[ctx.frame_index] = false;
} }
void void
Scissor(Ctx* ctx, Rect rect, Style* style) Scissor(ref Ctx ctx, Rect rect, Style* style)
{ {
DrawUI(ctx); DrawUI(ctx);
@ -630,14 +601,14 @@ Scissor(Ctx* ctx, Rect rect, Style* style)
} }
void void
EndScissor(Ctx* ctx) EndScissor(ref Ctx ctx)
{ {
DrawUI(ctx); DrawUI(ctx);
ResetScissor(); ResetScissor();
} }
void void
Panel(Ctx* ctx, UIPanel* panel) Panel(ref Ctx ctx, UIPanel* panel)
{ {
panel.item = MakeItem!(PANEL_FLAGS)("###panel_%s", panel.id); panel.item = MakeItem!(PANEL_FLAGS)("###panel_%s", panel.id);
Axis2D p_axis = Nil(panel.parent) ? A2D.X : panel.parent.axis; 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.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); f32 offset = -(panel.item.scroll_offset.y%fs.line_height);
u64 start_ln = cast(u64)(floor(panel.scroll_offset.y/fs.line_height)); u64 start_ln = cast(u64)(floor(panel.scroll_offset.y/fs.line_height));
const f32 PAD = 4.0f; const f32 PAD = 4.0f;
// Line counter // 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; f32 lc_width = PAD*2.0 + cast(f32)(lc_chars)*fs.max_advance;
Style style = PANEL_STYLE; Style style = PANEL_STYLE;
@ -709,7 +680,7 @@ Panel(Ctx* ctx, UIPanel* panel)
f32 panel_height = Size!(A2D.Y)(line_count_rect); f32 panel_height = Size!(A2D.Y)(line_count_rect);
panel.ed.line_height = cast(i64)ceil(panel_height/fs.line_height); 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) 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); text_rect = Pad(text_view_rect, PAD);
I64Vec2 cursor_coords = VecPos(&panel.ed.buf); I64Vec2 cursor_coords = VecPos(panel.ed);
LineBuffer* current_lbuf = GetLine(&panel.ed.buf, cursor_coords.y); LineBuffer* current_lbuf = GetLine(panel.ed, cursor_coords.y);
UIItem* cursor = MakeItem("###cursor_%s", panel.id); UIItem* cursor = MakeItem("###cursor_%s", panel.id);
if(ctx.focused_panel == panel) 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.x = Active(ES.InputMode) ? 2.0 : fs.max_advance;
cursor.size.y = fs.line_height; cursor.size.y = fs.line_height;
@ -760,7 +731,7 @@ Panel(Ctx* ctx, UIPanel* panel)
{ {
if(Active(ES.InputMode) && panel.move_text_with_cursor) 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) if(i == cursor_coords.y)
{ {
@ -799,7 +770,7 @@ Panel(Ctx* ctx, UIPanel* panel)
DrawLines(ctx, panel, start_ln, max_ln, text_rect, fs); DrawLines(ctx, panel, start_ln, max_ln, text_rect, fs);
} }
ResetBuffer(&panel.ed.buf); ResetBuffer(panel.ed);
EndScissor(ctx); EndScissor(ctx);
DrawBorder(ctx, text_view_rect, &style); DrawBorder(ctx, text_view_rect, &style);
@ -844,10 +815,10 @@ Panel(Ctx* ctx, UIPanel* panel)
} }
void 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; 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) static if(hl)
{ {
@ -873,7 +844,7 @@ struct SearchWindowCtx(T)
void void
SearchInputWindow(T)(string hash_text, SearchWindowCtx!(T)* window_ctx, bool ready_cond) if(is(T == Command) || is(T == string)) 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(); Vec2 extent = GetExtent();
f32 x = extent.x * 0.1; f32 x = extent.x * 0.1;
f32 y = extent.y * 0.2; 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; Rect opt_rect = inner_rect;
opt_rect.p0.y -= opt_start_offset; 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) 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); Rect[2] opt_rects = Split(opt_rect, full_opt_height, A2D.Y);
@ -1058,7 +1029,7 @@ SearchInputWindow(T)(string hash_text, SearchWindowCtx!(T)* window_ctx, bool rea
} }
bool bool
SaveFileWindow(Ctx* ctx) SaveFileWindow(ref Ctx ctx)
{ {
bool exit; bool exit;
Editor* ed = ctx.focused_panel.ed; Editor* ed = ctx.focused_panel.ed;
@ -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.data[0 .. ed.file_name.length] = Arr!(u8)(ed.file_name[0 .. $]);
ctx.cmd.exec_cmd_input.length = ed.file_name.length; ctx.cmd.exec_cmd_input.length = ed.file_name.length;
init = true;
} }
const PAD = 4.0f; const PAD = 4.0f;
@ -1133,19 +1103,16 @@ SaveFileWindow(Ctx* ctx)
} }
} }
if(exit) init = !exit;
{
init = false;
}
return exit; return exit;
} }
bool bool
OpenFileWindow(Ctx* ctx) OpenFileWindow(ref Ctx ctx)
{ {
bool exit; bool exit;
CmdPalette* cmd = &ctx.cmd; ref CmdPalette cmd = ctx.cmd;
if(!cmd.exec_cmd_opts.length && !cmd.exec_cmd_input.length) if(!cmd.exec_cmd_opts.length && !cmd.exec_cmd_input.length)
{ {
@ -1218,9 +1185,9 @@ OpenFileWindow(Ctx* ctx)
} }
void void
CommandPalette(Ctx* ctx) CommandPalette(ref Ctx ctx)
{ {
CmdPalette* cmd = &ctx.cmd; ref CmdPalette cmd = ctx.cmd;
bool enter_hit, buffer_changed, selection_changed; bool enter_hit, buffer_changed, selection_changed;
if(ctx.state == ES.CmdPalette) if(ctx.state == ES.CmdPalette)
@ -1417,15 +1384,9 @@ CreatePanel(Editor* ed = null)
{ {
bool allocated; bool allocated;
p = GetOrAlloc(&g_ctx.arena, &g_ctx.free_panels, g_NIL_PANEL, &allocated); p = GetOrAlloc(&g_ctx.arena, &g_ctx.free_panels, g_NIL_PANEL, &allocated);
if(allocated)
{
p.id = panel_id++; p.id = panel_id++;
}
if(!p.ed)
{
p.ed = CreateEditor(); p.ed = CreateEditor();
} }
}
p.item = MakeItem!(PANEL_FLAGS)("###panel_%s", p.id); p.item = MakeItem!(PANEL_FLAGS)("###panel_%s", p.id);
p.pct = 1.0; p.pct = 1.0;
@ -1500,7 +1461,7 @@ Hovered(bool current_frame, T, U)(T param, U* ptr, U index)
bool bool
Hovered(bool current_frame, T)(T param) Hovered(bool current_frame, T)(T param)
{ {
Ctx* ctx = GetCtx(); ref Ctx ctx = GetCtx();
bool result; bool result;
UIKey key = mixin(AssignKey!(T, param)); UIKey key = mixin(AssignKey!(T, param));
@ -1521,7 +1482,7 @@ Hovered(bool current_frame, T)(T param)
} }
void void
PushUIEvent(Ctx* ctx, UIInput input) PushUIEvent(ref Ctx ctx, UIInput input)
{ {
UIInput* ev = Alloc!(UIInput)(&ctx.temp_arena); UIInput* ev = Alloc!(UIInput)(&ctx.temp_arena);
*ev = input; *ev = input;
@ -1530,7 +1491,7 @@ PushUIEvent(Ctx* ctx, UIInput input)
} }
void void
DrawUI(Ctx* ctx, u32 atlas_index) DrawUI(ref Ctx ctx, u32 atlas_index)
{ {
if(ctx.pc.atlas_index != atlas_index) if(ctx.pc.atlas_index != atlas_index)
{ {
@ -1541,33 +1502,17 @@ DrawUI(Ctx* ctx, u32 atlas_index)
} }
void void
DrawSlug(Ctx* ctx) DrawUI(ref Ctx ctx)
{ {
version(ENABLE_RENDERER) version(ENABLE_RENDERER)
{ {
// TODO: fix this ref UIBuffer buffer = ctx.buffers[ctx.frame_index];
SlugBuffer* buffer = ctx.slug_buffers.ptr + ctx.f_idx; if(buffer.vtx_offset != buffer.count)
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; u32 count = buffer.count - buffer.vtx_offset;
if(b.vtx_offset != b.count) BindBuffers(&buffer.m_idx, &buffer.m_vtx);
{ DrawIndexed(6, count, 0, 0, buffer.vtx_offset);
u32 count = b.count - b.vtx_offset; buffer.vtx_offset += count;
BindBuffers(&b.m_idx, &b.m_vtx);
DrawIndexed(6, count, 0, 0, b.vtx_offset);
b.vtx_offset += count;
} }
} }
} }
@ -1575,10 +1520,10 @@ DrawUI(Ctx* ctx)
void void
BeginUI(Inputs* inputs) BeginUI(Inputs* inputs)
{ {
Ctx* ctx = GetCtx(); ref Ctx ctx = GetCtx();
Arena* a = &ctx.temp_arena; ref Arena arena = ctx.temp_arena;
Reset(a); Reset(&arena);
// Convert Inputs // Convert Inputs
ctx.events.first = ctx.events.last = null; ctx.events.first = ctx.events.last = null;
@ -1687,11 +1632,11 @@ BeginUI(Inputs* inputs)
// Ctx state // Ctx state
ctx.frame = next_frame; ctx.frame = next_frame;
ctx.f_idx = ctx.frame%FRAME_OVERLAP; ctx.frame_index = ctx.frame%FRAME_OVERLAP;
ctx.inputs = inputs; 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)); assert(!mouse_moved || ZeroKey(ctx.hover_key) || (ctx.frame == ctx.last_hover_frame));
@ -1704,7 +1649,7 @@ BeginUI(Inputs* inputs)
{ {
BeginFrame(); BeginFrame();
if(ctx.fonts_to_load[ctx.f_idx]) if(ctx.fonts_to_load[ctx.frame_index])
{ {
LoadFontSet(); LoadFontSet();
} }
@ -1714,22 +1659,19 @@ BeginUI(Inputs* inputs)
SetStencilTest(false); SetStencilTest(false);
PushConstants(ctx.pipeline, &ctx.pc); 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; UIBuffer* buffer = ctx.buffers.ptr + ctx.frame_index;
SlugBuffer* slug_buffer = ctx.slug_buffers.ptr + ctx.f_idx;
memset(buffer.vtx.ptr, 0, Vertex.sizeof * buffer.count); memset(buffer.vtx.ptr, 0, Vertex.sizeof * buffer.count);
memset(slug_buffer.vertices.ptr, 0, SlugVertex.sizeof * slug_buffer.quad_offset);
buffer.count = 0; buffer.count = 0;
buffer.vtx_offset = 0; buffer.vtx_offset = 0;
slug_buffer.quad_offset = 0;
} }
UIKey UIKey
FindHoverKey(bool priority)(Ctx* ctx) FindHoverKey(bool priority)(ref Ctx ctx)
{ {
UIKey hovered; UIKey hovered;
@ -1762,11 +1704,11 @@ FindHoverKey(bool priority)(Ctx* ctx)
void void
EndUI() 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; static FontSet* fs;
if(!fs) if(!fs)
{ {
@ -1814,7 +1756,7 @@ SetNil(Args...)(Args args)
{ {
static if(is(typeof(Args[i]) == UIItem**)) static if(is(typeof(Args[i]) == UIItem**))
{ {
*args[i] = g_UI_NIL; *args[i] = g_UI_NIL_ITEM;
} }
else else
{ {
@ -1824,7 +1766,7 @@ SetNil(Args...)(Args args)
} }
void 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_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); 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 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.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)); 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 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); 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 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; Vec4 col = style.border_col;
AnimateHot(hot_t, style.border_hl_col, &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 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; Vec4 col = style.col;
AnimateHot(hot_t, style.hl_col, &col); AnimateHot(hot_t, style.hl_col, &col);
@ -1955,18 +1897,10 @@ enum TextAlign
} alias TA = TextAlign; } alias TA = TextAlign;
void 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); FontSet* fs = GetFontSet(text_size_param);
}
else static assert(false, "invalid input parameter, V must be FontSet* or u32");
string text = Str(text_param); string text = Str(text_param);
DrawUI(ctx, fs.index); DrawUI(ctx, fs.index);
@ -2031,7 +1965,7 @@ InvertCol(Vec4 col)
} }
void 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); DrawUI(ctx);
@ -2050,7 +1984,10 @@ BeginScissor(Ctx* ctx, UIItem* item, bool scissor_x = true, bool scissor_y = tru
Vec2 Vec2
GetExtent() GetExtent()
{ {
version(ENABLE_RENDERER) return Vec2(RendererGetExtent()); else return Vec2(1280, 720); version(ENABLE_RENDERER)
return Vec2(RendererGetExtent());
else
return Vec2(1280, 720);
} }
template template
@ -2187,10 +2124,10 @@ ZeroKey(T)(T param) if(is(T == UIItem*) || is(T == UIKey))
} }
UIItem* UIItem*
NewItem(Ctx* ctx) NewItem(ref Ctx ctx)
{ {
bool allocated; 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* 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); return MakeItem(key, flags);
} }
@ -2213,7 +2150,7 @@ pragma(inline) UIItem*
MakeItem(T)(T k, UIFlags flags = UIF.None) if(KeyType!(T)) MakeItem(T)(T k, UIFlags flags = UIF.None) if(KeyType!(T))
{ {
UIKey key = mixin(AssignKey!(T, k)); UIKey key = mixin(AssignKey!(T, k));
Ctx* ctx = GetCtx(); ref Ctx ctx = GetCtx();
UIItem* item; UIItem* item;
Result!(UIItem*) res = ctx.items[key.hash]; Result!(UIItem*) res = ctx.items[key.hash];
@ -2309,14 +2246,7 @@ SetHot(UIItem* item, bool hot)
f32 f32
CalcTextWidth(T, U)(T text, U param) if((is(T == string) || StringType!T) && (is(U: u32) || is(U == FontSet*) )) 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)) 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) if(glyph)
{ {
Ctx* ctx = GetCtx(); ref Ctx ctx = GetCtx();
Vertex* v = null; Vertex* v = null;
f32 advance = glyph.advance; 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* pragma(inline) Vertex*
GetVertex(Ctx* ctx) GetVertex(ref Ctx ctx)
{ {
assert(ctx.buffers[ctx.f_idx].count < VERTEX_MAX_COUNT); assert(ctx.buffers[ctx.frame_index].count < VERTEX_MAX_COUNT);
return ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count++; return ctx.buffers[ctx.frame_index].vtx.ptr + ctx.buffers[ctx.frame_index].count++;
} }
bool bool
Nil(T)(T item) 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 == UIInput*)) return item == null || item == g_UI_NIL_INPUT;
else static if(is(T == UIPanel*)) return item == null || item == g_NIL_PANEL; else static if(is(T == UIPanel*)) return item == null || item == g_NIL_PANEL;
else static assert(false, "Invalid nil type checked"); else static assert(false, "Invalid nil type checked");
} }
bool 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)) 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 bool
Clicked(Ctx* ctx, UIItem* item) Clicked(ref Ctx ctx, UIItem* item)
{ {
bool result; bool result;
@ -2550,7 +2480,7 @@ OklabToSRGB(Vec4 v)
string string
EdScratchf(Args...)(string fmt, Args args) 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)); return Str(sformat(buf, fmt, args));
} }