From 1700119e577ee7a042e06da7a344714e1d8ee97c Mon Sep 17 00:00:00 2001 From: Matthew Date: Sun, 11 Jan 2026 20:08:55 +1100 Subject: [PATCH] delete a bunch of code --- src/editor/editor.d | 38 +- src/editor/ui.d | 1736 ++++++------------------------------------- src/editor/views.d | 465 ------------ 3 files changed, 239 insertions(+), 2000 deletions(-) diff --git a/src/editor/editor.d b/src/editor/editor.d index 137a542..5761766 100644 --- a/src/editor/editor.d +++ b/src/editor/editor.d @@ -182,42 +182,6 @@ Cycle(Inputs* inputs) UICtx* ui_ctx = GetCtx(); - debug - { - ui_ctx.dbg = false; - - for(InputEvent* ev = inputs.first; ev; ev = ev.next) - { - if(ev.key == Input.g && ev.md & MD.LeftCtrl) - { - ui_ctx.dbg = true; - break; - } - } - } - - UIItem* container = Container(A2D.Y, UIS2()); - UIItem* ed_container = Container(A2D.X, UISY(ST.Percentage, 0.98)); - EditorView(g_ed_ctx.base_panel); - Pop!("parent"); - - assert(ui_ctx.parent.top.value == container); - - StatusBar(&g_ed_ctx); - - UIItem* cmd_item = Get("###cmd_palette"); - - bool cmd_active = Active(ES.CmdPalette); - if(cmd_active || Ready(cmd_item)) - { - CommandPalette(&g_ed_ctx.cmd, cmd_active); - } - - if(Active(ES.RunCmd)) - { - - } - EndUI(); } @@ -462,6 +426,7 @@ AddEditor(Panel* target, Axis2D axis) panel.parent = target.parent; UIItem* ed_item = GetEditorItem(panel.ed); + /* if(!Nil(ed_item.parent)) { u64 count; @@ -476,6 +441,7 @@ AddEditor(Panel* target, Axis2D axis) c.resize_pct = pct; } } + */ FocusEditor(panel); } diff --git a/src/editor/ui.d b/src/editor/ui.d index 5b36c80..0cdfc20 100644 --- a/src/editor/ui.d +++ b/src/editor/ui.d @@ -90,70 +90,21 @@ __gshared const UIItem g_ui_nil_item; __gshared UIItem* g_UI_NIL; __gshared const UIInput g_ui_nil_input; __gshared UIInput* g_UI_NIL_INPUT; -__gshared const Stack!f32 g_nil_f32_stack; -__gshared Stack!f32* g_NIL_F32_STACK; -__gshared const Stack!Vec4[4] g_nil_gradient_col_stack; -__gshared Stack!Vec4[4]* g_NIL_GRAD_COL_STACK; -__gshared const Stack!Vec4 g_nil_vec4_stack; -__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, Y, Max, -} - -alias A2D = Axis2D; +} alias A2D = Axis2D; enum UIFlags : u64 { - None = 0, - DrawBackground = 1LU<<0, - DrawText = 1LU<<1, - DrawBorder = 1LU<<2, - Clickable = 1LU<<3, - Draggable = 1LU<<4, - ScrollX = 1LU<<5, - ScrollY = 1LU<<6, - ClampX = 1LU<<7, - ClampY = 1LU<<8, - Resizeable = 1LU<<9, - ResizeAdjacent = 1LU<<10, - FloatingWindow = 1LU<<11, // todo - Window = 1LU<<12, - TextInput = 1LU<<13, // todo - RightAlignText = 1LU<<14, - CenterAlignText = 1LU<<15, // todo - TextWrap = 1LU<<16, - ScissorX = 1LU<<17, - ScissorY = 1LU<<18, - FixedPosition = 1LU<<19, - FixedPosAnimated = 1LU<<20, // todo: add fixed_pos_target then interpolate position every frame - OverflowX = 1LU<<21, - OverflowY = 1LU<<22, - Gradient = 1LU<<23, - VerticalAlignText = 1LU<<24, - SetHot = 1LU<<25, - SetReady = 1LU<<26, - SetActive = 1LU<<27, - AnimateReady = 1LU<<28, // Fade in/out - AnimateHot = 1LU<<29, // Hover highlight - AnimateActive = 1LU<<30, // Animate selected (probably do later) - DrawDropShadow = 1LU<<31, - ScrollFitChildren = 1LU<<32, - - Clamp = UIFlags.ClampX | UIFlags.ClampY, - Scissor = UIFlags.ScissorX | UIFlags.ScissorY, - Scroll = UIFlags.ScrollX | UIFlags.ScrollY, - Overflow = UIFlags.OverflowX | UIFlags.OverflowY, -} -alias UIF = UIFlags; - -const UIFlags AUTO_FLAGS = UIF.ResizeAdjacent; -const UIFlags DRAW_FLAGS = UIF.DrawBackground|UIF.DrawBorder|UIF.DrawText|UIF.Scissor|UIF.DrawDropShadow; + None = 0, + Parent = 1<<0, + Panel = 1<<1, + Window = 1<<2, +} alias UIF = UIFlags; enum UISignal { @@ -161,8 +112,7 @@ enum UISignal Clicked = 1<<0, Dragged = 1<<1, Hovered = 1<<2, -} -alias UIS = UISignal; +} alias UIS = UISignal; enum UIEvent { @@ -173,8 +123,7 @@ enum UIEvent DragStart = 1<<3, Press = 1<<4, Scroll = 1<<5, -} -alias UIE = UIEvent; +} alias UIE = UIEvent; struct UIInput { @@ -199,44 +148,18 @@ enum UISyntaxHighlight None, D, Max, -} -alias UISH = UISyntaxHighlight; +} alias UISH = UISyntaxHighlight; -mixin template -UICtxParameter(T, string name) +enum ItemStateFlags { - static string - CtxParameterGen(T, string name)() - { - import std.traits, std.array; - - string stack_top = "\tStackTop!("~T.stringof~") "~name~";\n"; - string stack = "\tStack!("~T.stringof~")* "~name~"_top;\n"; - - return stack_top~stack; - } - - mixin(CtxParameterGen!(T, name)()); -} - -template -CtxMemberInfo(int i) -{ - import std.string : endsWith, startsWith; - import std.traits : isInstanceOf, isPointer; - - struct MemberInfo - { - string id; - bool is_stack, is_top; - } - - enum string id = __traits(identifier, UICtx.tupleof[i]); - enum bool is_top = endsWith(id, "_top"); - enum bool is_stack = startsWith(typeof(UICtx.tupleof[i]).stringof, "StackTop!"); - - enum MemberInfo CtxMemberInfo = MemberInfo(id: id, is_stack: is_stack, is_top: is_top); -} + None = 0, + Hot = 1<<0, + Ready = 1<<1, + Active = 1<<2, + SetHot = 1<<3, + SetReady = 1<<4, + SetActive = 1<<5, +} alias ISF = ItemStateFlags; struct PushConst { @@ -255,7 +178,7 @@ struct UICtx Arena arena; Arena temp_arena; - Arena key_stack_arena; + Arena stack_arena; Inputs* inputs; u64 frame; @@ -299,120 +222,7 @@ struct UICtx f32 fade_rate; Stack!(UIItem*)* key_item_stack; - - ItemStyle[UIElem.max] item_styles; - UIElement next_element; - - mixin UICtxParameter!(UISize[2], "size_info"); - mixin UICtxParameter!(u8[], "syntax_tokens"); - mixin UICtxParameter!(string, "display_string"); - mixin UICtxParameter!(UISyntaxHighlight, "syntax_highlight"); - mixin UICtxParameter!(Vec2[2], "scroll_clamp"); - mixin UICtxParameter!(Vec2, "scroll_target"); - mixin UICtxParameter!(Vec2, "fixed_pos"); - mixin UICtxParameter!(UIItem*, "parent"); - mixin UICtxParameter!(Axis2D, "layout_axis"); - mixin UICtxParameter!(u32, "text_size"); - - /* - mixin UICtxParameter!(Vec4, "bg_col"); - mixin UICtxParameter!(Vec4, "bg_col_end"); - mixin UICtxParameter!(Vec4, "bg_hl_col"); - mixin UICtxParameter!(Vec4, "border_col"); - mixin UICtxParameter!(Vec4, "border_hl_col"); - mixin UICtxParameter!(Vec4, "text_col"); - mixin UICtxParameter!(Vec4, "text_hl_col"); - mixin UICtxParameter!(Vec2[2], "padding"); - mixin UICtxParameter!(Vec4, "corner_radius"); - mixin UICtxParameter!(f32, "border_thickness"); - mixin UICtxParameter!(f32, "edge_softness"); - */ - - debug bool dbg; - debug u64 item_count; -} - -struct ItemStyle -{ - Vec4 bg_col; - Vec4 bg_hl_col; - Vec4 border_col; - Vec4 border_hl_col; - Vec4 text_col; - Vec4 text_hl_col; - Vec2[2] padding; - Vec4 corner_radius; - f32 border_thickness; - f32 edge_softness; -} - -enum UIElement -{ - Default, - LineCount, - LineCountText, - EditorPanel, - EditorTextView, - EditorTextCursor, - EditorText, - CmdWindow, - CmdOptWindow, - CmdOpt, - CmdOptAlt, - CmdTitleText, - CmdSubtitleText, - CmdInput, - CmdInputEmpty, - StatusInfo, - StatusMessage, - Max, -} -alias UIElem = UIElement; - -enum Element -{ - Panel, - PanelFocus, - Window, - WindowFocus, - Border, - BorderFocus, - Text, - Button, - ButtonAlt, // Alternating option colours - ButtonFocus, - Max, -} alias Elem = Element; - -struct UIStyle -{ - enum N = Elem.max; - - Vec4[N] cols; - Vec4 corner_radius; - Vec2[2] text_box_padding; - Vec2[2] button_padding; - f32 border_thickness; - f32 edge_softness; -} - -ItemStyle -DefaultItemStyle() -{ - ItemStyle style = { - bg_col: BG_COL, - bg_hl_col: BG_HL_COL, - border_col: BORDER_COL, - border_hl_col: BORDER_HL_COL, - text_col: TEXT_COL, - text_hl_col: TEXT_HL_COL, - padding: Vec2A2(0.0, 0.0, 0.0, 0.0), - corner_radius: 0.0, - border_thickness: 0.0, - edge_softness: 0.8, - }; - - return style; + Stack!(UIItem*)* parent_stack; } struct FontGlyphs @@ -436,66 +246,29 @@ struct StackTop(T) Stack!(T)* free; } -static string -UIItemParameterGen() -{ - string fields = ""; - static foreach(i, m; UICtx.tupleof) - { - { - enum info = CtxMemberInfo!(i); - static if(info.is_stack) - { - fields ~= typeof(UICtx.tupleof[i].top.value).stringof ~ " " ~ info.id; - static if(is(typeof(UICtx.tupleof[i]): f32)) - { - fields ~= " = 0.0"; - } - fields ~= ";\n"; - } - } - } - - return fields; -} - -mixin template -UIItemParameters() -{ - mixin(UIItemParameterGen()); -} - struct UIItem { IVec2 dragged; UIKey key; + UIItem* next, prev, first, last, parent; - u64 last_frame; - UISignal signal; - UIFlags flags; - UIElem element; - - UIItem* next, prev, first, last; // parent in mixin - UIItem* transient_next; - UIItem* last_relative_item; - Rect rect; Vec2 size; - string[] text_lines; - u8[][] token_lines; + Vec4 bg_col; + Vec4 border_col; + Vec4 corner_radius; Vec2 scroll_offset; Vec2 scroll_size; - u8[] text_buffer; - f32 max_text_width; - f32 resize_pct; - bool processed; - + UIFlags flags; + u64 last_frame; + Axis2D layout_axis; + f32 edge_softness; + f32 border_thickness; + f32 panel_pct; f32 ready_t; // Item visible f32 hot_t; // Item to be interacted with (e.g. hover) f32 active_t; // Item active (retained focus) - - mixin UIItemParameters!(); } enum SizeType @@ -593,101 +366,8 @@ struct UIKey enum bool KeyType(T) = (StringType!(T) || is(T == UIKey) || is(T == const(UIKey))); enum bool ItemAndKeyType(T) = (KeyType!(T) || is(T == UIItem*)); -// ****** -// Public -// ****** - void -BeginContainer(ST x_t = ST.Pct, ST y_t = ST.Pct)(Axis2D axis, f32 w, f32 h) -{ - PushSizeInfo(UIS2(x_t, y_t, w, h)); - PushAxisLayout(axis); - UIItem* item = MakeItem(ZeroKey()); - PushParent(item); -} -alias EndContainer = Pop!("parent"); - -enum WindowFlags -{ - None = 0<<0, - NoBorder = 1<<0, - NoBackground = 1<<1, - NoDropShadow = 1<<2, - Draggable = 1<<3, - NoTitleBar = 1<<4, -} alias WinF = WindowFlags; - -UIFlags -GetFlags(WinF flags)() -{ - UIFlags flags = UIF.DrawBackground|UIF.DrawBorder|UIF.DrawDropShadow|UIF.AnimateReady|UIF.Window; - static if(flags & WinF.NoBorder) - { - flags &= ~UIF.DrawBorder; - } - static if(flags & WinF.NoBackground) - { - flags &= ~UIF.DrawBackground; - } - static if(flags & WinF.NoDropShadow) - { - flags &= ~UIF.DrawDropShadow; - } - static if(flags & WinF.Draggable) - { - flags &= ~UIF.Window; - flags |= UIF.FloatingWindow; - } - - return flags; -} - -// Converts to parameters (string label, Args args, Axis2D axis, f32 x, f32 y, f32 w, f32 h) -void -BeginWindow(WinF flags = WinF.None, ST x_t = ST.Px, ST x_y = ST.Px, Args...)(string label, Args args) -{ - enum len = Args.length; - - static assert(is(typeof(Args[len-1]) == f32)); - static assert(is(typeof(Args[len-2]) == f32)); - static assert(is(typeof(Args[len-3]) == f32)); - static assert(is(typeof(Args[len-4]) == f32)); - static assert(is(typeof(Args[len-5]) == Axis2D)); - - string scratch = Scratchf!(Args[0 .. len-5])(label, args[0 .. len-5]); - - BeginWindow!(flags, x_t, x_y)(scratch, args[len-5], args[len-4], args[len-3], args[len-2], args[len-1]); -} - -void -BeginWindow(WinF flags = WinF.None, ST x_t = ST.Px, ST x_y = ST.Px)(string label, Axis2D axis, f32 x, f32 y, f32 w, f32 h) -{ - PushFixedPos(Vec2(x, y)); - PushSizeInfo(UIS2(x_t, y_t, w, h)); - PushAxisLayout(axis); - UIFlags flags = GetFlags!(flags); - - static assert((flags & WinF.Draggable) == 0 || (flags & ~WinF.NoTitleBar) == flags, "Unable to use NoTitleBar flag with the Draggable flag"); - - UIItem* window = MakeItem("###window_%s", label, flags); - - static if(flags & WinF.Draggable) - { - //UIItem* header - } -} - -void -EndWindow() -{ - UIItem* window = Pop!("parent"); - -} - -// ******** -// Internal -// ******** void InitUICtx(PlatformWindow* window) @@ -710,10 +390,6 @@ InitUICtx(PlatformWindow* window) g_UI_NIL = cast(UIItem*)&g_ui_nil_item; 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; Arena arena = CreateArena(MB(4)); @@ -725,7 +401,7 @@ InitUICtx(PlatformWindow* window) ctx.free_items = Alloc!(UIItem)(&arena); ctx.arena = arena; ctx.temp_arena = CreateArena(MB(1)); - ctx.key_stack_arena = CreateArena(MB(1)); + ctx.stack_arena = CreateArena(MB(1)); ctx.transient_items = g_UI_NIL; ctx.font = OpenFont(cast(u8[])FONT_BYTES); ctx.tab_width = 2; @@ -734,7 +410,7 @@ InitUICtx(PlatformWindow* window) assert(ctx.font); UIItem* fi = ctx.free_items; - fi.transient_next = fi.first = fi.last = fi.next = fi.prev = fi.parent = g_UI_NIL; + fi.first = fi.last = fi.next = fi.prev = fi.parent = g_UI_NIL; version(ENABLE_RENDERER) { @@ -807,130 +483,7 @@ InitUICtx(PlatformWindow* window) SetClearColors(&ctx.rd, [0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 0.0, 0.0]); } - foreach(i; 0 .. ctx.item_styles.length) - { - ctx.item_styles[i] = DefaultItemStyle(); - } - - with(UIElem) - { - with(ctx.item_styles[LineCount]) - { - padding = Vec2(4.0); - edge_softness = 0.0; - border_thickness = 1.0; - } - - with(ctx.item_styles[LineCountText]) - { - // None - } - - with(ctx.item_styles[EditorPanel]) - { - // None - } - - with(ctx.item_styles[EditorTextView]) - { - padding = Vec2(4.0); - edge_softness = 0.0; - border_thickness = 1.0; - } - - with(ctx.item_styles[EditorTextCursor]) - { - bg_col = Vec4(1.0); - } - - with(ctx.item_styles[EditorText]) - { - border_col = HL_BORDER_COL; - border_thickness = 4.0; - corner_radius = Vec4(8.0); - } - - with(ctx.item_styles[EditorText]) - { - - } - - with(ctx.item_styles[CmdWindow]) - { - corner_radius = Vec4(8.0); - } - - with(ctx.item_styles[CmdOptWindow]) - { - border_col = CMD_BORDER_COL; - border_thickness = 1.0; - corner_radius = Vec4(0.0, 0.0, 12.0, 12.0); - edge_softness = 1.0; - } - - with(ctx.item_styles[CmdOpt]) - { - bg_col = OPT_COL; - padding[A2D.X] = Vec2(8.0); - padding[A2D.Y] = Vec2(4.0); - } - - ctx.item_styles[CmdOptAlt] = ctx.item_styles[CmdOpt]; - - with(ctx.item_styles[CmdOptAlt]) - { - bg_col = OPT_ALT_COL; - } - - with(ctx.item_styles[CmdTitleText]) - { - padding[0] = Vec2(8.0); - padding[1] = Vec2(4.0, 2.0); - } - - with(ctx.item_styles[CmdSubtitleText]) - { - padding[0] = Vec2(8.0); - padding[1] = Vec2(0.0); - text_col = GREY; - } - - with(ctx.item_styles[CmdInput]) - { - bg_col = CMD_COL; - border_col = CMD_BORDER_COL; - border_thickness = 1.0; - corner_radius = Vec4(12.0, 12.0, 0.0, 0.0); - edge_softness = 1.0; - padding = Vec2(6.0); - - Logf("corner radius %s", corner_radius.v); - } - - ctx.item_styles[CmdInputEmpty] = ctx.item_styles[CmdInput]; - - with(ctx.item_styles[CmdInputEmpty]) - { - text_col = GREY; - } - - with(ctx.item_styles[StatusInfo]) - { - bg_col = BLUE; - corner_radius = Vec4(8.0); - padding = Vec2A2(8.0, 8.0, 0.0, 0.0); - edge_softness = 0.6; - } - - with(ctx.item_styles[StatusMessage]) - { - bg_col = BG_COL; - corner_radius = Vec4(0.0, 0.0, 0.0, 8.0); - edge_softness = 0.6; - } - } - - InitStacks(ctx); + MakeItem("###root", UIF.Parent); } FontAtlasBuf* @@ -999,160 +552,34 @@ LoadFontGlyphs() ctx.glyphs_to_load[fi] = false; } -void -Set(UIItem* item, UICtx* ctx) -{ - static foreach(i, m; UICtx.tupleof) - { - static foreach(j, m2; UIItem.tupleof) - { - { - enum ctx_id = __traits(identifier, UICtx.tupleof[i]); - enum item_id = __traits(identifier, UIItem.tupleof[j]); - static if(ctx_id == item_id) - { - mixin("item."~item_id~" = ctx."~ctx_id~".top.value;\n"); - } - } - } - } -} - -void -SetElement(UIElement element) -{ - g_ui_ctx.next_element = element; -} - -ItemStyle* -GetElementStyle(UIElement elem) -{ - return &g_ui_ctx.item_styles[elem]; -} - UIItem* -MakeItem(Args...)(string str, Args args) -{ - static if(Args.length) - { - enum has_flag = Args[Args.length-1].stringof == UIFlags.stringof; - - UIFlags flags = has_flag ? args[args.length-1] : UIF.None; - enum len = has_flag ? Args.length-1 : Args.length; - - string key = Scratchf(str, args[0 .. len]); - } - else - { - string key = str; - UIFlags flags = UIF.None; - } - - return MakeItem(key, flags); -} - -UIItem* -MakeItem(T)(T k, UIFlags flags = UIF.None) if(KeyType!(T)) +MakeItem(T)(T k, f32 x, f32 y, f32 w, f32 h, UIFlags flags = UIF.None) if(KeyType!(T)) { UICtx* ctx = GetCtx(); UIItem* item = Get(k); - - item.flags = flags; - item.signal = UIS.None; - item.element = ctx.next_element; - Set(item, ctx); + item.flags = flags; + item.parent = item.parent_stack.value; + item.rect.p0 = Vec2(x, y); + item.rect.p1 = Vec2(x+w, y+h); + if(Nil(ctx.root_first)) { ctx.root_first = ctx.root_last = item; - Push!("parent")(item, false); - } - if(item.flags & (UIF.Window | UIF.FloatingWindow) || Nil(ctx.root_first)) - { - item.parent = g_UI_NIL; - - ctx.root_last.next = item; - item.prev = ctx.root_last; - ctx.root_last = 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) + if(flags & UIF.Parent) { - if(item.size_info[item.parent.layout_axis].type != ST.Percentage) - { - Logf("Warning: Resizing not percentage SizeType item, disabling flag"); - item.flags &= ~UIF.Resizeable; - } - else - { - item.resize_pct = item.size_info[item.layout_axis].value; - } - } - - FontAtlasBuf* abuf = GetFontAtlas(item.text_size); - item.max_text_width = 0.0; - string str = item.display_string.length ? item.display_string : item.key.text; - if(item.flags & UIF.TextWrap) - { - f32 width = item.size_info[A2D.X].type == ST.TextSize ? item.parent.size.x : item.size.x; - u32 ch_per_line = cast(u32)floor(width/abuf.atlas.max_advance); - u64 lines = (str.length/ch_per_line) + (str.length%ch_per_line ? 1 : 0); - - item.text_lines = ScratchAlloc!(string)(lines); - - u64 start; - for(u64 i = 0; i < lines; i += 1) - { - u64 end = str.length-start <= ch_per_line ? str.length : start+ch_per_line; - item.text_lines[i] = str[start .. end]; - f32 text_width = CalcTextWidth(item.text_lines[i], abuf); - if(text_width > item.max_text_width) - { - item.max_text_width = text_width; - } - } - - if(item.syntax_tokens.length) - { - item.token_lines = ScratchAlloc!(u8[])(lines); - for(u64 i = 0; i < lines; i += 1) - { - u64 end = str.length-start <= ch_per_line ? str.length : start+ch_per_line; - item.token_lines[i] = item.syntax_tokens[start .. end]; - } - } - } - else - { - item.text_lines = ScratchAlloc!(string)(1); - item.text_lines[0] = str; - item.max_text_width = CalcTextWidth(str, abuf); - - if(item.syntax_tokens.length) - { - item.token_lines = ScratchAlloc!(u8[])(1); - item.token_lines[0] = item.syntax_tokens; - } - } - - static foreach(axis; A2D.min .. A2D.max) - { - } - - if(item.flags & UIF.AnimateReady) - { - bool is_ready = cast(bool)(item.flags & UIF.SetReady); - item.ready_t += ctx.fade_rate * (cast(f32)(is_ready) - item.ready_t); + Push(&ctx.parent_stack, item); } item.last_frame = ctx.frame; - item.processed = false; + + Push(&ctx.key_item_stack); return item; } @@ -1243,76 +670,6 @@ Hovered(bool current_frame, T)(T param) return result; } -void -Signal(UIItem* item) -{ - UICtx* ctx = GetCtx(); - - assert(!ZeroKey(item.key), "Zero key passed to Signal"); - - bool mouse_over = KeyEq(ctx.hover_key, item.key); - if(item.signal == UIS.None && !ZeroKey(item.key)) - { - if(mouse_over) - { - item.signal |= UIS.Hovered; - } - - item.dragged = 0; - - for(UIInput* i = ctx.events.first; !CheckNil(g_UI_NIL_INPUT, i); i = i.next) - { - bool taken; - - if(item.flags & UIF.Clickable && i.type == UIE.Click && mouse_over) - { - item.signal |= UIS.Clicked; - taken = true; - } - - if(ZeroKey(ctx.drag_key) && item.flags & UIF.Draggable && i.type == UIE.DragStart && mouse_over) - { - item.signal |= UIS.Dragged; - ctx.drag_key = item.key; - taken = true; - } - - if(KeyEq(ctx.drag_key, item.key) && i.type == UIE.Drag) - { - item.signal |= UIS.Dragged; - item.dragged += i.rel; - taken = true; - } - - if(KeyEq(ctx.drag_key, item.key) && i.type == UIE.DragRelease) - { - ctx.drag_key = ZeroKey(); - taken = true; - } - - if(taken) - { - DLLRemove(&ctx.events, i, g_UI_NIL_INPUT); - } - } - } - else if(item.flags & UIF.ResizeAdjacent && ZeroKey(ctx.drag_key)) - { - for(UIInput* i = ctx.events.first; !CheckNil(g_UI_NIL_INPUT, i); i = i.next) - { - if(mouse_over && i.type == UIE.DragStart) - { - item.signal |= UIS.Dragged; - } - - if(item.signal & UIS.Dragged) - { - item.dragged += i.rel; - } - } - } -} - void PushUIEvent(UICtx* ctx, UIInput input) { @@ -1355,8 +712,6 @@ BeginUI(Inputs* inputs) UICtx* ctx = GetCtx(); Arena* a = &ctx.temp_arena; - debug ctx.item_count = 0; - Reset(a); // Convert Inputs @@ -1372,13 +727,9 @@ BeginUI(Inputs* inputs) case Input.LeftClick: { mouse_down = i.pressed; - if(!mouse_down && !dragging) - { - PushUIEvent(ctx, UIInput(UIE.Click)); - } - else if(!mouse_down) + if(!mouse_down) { - PushUIEvent(ctx, UIInput(UIE.DragRelease)); + PushUIEvent(ctx, UIInput(dragging ? UIE.DragRelease : UIE.Click)); } dragging = false; } break; @@ -1442,8 +793,12 @@ BeginUI(Inputs* inputs) } } - ctx.key_item_stack = null; - ctx.root_first = ctx.root_last = g_UI_NIL; + + Reset(&ctx.stack_arena); + ctx.parent_stack = Alloc!(Stack!(UIItem*))(&ctx.stack_arena); + ctx.key_item_stack = Alloc!(Stack!(UIItem*))(&ctx.stack_arena); + + SetNil(&ctx.root_first, &ctx.root_last, &ctx.parent_stack.value, &ctx.key_item_stack.value); // Clean up items KVPair!(UIHash, UIItem*)*[] items = GetAllNodes(&ctx.temp_arena, &ctx.items); @@ -1458,38 +813,17 @@ BeginUI(Inputs* inputs) } } - for(UIItem* item = ctx.transient_items; !Nil(item);) - { - UIItem* next = item.transient_next; - memset(item, 0, UIItem.sizeof); - DLLPush(ctx.free_items, item, g_UI_NIL); - item = next; - } - // Ctx state - ctx.transient_items = g_UI_NIL; - ctx.frame = next_frame; - ctx.f_idx = ctx.frame%FRAME_OVERLAP; - ctx.inputs = inputs; + ctx.frame = next_frame; + ctx.f_idx = ctx.frame%FRAME_OVERLAP; + ctx.inputs = inputs; assert(!mouse_moved || ZeroKey(ctx.hover_key) || (ctx.frame == ctx.last_hover_frame)); - ResetStacks(ctx); - ctx.animation_rate = 1.0 - pow(2.0, (-30.0f * g_delta)); ctx.fade_rate = 1.0 - pow(2.0, (-50.0f * g_delta)); ctx.scroll_rate = 1.0 - pow(2.0, (-60.0f * g_delta)); - // Root Item - Push!("size_info")(UIS2(ST.Pixels, ST.Pixels, ctx.res.x, ctx.res.y), true); - MakeItem("###root"); -} - -void -EndUI() -{ - UICtx* ctx = GetCtx(); - version(ENABLE_RENDERER) { BeginFrame(&ctx.rd); @@ -1525,293 +859,16 @@ EndUI() memset(ctx.buffers[ctx.f_idx].vtx.ptr, 0, Vertex.sizeof * ctx.buffers[ctx.f_idx].count); ctx.buffers[ctx.f_idx].count = 0; ctx.buffers[ctx.f_idx].vtx_offset = 0; +} - // Automatic signals - for(UIItem* item = ctx.root_first; !Nil(item); item = Recurse!(false)(item, g_UI_NIL)) - { - if(item.flags & AUTO_FLAGS) - { - Signal(item); - - if(item.flags & UIF.ResizeAdjacent && item.dragged != IVec2(0)) - { - UIItem* prev = !Nil(item.prev) ? item.prev : g_UI_NIL; - UIItem* next = !Nil(item.next) ? item.next : g_UI_NIL; - Axis2D axis = item.parent.layout_axis; - f32 mov_pct = Remap(item.dragged.v[axis], 0.0, item.parent.size.v[axis], 0.0, 1.0); - - debug if(!(prev.flags & UIF.Resizeable) && !(next.flags & UIF.Resizeable)) - { - Logf("Warning: ResizeAdjacent flag set with no adjacent items having Resizeable flag"); - } - - if(prev.flags & UIF.Resizeable) - { - prev.resize_pct -= mov_pct; - prev.resize_pct = clamp(prev.resize_pct, 0.0, 1.0); - } - - if(next.flags & UIF.Resizeable) - { - next.resize_pct += mov_pct; - next.resize_pct = clamp(next.resize_pct, 0.0, 1.0); - } - } - } - } - - // Calculate item properties - static foreach(axis; A2D.min .. A2D.max) - { - // Pixel sizes - for(UIItem* item = ctx.root_first; !Nil(item); item = Recurse!(true)(item, g_UI_NIL)) - { - if(item.size_info[axis].type == ST.Pixels) - { - item.size.v[axis] = item.size_info[axis].value; - } - else if(item.size_info[axis].type == ST.TextSize) - { - f32 size = axis == A2D.X ? item.max_text_width : GetFontAtlas(item.text_size).atlas.line_height * item.text_lines.length; - item.size.v[axis] = floor(size) + AxisPadding!(axis)(item); - } - } - - // Percentage sizes - for(UIItem* item = ctx.root_first; !Nil(item); item = Recurse!(true)(item, g_UI_NIL)) - { - if(item.size_info[axis].type == ST.Percentage) - { - if(item.parent.layout_axis == axis && item.flags & UIF.Resizeable) - { - item.size_info[axis].value = item.resize_pct; - } - - for(UIItem* p = item.parent; !Nil(p); p = p.parent) - { - if(p.size_info[axis].type == ST.Pixels) - { - item.size.v[axis] = floor(item.size_info[axis].value * InnerSize!(axis)(item.parent)); - break; - } - } - } - } - - // Sum of children sizes - for(UIItem* item = ctx.root_first; !Nil(item); item = Recurse!(false)(item, g_UI_NIL)) - { - if(item.size_info[axis].type == ST.ChildrenSum) - { - if(item.layout_axis == axis) - { - for(UIItem* c = item.first; !Nil(c); c = c.next) - { - item.size.v[axis] += c.size.v[axis]; - } - } - else - { - for(UIItem* c = item.first; !Nil(c); c = c.next) - { - item.size.v[axis] = item.size.v[axis] < c.size.v[axis] ? c.size.v[axis] : item.size.v[axis]; - } - } - } - } - - // Violations - for(UIItem* item = ctx.root_first; !Nil(item); item = Recurse!(true)(item, g_UI_NIL)) - { - f32 size = InnerSize!(axis)(item); - - if(item.flags & ((UIF.ScissorX << axis) | (UIF.ScrollX << axis))) - { - continue; - } - - if(axis == item.layout_axis) - { - f32 children_size = 0.0; - for(UIItem* c = item.first; !Nil(c); c = c.next) - { - if(c.flags & UIF.FixedPosition) continue; - children_size += c.size.v[axis]; - } - - if(children_size > size) - { - f32 excess = children_size - size; - if(excess > 0.0009) - { - for(UIItem* c = item.last; !Nil(c); c = c.prev) - { - if(c.flags & (UIF.FixedPosition | (UIF.OverflowX< size ? size : c.size.v[axis]; - } - } - } - - // Scrollable Size Calculation & Offsets - for(UIItem* item = ctx.root_first; !Nil(item); item = Recurse!(true)(item, g_UI_NIL)) - { - if(item.flags & UIF.ScrollFitChildren) - { - f32 scroll_size = 0.0; - for(UIItem* c = item.first; !Nil(c); c = c.next) - { - scroll_size += c.size.v[axis]; - } - - item.scroll_size.v[axis] = scroll_size; - } - - if(item.flags & (UIF.ScrollX << axis)) - { - if(fabsf(item.scroll_offset.v[axis] - item.scroll_target.v[axis]) > 0.0009) - { - f32 v = ctx.scroll_rate * (item.scroll_target.v[axis] - item.scroll_offset.v[axis]); - item.scroll_offset.v[axis] += v; - - if(fabsf(item.scroll_offset.v[axis] - item.scroll_target.v[axis]) < 2.0) - { - item.scroll_offset.v[axis] = item.scroll_target.v[axis]; - } - } - } - - if(item.flags & ((UIF.ClampX << axis) | UIF.ScrollFitChildren)) - { - f32 upper = item.scroll_size.v[axis] >= item.size.v[axis] ? item.scroll_size.v[axis]-item.size.v[axis] : 0.0; - item.scroll_offset.v[axis] = clamp(item.scroll_offset.v[axis], 0.0, upper); - } - else if(item.flags & (UIF.ClampX << axis)) - { - item.scroll_offset.v[axis] = clamp(item.scroll_offset.v[axis], item.scroll_clamp[axis].x, item.scroll_clamp[axis].y); - } - } - - // Calculate final sizes - { - f32 pos = 0.0; - for(UIItem* item = ctx.root_first; !Nil(item); item = Recurse!(true)(item, g_UI_NIL)) - { - item.last_relative_item = g_UI_NIL; - - bool fixed = cast(bool)(item.flags & UIF.FixedPosition); - UIItem* parent = item.parent; - if(fixed) - { - item.rect.p0.v[axis] = parent.rect.p0.v[axis] + item.fixed_pos.v[axis] + InnerOffset!(axis, true)(item); - item.rect.p1.v[axis] = item.rect.p0.v[axis] + item.size.v[axis] - InnerOffset!(axis, false)(item); - } - else if(axis != parent.layout_axis) - { - item.rect.p0.v[axis] = parent.rect.p0.v[axis] + InnerOffset!(axis, true )(item); - item.rect.p1.v[axis] = parent.rect.p0.v[axis] + item.size.v[axis] - InnerOffset!(axis, false)(item); - } - else if(Nil(item.parent.last_relative_item)) - { - item.rect.p0.v[axis] = parent.rect.p0.v[axis] + InnerOffset!(axis, true)(item); - item.rect.p1.v[axis] = item.rect.p0.v[axis] + item.size.v[axis] - InnerOffset!(axis, false)(item); - } - else - { - UIItem* prev = parent.last_relative_item; - - item.rect.p0.v[axis] = prev.rect.p1.v[axis] + InnerOffset!(axis, false)(prev) + InnerOffset!(axis, true )(item); - item.rect.p1.v[axis] = item.rect.p0.v[axis] + item.size.v[axis] - InnerOffset!(axis, false)(item); - } - - if(axis == parent.layout_axis && !fixed && !Nil(parent)) - { - parent.last_relative_item = item; - } - - assert(!isNaN(item.rect.p0.v[axis])); - assert(!isNaN(item.rect.p1.v[axis])); - } - } - - // Calculate offsets for scrollable windows - { - for(UIItem* item = ctx.root_first; !Nil(item); item = Recurse!(true)(item, g_UI_NIL)) - { - if(item.flags & (UIF.ScrollX << axis)) - { - for(UIItem* c = item.first; !Nil(c); c = c.next) - { - c.rect.p0.v[axis] -= item.scroll_offset.v[axis]; - c.rect.p1.v[axis] -= item.scroll_offset.v[axis]; - } - } - } - } - } - - - // Render Items - for(UIItem* item = ctx.root_first; !Nil(item); item = Recurse!(true)(item, g_UI_NIL)) - { - if(item.flags & UIF.AnimateReady && fabsf(item.ready_t-1.0) > 0.00009) - { - UIItem* first = item.first, last = item.last; - - item.first = item.last = g_UI_NIL; - - UIItem* next = Recurse!(true)(item, g_UI_NIL); - - item.first = first; - item.last = last; - - for(UIItem* c = item.first; !Nil(c) && c != next; c = Recurse!(true)(c, g_UI_NIL)) - { - if(!(c.flags & UIF.AnimateReady)) - { - c.flags |= UIF.AnimateReady; - c.ready_t = item.ready_t; - } - } - } - else - { - item.ready_t = 1.0; - } - - if(!ZeroKey(item.key)) - { - PushKeyedItem(item); - } - - RenderItem(ctx, item); - } +void +EndUI() +{ + UICtx* ctx = GetCtx(); version(ENABLE_RENDERER) { DrawUI(ctx); - FinishRendering(&ctx.rd); SubmitAndPresent(&ctx.rd); } @@ -1829,26 +886,20 @@ EndUI() } } -UIItem* -NextNonChild(UIItem* item) -{ - UIItem* first = item.first; - UIItem* last = item.last; - - item.first = item.last = g_UI_NIL; - - UIItem* next = Recurse!(true)(item, g_UI_NIL); - - item.first = first; - item.last = last; - - return next; -} - void -FocusItem(Args...)(string str, Args args) +SetNil(Args...)(Args args) { - g_ui_ctx.focus_item = Get(str, args); + static foreach(i; 0 .. Args.length) + { + static if(is(typeof(Args[i]) == UIItem**)) + { + *args[i] = g_UI_NIL; + } + else + { + *args[i] = null; + } + } } void @@ -1858,30 +909,52 @@ Clamp(UICtx* ctx, Vertex* v) v.dst_end = Clamp(v.dst_end, Vec2(0.0), Vec2(ctx.res)); } -void -FocusItem(T)(T focus) if(ItemAndKeyType!(T)) +bool +Focused(T)(T param) if(ItemAndKeyType!(T)) { - g_ui_ctx.focus_item = mixin(AssignItem(T, focus)); + UIItem* item = mixin(AssignItem(T, param)); + return g_ui_ctx.focus_item == item; +} + +void +UpdateState(f32* v, bool cond) +{ + *v += g_ui_ctx.animation_rate * (cast(f32)(cond) - *v); + f32 diff = fabsf((*v)-1.0); + if(diff < 0.00009) + { + *v = 1.0; + } + else if(diff > 0.99998) + { + *v = 0.0; + } +} + +void +UpdateState(ISF flags)(UICtx* ctx, UIItem* item) +{ + static if(flags & ISF.Hot) UpdateState(&item.hot_t, cast(bool)(flags & ISF.SetHot) || Hovered!(true)(item)); + static if(flags & ISF.Ready) UpdateState(&item.ready_t, cast(bool)(flags & ISF.SetReady)); + static if(flags & ISF.Active) UpdateState(&item.active_t, cast(bool)(flags & ISF.SetActive) || Focused(item)); } pragma(inline) void -AnimateHot(Args...)(UIItem* item, Vec4 hl_col, Args cols) // Args == Vec4*[] +AnimateHot(/* Vec4*[] */ Args...)(f32 hot, Vec4 hl_col, Args cols) { - if(item.flags & UIF.AnimateHot) + if(hot != 0.0) { - bool is_hot = cast(bool)(item.flags & UIF.SetHot) || Hovered!(true)(item); - item.hot_t += g_ui_ctx.animation_rate * (cast(f32)(is_hot) - item.hot_t); static foreach(i; 0 .. Args.length) { - *(cols[i]) = Mix(*(cols[i]), hl_col, item.hot_t); + *(cols[i]) = Mix(*(cols[i]), hl_col, hot); } } } pragma(inline) void -AnimateReady(Args...)(UIItem* item, Args cols) +AnimateReady(Args...)(f32 ready, Args cols) { - if(item.flags & UIF.AnimateReady) + if(ready != 1.0) { static foreach(i; 0 .. Args.length) { @@ -1898,180 +971,141 @@ AnimateReady(Args...)(UIItem* item, Args cols) } void -RenderItem(UICtx* ctx, UIItem* item) +DrawDropShadow(UICtx* ctx, UIItem* item) { - if(item.processed) return; - if(!(item.flags & DRAW_FLAGS)) return; + Vec2 size = item.rect.p1-item.rect.p0; - ItemStyle* style = GetElementStyle(item.element); + f32 px = clamp(((size.x+size.y)/2.0)*0.004, 1.0, f32.max); + f32 alpha = 0.1; + AnimateReady(item.ready_t, &alpha); - Vec2 border_p0 = item.rect.p0 - Vec2(InnerOffset!(A2D.X, true )(item), InnerOffset!(A2D.Y, true )(item)); - Vec2 border_p1 = item.rect.p1 + Vec2(InnerOffset!(A2D.X, false)(item), InnerOffset!(A2D.Y, false)(item)); + Vertex* v = GetVertex(ctx); + v.dst_start = item.rect.p0 - Vec2(px); + v.dst_end = item.rect.p1 + Vec2(px); + v.cols = Vec4(0.0, 0.0, 0.0, alpha); + v.corner_radius = 0.8f; + v.edge_softness = 8.0f; - assert(border_p0.x <= item.rect.p0.x && border_p0.y <= item.rect.p0.y); - assert(border_p1.x >= item.rect.p1.x && border_p1.y >= item.rect.p1.y); + Clamp(ctx, v); +} - if(item.flags & UIF.DrawDropShadow) +void +DrawBorder(UICtx* ctx, UIItem* item) +{ + Vec4 col = item.border_col; + AnimateHot(item.hot_t, BORDER_HL_COL, &col); + AnimateReady(item.ready_t, &col); + + Vertex* v = GetVertex(ctx); + v.dst_start = item.rect.p0; + v.dst_end = item.rect.p1; + v.cols = col; + v.corner_radius = item.corner_radius; + v.border_thickness = item.border_thickness; + v.edge_softness = item.edge_softness; + + Clamp(ctx, v); +} + +void +DrawBackground(UICtx* ctx, UIItem* item, bool bordered = false) +{ + Vec4 col = item.bg_col; + AnimateHot(item.hot_t, BG_HL_COL, &col); + AnimateReady(item.ready_t, &col); + + Vertex* v = GetVertex(ctx); + v.dst_start = item.rect.p0 + item.border_thickness; + v.dst_end = item.rect.p1 - item.border_thickness; + v.cols = col; + v.corner_radius = item.corner_radius*(cast(f32)(bordered)*0.5); + v.edge_softness = item.edge_softness; + + Clamp(ctx, v); +} + +enum TextAlign +{ + Left, + Center, + Right, +} alias TA = TextAlign; + +void +DrawText(T, U)(UICtx* ctx, string text, T size_param, U col_param, Rect rect, TextAlign text_align, f32 ready = 1.0) + if((is(T == FontGlyphs*) || (is(T == u32)) && is(U == Vec4) || is(U == u8[]))) +{ + DrawUI(ctx, fg.index); + + static if(is(T == FontGlyphs*)) { - f32 px = clamp(((item.size.x+item.size.y)/2.0)*0.004, 1.0, f32.max); - f32 alpha = 0.1; - AnimateReady(item, &alpha); - - Vertex* v = GetVertex(ctx); - v.dst_start = border_p0 - Vec2(px); - v.dst_end = border_p1 + Vec2(px); - v.cols = Vec4(0.0, 0.0, 0.0, alpha); - v.corner_radius = 0.8f; - v.edge_softness = 8.0f; - - Clamp(ctx, v); + FontGlyphs* fg = size_param; + } + else + { + FontGlyphs* fg = GetFontGlyphs(size_param); } - if(item.flags & UIF.DrawBackground) + f32 x = rect.p0.x; + if(text_align & TA.Right) { - Vec4 bg_col = style.bg_col; - AnimateHot(item, BG_HL_COL, &bg_col); - AnimateReady(item, &bg_col); - - Vertex* v = GetVertex(ctx); - v.dst_start = item.rect.p0; - v.dst_end = item.rect.p1; - v.cols = bg_col; - v.corner_radius = item.flags & UIF.DrawBorder ? style.corner_radius*0.5 : style.corner_radius; - v.edge_softness = style.edge_softness; - - Clamp(ctx, v); + x = rect.p1.x - CalcTextWidth(text, &fg.abuf); } - - if(item.flags & UIF.DrawBorder) + else if(text_align & TA.Center) { - Vec4 col = style.border_col; - AnimateHot(item, BORDER_HL_COL, &col); - AnimateReady(item, &col); - - Vertex* v = GetVertex(ctx); - v.dst_start = border_p0; - v.dst_end = border_p1; - v.cols = style.border_col; - v.corner_radius = style.corner_radius; - v.border_thickness = style.border_thickness; - v.edge_softness = style.edge_softness; - - Clamp(ctx, v); + x = ((rect.p1.x-rect.p0.x - CalcTextWidth(text, &fg.abuf)) / 2.0); } + x = clamp(x, rect.p0.x, rect.p1.x); - if(item.flags & UIF.DrawText || item.display_string) + Glyphs[] glyphs = fg.abuf.atlas.glyphs[0 .. $]; + static if(is(U == u8[])) { - FontGlyphs* fg = GetFontGlyphs(item.text_size); - f32 y_pos = item.rect.p0.y; - Vec4[] syntax_cols = ctx.syntax_colors[item.syntax_highlight]; - f32 line_height = fg.abuf.atlas.line_height; - - DrawUI(ctx, fg.index); - - if(item.flags & UIF.VerticalAlignText) + u8[] tks = col_param; + foreach(j; 0 .. str.length) { - f32 adj = floor((item.rect.p1.y - item.rect.p0.y - line_height) / 2.0); - y_pos += adj; - } - else - { - y_pos += style.padding[A2D.Y].x; - } - - foreach(i; 0 .. item.text_lines.length) - { - string str = item.text_lines[i]; - u8[] tks = item.token_lines.length ? item.token_lines[i] : []; - f32 x_pos = 0.0; - if(item.flags & UIF.RightAlignText) - { - x_pos = item.rect.p1.x - style.padding[A2D.X].x - CalcTextWidth(str, &fg.abuf); - } - else if(item.flags & UIF.CenterAlignText) - { - x_pos = ((item.rect.p1.x-item.rect.p0.x - CalcTextWidth(str, &fg.abuf)) / 2.0) + style.padding[A2D.X].x; - } - else - { - x_pos = item.rect.p0.x + style.padding[A2D.X].x; - } + u8 ch = text[j]; + Glyph* g = ch < glyphs.length ? glyphs.ptr + ch : null; + Vec4 col = syntax_cols[tks[j]]; - x_pos = clamp(x_pos, item.rect.p0.x, item.rect.p1.x); - - if(tks.length) - { - foreach(j; 0 .. str.length) - { - u8 ch = str[j]; - Glyph* g = ch < fg.abuf.atlas.glyphs.length ? fg.abuf.atlas.glyphs.ptr + ch : null; - - Vec4 col = syntax_cols[tks[j]]; - AnimateReady(item, &col); - - DrawGlyph(item, g, &x_pos, y_pos, line_height, col); - } - } - else - { - Vec4 text_col = style.text_col; - AnimateReady(item, &text_col); - - foreach(j; 0 .. str.length) - { - u8 ch = str[j]; - Glyph* g = ch < fg.abuf.atlas.glyphs.length ? fg.abuf.atlas.glyphs.ptr + ch : null; - DrawGlyph(item, g, &x_pos, y_pos, line_height, text_col); - } - } - - y_pos += line_height; + AnimateReady(ready, &col); + DrawGlyph(rect, g, &x, rect.p0.y, line_height, col); } } - - // Doesn't really support nesting scissors, will maybe change this later. - bool scissor_x = cast(bool)(item.flags & UIF.ScissorX); - bool scissor_y = cast(bool)(item.flags & UIF.ScissorY); - scissor_x |= cast(bool)(item.flags & UIF.ScrollX); - scissor_y |= cast(bool)(item.flags & UIF.ScrollY); - if(scissor_x || scissor_y ) + else static if(is(U == Vec4)) { - DrawUI(ctx); + Vec4 col = col_param; + AnimateReady(ready, &col); - i32 x = cast(i32)clamp(scissor_x ? floor(item.rect.p0.x) : 0, 0.0, ctx.res.x); - i32 y = cast(i32)clamp(scissor_y ? floor(item.rect.p0.y) : 0, 0.0, ctx.res.y); - i32 w = cast(i32)clamp(scissor_x ? floor(item.rect.p1.x) - x : ctx.res.x, 0.0, ctx.res.x); - i32 h = cast(i32)clamp(scissor_y ? floor(item.rect.p1.y) - y : ctx.res.y, 0.0, ctx.res.y); - - SetScissor(&ctx.rd, x, y, w, h); - - UIItem* next = NextNonChild(item); - - bool scroll_x = cast(bool)(item.flags & UIF.ScrollX); - bool scroll_y = cast(bool)(item.flags & UIF.ScrollY); - if(scroll_x || scroll_y) + foreach(j; 0 .. str.length) { - for(UIItem* d = item.first; !Nil(d) && d != next; d = Recurse!(true)(d, g_UI_NIL)) - { - if(scroll_x && (d.rect.p1.x < item.rect.p0.x || d.rect.p0.x > item.rect.p1.x)) { d.processed = true; continue; } - if(scroll_y && (d.rect.p1.y < item.rect.p0.y || d.rect.p0.y > item.rect.p1.y)) { d.processed = true; continue; } - - RenderItem(ctx, d); - d.processed = true; - } + u8 ch = str[j]; + Glyph* g = ch < glyphs.length ? glyphs.ptr + ch : null; + DrawGlyph(rect, g, &x, rect.p0.y, line_height, text_col); } - else for(UIItem* d = item.first; !Nil(d) && d != next; d = Recurse!(true)(d, g_UI_NIL)) - { - RenderItem(ctx, d); - d.processed = true; - } - - DrawUI(ctx); - - ResetScissor(&ctx.rd); } } +void +BeginScissor(UICtx* ctx, UIItem* item, bool scissor_x = true, bool scissor_y = true) +{ + DrawUI(ctx); + + i32 x = cast(i32)clamp(scissor_x ? floor(item.rect.p0.x) : 0, 0.0, ctx.res.x); + i32 y = cast(i32)clamp(scissor_y ? floor(item.rect.p0.y) : 0, 0.0, ctx.res.y); + i32 w = cast(i32)clamp(scissor_x ? floor(item.rect.p1.x) - x : ctx.res.x, 0.0, ctx.res.x); + i32 h = cast(i32)clamp(scissor_y ? floor(item.rect.p1.y) - y : ctx.res.y, 0.0, ctx.res.y); + + SetScissor(&ctx.rd, x, y, w, h); + + ResetScissor(&ctx.rd); +} + +void +EndScissor(UICtx* ctx) +{ + ResetScissor(&ctx.rd); +} + u32[2] GetExtent() { @@ -2079,38 +1113,31 @@ GetExtent() } void -PushKeyedItem(UIItem* item) +Push(T)(Stack!(T)** stack, T value) { UICtx* ctx = GetCtx(); - assert(!Nil(item)); - assert(!ZeroKey(item.key)); + Stack!(T)* node = Alloc!(Stack!(T))(&ctx.stack_arena); - Stack!(UIItem*)* node = Alloc!(Stack!(UIItem*))(&ctx.key_stack_arena); - - node.next = ctx.key_item_stack; - node.value = item; + node.next = *stack; + node.value = value; - ctx.key_item_stack = node; + *stack = node; } -void -PushDisplayStringCopy(T)(T param, bool auto_pop = true) +T +Pop(T)(Stack!(T)** stack, T value) { - PushDisplayString(ScratchAlloc(mixin(AssignStr!(T, param))), auto_pop); -} + UICtx* ctx = GetCtx(); -void -PushDisplayString(Args...)(string fmt, Args args) -{ - static if(is(Args[Args.length-1] == bool)) + Stack!(T)* node = *stack; + + if((*stack).next != null) { - PushDisplayString(Scratchf(fmt, args[0 .. Args.length-1]), args[Args.length-1]); - } - else - { - PushDisplayString(Scratchf(fmt, args)); + *stack = (*stack).next; } + + return node.value; } template @@ -2125,234 +1152,6 @@ StackIDs(string stack, string ctx = "ctx") }; } -static string -PushScope(string stack, string value)() -{ - import std.conv; - return i"Push!(\"$(stack)\")($(value), false); scope(exit) Pop!(\"$(stack)\")();".text; -} - -struct UIPushInfo -{ - string s; // stack - string v; // value -} - -static string -PushOnce(UIPushInfo[] info)() -{ - import std.conv; - - string result = ""; - static foreach(i; info) - { - result ~= i"Push!(\"$(i.s)\")($(i.v), true); scope(exit) Pop!(\"$(i.s)\")();".text; - } - - return result; -} - -void -PushOnce(Args...)() -{ - static assert(Args.length%2 == 0, "Must provide key/value pairs in the form of string/value."); - - static foreach(idx; 0 .. Args.length/2) - { - { - enum i = idx*2; - Push!(Args[i+0])(Args[i+1], true); - } - } -} - -void -Push(string stack_str, T)(T value, bool auto_pop = true) -{ - import std.string : replace; - - enum ids = StackIDs!(stack_str, "g_ui_ctx"); - alias ST = typeof(mixin(ids.stack ~ ".top.value")); - - auto stack = &mixin(ids.stack); - auto top = mixin(ids.stack_top_node); - - Stack!(ST)* node = stack.free; - if(node) - { - stack.free = node.next; - } - else - { - node = Alloc!(Stack!(ST))(&g_ui_ctx.temp_arena); - } - - node.next = stack.top; - node.auto_pop = auto_pop; - static if(is(ST == string) && StringType!(T)) - { - node.value = Str(value); - } - else - { - node.value = value; - } - - stack.top = node; -} - -static string -PushScope(string stack_str, alias __value)() -{ - enum string id = __traits(identifier, __value); - static if(id == "__value") - { - string value_str = "cast(typeof("~StackIDs!(stack_str, "g_ui_ctx").stack~".top.value))(" ~ __value.stringof ~ ")"; - } - else - { - string value_str = __traits(identifier, __value); - } - - - return "Push!(\"" ~ stack_str ~ "\")(" ~ value_str ~ ");\n scope(exit) Pop!(\"" ~ stack_str ~ "\");"; -} - -auto -Pop(string stack_str)() -{ - import std.string : replace; - - enum ids = StackIDs!(stack_str, "g_ui_ctx"); - - auto stack = &mixin(ids.stack); - auto top = mixin(ids.stack_top_node); - - auto pop = stack.top; - if(pop != top) - { - stack.top = pop.next; - - pop.next = stack.free; - stack.free = pop; - } - - return pop.value; -} - -void -Pop(stack_strs...)() -{ - static foreach(stack; stack_strs) - { - Pop!(stack)(); - } -} - -static string -GenPushFuncs() -{ - import std.array : split; - import std.uni : toUpper; - - string funcs = ""; - static foreach(i, m; UICtx.tupleof) - { - { - enum info = CtxMemberInfo!(i); - static if(info.is_stack) - { - string[] parts = split(info.id, "_"); - - string fn_name = "Push"; - foreach(p; parts) - { - if(p.length == 1) - { - fn_name ~= toUpper(p[0 .. 1]); - } - else - { - fn_name ~= toUpper(p[0 .. 1]) ~ p[1 .. $]; - } - } - - funcs ~= "pragma(inline) void " ~ fn_name ~ "(T)(T value, bool auto_pop = true){ Push!(\"" ~ info.id ~ "\")(value, auto_pop); }\n"; - } - } - } - - return funcs; -} - -mixin(GenPushFuncs()); - -void -AutoPopStacks(UICtx* ctx) -{ - import std.string : endsWith, replace; - import std.traits : isInstanceOf, isPointer; - - static foreach(i, mem; UICtx.tupleof) - { - { - enum member_info = CtxMemberInfo!(i); - static if(member_info.is_stack) - { - if(ctx.tupleof[i].top.auto_pop) - { - ctx.tupleof[i].top.auto_pop = false; - Pop!(member_info.id); - } - } - } - } -} - -void -InitStacks(UICtx* ctx) -{ - import std.string : endsWith, chomp, replace; - import std.traits : isInstanceOf, isPointer; - - static foreach(i, mem; UICtx.tupleof) - { - { - enum member_info = CtxMemberInfo!(i); - static if(member_info.is_top) - { - enum global_default = replace("g_@_default", "@", chomp(member_info.id, "_top")); - - ctx.tupleof[i] = Alloc!(typeof(*UICtx.tupleof[i]))(&ctx.arena); - ctx.tupleof[i].value = mixin(global_default); - ctx.tupleof[i].next = null; - } - } - } -} - -void -ResetStacks(UICtx* ctx) -{ - import std.string : endsWith, replace; - import std.traits : isInstanceOf, isPointer; - - static foreach(i, mem; UICtx.tupleof) - { - { - enum member_info = CtxMemberInfo!(i); - static if(member_info.is_stack) - { - enum top = replace("ctx.@_top", "@", member_info.id); - ctx.tupleof[i].top = mixin(top); - ctx.tupleof[i].free = null; - - assert(ctx.tupleof[i].top.next == null, "Top stack node next isn't null"); - } - } - } -} - T* Recurse(bool pre = true, T)(T* node, T* nil) { @@ -2491,8 +1290,6 @@ NewItem(UICtx* ctx) { UIItem* item = g_UI_NIL; - debug ctx.item_count += 1; - item = DLLPop(ctx.free_items, g_UI_NIL); if(Nil(item)) { @@ -2516,25 +1313,15 @@ Get(T)(T k) if(KeyType!(T)) UICtx* ctx = GetCtx(); UIItem* item; - if(ZeroKey(key)) + Result!(UIItem*) res = ctx.items[key.hash]; + if(res.ok) { - item = NewItem(ctx); - item.transient_next = ctx.transient_items; - ctx.transient_items = item; + item = res.value; } else { - Result!(UIItem*) res = ctx.items[key.hash]; - if(res.ok) - { - debug ctx.item_count += 1; - item = res.value; - } - else - { - item = NewItem(ctx); - HTPush(&ctx.items, key.hash, item); - } + item = NewItem(ctx); + HTPush(&ctx.items, key.hash, item); } item.key = key; @@ -2582,7 +1369,7 @@ GlyphWidth(Glyph* g, FontAtlasBuf* abuf) } pragma(inline) void -DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, Vec4 col = Vec4(1.0)) +DrawGlyph(Rect rect, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, Vec4 col = Vec4(1.0)) { if(glyph) { @@ -2596,7 +1383,7 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, Vec4 c } else if(glyph.ch == '\t') { - *x_pos += advance * (GetCtx().tab_width - 1); + *x_pos += advance * (ctx.tab_width - 1); } else { @@ -2616,7 +1403,7 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, Vec4 c f32 end_x = *x_pos + advance; f32 width = end_x - *x_pos; - f32 bound_x = item.rect.p1.x; + f32 bound_x = rect.p1.x; if(end_x > bound_x) { f32 cull_pct = (end_x - bound_x) / width; @@ -2626,9 +1413,9 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, Vec4 c f32 end_y = y + line_height; f32 height = end_y - y; - if(end_y > item.rect.p1.y) + if(end_y > rect.p1.y) { - f32 cull_pct = (end_y - item.rect.p1.y) / height; + f32 cull_pct = (end_y - rect.p1.y) / height; v.dst_end.y -= (v.dst_end.y - v.dst_start.y) * cull_pct; v.src_end.y -= (v.src_end.y - v.src_start.y) * cull_pct; } @@ -2646,31 +1433,6 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, Vec4 c } } -pragma(inline) f32 -AxisPadding(Axis2D axis)(UIItem* item) -{ - ItemStyle* s = GetElementStyle(item.element); - return s.padding[axis].x + s.padding[axis].y; -} - -pragma(inline) f32 -InnerSize(Axis2D axis)(UIItem* item) -{ - return clamp(item.size[axis] - g_ui_ctx.item_styles[item.element].border_thickness*2.0, 0.0, f32.max); -} - -pragma(inline) f32 -InnerSize(UIItem* item, Axis2D axis) -{ - return clamp(item.size[axis] - g_ui_ctx.item_styles[item.element].border_thickness*2.0, 0.0, f32.max); -} - -pragma(inline) f32 -InnerOffset(Axis2D axis, bool start)(UIItem* item) -{ - return g_ui_ctx.item_styles[item.element].border_thickness; -} - pragma(inline) Vertex* GetVertex(UICtx* ctx) { @@ -2678,24 +1440,6 @@ GetVertex(UICtx* ctx) return ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count++; } -static UISize[2] -UIS2(SizeType t0 = ST.Percentage, SizeType t1 = ST.Percentage, f32 v0 = 1.0, f32 v1 = 1.0) -{ - return [UISize(t0, v0), UISize(t1, v1)]; -} - -static UISize[2] -UISX(SizeType type, f32 value = 1.0) -{ - return [UISize(type, value), UISize(ST.Percentage, 1.0)]; -} - -static UISize[2] -UISY(SizeType type, f32 value = 1.0) -{ - return [UISize(ST.Percentage, 1.0), UISize(type, value)]; -} - bool Nil(UIItem* item) { @@ -2708,12 +1452,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; } -static Vec2[2] -Vec2A2(f32 x0, f32 y0, f32 x1, f32 y1) -{ - return [Vec2(x0, y0), Vec2(x1, y1)]; -} - static f32 SRGB(f32 v) { diff --git a/src/editor/views.d b/src/editor/views.d index 8123ac4..0cc8831 100644 --- a/src/editor/views.d +++ b/src/editor/views.d @@ -39,468 +39,3 @@ struct Panel u64 id; u32 text_size; } - -void -LineCounterView(FontAtlasBuf* abuf, u64 max_line, u64 lines, i64 line_offset, f32 view_offset) -{ - UICtx* ctx = GetCtx(); - - u64 ch_width = max_line.toChars().length; - f32 lc_width = cast(f32)(ch_width+1)*abuf.atlas.max_advance; - - enum UIPushInfo[] lc_params = [ - { "layout_axis", q{ A2D.Y } }, - { "size_info", q{ UIS2(ST.Pixels, ST.Percentage, lc_width, 1.0) } }, - ]; - - mixin(PushOnce!(lc_params)); - - UIItem* line_count = MakeItem(ZERO, UIF.DrawBorder|UIF.ScissorY); - - mixin(PushScope!("size_info", q{ UISY(ST.Pixels, abuf.atlas.line_height) } )); - mixin(PushScope!("parent", q{ line_count } )); - - SetElement(UIElem.LineCountText); - u64 end_line = lines+line_offset; - for(u64 i = line_offset; i < end_line && i < max_line; i += 1) - { - char[] buf = ScratchAlloc!(char)(ch_width); - Push!("display_string")(Scratchf("%s", i)); - MakeItem(ZERO, UIF.DrawText); - } -} - -void -EditorTextView(UIItem* editor, Panel* p, FontAtlasBuf* abuf, u64 lines, i64 line_offset, f32 view_offset) -{ - Editor* ed = p.ed; - - PushLayoutAxis(A2D.Y); - - f32 text_size = cast(f32)p.text_size; - f32 clamp_y = cast(f32)(ed.buf.line_count-lines)*text_size; - f32 scroll_pos = cast(f32)(ed.line_offset)*text_size; - f32 padding = 8.0; - - f32 scroll_target = 0.0; - static bool toggled = true; - static f32 t = 0.0; - if(toggled) - { - scroll_target = 0.0; - t += g_delta; - if(t > 0.5) - { - toggled = !toggled; - } - } - else - { - scroll_target = 1000.0; - t -= g_delta; - if(t < 0.0) - { - toggled = !toggled; - } - } - - enum UIPushInfo[] text_view_params = [ - { "layout_axis", q{ A2D.Y } }, - { "size_info", q{ UIS2() } }, - { "scroll_target", q{ Vec2(0.0, scroll_target) } }, - //{ "scroll_clamp", q{ Vec2(0.0, clamp_y) } }, - ]; - mixin(PushOnce!(text_view_params)); - - SetElement(UIElem.EditorTextView); - editor = MakeItem(editor.key, UIF.DrawBorder|UIF.ScrollY|UIF.ClampY|UIF.ScissorY|UIF.ScrollFitChildren); - - mixin(PushScope!("parent", q{ editor })); - - UIKey zero = ZeroKey(); - - // Cursor - { - LineBuffer* lb = GetLine(&ed.buf, ed.cursor_pos.y); - - u8 ch = lb.text.length > ed.cursor_pos.y ? lb.text[ed.cursor_pos.y] : 0; - f32 line_h = abuf.atlas.line_height; - f32 cursor_x = CalcTextWidth(lb.text[0 .. ed.cursor_pos.x], abuf); - f32 cursor_y = cast(f32)(ed.cursor_pos.y - line_offset)*line_h; - Glyph* g = abuf.atlas.glyphs.length > ch ? abuf.atlas.glyphs.ptr + ch : abuf.atlas.glyphs.ptr + ' '; - - enum UIPushInfo[] cursor_info = [ - { "size_info", q{ UIS2(ST.Pixels, ST.Pixels, g.advance, line_h) } }, - { "fixed_pos", q{ Vec2(cursor_x, cursor_y) } }, - ]; - mixin(PushOnce!(cursor_info)); - - SetElement(UIElem.EditorTextCursor); - UIItem* cursor = MakeItem("###cursor", UIF.DrawBackground|UIF.FixedPosition); - } - - mixin(PushScope!("size_info", q{ UISY(ST.TextSize) } )); - mixin(PushScope!("syntax_highlight", q{ UISH.D } )); - - SetElement(UIElem.EditorText); - for(u64 i = 0; i < 200; i += 1) - { - MakeItem("%s", i, UIF.DrawText); - } - - /* - 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)) - { - string txt = Str(lb.text); - u8[] tokens = cast(u8[])(lb.style); - PushOnce!("display_string", txt, "syntax_tokens", tokens); - - UIItem* line = MakeItem(zero, UIF.DrawText); - } - */ -} - -void -EditorView(Panel* p) -{ - Editor* ed = p.ed; - UICtx* ctx = GetCtx(); - UIKey zero = ZeroKey(); - FontAtlasBuf* abuf = GetFontAtlas(p.text_size); - - mixin(PushScope!("text_size", q{ p.text_size })); - - if(CheckNil(g_NIL_ED, ed)) - { - for(Panel* c = p.first; !CheckNil(g_NIL_PANEL, c); c = c.next) - { - EditorView(c); - } - } - else - { - assert(ed); - - UIKey ed_key = MakeKey("###ed_%s", ed.editor_id); - UIItem* editor = Get(ed_key); - - f32 text_size = abuf.atlas.line_height; - - u64 frame_line_offset = ed.line_offset; - f32 frame_view_offset = -(editor.scroll_offset.y%text_size); - - enum UIPushInfo[] c_info = [ - { "size_info", q{ UIS2() } }, - ]; - mixin(PushOnce!(c_info)); - - UIItem* container = MakeItem(zero, UIF.DrawBackground); - - mixin(PushScope!("parent", q{ container } )); - - u64 view_lines; - if(editor.size.y > 0.0) - { - view_lines = cast(u64)floor(editor.size.y/text_size)+1; - const u64 SCROLL_BUFFER = 4; - - i64 start = ed.line_offset; - i64 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); - } - } - - for(UIInput* i = ctx.events.first; !CheckNil(g_UI_NIL_INPUT, i) && g_ed_ctx.focused_panel == p && !CmdModeActive(); 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); - } - - if(g_ed_ctx.focused_panel != p) break; - if(g_ed_ctx.state == ES.CmdPalette) break; - } - - ed.cursor_pos = VecPos(&ed.buf); - - u64 start = cast(u64)floor(editor.scroll_offset.y/text_size); - LineCounterView(abuf, ed.buf.line_count, view_lines, start, frame_view_offset); - EditorTextView(editor, p, abuf, view_lines, start, frame_view_offset); - } - - ResetBuffer(&ed.buf); -} - -UIItem* -CommandWindow(f32 w, f32 h, f32 x, f32 y, bool active) -{ - enum UIPushInfo[] cmd_params = [ - { "layout_axis", q{ A2D.Y } }, - { "fixed_pos", q{ Vec2(x, y) } }, - { "size_info", q{ UIS2(ST.Pixels, ST.Pixels, w, h) } }, - ]; - mixin(PushOnce!(cmd_params)); - - UIFlags cmd_flags = UIF.Window|UIF.FixedPosition|UIF.AnimateReady|UIF.DrawDropShadow|UIF.DrawBackground; - if(active) - { - cmd_flags |= UIF.SetReady; - } - - SetElement(UIElem.CmdWindow); - UIItem* window = MakeItem("###cmd_palette", cmd_flags); - Push!("parent")(window, false); - - return window; -} - -UIItem* -CommandInput(CmdPalette* cmd, string placeholder = "") -{ - string input_str = cmd.icount ? Str(cmd.buffer[0 .. cmd.icount]) : "Search..."; - - enum UIPushInfo[] cmd_input_params = [ - { "text_size", q{ 14 }}, - { "size_info", q{ UISY(ST.TextSize) } }, - { "display_string", q{ input_str } }, - ]; - - mixin(PushOnce!(cmd_input_params)); - - SetElement(cmd.icount ? UIElem.CmdInput : UIElem.CmdInputEmpty); - return MakeItem("###cmd_input", UIF.DrawBorder|UIF.DrawBackground|UIF.DrawText|UIF.Overflow); -} - -UIItem* -CommandOpt(T)(CmdPalette* cmd, T opt, u64 i) -{ - UIFlags flags = UIF.DrawBackground|UIF.AnimateHot|UIF.Clickable; - - SetElement(i%2 ? UIElem.CmdOpt : UIElem.CmdOptAlt); - PushLayoutAxis(A2D.Y); - - static if(is(T == string)) - { - PushDisplayString(cmd.opt_strs[i]); - - UIKey k = MakeKey("###opt_%s", i); - Hovered!(true)(k, &cmd.selected, i); - - UIItem* item = MakeItem(k, flags|UIF.DrawText|SetHot(cmd.selected == i)); - - Signal(item); - - return item; - } - else if(is(T == Command*)) - { - UIKey k = MakeKey("###optc_%s", i); - Hovered!(true)(k, &cmd.selected, i); - - UIItem* optc = MakeItem(k, flags|SetHot(cmd.selected == i)); - - Signal(optc); - - PushParent(optc, false); - PushSizeInfo(UISY(ST.TextSize), false); - - PushTextSize(CMD_TITLE_PX); - PushDisplayStringCopy(cmd.commands[i].name); - - SetElement(UIElem.CmdTitleText); - MakeItem(ZERO, UIF.DrawText); - - PushTextSize(CMD_SUB_PX); - PushDisplayStringCopy(cmd.commands[i].desc); - - SetElement(UIElem.CmdSubtitleText); - MakeItem(ZERO, UIF.DrawText); - - Pop!("parent", "size_info"); - - return optc; - } -} - -void -CommandPalette(CmdPalette* cmd, bool active) -{ - UICtx* ctx = GetCtx(); - Vec2 ext = GetExtent(); - - f32 w = ext.x*0.6; - f32 h = ext.y*0.7; - - UIItem* cmd_item = CommandWindow(w, h, ext.x*0.2, ext.y*0.1, active); - - UIItem* input = CommandInput(cmd, "Search..."); - - // Command Palette Options - { - u32 title_px = 14; - u32 sub_px = 10; - f32 title_size = GetLineHeight(title_px); - f32 sub_size = GetLineHeight(sub_px); - f32 title_pad = 2.0f; - f32 y_pad = 4.0; - f32 x_pad = 8.0; - f32 opt_height = cast(f32)(title_size + sub_size) + y_pad*2.0 + title_pad; - - enum UIPushInfo[] cmd_opts_box_params = [ - { "layout_axis", q{ A2D.Y }}, - { "size_info", q{ UISY(ST.Pixels, h-opt_height) } }, - ]; - - mixin(PushOnce!(cmd_opts_box_params)); - - SetElement(UIElem.CmdOptWindow); - UIItem* opt_box = MakeItem(ZERO, UIF.DrawBorder); - - mixin(PushScope!("parent", q{ opt_box })); - mixin(PushScope!("size_info", q{ UISY(ST.Pixels, opt_height) } )); - - u64 max_opts = cast(u64)ceil(h/opt_height); - - bool opts = cast(bool)cmd.opt_strs.length; - if(opts) - { - for(u64 i = 0; i < cmd.opt_strs.length && i < max_opts; i += 1) - { - UIItem* opt = CommandOpt(cmd, cmd.opt_strs[i], i); - } - } - else - { - for(u64 i = 0; i < cmd.commands.length && i < max_opts; i += 1) - { - UIItem* opt = CommandOpt(cmd, &cmd.commands[i], i); - } - } - } - - for(UIInput* i = ctx.events.first; !CheckNil(g_UI_NIL_INPUT, i); i = i.next) - { - bool taken = HandleCmdMode(cmd, i); - - if(taken) - { - DLLRemove(&ctx.events, i, g_UI_NIL_INPUT); - } - } - - Pop!("parent"); -} - -void -CommandTextInput(CmdPalette* cmd, string[] opts, void function(string) callback) -{ - UICtx* ctx = GetCtx(); - Vec2 ext = GetExtent(); - - -} - -UIFlags -SetHot(bool cond) -{ - return (cond ? UIF.SetHot : UIF.None); -} - -UIItem* -Container(bool push = true)(Axis2D axis, UISize[2] size_info) -{ - enum UIPushInfo[] container_info = [ - { "layout_axis", q{ axis } }, - { "size_info", q{ size_info }}, - ]; - - mixin(PushOnce!(container_info)); - - UIItem* item = MakeItem(ZERO); - - static if(push) - { - Push!("parent")(item, false); - } - - return item; -} - -void -StatusBar(EditorCtx* ed_ctx) -{ - enum UIPushInfo[] bar_info = [ - { "size_info", q{ UISY(ST.Percentage, 0.02)} }, - { "layout_axis", q{ A2D.X} }, - ]; - mixin(PushOnce!(bar_info)); - - ItemStyle* info_style = GetElementStyle(UIElem.StatusInfo); - - Vec4 status_col = BLUE; - string status = "Normal"; - if(ed_ctx.state == ES.InputMode) - { - status = "Input"; - status_col = YELLOW; - } - else if(ed_ctx.state == ES.CmdPalette) - { - status = "Command"; - status_col = RED; - } - - info_style.bg_col = status_col; - - UIItem* bar = MakeItem(ZERO); - - mixin(PushScope!("parent", q{ bar })); - - enum UIPushInfo[] status_info = [ - { "text_size", q{ 16 }}, - { "size_info", q{ UISX(ST.TextSize) } }, - { "display_string", q{ status } }, - ]; - mixin(PushOnce!(status_info)); - - SetElement(UIElem.StatusInfo); - MakeItem(ZERO, UIF.DrawBackground|UIF.DrawText|UIF.VerticalAlignText); - - enum UIPushInfo[] rest_info = [ - { "size_info", q{ UIS2() }}, - ]; - - SetElement(UIElem.StatusMessage); - MakeItem(ZERO, UIF.DrawBackground); -} -