From 94e64fef9ea8b0c69ffede81682209e7ab3bf9ed Mon Sep 17 00:00:00 2001 From: Matthew Date: Thu, 25 Dec 2025 21:03:55 +1100 Subject: [PATCH] command palette is back, many other fixes i dont remember --- assets/gui.vert.spv | Bin 8832 -> 8996 bytes src/dlib | 2 +- src/editor/buffer.d | 16 +- src/editor/editor.d | 468 +++++++++++--------------- src/editor/main.d | 4 +- src/editor/parsing.d | 89 ++--- src/editor/ui.d | 668 ++++++++++++++++---------------------- src/editor/views.d | 250 ++++++++++---- src/shaders/gui.vert.glsl | 37 +-- 9 files changed, 718 insertions(+), 816 deletions(-) diff --git a/assets/gui.vert.spv b/assets/gui.vert.spv index fb74b31caffce249b1f43744b54ad939df91ea75..3fea61867687ab8c755a89df0346f6b3b66ba52a 100644 GIT binary patch delta 2857 zcmaJ>ZERCj7{2#*>)N`H&M~^JUDpjz7BH;1$l{z+!Lj`qvLI3Uu&HY|7RQQhha)km z3t55@=f(@ck2skyrV>z6)JSx?p@E4ZDk_8zkstnN(Z41>&+R=)gM*Vi_q@;hKIc6j z?>YC?Cy%s@yi&VY)3jk=1lR{01}15idxCC4uooLrDj{dznFVNE$>WuYD*tW2` zHUJjr>Wzhy8F#!d8V|+8k)HlUXrOLaopczbH7oBf3tF-V?=Gv`6=XIkH1fQ6nlWf; z8jXA@H)`@9%B0*G?OYj<79)_qD%>YQS?fhsN^GyHG36($5zUT5(>B|HrXxE6yv^ zvyB%bYwpkh>R<|TwQ=+<@o@K=a5DTSiD-nm z9f-FTRWiZoYzOq&pf)#JZAw(L}=3-rGTfKsIPT!86u3S5_4E>VNY`^^sJKeE%S3Tiic4IJ z1%%N1fjo<|e&jqF##t|No5filavl}qtOt3H#ktAs@qF6kY}E6agQql?<=~sAz-e-u z`Th&7826h!nEwUxd^2v-xMMD)6^UuHu|}=MD*W0lDSnIfKT(~0j0T>T)9AI{G9u|E8 z@FVD%>3)E5avmOij8CGcmT~e=EY5RNv!8^`^HBVhr2$Ww%liTjR!Rv@!?puV_!W8{ z7H_#sMtzI)HS(EnncgfnecsZwn2oIoGxNOO0QSn9&*LO}6Bw4_ z$_yI?8w)XLVwX5;Cwphp2dg~u_=B>E45!@y#IJ0m|T+x?z!GpvsR{{FZQW?r;TU@H{vR`3af!ds2+10Y>@c7$x5fs6A|e&8D(_4x9Q@ z0QKbDr_yt^Y)bznZ0h-9sV8p*pkHT}b|VNI2k_~B4Y0&&+bq?T<)?IHk;C)g-tzw0MwJ$14{oaY&Lb_e}Fv;SmRUL zc@QQz2QUFSMJmB_u-S&Kid}$x2xtLzTfU!Q)4u>1vV6b5rk`iW$ymFK0O#V*hjU%j zIyH?#HQ6TEY+S7i{bk@1Kr#PFe>MO2VH&Xk^lez delta 2852 zcmZXUdu)?c7{liYPcR#Q2{Y)IW`h&#(KAYxG^7o%eaK=e+0i+uii| z{B4h!SWPgz+i{#DLccH|oE6RqgWa#+?!MRk=f;ALWV|)CI&Q}L%FCutjz&9@(Y1-z znAWVl-dy&LF022)qXEZuU%^$m(J_o8V*f_hoAtgrlk}CCy}nwr(^rzOvgyuNv%wcJ z1H<%yFI><#lx4omt296PLItxt-d`A^s#)r9^>rl86@OjdpufWH`y=m+zbV^X`%f>A zt%%Oa?p)fW;-VsN|I?=q>-9N$LyjIZO+`Ir*(&X;eQO=eoh|M2TDn@Ks(Ze3#PpVi zs?m5|iIwe%cut{!Di0_-;+{1R2P>xW>NKZSE$O(%+qI@s8)AMJWWPC;On0>;yVwAy zxL|sN74Bf)$za@d^UUN?wQj&H995fPvkP>zxYn9%@DS$`;0S&$0M5AJ3?I(8;0zw_ z_c+JPjpru=FY^2xP(0%ldj@_>1QceuKl{77+Vk-n!-vp}lfz50+@C!$8)=r0(<1?) z*_#HOg9iU&8|U=3g^GPelRW=K(=qz5%tWyfLR8hB^gNqA{M|I4Yefvq9qf1>&v$ zxb)ok6XI;p#t%r(jXx#MEk>P8p7V_q8uDC7fb%Tu1iqC{vh~AxCfF(!e_kuo;e<8H z;+bIMFh6KzBiN`7AM|YaFS2U_&YS&}kGj*%gz#MbPlT_no**l7gG%yRM+=2Yp>2cd z4Y#{9OnA)m?o87=Chazw36YffB2s8}My_+OH>V>HncY=E(_Hm{`9J-lO#|l#W>cHtD=i>%Rr3#QL{O z=e=70t^7n08}O`j9^xr3=ei_b7o@1)ky?UJ7%TCWeQtM2?7Q9nBa>6V4vh<;X!}VT~4SR0AUE)v z!KBeubZ(uwCgLp;3M?2kq=A4%imLL?uSPXrh;4XM z`hZ{?elDH-69V~gVr>5X(vhv+eVvxhb7~ScI;o-ebw&h7nec=c_?2|*%>vE1sILW@ zof2pUC(btG(hxSw*YG=mFCnpK;buc!Xe`w(id_=;){Pg);G6iPaLG)rTQU;uXTjEf Y&}^w|b@!Ox>&6A+vLk=%W7jDB1FUMLS^xk5 diff --git a/src/dlib b/src/dlib index 8098145..bda9abf 160000 --- a/src/dlib +++ b/src/dlib @@ -1 +1 @@ -Subproject commit 809814577db807d5911e79216d6e114a2d5a2dfd +Subproject commit bda9abf8b9c74844cb30edb32e81543cbd5ae89d diff --git a/src/editor/buffer.d b/src/editor/buffer.d index ced8f4c..6c4ee21 100644 --- a/src/editor/buffer.d +++ b/src/editor/buffer.d @@ -397,36 +397,36 @@ Insert(FlatBuffer* fb, u8[] insert, u64 length) Insert(fb, insert, length, fb.pos); } -pragma(inline) u64 +pragma(inline) i64 CurrentLine(FlatBuffer* fb) { return LineFromPos(fb, fb.pos); } -pragma(inline) u64 +pragma(inline) i64 CurrentCol(FlatBuffer* fb) { return LinePos(fb, fb.pos); } -pragma(inline) u64 +pragma(inline) i64 LinePos(FlatBuffer* fb, u64 pos) { u64 line = LineFromPos(fb, pos); return pos - fb.lines[line].pos; } -pragma(inline) U64Vec2 +pragma(inline) I64Vec2 VecPos(FlatBuffer* fb) { - return U64Vec2(CurrentCol(fb), CurrentLine(fb)); + return I64Vec2(CurrentCol(fb), CurrentLine(fb)); } -pragma(inline) u64 +pragma(inline) i64 LineFromPos(FlatBuffer* fb, u64 pos) { - u64 line = 0; - for(u64 i = 0; i < fb.line_count; i += 1) + i64 line = 0; + for(i64 i = 0; i < fb.line_count; i += 1) { if(fb.lines[i].pos > pos) { diff --git a/src/editor/editor.d b/src/editor/editor.d index 2cd5a2b..5675a66 100644 --- a/src/editor/editor.d +++ b/src/editor/editor.d @@ -8,6 +8,7 @@ import ui; import parsing; import views; +import std.algorithm.comparison : clamp; import std.format; import std.stdio; import std.exception; @@ -23,8 +24,7 @@ struct EditorCtx { Arena arena; PlatformWindow* window; - UIPanel* base_panel; - u64 panel_id; + Panel* base_panel; EditState state; u8[128] input_buf; u32 icount; @@ -32,6 +32,9 @@ struct EditorCtx Timer timer; CmdPalette cmd; u8[][] file_names; + u64 panel_id; + + Editor* focused_editor; } struct CmdPalette @@ -55,11 +58,11 @@ struct Editor FlatBuffer buf; Tokenizer tk; - U64Vec2 cursor_pos; + I64Vec2 cursor_pos; Vec2 select_start; Vec2 select_end; - u64 line_offset; + i64 line_offset; f32 text_size; } @@ -115,7 +118,8 @@ enum EditState alias ES = EditState; -bool g_input_mode = false; +__gshared bool g_input_mode = false; +__gshared EditorCtx g_ed_ctx; const Command NO_CMD = { name: [], @@ -123,40 +127,34 @@ const Command NO_CMD = { }; void -Cycle(EditorCtx* ctx, Inputs* inputs) +Cycle(Inputs* inputs) { ResetScratch(MB(4)); - g_delta = DeltaTime(&ctx.timer); + g_delta = DeltaTime(&g_ed_ctx.timer); debug if(g_frame_step) { g_delta = 0.01; } - assert(Nil(ctx.base_panel.next)); - //HandleInputs(ctx, inputs); debug if(g_frame_step && !g_frame_continue) return; debug g_frame_continue = false; - g_input_mode = ctx.state == ES.InputMode; + g_input_mode = g_ed_ctx.state == ES.InputMode; BeginUI(inputs); UICtx* ui_ctx = GetCtx(); - static Editor* ed; + EditorView(g_ed_ctx.base_panel); - if(!ed) + if(g_ed_ctx.state == ES.CmdOpen) { - ed = CreateEditor(ctx); - OpenFile(ed, CastStr!(u8)("src/editor/ui.d")); + CommandPalette(&g_ed_ctx.cmd); } - - EditorView(ed); - /* UIPanel* root = ctx.base_panel; @@ -203,26 +201,22 @@ Cycle(EditorCtx* ctx, Inputs* inputs) EndUI(); } - -EditorCtx +void InitEditorCtx(PlatformWindow* window) { InitUICtx(window); - EditorCtx ctx = { - window: window, - arena: CreateArena(MB(2)), - cmd: { - arena: CreateArena(MB(1)), - cmd_arena: CreateArena(MB(1)), - buffer: Alloc!(u8)(1024), - }, - }; + EditorCtx* ctx = &g_ed_ctx; + + ctx.window = window; + ctx.arena = CreateArena(MB(2)); + ctx.cmd.arena = CreateArena(MB(1)); + ctx.cmd.cmd_arena = CreateArena(MB(1)); + ctx.cmd.buffer = Alloc!(u8)(1024); + ctx.base_panel = CreatePanel(ctx, CreateEditor(ctx)); + ctx.timer = CreateTimer(); - ctx.base_panel = CreatePanel(&ctx); - ctx.base_panel.ed = CreateEditor(&ctx); - ctx.timer = CreateTimer(); - //SetFocusedPanel(ctx.base_panel); + FocusEditor(ctx.base_panel.ed); if(getcwd() != "/") { @@ -254,24 +248,25 @@ InitEditorCtx(PlatformWindow* window) Logf("failed to open directory for filenames"); } } - - return ctx; } -UIPanel* -CreatePanel(EditorCtx* ctx, SizeType size_type = ST.Percentage) +void +FocusEditor(Editor* ed) { - UIPanel* p = Alloc!(UIPanel)(&ctx.arena); - p.axis = A2D.Y; - p.id = Alloc!(u8)(&ctx.arena, 10); - p.pct = 1.0; - p.scroll_offset = 0.0; - p.scroll_target = 0.0; + assert(ed); + g_ed_ctx.focused_editor = ed; + Logf("editor %s", ed.editor_id); +} - (cast(char[])p.id).sformat("##%08s", ctx.panel_id); - p.parent = p.first = p.last = p.next = p.prev = g_UI_NIL_PANEL; +Panel* +CreatePanel(EditorCtx* ctx, Editor* ed = null) +{ + Panel* p = Alloc!(Panel)(&ctx.arena); - ctx.panel_id += 1; + p.layout_axis = A2D.Y; + p.ed = ed; + p.id = ctx.panel_id++; + p.parent = p.first = p.last = p.next = p.prev = g_NIL_PANEL; return p; } @@ -409,8 +404,6 @@ OpenFile(Editor* ed, u8[] file_name) } } -// Load all files then move things into editor after being created when selected - Editor* CreateEditor(EditorCtx* ctx) { @@ -423,107 +416,71 @@ CreateEditor(EditorCtx* ctx) return ed; } -debug -{ - __gshared u64 panel_count = 0; - __gshared UIPanel*[1024] panels = null; -} - void -AddEditor(EditorCtx* ctx, UIPanel* target, Axis2D axis) +AddEditor(EditorCtx* ctx, Panel* target, Axis2D axis) { - if(Nil(target.parent) || target.parent.axis != axis) + if(CheckNil(g_NIL_PANEL, target.parent) || target.parent.layout_axis != axis) { - UIPanel* first = CreatePanel(ctx); - UIPanel* second = CreatePanel(ctx); + Panel* first = CreatePanel(ctx, target.ed); + Panel* second = CreatePanel(ctx, CreateEditor(ctx)); - first.ed = target.ed; - second.ed = CreateEditor(ctx); + target.layout_axis = axis; + target.ed = null; - first.pct = second.pct = 0.5; + DLLPush(target, first, g_NIL_PANEL); + DLLPush(target, second, g_NIL_PANEL); - target.axis = axis; - target.ed = null; + first.parent = second.parent = target; - //PushPanel(target, first); - //PushPanel(target, second); - - //SetFocusedPanel(second); - - debug - { - panels[panel_count+0] = first; - panels[panel_count+1] = second; - - panel_count += 2; - } + FocusEditor(second.ed); } - else if(target.parent.axis == axis) + else if(target.parent.layout_axis == axis) { - UIPanel* panel = CreatePanel(ctx); - panel.ed = CreateEditor(ctx); + Panel* panel = CreatePanel(ctx, CreateEditor(ctx)); - //InsertPanel(target.parent, target, panel); + DLLPush(target.parent, target, panel); + panel.parent = target.parent; - u64 count = 0; - for(UIPanel* p = target.parent.first; !Nil(p); p = p.next, count += 1) {} - - f32 pct = 1.0/count; - for(UIPanel* p = target.parent.first; !Nil(p); p = p.next) + UIItem* ed_item = GetEditorItem(panel.ed); + if(!Nil(ed_item.parent)) { - p.pct = pct; - } - - //SetFocusedPanel(panel); - - debug - { - panels[panel_count] = panel; - - panel_count += 1; - } - } - - debug for(u64 i = 0; i < panel_count; i += 1) - { - bool root_found = false; - for(UIPanel* p = panels[i]; !Nil(p); p = p.parent) - { - if(p == ctx.base_panel) + u64 count; + for(UIItem* c = ed_item.parent.first; !Nil(c); c = c.next) { - root_found = true; - break; + count += 1; + } + + f32 pct = 1.0/cast(f32)count; + for(UIItem* c = ed_item.parent.first; !Nil(c); c = c.next) + { + c.resize_pct = pct; } } - if(!root_found) - { - Logf("[DEBUG] panel %s unable to reach root", cast(char[])panels[panel_count].id); - assert(root_found); - } + FocusEditor(panel.ed); } } +UIItem* +GetEditorItem(Editor* ed) +{ + return Get("###ed_%s", ed.editor_id); +} + pragma(inline) void -InsertInputToBuf(EditorCtx* ctx) +InsertInputToBuf(EditorCtx* ctx, Editor* ed) { if(ctx.icount > 0) { - /* - UIPanel* p = GetFocusedPanel(); - if(!Nil(p)) - { - Insert(&p.ed.buf, ctx.input_buf, ctx.icount); - ctx.icount = 0; - } - */ + Insert(&ed.buf, ctx.input_buf, ctx.icount); + ctx.icount = 0; } } void -ResetCtx(EditorCtx* ctx) +ResetCtx(EditorCtx* ctx, Editor* ed) { - InsertInputToBuf(ctx); + InsertInputToBuf(ctx, ed); ctx.state = ES.NormalMode; ctx.cmd.icount = 0; @@ -586,137 +543,118 @@ MovePanelFocus(A2D axis, bool prev)(UIPanel* panel) } void -HandleInputs(EditorCtx* ctx, Inputs* inputs) +HandleInputs(Panel* p, LinkedList!(UIInput)* inputs) { + Editor* ed = p.ed; + EditorCtx* ctx = &g_ed_ctx; u8[] cb_text; - UIPanel* panel = g_UI_NIL_PANEL;//GetFocusedPanel(); - FlatBuffer* fb = !Nil(panel) ? &panel.ed.buf : null; + FlatBuffer* fb = &ed.buf; for(auto node = inputs.first; node != null; node = node.next) { bool taken = false; - Input key = node.key; - Modifier md = node.md; - bool pressed = node.pressed; + Input key = node.key; + Modifier md = node.md; - if (pressed) + if(key == Input.Escape) { - if(key == Input.Escape) + ResetCtx(ctx, ed); + taken = true; + } + else if(ctx.state == ES.InputMode) + { + taken = HandleInputMode(ctx, p, node); + } + else if(ctx.state == ES.CmdOpen) + { + taken = HandleCmdMode(ctx, p, node); + } + else if(ctx.state == ES.SetPanelFocus) + { + switch(key) with(Input) { - ResetCtx(ctx); - taken = true; + case Escape: + { + ResetCtx(ctx, ed); + taken = true; + } break; + default: break; } - else if(ctx.state == ES.InputMode) + } + else + { + switch(key) with(Input) { - taken = HandleInputMode(ctx, node); - } - else if(ctx.state == ES.CmdOpen) - { - taken = HandleCmdMode(ctx, node); - } - else if(ctx.state == ES.SetPanelFocus) - { - switch(key) with(Input) - { - case Up: + case a, i: + { + if(key == a && Shift(md) && fb) + { + MoveToEOL(fb); + } + else if(key == a) { - if(MovePanelFocus!(A2D.Y, true )(panel)) goto case Escape; - } break; - case Down: + Move(fb, Right, MD.None); + } + else if(key == i && Shift(md)) { - if(MovePanelFocus!(A2D.Y, false)(panel)) goto case Escape; - } break; - case Left: - { - if(MovePanelFocus!(A2D.X, true )(panel)) goto case Escape; - } break; - case Right: - { - if(MovePanelFocus!(A2D.X, false)(panel)) goto case Escape; - } break; - case Escape: - { - ResetCtx(ctx); - taken = true; - } break; - default: break; - } - } - else - { - switch(key) with(Input) - { - case a, i: - { - if(key == a && Shift(md) && fb) - { - MoveToEOL(fb); - } - else if(key == a) - { - Move(fb, Right, MD.None); - } - else if(key == i && Shift(md)) - { - MoveToSOL(fb); - } + MoveToSOL(fb); + } - ctx.state = ES.InputMode; + ctx.state = ES.InputMode; + taken = true; + } break; + case Semicolon: + { + if(Shift(node.md)) + { + ctx.state = ES.CmdOpen; taken = true; - } break; - case Semicolon: + } + } break; + case v: + { + if(Ctrl(md)) { - if(Shift(node.md)) - { - ctx.state = ES.CmdOpen; - taken = true; - } - } break; - case v: + cb_text = ClipboardText(ctx.window); + } + if(Shift(md)) { - if(Ctrl(md)) - { - cb_text = ClipboardText(ctx.window); - } - if(Shift(md)) - { - ToggleSelection(fb, SM.Line); - } - else - { - ToggleSelection(fb, SM.Normal); - } - } break; - case c: + ToggleSelection(fb, SM.Line); + } + else { - if(Ctrl(md)) - { - // Copy - taken = true; - } - } break; - case w: + ToggleSelection(fb, SM.Normal); + } + } break; + case c: + { + if(Ctrl(md)) { - if(Ctrl(md)) - { - ctx.state = ES.SetPanelFocus; - } - } break; - debug case d: + // Copy + taken = true; + } + } break; + case w: + { + if(Ctrl(md)) { - g_ui_ctx.dbg = !g_ui_ctx.dbg; - } break; - debug case g: - { - g_frame_step = !g_frame_step; - } break; - debug case s: - { - g_frame_continue = true; - } break; - default: taken = Move(fb, key, md); break; - } + ctx.state = ES.SetPanelFocus; + } + } break; + debug case d: + { + g_ui_ctx.dbg = !g_ui_ctx.dbg; + } break; + debug case g: + { + g_frame_step = !g_frame_step; + } break; + debug case s: + { + g_frame_continue = true; + } break; + default: taken = Move(fb, key, md); break; } } @@ -726,7 +664,7 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs) } } - InsertInputToBuf(ctx); + InsertInputToBuf(ctx, ed); if(cb_text.length > 0) { @@ -735,20 +673,13 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs) } void -MoveCursor(InputEvent* ev) +MoveCursor(Editor* ed, UIInput* ev) { - UIPanel* p = g_UI_NIL_PANEL;//GetFocusedPanel(); - - if(!Nil(p)) + switch(ev.key) with(Input) { - FlatBuffer* fb = &p.ed.buf; - switch(ev.key) with(Input) - { - case Up, Down, Left, Right: Move(fb, ev.key, ev.md); break; - default: break; - } + case Up, Down, Left, Right: Move(&ed.buf, ev.key, ev.md); break; + default: break; } - } pragma(inline) void @@ -775,7 +706,7 @@ CharCases() } bool -HandleInputMode(EditorCtx* ctx, InputEvent* ev) +HandleInputMode(EditorCtx* ctx, Panel* p, UIInput* ev) { bool taken = false; @@ -784,17 +715,13 @@ HandleInputMode(EditorCtx* ctx, InputEvent* ev) mixin(CharCases()); case Input.Backspace: { - UIPanel* p = g_UI_NIL_PANEL;//GetFocusedPanel(); - if(!Nil(p)) - { - Backspace(&p.ed.buf); - } + Backspace(&p.ed.buf); } break; case Input.Escape: { ctx.state = ES.NormalMode; } break; - default: MoveCursor(ev); break; + default: MoveCursor(p.ed, ev); break; } return taken; @@ -933,11 +860,11 @@ GetCommands(CmdPalette* cmd) } bool -HandleCmdMode(EditorCtx* ctx, InputEvent* ev) +HandleCmdMode(EditorCtx* ctx, Panel* panel, UIInput* ev) { - u8 result = 0; - bool taken = false; + bool taken; CmdPalette* cmd = &ctx.cmd; + Editor* ed = panel.ed; u64 prev_count = cmd.icount; switch(ev.key) with(Input) @@ -956,36 +883,31 @@ HandleCmdMode(EditorCtx* ctx, InputEvent* ev) } } - UIPanel* p = g_UI_NIL_PANEL;//GetFocusedPanel(); - switch(cmd.current.type) { case CT.OpenFile: { - if(!Nil(p) && cmd.selected >= 0 && cmd.selected < cmd.opt_strs.length) + if(cmd.selected >= 0 && cmd.selected < cmd.opt_strs.length) { - OpenFile(p.ed, cmd.opt_strs[cmd.selected]); + OpenFile(ed, cmd.opt_strs[cmd.selected]); } } break; case CT.SaveFile: { - if(!Nil(p)) - { - SaveFile(p.ed, GetParam(cmd)); - } + SaveFile(ed, GetParam(cmd)); } break; case CT.VSplit, CT.HSplit: { - AddEditor(ctx, p, cmd.current.type == CT.VSplit ? A2D.X : A2D.Y); + AddEditor(ctx, panel, cmd.current.type == CT.VSplit ? A2D.X : A2D.Y); } break; default: break; } - ResetCtx(ctx); + ResetCtx(ctx, ed); } goto CmdInputEnd; case Backspace: { - if(CondIncr!(-1)(cmd.icount > 0, &cmd.icount) && cmd.buffer[cmd.icount] == ' ') + if(cmd.icount > 0 && cmd.buffer[--cmd.icount] == ' ') { cmd.current = cast(Command)NO_CMD; } @@ -1005,22 +927,18 @@ HandleCmdMode(EditorCtx* ctx, InputEvent* ev) cmd.buffer[cmd.icount++] = ' '; } } break; - case Up: + case Up, Down: { - CondIncr!(-1)(cmd.selected > 0, &cmd.selected); + cmd.selected = clamp(cmd.selected+(ev.key == Up ? -1 : +1), 0, cmd.opt_strs.length-1); } break; - case Down: + default: { - CondIncr!(+1)(cmd.selected < cmd.opt_strs.length-1, &cmd.selected); + if(ev.text.length) + { + cmd.buffer[cmd.icount .. cmd.icount+ev.text.length] = cast(u8[])ev.text[0 .. $]; + cmd.icount += ev.text.length; + } } break; - mixin(TextLineCharCases()); - default: break; - } - - if(result != 0) - { - Check(cmd, 1); - cmd.buffer[cmd.icount++] = result; } if(cmd.current.type == CT.None && (cmd.commands.length == 0 || prev_count != cmd.icount)) diff --git a/src/editor/main.d b/src/editor/main.d index 3d348de..3ac0f20 100644 --- a/src/editor/main.d +++ b/src/editor/main.d @@ -27,7 +27,7 @@ void main(string[] argv) StartPlatformThread(&window); - EditorCtx ctx = InitEditorCtx(&window); + InitEditorCtx(&window); import ui; import vulkan; @@ -58,6 +58,6 @@ void main(string[] argv) } } - Cycle(&ctx, inputs); + Cycle(inputs); } } diff --git a/src/editor/parsing.d b/src/editor/parsing.d index 55b9f15..d5e48cb 100644 --- a/src/editor/parsing.d +++ b/src/editor/parsing.d @@ -89,24 +89,25 @@ const Vec4 GREEN = Vec4(0.0, 1.0, 0.0, 1.0); const Vec4 TURQUOISE = Vec4(0.15, 0.59, 0.76, 1.0); const Vec4 PINK = Vec4(0.85, 0.48, 0.60, 1.0); -const Vec4[TS.max] SYNTAX_COLORS = SyntaxCols(); +const Vec4[TS.max] DEFAULT_COLORS = Vec4(1.0); +const Vec4[TS.max] SYNTAX_COLORS = SyntaxCols(); static Vec4[TS.max] SyntaxCols() { Vec4[TS.max] colors = [ - TS.Op: YELLOW, - TS.Bracket: GREY, - TS.Function: PURPLE, - TS.Macro: PURPLE, - TS.Keyword: BLUE, - TS.String: GREEN, - TS.Char: GREEN, - TS.Import: RED, + TS.Op: YELLOW, + TS.Bracket: GREY, + TS.Function: PURPLE, + TS.Macro: PURPLE, + TS.Keyword: BLUE, + TS.String: GREEN, + TS.Char: GREEN, + TS.Import: RED, TS.ImportTarget: RED, - TS.Type: TURQUOISE, - TS.Number: PINK, - TS.Comment: GREY, + TS.Type: TURQUOISE, + TS.Number: PINK, + TS.Comment: GREY, ]; Vec4[TS.max] result = Vec4(0.8, 0.8, 0.8, 1.0); @@ -125,47 +126,47 @@ SyntaxCols() } const TokenStyle[TT.max] TOKEN_STYLES = [ - TT.Dollar: TS.Op, - TT.Hash: TS.Op, - TT.Tilde: TS.Op, - TT.Percent: TS.Op, - TT.Caret: TS.Op, - TT.Ampersand: TS.Op, - TT.Asterisk: TS.Op, - TT.Minus: TS.Op, - TT.Equals: TS.Op, - TT.Plus: TS.Op, - TT.LessThan: TS.Op, + TT.Dollar: TS.Op, + TT.Hash: TS.Op, + TT.Tilde: TS.Op, + TT.Percent: TS.Op, + TT.Caret: TS.Op, + TT.Ampersand: TS.Op, + TT.Asterisk: TS.Op, + TT.Minus: TS.Op, + TT.Equals: TS.Op, + TT.Plus: TS.Op, + TT.LessThan: TS.Op, TT.GreaterThan: TS.Op, TT.Exclamation: TS.Op, - TT.Slash: TS.Op, + TT.Slash: TS.Op, - TT.LeftParen: TS.Bracket, - TT.RightParen: TS.Bracket, - TT.LeftSquareBrace: TS.Bracket, + TT.LeftParen: TS.Bracket, + TT.RightParen: TS.Bracket, + TT.LeftSquareBrace: TS.Bracket, TT.RightSquareBrace: TS.Bracket, - TT.LeftBrace: TS.Bracket, - TT.RightBrace: TS.Bracket, - TT.VertBar: TS.Bracket, - TT.Semicolon: TS.Bracket, - TT.Colon: TS.Bracket, - TT.Question: TS.Bracket, - TT.Comma: TS.Bracket, + TT.LeftBrace: TS.Bracket, + TT.RightBrace: TS.Bracket, + TT.VertBar: TS.Bracket, + TT.Semicolon: TS.Bracket, + TT.Colon: TS.Bracket, + TT.Question: TS.Bracket, + TT.Comma: TS.Bracket, TT.SingleQuote: TS.Char, TT.DoubleQuote: TS.String, - TT.BackTick: TS.String, + TT.BackTick: TS.String, - TT.Keyword: TS.Keyword, - TT.TypeKeyword: TS.Keyword, - TT.EnumKeyword: TS.Keyword, - TT.Function: TS.Function, - TT.Macro: TS.Macro, - TT.Type: TS.Type, - TT.Number: TS.Number, - TT.Import: TS.Import, + TT.Keyword: TS.Keyword, + TT.TypeKeyword: TS.Keyword, + TT.EnumKeyword: TS.Keyword, + TT.Function: TS.Function, + TT.Macro: TS.Macro, + TT.Type: TS.Type, + TT.Number: TS.Number, + TT.Import: TS.Import, TT.ImportTarget: TS.Import, - TT.Comment: TS.Comment, + TT.Comment: TS.Comment, ]; const TT[128] D_STD_TOKEN = [ diff --git a/src/editor/ui.d b/src/editor/ui.d index b9fd2f9..2ea532e 100644 --- a/src/editor/ui.d +++ b/src/editor/ui.d @@ -6,7 +6,6 @@ import vulkan : RendererGetExtent = GetExtent; import buffer; import parsing; import editor; -import views : Nil; import views; import std.stdio; @@ -29,12 +28,12 @@ import core.stdc.stdio : sprintf; *********************************/ -enum Vec4[4] BG_COL = Vec4(0.13, 0.13, 0.13, 1.0); -enum Vec4[4] BG_HL_COL = Vec4(0.24, 0.45, 0.81, 1.0); -enum Vec4[4] BORDER_COL = Vec4(0.254, 0.254, 0.266, 1.0); -enum Vec4[4] BORDER_HL_COL = Vec4(0.035, 0.549, 0.824, 1.0); -enum Vec4 TEXT_COL = Vec4(1.0); -enum Vec4 TEXT_HL_COL = Vec4(0.0, 0.0, 0.0, 1.0); +enum Vec4 BG_COL = Vec4(0.13, 0.13, 0.13, 1.0); +enum Vec4 BG_HL_COL = Vec4(0.24, 0.45, 0.81, 1.0); +enum Vec4 BORDER_COL = Vec4(0.254, 0.254, 0.266, 1.0); +enum Vec4 BORDER_HL_COL = Vec4(0.035, 0.549, 0.824, 1.0); +enum Vec4 TEXT_COL = Vec4(1.0); +enum Vec4 TEXT_HL_COL = Vec4(0.0, 0.0, 0.0, 1.0); const u64 VERTEX_MAX_COUNT = 10000; const Vec2 CLICK_BUFFER = Vec2(3.0, 3.0); @@ -44,20 +43,20 @@ const f32 TEXT_SIZE = 16.0; const f32 SCROLL_SPEED = 48.0; const f32 LINE_COUNT_PADDING = 4.0; -UIPanel g_root_panel; -UICtx g_ui_ctx; +__gshared UICtx g_ui_ctx; -const u8[] FONT_BYTES = import("pc-9800.ttf"); +//const u8[] FONT_BYTES = import("pc-9800.ttf"); +const u8[] FONT_BYTES = import("NuberNextCondensed-DemiBold.otf"); const u8[] VERTEX_BYTES = import("gui.vert.spv"); const u8[] FRAGMENT_BYTES = import("gui.frag.spv"); -f32 g_corner_radius_default = 2.0; -f32 g_edge_softness_default = 0.1; +Vec4 g_corner_radius_default = 0.0; +f32 g_edge_softness_default = 0.8; f32 g_border_thickness_default = 0.0; -Vec4[4] g_bg_col_default = BG_COL; -Vec4[4] g_bg_hl_col_default = BG_HL_COL; -Vec4[4] g_border_col_default = BORDER_COL; -Vec4[4] g_border_hl_col_default = BORDER_HL_COL; +Vec4 g_bg_col_default = BG_COL; +Vec4 g_bg_hl_col_default = BG_HL_COL; +Vec4 g_border_col_default = BORDER_COL; +Vec4 g_border_hl_col_default = BORDER_HL_COL; Vec4 g_text_col_default = TEXT_COL; Vec4 g_text_hl_col_default = TEXT_HL_COL; UISize[2] g_size_info_default = [UISize(ST.Percentage, 1.0), UISize(ST.Percentage, 1.0)]; @@ -68,12 +67,13 @@ Vec2 g_scroll_target_default = Vec2(0.0); Vec2 g_scroll_clamp_default = Vec2(0.0); Vec2 g_view_offset_default = Vec2(0.0); string g_display_string_default = null; +UISH g_syntax_highlight_default = UISH.None; +u8[] g_syntax_tokens_default = []; +Vec2 g_fixed_pos_default = Vec2(0.0); alias g_parent_default = g_UI_NIL; const UI_COUNT = 5000; -__gshared const UIPanel g_ui_nil_panel; -__gshared UIPanel* g_UI_NIL_PANEL; __gshared const UIItem g_ui_nil_item; __gshared UIItem* g_UI_NIL; __gshared const UIInput g_ui_nil_input; @@ -87,7 +87,6 @@ __gshared Stack!Vec4* g_NIL_VEC4_STACK; __gshared const Stack!u32 g_nil_u32_stack; __gshared Stack!u32* g_NIL_U32_STACK; - enum Axis2D { X, @@ -99,30 +98,35 @@ alias A2D = Axis2D; enum UIFlags { - None = 0, - DrawBackground = 1<<0, - DrawText = 1<<1, - DrawBorder = 1<<2, - Clickable = 1<<3, - Draggable = 1<<4, - ScrollX = 1<<5, - ScrollY = 1<<6, - ClampX = 1<<7, - ClampY = 1<<8, - Resizeable = 1<<9, - ResizeAdjacent = 1<<10, - FloatingWindow = 1<<11, - CenteredWindow = 1<<12, - TextInput = 1<<13, // todo - RightAlignText = 1<<14, - CenterAlignText = 1<<15, // todo - TextWrap = 1<<16, - PortalViewX = 1<<17, // Stencil mask this area, no bounds checking children within (for views to drag and view elements) - PortalViewY = 1<<18, + None = 0, + DrawBackground = 1<<0, + DrawText = 1<<1, + DrawBorder = 1<<2, + Clickable = 1<<3, + Draggable = 1<<4, + ScrollX = 1<<5, + ScrollY = 1<<6, + ClampX = 1<<7, + ClampY = 1<<8, + Resizeable = 1<<9, + ResizeAdjacent = 1<<10, + FloatingWindow = 1<<11, // todo + Window = 1<<12, + TextInput = 1<<13, // todo + RightAlignText = 1<<14, + CenterAlignText = 1<<15, // todo + TextWrap = 1<<16, + PortalViewX = 1<<17, + PortalViewY = 1<<18, + FixedPosition = 1<<19, + FixedPosAnimated = 1<<20, // todo: add fixed_pos_target then interpolate position every frame + OverflowX = 1<<21, + OverflowY = 1<<22, - Clamp = UIFlags.ClampX | UIFlags.ClampY, - PortalView = UIFlags.PortalViewX | UIFlags.PortalViewY, - Scroll = UIFlags.ScrollX | UIFlags.ScrollY, + Clamp = UIFlags.ClampX | UIFlags.ClampY, + PortalView = UIFlags.PortalViewX | UIFlags.PortalViewY, + Scroll = UIFlags.ScrollX | UIFlags.ScrollY, + Overflow = UIFlags.OverflowX | UIFlags.OverflowY, } alias UIF = UIFlags; @@ -145,6 +149,7 @@ enum UIEvent Drag = 1<<2, DragStart = 1<<3, Press = 1<<4, + Scroll = 1<<5, } alias UIE = UIEvent; @@ -152,18 +157,28 @@ struct UIInput { UIEvent type; UIInput* next, prev; + Modifier md; union { struct { - Input key; - string text; + Input key; + string text; }; IVec2 rel; IVec2 pos; + i32 scroll; } } +enum UISyntaxHighlight +{ + None, + D, + Max, +} +alias UISH = UISyntaxHighlight; + mixin template UICtxParameter(T, string name) { @@ -237,31 +252,34 @@ struct UICtx u32 tab_width; f32 text_size; + Vec4[TS.max][UISH.max] syntax_colors; UIItem* window_root; UIItem* root; UIItem* drag_item; - UIPanel* parent_panel; - UIPanel* focused_panel; + UIItem* focus_item; - mixin UICtxParameter!(Vec4[4], "bg_col"); - mixin UICtxParameter!(Vec4[4], "bg_hl_col"); - mixin UICtxParameter!(Vec4[4], "border_col"); - mixin UICtxParameter!(Vec4[4], "border_hl_col"); - mixin UICtxParameter!(UISize[2], "size_info"); - mixin UICtxParameter!(Vec4, "text_col"); - mixin UICtxParameter!(Vec4, "text_hl_col"); - mixin UICtxParameter!(Vec2[2], "scroll_clamp"); - mixin UICtxParameter!(Vec2, "scroll_target"); - mixin UICtxParameter!(Vec2, "padding"); - mixin UICtxParameter!(Vec2, "view_offset"); - mixin UICtxParameter!(UIItem*, "parent"); - mixin UICtxParameter!(string, "display_string"); - mixin UICtxParameter!(Axis2D, "layout_axis"); - mixin UICtxParameter!(f32, "corner_radius"); - mixin UICtxParameter!(f32, "border_thickness"); - mixin UICtxParameter!(f32, "edge_softness"); - mixin UICtxParameter!(f32, "text_scale"); + mixin UICtxParameter!(Vec4, "bg_col"); + mixin UICtxParameter!(Vec4, "bg_hl_col"); + mixin UICtxParameter!(Vec4, "border_col"); + mixin UICtxParameter!(Vec4, "border_hl_col"); + mixin UICtxParameter!(UISize[2], "size_info"); + mixin UICtxParameter!(Vec4, "text_col"); + mixin UICtxParameter!(Vec4, "text_hl_col"); + mixin UICtxParameter!(Vec2[2], "scroll_clamp"); + mixin UICtxParameter!(Vec2, "scroll_target"); + mixin UICtxParameter!(Vec2, "padding"); + mixin UICtxParameter!(Vec2, "view_offset"); + mixin UICtxParameter!(Vec2, "fixed_pos"); + mixin UICtxParameter!(UIItem*, "parent"); + mixin UICtxParameter!(string, "display_string"); + mixin UICtxParameter!(u8[], "syntax_tokens"); + mixin UICtxParameter!(Axis2D, "layout_axis"); + mixin UICtxParameter!(Vec4, "corner_radius"); + mixin UICtxParameter!(f32, "border_thickness"); + mixin UICtxParameter!(f32, "edge_softness"); + mixin UICtxParameter!(f32, "text_scale"); + mixin UICtxParameter!(UISyntaxHighlight, "syntax_highlight"); debug bool dbg; } @@ -324,13 +342,15 @@ struct UIItem Vec2 size; string[] text_lines; + u8[][] token_lines; + Vec2 scroll_offset; + Vec2 pos_offset; + u8[] text_buffer; f32 max_text_width; f32 resize_pct; - Vec2 scroll_offset; + bool rendered; mixin UIItemParameters!(); - - bool rendered; } enum SizeType @@ -362,7 +382,7 @@ struct UIBuffer struct GlyphBounds { - f32 r = 0.0, l = 0.0, t = 0.0, b = 0.0, w = 0.0, h = 0.0; + f32 r = 0.0, l = 0.0, t = 0.0, b = 0.0, w = 0.0, h = 0.0; f32 atlas_r = 0.0, atlas_l = 0.0, atlas_t = 0.0, atlas_b = 0.0; } @@ -374,7 +394,8 @@ struct VPos struct Vertex { - Vec4[4] cols; + Vec4 cols; + Vec4 corner_radius; Vec2[2] bounds; union { @@ -388,7 +409,6 @@ struct Vertex }; }; f32 border_thickness; - f32 corner_radius; f32 edge_softness; f32 raised; u32 texture; @@ -410,30 +430,6 @@ struct UIKey u64 hash; } -struct UIPanel -{ - u8[] id; - Editor* ed; - - UIPanel* parent, next, prev, first, last, list_next; - Axis2D axis; - f32 pct; - Vec4 color; - - Rect rect; - Vec2 size; - - i64 start_ln, end_ln, vis_lines, prev_start_ln; - f32 scroll_offset, scroll_target; -} - -struct TextPart -{ - UIItem* item; - TextPart* next; - u32 count; -} - enum bool StringType(T) = (is(T: string) || is(T: u8[]) || is(T: char[])); void @@ -456,15 +452,12 @@ InitUICtx(PlatformWindow* window) } g_UI_NIL = cast(UIItem*)&g_ui_nil_item; - g_UI_NIL_PANEL = cast(UIPanel*)&g_ui_nil_panel; g_UI_NIL_INPUT = cast(UIInput*)&g_ui_nil_input; g_NIL_F32_STACK = cast(Stack!f32*)&g_nil_f32_stack; g_NIL_GRAD_COL_STACK = cast(Stack!Vec4[4]*)&g_nil_gradient_col_stack; g_NIL_VEC4_STACK = cast(Stack!Vec4*)&g_nil_vec4_stack; g_NIL_U32_STACK = cast(Stack!u32*)&g_nil_u32_stack; - g_ui_ctx.parent_panel = g_UI_NIL_PANEL; - Arena arena = CreateArena(MB(4)); UIBuffer[FRAME_OVERLAP] buffers; @@ -480,6 +473,7 @@ InitUICtx(PlatformWindow* window) font_data: cast(u8[])FONT_BYTES, text_size: 16.0, tab_width: 2, + syntax_colors: [DEFAULT_COLORS, SYNTAX_COLORS], }; UIItem* fi = ctx.free_items; @@ -511,19 +505,19 @@ InitUICtx(PlatformWindow* window) ctx.pipeline_layout = CreatePipelineLayout(&ctx.rd, ctx.desc_set_layout, Mat4.sizeof); Attribute[13] attributes = [ - { binding: 0, location: 0, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof + Vec4.sizeof * 0 }, - { binding: 0, location: 1, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof + Vec4.sizeof * 1 }, - { binding: 0, location: 2, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof + Vec4.sizeof * 2 }, - { binding: 0, location: 3, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof + Vec4.sizeof * 3 }, - { binding: 0, location: 4, format: FMT.RG_F32, offset: Vertex.dst_start.offsetof }, - { binding: 0, location: 5, format: FMT.RG_F32, offset: Vertex.dst_end.offsetof }, - { binding: 0, location: 6, format: FMT.RG_F32, offset: Vertex.src_start.offsetof }, - { binding: 0, location: 7, format: FMT.RG_F32, offset: Vertex.src_end.offsetof }, - { binding: 0, location: 8, format: FMT.R_F32, offset: Vertex.border_thickness.offsetof } , - { binding: 0, location: 9, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof }, - { binding: 0, location: 10, format: FMT.R_F32, offset: Vertex.edge_softness.offsetof }, - { binding: 0, location: 11, format: FMT.R_F32, offset: Vertex.raised.offsetof }, - { binding: 0, location: 12, format: FMT.R_U32, offset: Vertex.texture.offsetof }, + { binding: 0, location: 0, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof }, + { binding: 0, location: 1, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*0 }, + { binding: 0, location: 2, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*1 }, + { binding: 0, location: 3, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*2 }, + { binding: 0, location: 4, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*3 }, + { binding: 0, location: 5, format: FMT.RG_F32, offset: Vertex.dst_start.offsetof }, + { binding: 0, location: 6, format: FMT.RG_F32, offset: Vertex.dst_end.offsetof }, + { binding: 0, location: 7, format: FMT.RG_F32, offset: Vertex.src_start.offsetof }, + { binding: 0, location: 8, format: FMT.RG_F32, offset: Vertex.src_end.offsetof }, + { binding: 0, location: 9, format: FMT.R_F32, offset: Vertex.border_thickness.offsetof }, + { binding: 0, location: 10, format: FMT.R_F32, offset: Vertex.edge_softness.offsetof }, + { binding: 0, location: 11, format: FMT.R_F32, offset: Vertex.raised.offsetof }, + { binding: 0, location: 12, format: FMT.R_U32, offset: Vertex.texture.offsetof }, ]; GfxPipelineInfo ui_info = { @@ -601,15 +595,22 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T) item.flags = flags; Set(item, ctx); - if(item.flags & (UIF.CenteredWindow | UIF.FloatingWindow)) + if(item.flags & (UIF.Window | UIF.FloatingWindow)) { - item.parent = ctx.window_root; - DLLPush(item.parent, item, g_UI_NIL); + item.parent = g_UI_NIL; + UIItem* next = ctx.root; + while(!Nil(next.next)) + { + next = next.next; + } + + next.next = item; } else if(!Nil(item.parent)) { DLLPush(item.parent, item, g_UI_NIL); } + AutoPopStacks(ctx); if(item.last_frame != ctx.frame-1 && item.flags & UIF.Resizeable) @@ -638,6 +639,13 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T) u64 lines = cast(u64)(ceil(text_width/width)); item.text_lines = ScratchAlloc!(string)(lines); + assert(!item.syntax_tokens.length || item.syntax_tokens.length == str.length); + + if(item.syntax_tokens.length) + { + item.token_lines = ScratchAlloc!(u8[])(lines); + } + f32 w = 0.0; u64 line = 0; u64 ch_start = 0; @@ -650,7 +658,13 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T) f32 glyph_w = GlyphWidth(g); if(glyph_w+w > width) { - item.text_lines[line++] = str[ch_start .. i]; + item.text_lines[line] = str[ch_start .. i]; + if(item.syntax_tokens.length) + { + item.token_lines[line] = item.syntax_tokens[ch_start .. i]; + } + + line += 1; ch_start = i; item.max_text_width = item.max_text_width < w ? w : item.max_text_width; @@ -658,6 +672,11 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T) if(line == lines-1) { item.text_lines[line] = str[ch_start .. $]; + if(item.syntax_tokens.length) + { + item.token_lines[line] = item.syntax_tokens[ch_start .. $]; + } + w = CalcTextWidth(item.text_lines[line]); item.max_text_width = item.max_text_width < w ? w : item.max_text_width; @@ -676,6 +695,12 @@ InitSingleLine: item.text_lines = ScratchAlloc!(string)(1); item.text_lines[0] = str; item.max_text_width = CalcTextWidth(item.text_lines[0]); + + if(item.syntax_tokens.length) + { + item.token_lines = ScratchAlloc!(u8[])(1); + item.token_lines[0] = item.syntax_tokens; + } } f32 scroll_speed = 1 - pow(2, (-60.0f * g_delta)); @@ -795,11 +820,12 @@ BeginUI(Inputs* inputs) // Convert Inputs ctx.events.first = ctx.events.last = null; + static bool dragging; static bool mouse_down; - for(auto i = inputs.first; i; i = i.next) + for(InputEvent* i = inputs.first; i; i = i.next) { - switch(i.key) + switch(i.key) { case Input.LeftClick: { @@ -830,9 +856,19 @@ BeginUI(Inputs* inputs) PushUIEvent(ctx, UIInput(type: UIE.Drag, rel: IVec2(i.rel_x, i.rel_y))); } } break; + case Input.ScrollUp, Input.ScrollDown: + { + if(i.pressed) + { + PushUIEvent(ctx, UIInput(type: UIE.Scroll, md: i.md, scroll: i.key == Input.ScrollUp ? -1 : 1)); + } + } break; default: { - PushUIEvent(ctx, UIInput(type: UIE.Press, key: i.key, text: i.pressed ? i.text : [])); + if(i.pressed) + { + PushUIEvent(ctx, UIInput(type: UIE.Press, md: i.md, key: i.key, text: i.pressed ? i.text : [])); + } } break; } } @@ -871,7 +907,7 @@ BeginUI(Inputs* inputs) BeginRendering(&ctx.rd); } - Vec2 ext = GetExtent(&ctx.rd); + Vec2 ext = GetExtent(); if(ext != ctx.res) { ctx.res = ext; @@ -1027,6 +1063,11 @@ EndUI() f32 excess = children_size - size; for(UIItem* c = item.last; !Nil(c); c = c.prev) { + if(c.flags & (UIF.FixedPosition | (UIF.OverflowX< size ? size : c.size.v[axis]; } } @@ -1071,51 +1120,46 @@ EndUI() f32 pos = 0.0; for(UIItem* item = ctx.root; !Nil(item);) { - if(item.parent.layout_axis != axis) + bool fixed = cast(bool)(item.flags & UIF.FixedPosition); + + bool first_child_fixed = item.parent.flags & UIF.FixedPosition && item == item.parent.first; + bool on_layout_axis = item.parent.layout_axis == axis; + if(!on_layout_axis || first_child_fixed) { pos = item.parent.rect.p0.v[axis] + item.parent.padding.v[axis]; } - else if(item == item.parent.first) + + if(item.view_offset.x != 0.0 || item.view_offset.y != 0.0) { - pos += item.parent.padding.v[axis] + item.parent.view_offset.v[axis]; + for(UIItem* c = item.first; !Nil(c); c = c.next) + { + if(!(c.flags & UIF.FixedPosition)) + { + c.pos_offset = item.view_offset; + break; + } + } } - f32 inner_pos = pos; - f32 next_pos = 0.0; - f32 end_pos = inner_pos + item.size.v[axis]; + f32 next_pos = 0.0; + if(fixed) + { + item.rect.p0.v[axis] = item.fixed_pos.v[axis] + item.parent.rect.p0.v[axis]; + item.rect.p1.v[axis] = item.rect.p0.v[axis] + item.size.v[axis]; - item.rect.p0.v[axis] = inner_pos; - item.rect.p1.v[axis] = end_pos; + next_pos = pos; + } + else + { + item.rect.p0.v[axis] = pos + item.pos_offset.v[axis]; + item.rect.p1.v[axis] = item.rect.p0.v[axis] + item.size.v[axis]; - next_pos = item.parent.layout_axis == axis ? end_pos : pos; + next_pos = item.parent.layout_axis == axis ? item.rect.p1.v[axis] : item.rect.p0.v[axis]; + } assert(!isNaN(item.rect.p0.v[axis])); assert(!isNaN(item.rect.p1.v[axis])); - /* - debug - { - bool portal = cast(bool)(item.parent.flags & (UIF.PortalViewX << axis)); - - if(!portal && item != ctx.root) - { - UIItem* p = item.parent; - f32 i0 = item.rect.p0.v[axis]; - f32 i1 = item.rect.p1.v[axis]; - f32 p0 = item.parent.rect.p0.v[axis] + item.parent.border_thickness; - f32 p1 = item.parent.rect.p1.v[axis] - item.parent.border_thickness; - - bool in_bounds_start = i0 >= p0; - bool in_bounds_end = i1 <= p1; - if(!in_bounds_start || !in_bounds_end) - { - Errf("[%s] failed bounds check, item bounds: [%s] parent bounds: [%s]", item.key.hash_text, [i0, i1], [p0, p1]); - } - assert(in_bounds_start && in_bounds_end); - } - } - */ - if(!Nil(item.first)) { item = item.first; @@ -1169,6 +1213,26 @@ EndUI() } } +void +FocusItem(Args...)(string str, Args args) +{ + g_ui_ctx.focus_item = Get(str, args); +} + +void +FocusItem(T)(T focus) if(is(T == UIKey) || StringType!T || is(T == UIItem*)) +{ + static if(is(T == UIItem*)) + { + assert(!Nil(focus)); + g_ui_ctx.focus_item = focus; + } + else + { + g_ui_ctx.focus_item = Get(focus); + } +} + void RenderItem(UICtx* ctx, UIItem* item) { @@ -1194,7 +1258,7 @@ RenderItem(UICtx* ctx, UIItem* item) v.dst_start = item.rect.p0 + item.border_thickness; v.dst_end = item.rect.p1 - item.border_thickness; v.cols = item.bg_col; - v.corner_radius = item.corner_radius; + v.corner_radius = item.flags & UIF.DrawBorder ? item.corner_radius*0.5 : item.corner_radius; v.bounds = ItemBounds(item.parent); AddVertexCount(ctx); @@ -1222,24 +1286,37 @@ RenderItem(UICtx* ctx, UIItem* item) } else { - FontAtlas* atl = &ctx.atlas_buf.atlas; - - f32 y_pos = item.rect.p0.y + item.padding.y; + // The math around all this is fucked + FontAtlas* atl = &ctx.atlas_buf.atlas; + f32 y_pos = item.rect.p0.y + item.padding.y; + Vec4[] syntax_cols = ctx.syntax_colors[item.syntax_highlight]; foreach(i; 0 .. item.text_lines.length) { string str = item.text_lines[i]; - - f32 x_pos = item.flags & UIF.RightAlignText ? item.rect.p1.x - item.padding.x - CalcTextWidth(str) : - item.rect.p0.x + item.padding.x; + u8[] tks = item.token_lines.length ? item.token_lines[i] : []; + f32 x_pos = item.flags & UIF.RightAlignText ? item.rect.p1.x - item.padding.x - CalcTextWidth(str) : + item.rect.p0.x + item.padding.x; x_pos = clamp(x_pos, item.rect.p0.x, item.rect.p1.x); - foreach(j; 0 .. str.length) + if(tks.length) { - u8 ch = str[j]; - Glyph* g = ch < atl.glyphs.length ? atl.glyphs.ptr + ch : null; - DrawGlyph(item, g, &x_pos, y_pos); + foreach(j; 0 .. str.length) + { + u8 ch = str[j]; + Glyph* g = ch < atl.glyphs.length ? atl.glyphs.ptr + ch : null; + DrawGlyph(item, g, &x_pos, y_pos, syntax_cols[tks[j]]); + } + } + else + { + foreach(j; 0 .. str.length) + { + u8 ch = str[j]; + Glyph* g = ch < atl.glyphs.length ? atl.glyphs.ptr + ch : null; + DrawGlyph(item, g, &x_pos, y_pos, item.text_col); + } } y_pos += TEXT_SIZE; @@ -1282,16 +1359,9 @@ RenderItems(UIItem* root) } u32[2] -GetExtent(Renderer* rd) +GetExtent() { - version(ENABLE_RENDERER) - { - return RendererGetExtent(rd); - } - else - { - return [1280, 720]; - } + version(ENABLE_RENDERER) return RendererGetExtent(&g_ui_ctx.rd); else return [1280, 720]; } template @@ -1330,6 +1400,13 @@ PushSizeInfoY(SizeType type, f32 value, f32 strictness = 1.0, bool auto_pop = fa PushSizeInfoVec!(1)(type, value, strictness, auto_pop); } +void +PushCornerRadius(f32 v, bool auto_pop) +{ + Vec4 value = v; + Push!("corner_radius")(value, auto_pop); +} + void PushScrollClampVec(int i)(Vec2 clamp, bool auto_pop) { @@ -1350,20 +1427,6 @@ PushScrollClampY(f32 start, f32 end, bool auto_pop = false) PushScrollClampVec!(1)(Vec2(start, end), auto_pop); } -void -PushBorderCol(Vec4 col, bool auto_pop = false) -{ - Vec4[4] arr = col; - PushBorderCol(arr, auto_pop); -} - -void -PushBgCol(Vec4 col, bool auto_pop = false) -{ - Vec4[4] arr = col; - PushBgCol(arr, auto_pop); -} - void PushPaddingX(f32 padding, bool auto_pop = false) { @@ -1602,53 +1665,6 @@ Recurse(bool pre = true, T)(T* node, T* nil) return result; } -f32 -LineCounterWidth(u32 char_width) -{ - return f32(char_width)*GetCtx().char_width + LINE_COUNT_PADDING*2.0; -} - -Vec2 -InnerSize(UIPanel* panel) -{ - return panel.size - Vec2(g_ui_ctx.border_thickness_top.value*2.0); -} - -void -SetScrollOffset(UIPanel* panel) -{ - f32 scroll_speed = 5.0; - - U64Vec2 pos = VecPos(&panel.ed.buf); - - f32 c_start = TEXT_SIZE * pos.y+1; - f32 c_end = c_start + TEXT_SIZE; - f32 height = f32(panel.vis_lines)*TEXT_SIZE; - - f32 boundary_buf = TEXT_SIZE*4.0; - f32 top_boundary = panel.scroll_offset+boundary_buf; - f32 bot_boundary = panel.scroll_offset+height-boundary_buf; - - if(panel.scroll_offset != 0.0 && c_start < top_boundary) - { - panel.scroll_target = Max(0.0, c_start-boundary_buf); - } - else if(c_end > bot_boundary) - { - panel.scroll_target = panel.scroll_offset + (c_end-bot_boundary); - } - - if(panel.scroll_offset != panel.scroll_target) - { - panel.scroll_offset += (scroll_speed * (panel.scroll_target - panel.scroll_offset)) * (g_delta * 2.0); - - if(fabsf(panel.scroll_offset-panel.scroll_target) < 0.0009) - { - panel.scroll_offset = panel.scroll_target; - } - } -} - UICtx* GetCtx() { @@ -1658,7 +1674,7 @@ GetCtx() Vec2 RootSize() { - return cast(Vec2)GetExtent(&g_ui_ctx.rd); + return cast(Vec2)GetExtent(); } UIKey @@ -1761,7 +1777,7 @@ NewItem(UICtx* ctx) UIItem* Get(Args...)(string str, Args args) { - char[] key = sformat(ScratchAlloc!(cast(u64)(str.length*1.5), str, args)); + char[] key = sformat(ScratchAlloc!(char)(cast(u64)(str.length*1.5)), str, args); return Get(key); } @@ -1807,8 +1823,17 @@ Get(T)(T k) if(is(T: UIKey) || StringType!T) } f32 -CalcTextWidth(string str) +CalcTextWidth(T)(T text) if(is(T == string) || StringType!T) { + static if(is(T == string)) + { + string str = text; + } + else + { + string str = ConvToStr(text); + } + u32 tab_width = g_ui_ctx.tab_width; Glyph* space = g_ui_ctx.atlas_buf.atlas.glyphs.ptr + ' '; @@ -1824,20 +1849,11 @@ CalcTextWidth(string str) pragma(inline) f32 GlyphWidth(Glyph* g) { - f32 width = g.ch == '\t' ? (g_ui_ctx.atlas_buf.atlas.glyphs[' '].advance*cast(f32)(g_ui_ctx.tab_width)) : g.advance; - - return width; -} - -struct TextBuffer -{ - u8[] text; - TS[] style; - TextBuffer* next; + return g.ch == '\t' ? (g_ui_ctx.atlas_buf.atlas.glyphs[' '].advance*cast(f32)(g_ui_ctx.tab_width)) : g.advance; } void -DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y) +DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y, Vec4 col = Vec4(1.0)) { if(glyph) { @@ -1870,9 +1886,11 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y) v = ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count; - v.dst_start = Vec2(*x_pos+gb.l, y); - v.dst_end = Vec2(*x_pos+gb.w+gb.l, y+gb.h); - v.cols = item.text_col; + f32 y_pos = (y - gb.t) + TEXT_SIZE; + + v.dst_start = Vec2(*x_pos+gb.l, y_pos); + v.dst_end = Vec2(*x_pos+gb.w+gb.l, y_pos+gb.h); + v.cols = col; v.texture = true; v.bounds = ItemBounds(item); @@ -1892,8 +1910,8 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y) v.src_end.x -= (v.src_end.x - v.src_start.x) * cull_pct; } - f32 end_y = y + TEXT_SIZE; - f32 height = end_y - y; + f32 end_y = y + TEXT_SIZE; + f32 height = end_y - y; if(end_y > item.rect.p1.y) { f32 cull_pct = (end_y - item.rect.p1.y) / height; @@ -1933,31 +1951,6 @@ GetVertex(UICtx* ctx) return ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count; } -pragma(inline) void -DrawCmdRect(Vec2 pos, Vec2 size, bool edit) -{ - UICtx* ctx = GetCtx(); - - Vec4[4] bg_col = edit ? ctx.bg_hl_col_top.value : ctx.bg_col_top.value; - Vec4[4] border_col = edit ? ctx.border_hl_col_top.value : ctx.border_col_top.value; - - DrawRect(pos, size, ctx.corner_radius_top.value, ctx.border_thickness_top.value, bg_col); - DrawBorder(pos, size, ctx.border_thickness_top.value, ctx.corner_radius_top.value, ctx.edge_softness_top.value, border_col); -} - -pragma(inline) void -DrawPanel(UIPanel* panel, f32 lc_w, bool focus) -{ - UICtx* ctx = GetCtx(); - - Vec2 pos = panel.rect.p0; - Vec2 size = panel.size; - - DrawRect(pos, size, ctx.corner_radius_top.value, ctx.border_thickness_top.value, ctx.bg_col_top.value); - DrawRect(pos, Vec2(lc_w, size.y), 0.0, 0.0, focus ? ctx.bg_hl_col_top.value : ctx.bg_col_top.value); - DrawBorder(pos, size, ctx.border_thickness_top.value, ctx.corner_radius_top.value, ctx.edge_softness_top.value, focus ? ctx.border_hl_col_top.value : ctx.border_col_top.value); -} - static UISize[2] MakeUISize(UISize x, UISize y) { @@ -1983,62 +1976,6 @@ GetGlyph(u8 ch) return ch < a.glyphs.length ? a.glyphs.ptr + ch : a.glyphs.ptr; } -pragma(inline) void -DrawRect(f32 x, f32 y, u8 ch, Vec4 col, bool edit_mode) -{ - Glyph* g = GetGlyph(ch); - Vec4[4] cols = col; - DrawRect(Vec2(x, y-TEXT_SIZE*0.8), Vec2(edit_mode ? 1.0 : g.advance, TEXT_SIZE), 0.0, 0.0, cols); -} - -pragma(inline) void -DrawRect(Vec2 pos, Vec2 size, f32 corner_radius, f32 border_thickness, Vec4[4] cols) -{ - UICtx* ctx = GetCtx(); - DrawRect(pos.x, pos.y, size.x, size.y, corner_radius, border_thickness, cols); -} - -void -DrawRect(f32 x, f32 y, f32 w, f32 h, f32 corner_radius, f32 border, Vec4[4] cols) -{ - UICtx* ctx = GetCtx(); - - Vertex* v = GetVertex(ctx); - v.dst_start.x = x; - v.dst_start.y = y; - v.dst_end.x = x+w; - v.dst_end.y = y+h; - v.cols = cols; - v.corner_radius = corner_radius; - - v.border_thickness = v.edge_softness = v.raised = 0.0; - - if(border > 0.0) - { - v.dst_start += border; - v.dst_end -= border; - } - - AddVertexCount(ctx); -} - -void -DrawBorder(Vec2 pos, Vec2 size, f32 border, f32 radius, f32 softness, Vec4[4] cols) -{ - UICtx* ctx = GetCtx(); - - Vertex* v = GetVertex(ctx); - v.dst_start = pos; - v.dst_end = pos + size; - v.cols = cols; - v.corner_radius = radius; - v.border_thickness = border; - v.edge_softness = softness; - v.raised = 0.0; - - AddVertexCount(ctx); -} - pragma(inline) void AddVertexCount(UICtx* ctx) { @@ -2058,67 +1995,6 @@ InBounds(T)(T pos, Rect* rect) return pos.x >= rect.p0.x && pos.x <= rect.p1.x && pos.y >= rect.p0.y && pos.y <= rect.p1.y; } -bool -Clicked(UIItem* item, Rect* rect) -{ - bool result; - UICtx* ctx = GetCtx(); - - for(auto n = ctx.inputs.first; !CheckNil(null, n) && Nil(ctx.drag_item); n = n.next) - { - InputEvent* ev = n; - - if(ev.key == Input.LeftClick && ev.pressed && InBounds(ev, rect)) - { - result = true; - DLLRemove(ctx.inputs, n, null); - break; - } - } - - return result; -} - -bool -Dragged(UIItem* item, Rect* rect) -{ - bool result; - UICtx* ctx = GetCtx(); - - item.dragged = 0; - - if(Nil(ctx.drag_item) && Clicked(item, rect)) - { - ctx.drag_item = item; - } - - for(auto n = ctx.inputs.first; !CheckNil(null, n) && ctx.drag_item == item; n = n.next) - { - InputEvent* ev = n; - bool taken; - - if(ev.key == Input.MouseMotion) - { - item.dragged.x += ev.rel_x; - item.dragged.y += ev.rel_y; - result = true; - taken = true; - } - else if(ev.key == Input.LeftClick && !ev.pressed) - { - ctx.drag_item = g_UI_NIL; - taken = true; - } - - if(taken) - { - DLLRemove(ctx.inputs, n, null); - } - } - - return result; -} - static Vec4[4] Vec4Arr(Vec4 vec) { @@ -2168,7 +2044,7 @@ unittest EndUI(); - Vec2 extent = GetExtent(null); + Vec2 extent = GetExtent(); assert(extent == ctx.root.size); BeginUI(&inputs); diff --git a/src/editor/views.d b/src/editor/views.d index 075321b..e1be8a2 100644 --- a/src/editor/views.d +++ b/src/editor/views.d @@ -8,14 +8,33 @@ import std.algorithm.comparison : clamp; import std.format; import std.conv; -bool -Nil(UIPanel* panel) +__gshared const Panel g_nil_panel; +__gshared Panel* g_NIL_PANEL; +__gshared const Editor g_nil_ed; +__gshared Editor* g_NIL_ED; + +Vec4 BG_COL = Vec4(0.18, 0.18, 0.18, 1.0); + +Vec4 CMD_COL = Vec4(0.22, 0.22, 0.22, 1.0); +Vec4 HL_BG_COL = Vec4(0.160, 0.533, 0.803, 1.0); +Vec4 HL_BORDER_COL = Vec4(0.172, 0.643, 0.988, 1.0); + +shared static this() { - return panel == null || panel == g_UI_NIL_PANEL; + g_NIL_PANEL = cast(Panel* )&g_nil_panel; + g_NIL_ED = cast(Editor*)&g_nil_ed; +} + +struct Panel +{ + Panel* first, last, next, prev, parent; + Axis2D layout_axis; + Editor* ed; + u64 id; } void -LineCounterView(u64 max_line, u64 lines, u64 line_offset, f32 view_offset) +LineCounterView(u64 max_line, u64 lines, i64 line_offset, f32 view_offset) { UICtx* ctx = GetCtx(); UIKey zero = ZeroKey(); @@ -35,7 +54,7 @@ LineCounterView(u64 max_line, u64 lines, u64 line_offset, f32 view_offset) PushParent(line_count); u64 end_line = lines+line_offset; - for(u64 i = line_offset; i < end_line; i += 1) + for(u64 i = line_offset; i < end_line && i < max_line; i += 1) { char[] buf = ScratchAlloc!(char)(ch_width); Push!("display_string")(ConvToStr(sformat(buf, "%s", i)), true); @@ -46,8 +65,10 @@ LineCounterView(u64 max_line, u64 lines, u64 line_offset, f32 view_offset) } void -EditorTextView(UIItem* editor, Editor* ed, u64 lines, u64 line_offset, f32 view_offset) +EditorTextView(UIItem* editor, Panel* p, u64 lines, i64 line_offset, f32 view_offset) { + Editor* ed = p.ed; + PushLayoutAxis(A2D.Y, true); f32 clamp_y = cast(f32)(ed.buf.line_count-lines)*TEXT_SIZE; @@ -60,94 +81,181 @@ EditorTextView(UIItem* editor, Editor* ed, u64 lines, u64 line_offset, f32 view_ PushScrollTargetY(scroll_pos, true); PushViewOffsetY(view_offset, true); - static bool end; - static f32 count = 0.0; - - if(!end) - { - ed.cursor_pos.y = 500; - count += g_delta; - if(count > 0.5) - { - end = !end; - } - } - else - { - ed.cursor_pos.y = 0; - count -= g_delta; - if(count <= 0.0) - { - end = !end; - } - } - editor = MakeItem(editor.key, UIF.DrawBorder|UIF.ScrollY|UIF.ClampY); - u64 end_line = line_offset+lines; - + PushParent(editor); UIKey zero = ZeroKey(); - PushSizeInfoY(ST.TextSize, 1.0); - PushParent(editor); + // Cursor + { + LineBuffer* lb = GetLine(&ed.buf, ed.cursor_pos.y); - scope(exit) Pop!("size_info", "parent"); + f32 cursor_x = CalcTextWidth(lb.text[0 .. ed.cursor_pos.x]); + f32 cursor_y = cast(f32)(ed.cursor_pos.y - line_offset)*TEXT_SIZE + view_offset; + PushSizeInfo(MakeUISize(UISize(ST.Pixels, GetCtx().char_width), UISize(ST.Pixels, TEXT_SIZE)), true); + PushFixedPos(Vec2(cursor_x, cursor_y), true); + PushBgCol(Vec4(1.0), true); + MakeItem(zero, UIF.DrawBackground|UIF.FixedPosition); + } + + u64 end_line = line_offset+lines; + PushSizeInfoY(ST.TextSize, 1.0); + PushSyntaxHighlight(UISH.D); + + scope(exit) Pop!("size_info", "parent", "syntax_highlight"); u64 i = line_offset; for(LineBuffer* lb = GetLine(&ed.buf, i); !CheckNil(g_NIL_LINE_BUF, lb) && i < line_offset+lines; i += 1, lb = GetLine(&ed.buf, i)) { PushDisplayString(ConvToStr(lb.text), true); + PushSyntaxTokens(cast(u8[])lb.style, true); UIItem* line = MakeItem(zero, UIF.DrawText); } } void -EditorView(Editor* ed) +EditorView(Panel* p) { - UICtx* ctx = GetCtx(); - UIKey zero = ZeroKey(); - UIKey ed_key = MakeKey("###ed_%s", ed.editor_id); - UIItem* editor = Get(ed_key); + Editor* ed = p.ed; + UICtx* ctx = GetCtx(); + UIKey zero = ZeroKey(); - u64 frame_line_offset = ed.line_offset; - f32 frame_view_offset = -(editor.scroll_offset.y%TEXT_SIZE); - - PushBgCol(Vec4(0.2, 0.3, 0.8, 1.0), true); - PushSizeInfoX(ST.Percentage, 1.0, 1.0, true); - - UIItem* container = MakeItem(zero, UIF.DrawBackground); - - PushParent(container); - PushBorderCol(Vec4(1.0)); - - scope(exit) Pop!("parent", "border_col"); - - u64 view_lines; - if(editor.size.y > 0.0) + if(CheckNil(g_NIL_ED, ed)) { - view_lines = cast(u64)ceil(editor.size.y/TEXT_SIZE)+1; - - const u64 SCROLL_BUFFER = 4; - - u64 start = ed.line_offset; - u64 end = start+view_lines; - - if(ed.cursor_pos.y < start) + for(Panel* c = p.first; !CheckNil(g_NIL_PANEL, c); c = c.next) { - u64 pos = ed.cursor_pos.y > SCROLL_BUFFER ? ed.cursor_pos.y - SCROLL_BUFFER : ed.cursor_pos.y; - ed.line_offset = clamp(pos, 0, ed.buf.line_count); + EditorView(c); } - else if(ed.cursor_pos.y > end) + } + else + { + UIKey ed_key = MakeKey("###ed_%s", ed.editor_id); + UIItem* editor = Get(ed_key); + + u64 frame_line_offset = ed.line_offset; + f32 frame_view_offset = -(editor.scroll_offset.y%TEXT_SIZE); + + PushBgCol(BG_COL, true); + PushSizeInfoX(ST.Percentage, 1.0, 1.0, true); + + UIItem* container = MakeItem(zero, UIF.DrawBackground); + + PushParent(container); + PushBorderCol(Vec4(1.0)); + + scope(exit) Pop!("parent", "border_col"); + + u64 view_lines; + if(editor.size.y > 0.0) { - ed.line_offset = clamp(ed.cursor_pos.y + SCROLL_BUFFER - view_lines, 0, ed.buf.line_count); - } + view_lines = cast(u64)ceil(editor.size.y/TEXT_SIZE)+1; + + const u64 SCROLL_BUFFER = 4; + + u64 start = ed.line_offset; + u64 end = start+view_lines; + + if(ed.cursor_pos.y < start) + { + u64 pos = ed.cursor_pos.y > SCROLL_BUFFER ? ed.cursor_pos.y - SCROLL_BUFFER : ed.cursor_pos.y; + ed.line_offset = clamp(pos, 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); + } + } + + u64 start = cast(u64)floor(editor.scroll_offset.y/TEXT_SIZE); + LineCounterView(ed.buf.line_count, view_lines, start, frame_view_offset); + EditorTextView(editor, p, view_lines, start, frame_view_offset); + + for(UIInput* i = ctx.events.first; !CheckNil(g_UI_NIL_INPUT, i) && g_ed_ctx.focused_editor == p.ed; i = i.next) + { + bool taken; + + if(i.type == UIE.Scroll) + { + ed.line_offset = clamp(ed.line_offset+(i.scroll*2), 0, ed.buf.line_count); + if(ed.cursor_pos.y < ed.line_offset) + { + ed.cursor_pos.y = ed.line_offset; + } + else if(ed.cursor_pos.y > ed.line_offset+view_lines) + { + ed.cursor_pos.y = ed.line_offset+view_lines-1; + } + + taken = true; + } + else + { + HandleInputs(p, &ctx.events); + } + + if(taken) + { + DLLRemove(&ctx.events, i, g_UI_NIL_INPUT); + } + } + + ed.cursor_pos = VecPos(&ed.buf); + } +} + +void +CommandPalette(CmdPalette* cmd) +{ + UICtx* ctx = GetCtx(); + Vec2 ext = GetExtent(); + + f32 w = ext.x*0.4; + f32 h = ext.y*0.7; + + PushFixedPos(Vec2(ext.x*0.3, ext.y*0.1), true); + PushBgCol(BG_COL, true); + PushBorderCol(HL_BORDER_COL, true); + PushBorderThickness(2.0f, true); + PushCornerRadius(8.0f, true); + PushViewOffset(Vec2(-2.0f), true); + PushLayoutAxis(A2D.Y, true); + PushSizeInfo(MakeUISize(UISize(ST.Pixels, w), UISize(ST.Pixels, h))); + + UIItem* cmd_item = MakeItem("###cmd_palette", UIF.Window|UIF.FixedPosition|UIF.DrawBackground|UIF.DrawBorder); + + f32 padding_y = 8.0; + PushParent(cmd_item); + PushPadding(Vec2(4.0, padding_y), true); + scope(exit) Pop!("parent", "padding")(); + + PushBgCol(HL_BG_COL, true); + PushBorderCol(HL_BORDER_COL); + PushBorderThickness(2.0f, true); + PushCornerRadius(Vec4(8.0, 8.0, 0.0, 0.0), true); + PushSizeInfo(MakeUISize(UISize(ST.Pixels, w-padding_y), UISize(ST.TextSize, 1.0)), true); + PushDisplayString(ConvToStr(cmd.buffer[0 .. cmd.icount]), true); + + UIKey zero = ZeroKey(); + + MakeItem(zero, UIF.DrawBorder|UIF.DrawBackground|UIF.DrawText|UIF.Overflow); + + PushPadding(Vec2(4.0)); + PushSizeInfoY(ST.TextSize, 1.0); + scope(exit) Pop!("size_info", "padding")(); + + Vec4[2] opt_cols = [ + Vec4(0.22, 0.22, 0.22, 1.0), + Vec4(0.35, 0.35, 0.35, 1.0), + ]; + + foreach(i; 0 .. cmd.opt_strs.length) + { + PushDisplayString(ConvToStr(cmd.opt_strs[i]), true); + PushBgCol(cmd.selected == i ? HL_BG_COL : opt_cols[i%2], true); + MakeItem(zero, UIF.DrawBackground|UIF.DrawText); } - u64 start = cast(u64)floor(editor.scroll_offset.y/TEXT_SIZE); - - LineCounterView(ed.buf.line_count, view_lines, start, frame_view_offset); - - EditorTextView(editor, ed, view_lines, start, frame_view_offset); + //PushDisplayString(ConvToStr(cmd.buffer)); } /* diff --git a/src/shaders/gui.vert.glsl b/src/shaders/gui.vert.glsl index e4919ab..ba71ca7 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 = 0) in vec4 in_col; +layout (location = 1) in float in_corner_radius_x0y0; +layout (location = 2) in float in_corner_radius_x1y0; +layout (location = 3) in float in_corner_radius_x0y1; +layout (location = 4) in float in_corner_radius_x1y1; +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 edge_softness; layout (location = 11) in float raised; -layout (location = 12) in uint in_has_texture; +layout (location = 12) in uint in_has_texture; layout (location = 0) flat out uint out_has_texture; @@ -33,7 +33,6 @@ layout (location = 1) out struct FragDataOut { float border_thickness; } FragData; - vec2 Vertices[4] = vec2[4]( vec2(-1.0, -1.0), vec2(-1.0, +1.0), @@ -68,22 +67,22 @@ void main() vec2(in_src_end.x, in_src_end.y) ); - vec4 cols[4] = vec4[4]( - in_col_1, - in_col_2, - in_col_3, - in_col_4 + float corner_radius[4] = float[4]( + in_corner_radius_x0y0, + in_corner_radius_x0y1, + in_corner_radius_x1y0, + in_corner_radius_x1y1 ); vec2 dst_verts_pct = vec2(bool(gl_VertexIndex >> 1) ? 1.0f : 0.0f, bool(gl_VertexIndex & 1) ? 0.0f : 1.0f); - FragData.color = cols[gl_VertexIndex]; + FragData.color = in_col; FragData.uv = uvs[gl_VertexIndex] / tex_size; FragData.dst_pos = pos; FragData.dst_center = center; FragData.dst_half_size = half_size; - FragData.corner_radius = corner_radius; + FragData.corner_radius = corner_radius[gl_VertexIndex]; FragData.softness = edge_softness; FragData.raised = raised; FragData.border_thickness = border_thickness;