diff --git a/assets/gui.frag.spv b/assets/gui.frag.spv index de3dd14..339a727 100644 Binary files a/assets/gui.frag.spv and b/assets/gui.frag.spv differ diff --git a/assets/gui.vert.spv b/assets/gui.vert.spv index 67ca878..d5ad7a1 100644 Binary files a/assets/gui.vert.spv and b/assets/gui.vert.spv differ diff --git a/src/editor/buffer.d b/src/editor/buffer.d index ebfa545..ced8f4c 100644 --- a/src/editor/buffer.d +++ b/src/editor/buffer.d @@ -12,25 +12,27 @@ struct FlatBuffer Arena arena; Arena ls_arena; LineBuffers linebufs; + BufferInfo info; u8[] file_name; - - u8[] _buf; - u8* pbuf; + u8[] data; u64 length; Line[] lines; - u64 line_count; - i64 pos; i64 col_pos; - - I64Vec2 sel; SelectMode sel_mode; - f32 view_width; - bool dirty; + + alias info this; +} + +struct BufferInfo +{ + u64 line_count; + I64Vec2 selection; + IVec2 position; } enum SelectMode @@ -55,9 +57,6 @@ struct LineBuffers Arena arena; LineBuffer* first; LineBuffer* last; - u64 count; - u64 start; - u64 end; } struct LineBuffer @@ -142,30 +141,29 @@ Init(FlatBuffer* fb, u8[] data, u8[] file_name) fb.file_name = file_name; fb.line_count = CountLF(data); fb.length = data.length; - fb.sel = -1; + fb.selection = -1; fb.sel_mode = SM.None; fb.linebufs = CreateLineBuffers(MB(1)); SetBuffers(fb, buf); - MemCpy(fb.pbuf, data.ptr, data.length); + MemCpy(fb.data.ptr, data.ptr, data.length); } void SetBuffers(FlatBuffer* fb, u8[] data) { - fb._buf = data; - fb.pbuf = fb._buf.ptr+BUF_START; + fb.data = data; } void Change(FlatBuffer* fb, u8[] data, u8[] file_name) { - Free(fb._buf); + Free(fb.data); Reset(&fb.linebufs.arena); Init(fb, data, file_name); - ResetTokenizer(&fb.tk, fb._buf.length); + ResetTokenizer(&fb.tk, fb.data.length); Fix(fb); } @@ -182,14 +180,14 @@ CountLF(u8[] data) } pragma(inline) bool -ScanLineRightBrace(u8* pbuf, u64 start, u64 len) +ScanLineRightBrace(u8* data, u64 start, u64 len) { bool result; for(u64 i = start; i < len; i += 1) { - if(pbuf[i] == '\t' || pbuf[i] == ' ') continue; + if(data[i] == '\t' || data[i] == ' ') continue; - if(pbuf[i] == '}' || pbuf[i] == ']' || pbuf[i] == ')') + if(data[i] == '}' || data[i] == ']' || data[i] == ')') { result = true; break; @@ -216,7 +214,7 @@ Fix(FlatBuffer* fb) u64 ls_idx = 1; for(u64 i = 0; i < length; i += 1) { - if(pbuf[i] == '{' || pbuf[i] == '(' || pbuf[i] == '[') + if(data[i] == '{' || data[i] == '(' || data[i] == '[') { if(pending_level > 0) { @@ -228,7 +226,7 @@ Fix(FlatBuffer* fb) } } - else if(pbuf[i] == '}' || pbuf[i] == ')' || pbuf[i] == ']') + else if(data[i] == '}' || data[i] == ')' || data[i] == ']') { if(ignore > 0) { @@ -248,7 +246,7 @@ Fix(FlatBuffer* fb) } } - if(pbuf[i] == '\n') + if(data[i] == '\n') { level += pending_level; pending_level = 0; @@ -284,10 +282,10 @@ CreateLineBuffers(u64 arena_size) void Insert(FlatBuffer* fb, u8[] insert, u64 length, u64 pos) { - if(fb.length + length > fb._buf.length-SPACING) + if(fb.length + length > fb.data.length-SPACING) { - SetBuffers(&fb.tk, Realloc(fb.tk._tokens, fb._buf.length*2)); - SetBuffers(fb, Realloc(fb._buf, fb._buf.length*2)); + SetBuffers(&fb.tk, Realloc(fb.tk.tokens, fb.data.length*2)); + SetBuffers(fb, Realloc(fb.data, fb.data.length*2)); } u64 new_lines; @@ -311,8 +309,8 @@ Insert(FlatBuffer* fb, u8[] insert, u64 length, u64 pos) if(new_ch == '\n' && pos > 0) { - u8 l = fb.pbuf[pos-1]; - u8 r = fb.pbuf[pos]; + u8 l = fb.data[pos-1]; + u8 r = fb.data[pos]; bool expand = (l == '(' && r == ')') || (l == '{' && r == '}') || (l == '[' && r == ']'); u32 level = LevelFromPos(fb, pos) + u32(expand); @@ -343,11 +341,11 @@ Insert(FlatBuffer* fb, u8[] insert, u64 length, u64 pos) u64 temp_len = fb.length-pos; - u8[] temp = Alloc!(u8)(&fb.arena, fb.pbuf[pos .. pos+temp_len]); + u8[] temp = Alloc!(u8)(&fb.arena, fb.data[pos .. pos+temp_len]); - fb.pbuf[pos .. pos+length] = insert[0 .. length]; + fb.data[pos .. pos+length] = insert[0 .. length]; pos += length; - fb.pbuf[pos .. pos+temp_len] = temp[0 .. temp_len]; + fb.data[pos .. pos+temp_len] = temp[0 .. temp_len]; fb.length += length; @@ -378,19 +376,19 @@ StartSelection(FlatBuffer* fb, SelectMode mode) if(mode == SM.Normal) { - fb.sel = fb.pos; + fb.selection = fb.pos; } else if(mode == SM.Line) { - fb.sel = CurrentLine(fb); + fb.selection = CurrentLine(fb); } } void EndSelection(FlatBuffer* fb) { - fb.sel = -1; - fb.sel_mode = SM.None; + fb.selection = -1; + fb.sel_mode = SM.None; } void @@ -454,13 +452,6 @@ LineLength(FlatBuffer* fb, u64 line) return fb.lines[line].length; } -void -StartLineBuffer(FlatBuffer* fb, f32 view_width) -{ - Reset(&fb.linebufs.arena); - fb.view_width = view_width; -} - LineBuffer* GetLine(FlatBuffer* fb, u64 line) { @@ -479,9 +470,8 @@ SliceLineBuffer(FlatBuffer* fb, Line* ls) { LineBuffer* lbuf = Alloc!(LineBuffer)(&fb.linebufs.arena); - lbuf.text = fb.pbuf[ls.pos .. ls.pos+ls.length]; - lbuf.style = fb.tk.ptokens[ls.pos .. ls.pos+ls.length]; - fb.linebufs.count += 1; + lbuf.text = fb.data[ls.pos .. ls.pos+ls.length]; + lbuf.style = fb.tk.tokens[ls.pos .. ls.pos+ls.length]; return lbuf; } @@ -489,7 +479,7 @@ SliceLineBuffer(FlatBuffer* fb, Line* ls) void MoveToEOL(FlatBuffer* fb) { - if(fb.pbuf[fb.pos] != '\n') + if(fb.data[fb.pos] != '\n') { for(u64 i = 0; i < fb.lines.length; i += 1) { @@ -505,7 +495,7 @@ MoveToEOL(FlatBuffer* fb) void MoveToSOL(FlatBuffer* fb) { - if(fb.pos != 0 && fb.pbuf[fb.pos-1] != '\n') + if(fb.pos != 0 && fb.data[fb.pos-1] != '\n') { for(u64 i = 0; i < fb.lines.length; i += 1) { @@ -577,7 +567,7 @@ MoveToEmptyLine(bool up)(FlatBuffer* fb) break; } - ch = fb.pbuf[i]; + ch = fb.data[i]; } static if(up) @@ -588,10 +578,10 @@ MoveToEmptyLine(bool up)(FlatBuffer* fb) break; } - ch = fb.pbuf[i-1]; + ch = fb.data[i-1]; } - if(started && !CheckWhiteSpace(fb.pbuf[i])) + if(started && !CheckWhiteSpace(fb.data[i])) { started = false; } @@ -674,8 +664,8 @@ MoveToWordEdge(bool forward)(FlatBuffer* fb) if((forward && fb.pos < fb.length-1) || (!forward && fb.pos > 0)) { - ChType type = GetChType(fb.pbuf[fb.pos]); - if(type != GetChType(fb.pbuf[fb.pos+step])) + ChType type = GetChType(fb.data[fb.pos]); + if(type != GetChType(fb.data[fb.pos+step])) { fb.pos += step; } @@ -683,11 +673,11 @@ MoveToWordEdge(bool forward)(FlatBuffer* fb) { static if(forward) { - u8 next = i < fb.length-1 ? fb.pbuf[i+1] : 0; + u8 next = i < fb.length-1 ? fb.data[i+1] : 0; } else { - u8 next = i > 1 ? fb.pbuf[i-1] : 0; + u8 next = i > 1 ? fb.data[i-1] : 0; } static if(forward) if(i == fb.length-2) @@ -712,7 +702,7 @@ MoveToWordEdge(bool forward)(FlatBuffer* fb) } } - while(CheckWhiteSpace(fb.pbuf[fb.pos])) + while(CheckWhiteSpace(fb.data[fb.pos])) { bool exit = forward ? fb.pos == fb.length-1 : fb.pos == 0; if(exit) break; @@ -725,7 +715,7 @@ MoveToWordEdge(bool forward)(FlatBuffer* fb) void MoveToNextWord(bool forward)(FlatBuffer* fb) { - ChType type = GetChType(fb.pbuf[fb.pos]); + ChType type = GetChType(fb.data[fb.pos]); bool hit_ws; u64 step = forward ? 1 : -1; @@ -743,7 +733,7 @@ MoveToNextWord(bool forward)(FlatBuffer* fb) break; } - u8 ch = fb.pbuf[i]; + u8 ch = fb.data[i]; if(CheckWhiteSpace(ch)) { @@ -847,7 +837,7 @@ Move(FlatBuffer* fb, Input key, Modifier md) } break; case Left: { - if(fb.pos > 0 && fb.pbuf[fb.pos-1] != '\n') + if(fb.pos > 0 && fb.data[fb.pos-1] != '\n') { fb.pos -= 1; taken = true; @@ -855,7 +845,7 @@ Move(FlatBuffer* fb, Input key, Modifier md) } break; case Right: { - if(fb.pos < fb.length && fb.pbuf[fb.pos] != '\n') + if(fb.pos < fb.length && fb.data[fb.pos] != '\n') { fb.pos += 1; taken = true; @@ -874,7 +864,7 @@ Move(FlatBuffer* fb, Input key, Modifier md) UpdateSelection(fb); - Logf("selection %s", fb.sel.v); + Logf("selection %s", fb.selection.v); return taken; } @@ -884,12 +874,12 @@ UpdateSelection(FlatBuffer* fb) { if(fb.sel_mode == SM.Normal) { - fb.sel.y = fb.pos; + fb.selection.y = fb.pos; } if(fb.sel_mode == SM.Line) { - fb.sel.y = CurrentLine(fb); + fb.selection.y = CurrentLine(fb); } } @@ -911,7 +901,7 @@ Delete(FlatBuffer* fb, u64 length, u64 pos) for(u64 i = pos; i < fb.length && i < pos+length; i += 1) { - if(fb.pbuf[i] == '\n') + if(fb.data[i] == '\n') { fb.line_count -= 1; } @@ -921,8 +911,8 @@ Delete(FlatBuffer* fb, u64 length, u64 pos) if(end != fb.length) { temp = Alloc!(u8)(&fb.arena, fb.length-end); - temp[0 .. temp.length] = fb.pbuf[end .. fb.length]; - fb.pbuf[pos .. pos+temp.length] = temp[0 .. temp.length]; + temp[0 .. temp.length] = fb.data[end .. fb.length]; + fb.data[pos .. pos+temp.length] = temp[0 .. temp.length]; } fb.length -= length; diff --git a/src/editor/editor.d b/src/editor/editor.d index a46714a..35d478e 100644 --- a/src/editor/editor.d +++ b/src/editor/editor.d @@ -28,6 +28,7 @@ struct EditorCtx EditState state; u8[128] input_buf; u32 icount; + u64 editor_id_incr; Timer timer; CmdPalette cmd; u8[][] file_names; @@ -49,14 +50,17 @@ struct CmdPalette struct Editor { Arena arena; + u64 editor_id; FlatBuffer buf; Tokenizer tk; - Vec2 cursor_pos; + U64Vec2 cursor_pos; Vec2 select_start; Vec2 select_end; + u64 line_offset; + f32 text_size; } @@ -414,7 +418,7 @@ SaveFile(Editor* ed, u8[] file_name) u64 tab_count; for(u64 i = 0; i < ed.buf.length; i += 1) { - if(ed.buf.pbuf[i] == '\t') + if(ed.buf.data[i] == '\t') { tab_count += 1; } @@ -427,7 +431,7 @@ SaveFile(Editor* ed, u8[] file_name) u64 buf_pos; for(u64 i = 0; i < ed.buf.length; i += 1) { - if(ed.buf.pbuf[i] == '\t') + if(ed.buf.data[i] == '\t') { for(u64 j = 0; j < tab_width; j += 1) { @@ -436,7 +440,7 @@ SaveFile(Editor* ed, u8[] file_name) } else { - temp_buf[buf_pos++] = ed.buf.pbuf[i]; + temp_buf[buf_pos++] = ed.buf.data[i]; } } @@ -488,8 +492,9 @@ CreateEditor(EditorCtx* ctx) { Editor* ed = Alloc!(Editor)(&ctx.arena); - ed.arena = CreateArena(MB(4)); - ed.buf = CreateFlatBuffer([], []); + ed.arena = CreateArena(MB(4)); + ed.buf = CreateFlatBuffer([], []); + ed.editor_id = ctx.editor_id_incr++; return ed; } @@ -596,10 +601,10 @@ ResetCtx(EditorCtx* ctx) { InsertInputToBuf(ctx); - ctx.state = ES.NormalMode; - ctx.cmd.icount = 0; + ctx.state = ES.NormalMode; + ctx.cmd.icount = 0; ctx.cmd.commands = []; - ctx.cmd.current = cast(Command)NO_CMD; + ctx.cmd.current = cast(Command)NO_CMD; ctx.cmd.selected = 0; } diff --git a/src/editor/parsing.d b/src/editor/parsing.d index ae20889..55b9f15 100644 --- a/src/editor/parsing.d +++ b/src/editor/parsing.d @@ -389,8 +389,7 @@ struct Token struct Tokenizer { Arena arena; - TokenStyle[] _tokens; - TokenStyle* ptokens; + TokenStyle[] tokens; u64 tk_count; u64 pos; Token* first; @@ -406,8 +405,7 @@ Nil(Token* tk) void SetBuffers(Tokenizer* tk, TokenStyle[] tokens) { - tk._tokens = tokens; - tk.ptokens = tokens.ptr+BUF_START; + tk.tokens = tokens; } Tokenizer @@ -417,7 +415,7 @@ CreateTokenizer(FlatBuffer* fb) arena: CreateArena(MB(4)), }; - SetBuffers(&tk, Alloc!(TS)(fb._buf.length)); + SetBuffers(&tk, Alloc!(TS)(fb.data.length)); g_NIL_TOKEN = cast(Token*)&g_nil_tk; tk.first = tk.last = g_NIL_TOKEN; @@ -445,7 +443,7 @@ void ResetTokenizer(Tokenizer* tk, u64 len) { Reset(&tk.arena); - Free(tk._tokens); + Free(tk.tokens); SetBuffers(tk, Alloc!(TS)(len)); tk.pos = 0; @@ -469,7 +467,7 @@ MakeToken(Tokenizer* tk, TokenType type, u64 start, u64 end) u8 Peek(FlatBuffer* fb) { - return fb.tk.pos+1 < fb.length ? fb.pbuf[fb.tk.pos+1] : 0; + return fb.tk.pos+1 < fb.length ? fb.data[fb.tk.pos+1] : 0; } void @@ -483,7 +481,7 @@ TokenizeD(FlatBuffer* fb) for(; tk.pos < fb.length;) { - u8 ch = fb.pbuf[tk.pos]; + u8 ch = fb.data[tk.pos]; bool alpha = (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); if(ch == ' ' || ch == '\t') @@ -492,7 +490,7 @@ TokenizeD(FlatBuffer* fb) for(tk.pos += 1; tk.pos < fb.length; tk.pos += 1) { - if(fb.pbuf[tk.pos] != ' ' && fb.pbuf[tk.pos] != '\t') + if(fb.data[tk.pos] != ' ' && fb.data[tk.pos] != '\t') { break; } @@ -577,7 +575,7 @@ TokenizeD(FlatBuffer* fb) for(; tk.pos < fb.length; tk.pos += 1) { - u8 c = fb.pbuf[tk.pos]; + u8 c = fb.data[tk.pos]; if(CheckWhiteSpace(c)) break; if(!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z')) break; @@ -591,7 +589,7 @@ TokenizeD(FlatBuffer* fb) for(; tk.pos < fb.length; tk.pos += 1) { - if(fb.pbuf[tk.pos] != '.') break; + if(fb.data[tk.pos] != '.') break; } t.end = tk.pos; @@ -602,7 +600,7 @@ TokenizeD(FlatBuffer* fb) for(; tk.pos < fb.length; tk.pos += 1) { - if(CheckWhiteSpace(fb.pbuf[tk.pos])) break; + if(CheckWhiteSpace(fb.data[tk.pos])) break; } t.end = tk.pos; @@ -619,7 +617,7 @@ TokenizeD(FlatBuffer* fb) for(; tk.pos < fb.length; tk.pos += 1) { - if(CheckEOL(fb.pbuf[tk.pos])) + if(CheckEOL(fb.data[tk.pos])) { break; } @@ -634,7 +632,7 @@ TokenizeD(FlatBuffer* fb) for(; tk.pos < fb.length; tk.pos += 1) { - if(fb.pbuf[tk.pos] == '/' && fb.pbuf[tk.pos-1] == '*') + if(fb.data[tk.pos] == '/' && fb.data[tk.pos-1] == '*') { break; } @@ -655,7 +653,7 @@ TokenizeD(FlatBuffer* fb) for(; tk.pos < fb.length; tk.pos += 1) { - if(CheckWhiteSpace(fb.pbuf[tk.pos])) + if(CheckWhiteSpace(fb.data[tk.pos])) { break; } @@ -716,7 +714,7 @@ TokenizeD(FlatBuffer* fb) for(auto token = tk.first; !Nil(token); token = token.next) { - tk.ptokens[token.start .. token.end] = TOKEN_STYLES[token.type]; + tk.tokens[token.start .. token.end] = TOKEN_STYLES[token.type]; } } @@ -826,7 +824,7 @@ CheckFuncOrTemplateSig(FlatBuffer* fb, Token* token) u8[] TokenStr(FlatBuffer* fb, Token* t) { - return fb.pbuf[t.start .. t.end]; + return fb.data[t.start .. t.end]; } Token* @@ -911,7 +909,7 @@ ParseNum(FlatBuffer* fb) { tk.pos += 1; - u8 ch = fb.pbuf[tk.pos]; + u8 ch = fb.data[tk.pos]; if(ch != '_' && ch != '.' && !(ch >= '0' && ch <= '9') && ch != 'x' && ch != 'X' && !((ch == '-' || ch == '+') && first)) { @@ -923,7 +921,7 @@ ParseNum(FlatBuffer* fb) while (tk.pos < fb.length) { - u8 ch = fb.pbuf[tk.pos]; + u8 ch = fb.data[tk.pos]; if(ch != 'l' && ch != 'u' && ch != 'U' && ch != 'L' && ch != 'f' && ch != 'F') { break; @@ -952,9 +950,9 @@ ParseStr(u8 str_ch)(FlatBuffer* fb) static if(str_ch == '`') tk.pos += 1; bool ignore = str_ch != '`'; - for(; (fb.pbuf[tk.pos] != str_ch || ignore) && tk.pos < fb.length; tk.pos += 1) + for(; (fb.data[tk.pos] != str_ch || ignore) && tk.pos < fb.length; tk.pos += 1) { - static if(str_ch != '`') ignore = fb.pbuf[tk.pos] == '\\'; + static if(str_ch != '`') ignore = fb.data[tk.pos] == '\\'; } tk.pos += 1; @@ -971,7 +969,7 @@ ParseId(FlatBuffer* fb) for(; tk.pos < fb.length; tk.pos += 1) { - u8 ch = fb.pbuf[tk.pos]; + u8 ch = fb.data[tk.pos]; if(!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && ch != '.' && ch != '_' && !(ch >= '0' && ch <= '9')) { @@ -980,11 +978,11 @@ ParseId(FlatBuffer* fb) } } - u8 ch = fb.pbuf[t.start]; + u8 ch = fb.data[t.start]; if(ch < D_KEYWORDS.length && D_KEYWORDS[ch] != null && D_KEYWORDS[ch].length > 0) { bool found = false; - u8[] id = fb.pbuf[t.start .. t.end]; + u8[] id = fb.data[t.start .. t.end]; foreach(ref k; D_TYPES[ch]) { @@ -1032,7 +1030,7 @@ FixOpAssign(FlatBuffer* fb, Token* t) { if(t.end+1 < fb.length) { - u8[] str = fb.pbuf[t.start .. t.end+1]; + u8[] str = fb.data[t.start .. t.end+1]; if( str == "/=" || str == "+=" || @@ -1075,7 +1073,7 @@ SkipWhiteSpace(FlatBuffer* fb) { while (fb.tk.pos < fb.length) { - u8 ch = fb.pbuf[fb.tk.pos]; + u8 ch = fb.data[fb.tk.pos]; bool white_space = CheckWhiteSpace(ch); diff --git a/src/editor/ui.d b/src/editor/ui.d index 2d1b02b..81ce0da 100644 --- a/src/editor/ui.d +++ b/src/editor/ui.d @@ -90,7 +90,7 @@ enum Axis2D { X, Y, - Max + Max, } alias A2D = Axis2D; @@ -111,10 +111,11 @@ enum UIFlags ResizeAdjacent = 1<<10, FloatingWindow = 1<<11, CenteredWindow = 1<<12, - TextInput = 1<<13, + TextInput = 1<<13, // todo RightAlignText = 1<<14, - CenterAlignText = 1<<15, - TextWrap = 1<<16, + CenterAlignText = 1<<15, // todo + TextWrap = 1<<16, + PortalView = 1<<17, // Stencil mask this area, no bounds checking children within (for views to drag and view elements) Clamp = UIFlags.ClampX | UIFlags.ClampY, } @@ -241,6 +242,7 @@ struct UICtx mixin UICtxParameter!(Vec4, "text_hl_col"); mixin UICtxParameter!(Vec2[2], "scroll_clamp"); mixin UICtxParameter!(Vec2, "scroll_target"); + mixin UICtxParameter!(Vec2, "fixed_pos"); mixin UICtxParameter!(Vec2, "padding"); mixin UICtxParameter!(UIItem*, "parent"); mixin UICtxParameter!(Axis2D, "layout_axis"); @@ -357,6 +359,7 @@ struct VPos struct Vertex { Vec4[4] cols; + Vec2[2] bounds; union { VPos[2] pos; @@ -368,12 +371,11 @@ struct Vertex Vec2 src_end; }; }; - f32 border_thickness; - f32 corner_radius; - f32 edge_softness; - f32 raised; - f32 z_index; - u32 texture; + f32 border_thickness; + f32 corner_radius; + f32 edge_softness; + f32 raised; + u32 texture; } union Rect @@ -557,8 +559,6 @@ Set(UIItem* item, UICtx* ctx) UIItem* MakeItem(Args...)(string str, Args args) { - UIItem* item = g_UI_NIL; - static if(Args.length) { enum has_flag = Args[Args.length-1].stringof == UIFlags.stringof; @@ -567,11 +567,14 @@ MakeItem(Args...)(string str, Args args) enum len = has_flag ? Args.length-1 : Args.length; char[] key = sformat(ScratchAlloc!(char)(cast(u64)(str.length*1.5)), str, args[0 .. len]); - - item = MakeItem(key, flags); + } + else + { + char[] key = CastStr(char)(str); + UIFlags flags = UIF.None; } - return item; + return MakeItem(key, flags); } UIItem* @@ -802,7 +805,7 @@ BeginUI(Inputs* inputs) foreach(i; 0 .. items.length) { UIItem* item = items[i].value; - if(item.last_frame != ctx.frame) + if(item.last_frame != ctx.frame || ZeroKey(item.key)) { Logf("discarding %s", cast(char[])item.key.hash_text); item.first = item.last = item.parent = item.prev = item.next = g_UI_NIL; @@ -986,30 +989,6 @@ EndUI() break; } } - - if(excess > 0.0009) - { - for(UIItem* c = item.last; !Nil(c); c = c.prev) - { - f32 reduced = Min(excess, c.size[axis]); - excess -= reduced; - c.size.v[axis] -= reduced; - - if(excess < 0.0009) - { - break; - } - } - - assert(excess < 0.0009); - } - } - } - else - { - for(UIItem* c = item.first; !Nil(c); c = c.next) - { - c.size.v[axis] = c.size.v[axis] > size ? size : c.size.v[axis]; } } } @@ -1108,6 +1087,7 @@ RenderItems(UIItem* root) v.dst_end = item.rect.p1 - item.border_thickness; v.cols = item.bg_col; v.corner_radius = item.corner_radius; + v.bounds = ItemBounds(item.parent); AddVertexCount(ctx); } @@ -1121,6 +1101,7 @@ RenderItems(UIItem* root) v.corner_radius = item.corner_radius; v.border_thickness = item.border_thickness; v.edge_softness = item.edge_softness; + v.bounds = ItemBounds(item.parent); AddVertexCount(ctx); } @@ -1389,6 +1370,13 @@ RootSize() return cast(Vec2)GetExtent(&g_ui_ctx.rd); } +UIKey +MakeKey(Args...)(string str, Args args) +{ + char[] key = sformat(ScratchAlloc!(char)(cast(u64)(str.length)), str, args); + return MakeKey(key); +} + UIKey MakeKey(T)(T str) if(StringType!T) { @@ -1403,50 +1391,72 @@ MakeKey(T)(T str) if(StringType!T) UIKey key; - bool hash_only = false; - i64 pos = 0; - u32 hash_count = 0; - for(i64 i = id.length-1; i >= 0; i -= 1) + if(str.length) { - if(i == 0 && id[i] == '#') + bool hash_only = false; + i64 pos = 0; + u32 hash_count = 0; + for(i64 i = id.length-1; i >= 0; i -= 1) { - hash_only = true; - } - - if(hash_count == 2) - { - if(id[i] == '#') + if(i == 0 && id[i] == '#') { - hash_count += 1; - pos = i; + hash_only = true; } - break; + if(hash_count == 2) + { + if(id[i] == '#') + { + hash_count += 1; + pos = i; + } + + break; + } + + if(id[i] == '#') + { + pos = i; + hash_count += 1; + } } - if(id[i] == '#') + if(hash_count < 2 || hash_only) { - pos = i; - hash_count += 1; + key.text = hash_only ? "" : id; + key.hash_text = hash_only ? id : ""; + key.hash = Hash(id); + } + else if(hash_count == 2 || hash_count == 3) + { + key.text = id[0 .. pos]; + key.hash_text = id[pos .. $]; + key.hash = hash_count == 2 ? Hash(id) : Hash(id[pos+hash_count .. $]); } - } - - if(hash_count < 2 || hash_only) - { - key.text = hash_only ? "" : id; - key.hash_text = hash_only ? id : ""; - key.hash = Hash(id); - } - else if(hash_count == 2 || hash_count == 3) - { - key.text = id[0 .. pos]; - key.hash_text = id[pos .. $]; - key.hash = hash_count == 2 ? Hash(id) : Hash(id[pos+hash_count .. $]); } return key; } +UIKey +ZeroKey() +{ + return UIKey(); +} + +bool +ZeroKey(UIKey key) +{ + return key.hash == 0 && key.hash_text.length == 0; +} + +UIItem* +Get(Args...)(string str, Args args) +{ + char[] key = sformat(ScratchAlloc!(cast(u64)(str.length*1.5), str, args)); + return Get(key); +} + pragma(inline) UIItem* Get(T)(T k) if(is(T: UIKey) || StringType!T) { @@ -1550,6 +1560,7 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y) v.dst_end = Vec2(*x_pos+gb.w+gb.l, y+gb.h); v.cols = item.text_col; v.texture = true; + v.bounds = ItemBounds(item); if(glyph.ch != '\t' && glyph.ch != '\n') { @@ -1557,6 +1568,7 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y) v.src_end = Vec2(gb.atlas_r, gb.atlas_b); } + /* f32 end_x = *x_pos + advance; f32 width = end_x - *x_pos; f32 bound_x = item.flags & UIF.RightAlignText ? item.rect.p0.x : item.rect.p1.x; @@ -1589,6 +1601,7 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y) v.pos[i].end[axis] = v.pos[i].start.v[axis] > v.pos[i].end.v[axis] ? v.pos[i].start.v[axis] : v.pos[i].end.v[axis]; } } + */ AddVertexCount(ctx); @@ -1596,6 +1609,12 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y) } } +pragma(inline) Vec2[2] +ItemBounds(UIItem* item) +{ + return [item.rect.p0, item.rect.p1]; +} + pragma(inline) f32 InnerSize(Axis2D axis)(UIItem* item) { @@ -1794,6 +1813,13 @@ Dragged(UIItem* item, Rect* rect) return result; } +pragma(inline) Vec4[4] +Vec4Arr(Vec4 col) +{ + Vec4[4] arr = col; + return arr; +} + unittest { { // UI Key diff --git a/src/editor/views.d b/src/editor/views.d index e1e12de..f42a734 100644 --- a/src/editor/views.d +++ b/src/editor/views.d @@ -4,6 +4,7 @@ import editor; import parsing; import buffer; +import std.algorithm.comparison : clamp; import std.format; import std.conv; @@ -13,6 +14,74 @@ Nil(UIPanel* panel) return panel == null || panel == g_UI_NIL_PANEL; } +void +EditorView(Editor* ed) +{ + UICtx* ctx = GetCtx(); + UIKey zero = ZeroKey(); + UIKey ed_key = MakeKey("###ed_%s", ed.editor_id); + UIItem* editor = Get(ed_key); + + u64 frame_line_offset = ed.line_offset; + u64 frame_view_offset = editor.scroll_offset%TEXT_SIZE; + + Push!("border_col" )(ctx, Vec4Arr(Vec4(1.0))); + + // Line Counter + f32 lc_width = ed.buf.line_count.toChars().length*ctx.char_width; + + Push!("view_offset" )(ctx, Vec2(0.0, frame_view_offset)); + Push!("padding", true)(ctx, Vec2(4.0, 0.0)); + Push!("size_info", true)(ctx, MakeUISizeX(ST.Pixels, lc_width)); + + UIItem* line_count = MakeItem(zero, UIF.DrawBorder); + + // Editor + f32 scroll_pos = cast(f32)(ed.line_offset)*TEXT_SIZE; + + Push!("scroll_clamp", true)(ctx, cast(Vec2[2])[Vec2(0.0), Vec2(0.0, cast(f32)(ed.buf.line_count)*TEXT_SIZE)]); + Push!("size_info", true)(ctx, MakeUISize(UISize(ST.Percentage, 1.0), UISize(ST.Percentage, 1.0))); + Push!("border_col", true)(ctx, Vec4Arr(Vec4(1.0))); + Push!("scroll_target", true)(ctx, Vec2(0.0, scroll_pos)); + + editor = MakeItem(ed_key, UIF.DrawBorder|UIF.ScrollY|UIF.ClampY); + + Pop!("view_offset")(ctx); + + u64 view_lines; + if(editor.size.y > 0.0) + { + view_lines = cast(u64)ceil(editor.size.y/TEXT_SIZE); + + const u64 SCROLL_BUFFER = 2; + + u64 start = ed.line_offset; + u64 end = start+view_lines; + + if(ed.cursor_pos.y < start) + { + ed.line_offset = clamp(ed.cursor_pos.y - SCROLL_BUFFER, 0, ed.buf.line_count); + } + else if(ed.cursor_pos.y > end) + { + ed.line_offset = clamp(ed.cursor_pos.y + SCROLL_BUFFER - view_lines, 0, ed.buf.line_count); + } + } + + Push!("size_info")(ctx, MakeUISizeY(ST.Pixels, TEXT_SIZE)); + Push!("parent" )(ctx, line_count); + Push!("text_col" )(ctx, Vec4(1.0)); + + u64 i = prev_offset; + for(LineBuffer* lb = GetLine(&ed.buf, i); i < prev_offset+view_lines; i += 1) + { + + } + + Pop!("parent")(ctx); + +} + /* void Panel(UIPanel* panel) diff --git a/src/shaders/gui.frag.glsl b/src/shaders/gui.frag.glsl index 5ae2b2a..d84a0d5 100644 --- a/src/shaders/gui.frag.glsl +++ b/src/shaders/gui.frag.glsl @@ -14,6 +14,8 @@ layout (location = 1) in struct FragDataIn { vec2 dst_center; vec2 dst_half_size; vec2 sdf_sample_pos; + vec2 bounds_p0; + vec2 bounds_p1; float corner_radius; float softness; float raised; diff --git a/src/shaders/gui.vert.glsl b/src/shaders/gui.vert.glsl index f179450..eea89ed 100644 --- a/src/shaders/gui.vert.glsl +++ b/src/shaders/gui.vert.glsl @@ -4,19 +4,19 @@ #include "gui.layout" -layout (location = 0) in vec4 in_col_1; -layout (location = 1) in vec4 in_col_2; -layout (location = 2) in vec4 in_col_3; -layout (location = 3) in vec4 in_col_4; -layout (location = 4) in vec2 in_dst_start; -layout (location = 5) in vec2 in_dst_end; -layout (location = 6) in vec2 in_src_start; -layout (location = 7) in vec2 in_src_end; -layout (location = 8) in float border_thickness; -layout (location = 9) in float corner_radius; -layout (location = 10) in float edge_softness; -layout (location = 11) in float raised; -layout (location = 12) in float z_index; +layout (location = 0) in vec4 in_col_1; +layout (location = 1) in vec4 in_col_2; +layout (location = 2) in vec4 in_col_3; +layout (location = 3) in vec4 in_col_4; +layout (location = 4) in vec4 in_bounds; +layout (location = 5) in vec2 in_dst_start; +layout (location = 6) in vec2 in_dst_end; +layout (location = 7) in vec2 in_src_start; +layout (location = 8) in vec2 in_src_end; +layout (location = 9) in float border_thickness; +layout (location = 10) in float corner_radius; +layout (location = 11) in float edge_softness; +layout (location = 12) in float raised; layout (location = 13) in uint in_has_texture; layout (location = 0) flat out uint out_has_texture;