more work
This commit is contained in:
parent
62cd8c471f
commit
dcb0d620c7
Binary file not shown.
Binary file not shown.
2
src/dlib
2
src/dlib
@ -1 +1 @@
|
||||
Subproject commit 10c7fdcaedfdd98af47c640e00f1fad8705f476d
|
||||
Subproject commit 9f70b8982c71d6d24031a08c6f2780be2dd402e0
|
||||
@ -32,7 +32,7 @@ struct EditorCtx
|
||||
string[] file_names;
|
||||
u64 panel_id;
|
||||
|
||||
Editor* focused_editor;
|
||||
Panel* focused_panel;
|
||||
}
|
||||
|
||||
struct CmdPalette
|
||||
@ -109,12 +109,19 @@ enum EditState
|
||||
{
|
||||
NormalMode,
|
||||
InputMode,
|
||||
CmdOpen,
|
||||
CmdPalette,
|
||||
RunCmd,
|
||||
SetPanelFocus, // if moving left/right move up parent tree until one is found with a2d.x, same thing for up/down a2d.y
|
||||
}
|
||||
|
||||
alias ES = EditState;
|
||||
|
||||
bool
|
||||
CmdModeActive()
|
||||
{
|
||||
return g_ed_ctx.state == ES.CmdPalette;
|
||||
}
|
||||
|
||||
__gshared bool g_input_mode = false;
|
||||
__gshared EditorCtx g_ed_ctx;
|
||||
|
||||
@ -200,12 +207,17 @@ Cycle(Inputs* inputs)
|
||||
|
||||
UIItem* cmd_item = Get("###cmd_palette");
|
||||
|
||||
bool cmd_active = Active(ES.CmdOpen);
|
||||
bool cmd_active = Active(ES.CmdPalette);
|
||||
if(cmd_active || Ready(cmd_item))
|
||||
{
|
||||
CommandPalette(&g_ed_ctx.cmd, cmd_active);
|
||||
}
|
||||
|
||||
if(Active(ES.RunCmd))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
EndUI();
|
||||
}
|
||||
|
||||
@ -221,10 +233,10 @@ InitEditorCtx(PlatformWindow* window)
|
||||
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.base_panel = CreatePanel(CreateEditor());
|
||||
ctx.timer = CreateTimer();
|
||||
|
||||
FocusEditor(ctx.base_panel.ed);
|
||||
FocusEditor(ctx.base_panel);
|
||||
|
||||
if(getcwd() != "/")
|
||||
{
|
||||
@ -259,21 +271,20 @@ InitEditorCtx(PlatformWindow* window)
|
||||
}
|
||||
|
||||
void
|
||||
FocusEditor(Editor* ed)
|
||||
FocusEditor(Panel* p)
|
||||
{
|
||||
assert(ed);
|
||||
g_ed_ctx.focused_editor = ed;
|
||||
Logf("editor %s", ed.editor_id);
|
||||
assert(p.ed);
|
||||
g_ed_ctx.focused_panel = p;
|
||||
}
|
||||
|
||||
Panel*
|
||||
CreatePanel(EditorCtx* ctx, Editor* ed = null)
|
||||
CreatePanel(Editor* ed = null)
|
||||
{
|
||||
Panel* p = Alloc!(Panel)(&ctx.arena);
|
||||
Panel* p = Alloc!(Panel)(&g_ed_ctx.arena);
|
||||
|
||||
p.layout_axis = A2D.Y;
|
||||
p.ed = ed;
|
||||
p.id = ctx.panel_id++;
|
||||
p.id = g_ed_ctx.panel_id++;
|
||||
p.text_size = 14;
|
||||
p.parent = p.first = p.last = p.next = p.prev = g_NIL_PANEL;
|
||||
|
||||
@ -414,24 +425,24 @@ OpenFile(Editor* ed, string file_name)
|
||||
}
|
||||
|
||||
Editor*
|
||||
CreateEditor(EditorCtx* ctx)
|
||||
CreateEditor()
|
||||
{
|
||||
Editor* ed = Alloc!(Editor)(&ctx.arena);
|
||||
Editor* ed = Alloc!(Editor)(&g_ed_ctx.arena);
|
||||
|
||||
ed.arena = CreateArena(MB(4));
|
||||
ed.buf = CreateFlatBuffer([], []);
|
||||
ed.editor_id = ctx.editor_id_incr++;
|
||||
ed.editor_id = g_ed_ctx.editor_id_incr++;
|
||||
|
||||
return ed;
|
||||
}
|
||||
|
||||
void
|
||||
AddEditor(EditorCtx* ctx, Panel* target, Axis2D axis)
|
||||
AddEditor(Panel* target, Axis2D axis)
|
||||
{
|
||||
if(CheckNil(g_NIL_PANEL, target.parent) || target.parent.layout_axis != axis)
|
||||
{
|
||||
Panel* first = CreatePanel(ctx, target.ed);
|
||||
Panel* second = CreatePanel(ctx, CreateEditor(ctx));
|
||||
Panel* first = CreatePanel(target.ed);
|
||||
Panel* second = CreatePanel(CreateEditor());
|
||||
|
||||
target.layout_axis = axis;
|
||||
target.ed = null;
|
||||
@ -441,11 +452,11 @@ AddEditor(EditorCtx* ctx, Panel* target, Axis2D axis)
|
||||
|
||||
first.parent = second.parent = target;
|
||||
|
||||
FocusEditor(second.ed);
|
||||
FocusEditor(second);
|
||||
}
|
||||
else if(target.parent.layout_axis == axis)
|
||||
{
|
||||
Panel* panel = CreatePanel(ctx, CreateEditor(ctx));
|
||||
Panel* panel = CreatePanel(CreateEditor());
|
||||
|
||||
DLLPush(target.parent, target, panel);
|
||||
panel.parent = target.parent;
|
||||
@ -466,7 +477,7 @@ AddEditor(EditorCtx* ctx, Panel* target, Axis2D axis)
|
||||
}
|
||||
}
|
||||
|
||||
FocusEditor(panel.ed);
|
||||
FocusEditor(panel);
|
||||
}
|
||||
}
|
||||
|
||||
@ -487,15 +498,20 @@ InsertInputToBuf(EditorCtx* ctx, Editor* ed)
|
||||
}
|
||||
|
||||
void
|
||||
ResetCtx(EditorCtx* ctx, Editor* ed)
|
||||
ResetCtx(Editor* ed)
|
||||
{
|
||||
InsertInputToBuf(ctx, ed);
|
||||
InsertInputToBuf(&g_ed_ctx, ed);
|
||||
ResetCtx();
|
||||
}
|
||||
|
||||
ctx.state = ES.NormalMode;
|
||||
ctx.cmd.icount = 0;
|
||||
ctx.cmd.commands = [];
|
||||
ctx.cmd.current = cast(Command)NO_CMD;
|
||||
ctx.cmd.selected = 0;
|
||||
void
|
||||
ResetCtx()
|
||||
{
|
||||
g_ed_ctx.state = ES.NormalMode;
|
||||
g_ed_ctx.cmd.icount = 0;
|
||||
g_ed_ctx.cmd.commands = [];
|
||||
g_ed_ctx.cmd.current = cast(Command)NO_CMD;
|
||||
g_ed_ctx.cmd.selected = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -568,24 +584,20 @@ HandleInputs(Panel* p, LinkedList!(UIInput)* inputs)
|
||||
|
||||
if(key == Input.Escape)
|
||||
{
|
||||
ResetCtx(ctx, ed);
|
||||
ResetCtx(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)
|
||||
{
|
||||
case Escape:
|
||||
{
|
||||
ResetCtx(ctx, ed);
|
||||
ResetCtx(ed);
|
||||
taken = true;
|
||||
} break;
|
||||
default: break;
|
||||
@ -617,7 +629,7 @@ HandleInputs(Panel* p, LinkedList!(UIInput)* inputs)
|
||||
{
|
||||
if(Shift(node.md))
|
||||
{
|
||||
ctx.state = ES.CmdOpen;
|
||||
ctx.state = ES.CmdPalette;
|
||||
ctx.cmd.commands = cast(Command[])CMD_LIST;
|
||||
ctx.cmd.icount = 0;
|
||||
ctx.cmd.params = [];
|
||||
@ -816,37 +828,12 @@ StrContains(bool begins_with, T, U)(T str_param, U match_param) if(StringType!(T
|
||||
return count == match.length;
|
||||
}
|
||||
|
||||
void
|
||||
GetCommands(CmdPalette* cmd)
|
||||
{
|
||||
Reset(&cmd.arena);
|
||||
|
||||
cmd.commands = Alloc!(Command)(&cmd.arena, CMD_LIST.length);
|
||||
cmd.params = [];
|
||||
u8[] str = cmd.buffer[0 .. cmd.icount];
|
||||
|
||||
u64 count;
|
||||
if(str.length > 0)
|
||||
{
|
||||
for(u64 i = 0; i < CMD_LIST.length; i += 1)
|
||||
{
|
||||
if(StrContains!(true)(CMD_LIST[i].cmd, str) || StrContains!(true)(CMD_LIST[i].name, str))
|
||||
{
|
||||
cmd.commands[count] = cast(Command)CMD_LIST[i];
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd.commands = count ? cmd.commands[0 .. count] : cast(Command[])CMD_LIST;
|
||||
}
|
||||
|
||||
bool
|
||||
HandleCmdMode(EditorCtx* ctx, Panel* panel, UIInput* ev)
|
||||
HandleCmdMode(CmdPalette* cmd, UIInput* ev)
|
||||
{
|
||||
bool taken;
|
||||
CmdPalette* cmd = &ctx.cmd;
|
||||
Editor* ed = panel.ed;
|
||||
bool taken;
|
||||
Panel* panel = g_ed_ctx.focused_panel;
|
||||
Editor* ed = panel.ed;
|
||||
|
||||
u64 prev_count = cmd.icount;
|
||||
switch(ev.key) with(Input)
|
||||
@ -855,43 +842,19 @@ HandleCmdMode(EditorCtx* ctx, Panel* panel, UIInput* ev)
|
||||
{
|
||||
if(cmd.current.type == CT.None && cmd.commands.length > 0)
|
||||
{
|
||||
if(cmd.commands[cmd.selected].type == CT.OpenFile)
|
||||
{
|
||||
goto case Tab;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.current = cmd.commands[cmd.selected];
|
||||
}
|
||||
cmd.current = cmd.commands[cmd.selected];
|
||||
g_ed_ctx.state = ES.RunCmd;
|
||||
}
|
||||
|
||||
switch(cmd.current.type)
|
||||
{
|
||||
case CT.OpenFile:
|
||||
{
|
||||
if(cmd.selected >= 0 && cmd.selected < cmd.opt_strs.length)
|
||||
{
|
||||
OpenFile(ed, cmd.opt_strs[cmd.selected]);
|
||||
}
|
||||
} break;
|
||||
case CT.SaveFile:
|
||||
{
|
||||
SaveFile(ed, GetParam(cmd));
|
||||
} break;
|
||||
case CT.VSplit, CT.HSplit:
|
||||
{
|
||||
AddEditor(ctx, panel, cmd.current.type == CT.VSplit ? A2D.X : A2D.Y);
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
ResetCtx(ctx, ed);
|
||||
} goto CmdInputEnd;
|
||||
case Backspace:
|
||||
{
|
||||
if(cmd.icount > 0 && cmd.buffer[--cmd.icount] == ' ')
|
||||
if(cmd.icount > 0)
|
||||
{
|
||||
cmd.current = cast(Command)NO_CMD;
|
||||
cmd.icount -= 1;
|
||||
if(cmd.icount == cmd.current.name.length)
|
||||
{
|
||||
cmd.current = cast(Command)NO_CMD;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Space:
|
||||
@ -911,8 +874,20 @@ HandleCmdMode(EditorCtx* ctx, Panel* panel, UIInput* ev)
|
||||
} break;
|
||||
case Up, Down:
|
||||
{
|
||||
cmd.selected = clamp(cmd.selected+(ev.key == Up ? -1 : +1), 0, cmd.opt_strs.length-1);
|
||||
i32 incr = ev.key == Up ? -1 : +1;
|
||||
if(cmd.opt_strs.length)
|
||||
{
|
||||
cmd.selected = clamp(cmd.selected+incr, 0, cmd.opt_strs.length-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.selected = clamp(cmd.selected+incr, 0, cmd.commands.length);
|
||||
}
|
||||
} break;
|
||||
case Escape:
|
||||
{
|
||||
ResetCtx();
|
||||
} goto CmdInputEnd;
|
||||
default:
|
||||
{
|
||||
if(ev.text.length)
|
||||
@ -923,9 +898,33 @@ HandleCmdMode(EditorCtx* ctx, Panel* panel, UIInput* ev)
|
||||
} break;
|
||||
}
|
||||
|
||||
if(cmd.current.type == CT.None && prev_count != cmd.icount)
|
||||
if(cmd.current.type == CT.None)
|
||||
{
|
||||
GetCommands(cmd);
|
||||
cmd.opt_strs = [];
|
||||
|
||||
if(prev_count != cmd.icount)
|
||||
{
|
||||
Reset(&cmd.arena);
|
||||
|
||||
cmd.commands = Alloc!(Command)(&cmd.arena, CMD_LIST.length);
|
||||
cmd.params = [];
|
||||
u8[] str = cmd.buffer[0 .. cmd.icount];
|
||||
|
||||
u64 count;
|
||||
if(str.length > 0)
|
||||
{
|
||||
for(u64 i = 0; i < CMD_LIST.length; i += 1)
|
||||
{
|
||||
if(StrContains!(true)(CMD_LIST[i].cmd, str) || StrContains!(true)(CMD_LIST[i].name, str))
|
||||
{
|
||||
cmd.commands[count] = cast(Command)CMD_LIST[i];
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd.commands = count ? cmd.commands[0 .. count] : cast(Command[])CMD_LIST;
|
||||
}
|
||||
}
|
||||
else if(prev_count != cmd.icount)
|
||||
{
|
||||
@ -933,7 +932,7 @@ HandleCmdMode(EditorCtx* ctx, Panel* panel, UIInput* ev)
|
||||
{
|
||||
case OpenFile:
|
||||
{
|
||||
PopulateParams(cmd, ctx.file_names);
|
||||
PopulateParams(cmd, g_ed_ctx.file_names);
|
||||
} break;
|
||||
case SaveFile:
|
||||
{
|
||||
|
||||
318
src/editor/ui.d
318
src/editor/ui.d
@ -31,7 +31,7 @@ import core.stdc.stdio : sprintf;
|
||||
*********************************/
|
||||
|
||||
enum Vec4 BG_COL = SRGBVec4(0.13, 0.13, 0.13, 1.0);
|
||||
enum Vec4 BG_HL_COL = SRGBVec4(0.24, 0.45, 0.81, 1.0);
|
||||
enum Vec4 BG_HL_COL = SRGBVec4(0.12, 0.30, 0.63, 1.0);
|
||||
enum Vec4 BORDER_COL = SRGBVec4(0.254, 0.254, 0.266, 1.0);
|
||||
enum Vec4 BORDER_HL_COL = SRGBVec4(0.035, 0.549, 0.824, 1.0);
|
||||
enum Vec4 TEXT_COL = SRGBVec4(1.0);
|
||||
@ -48,8 +48,8 @@ const f32 LINE_COUNT_PADDING = 4.0;
|
||||
|
||||
__gshared UICtx g_ui_ctx;
|
||||
|
||||
//const u8[] FONT_BYTES = import("pc-9800.ttf");
|
||||
//const u8[] FONT_BYTES = import("NuberNextCondensed-DemiBold.otf");
|
||||
//u8[] FONT_BYTES = Arr!(u8)(import("pc-9800.ttf"));
|
||||
//u8[] FONT_BYTES = Arr!(u8)(import("NuberNextCondensed-DemiBold.otf"));
|
||||
u8[] FONT_BYTES = cast(u8[])import("jetbrains-mono/JetBrainsMono-Regular.ttf");
|
||||
u8[] VERTEX_BYTES = cast(u8[])import("gui.vert.spv");
|
||||
u8[] FRAGMENT_BYTES = cast(u8[])import("gui.frag.spv");
|
||||
@ -230,6 +230,12 @@ CtxMemberInfo(int i)
|
||||
enum MemberInfo CtxMemberInfo = MemberInfo(id: id, is_stack: is_stack, is_top: is_top);
|
||||
}
|
||||
|
||||
struct PushConst
|
||||
{
|
||||
Mat4 projection;
|
||||
u32 atlas_index;
|
||||
}
|
||||
|
||||
struct UICtx
|
||||
{
|
||||
enum FO = FRAME_OVERLAP;
|
||||
@ -241,6 +247,8 @@ struct UICtx
|
||||
|
||||
Arena arena;
|
||||
Arena temp_arena;
|
||||
Arena key_stack_arena;
|
||||
|
||||
Inputs* inputs;
|
||||
u64 frame;
|
||||
u64 f_idx;
|
||||
@ -257,13 +265,15 @@ struct UICtx
|
||||
DescSetLayout desc_set_layout;
|
||||
DescSet[FO] desc_sets;
|
||||
PipelineLayout pipeline_layout;
|
||||
Mat4 projection;
|
||||
PushConst pc;
|
||||
Vec2 res;
|
||||
|
||||
FontFace font;
|
||||
FontGlyphs[FS] glyph_sets;
|
||||
u32 glyph_sets_used;
|
||||
bool[FO] glyphs_to_load;
|
||||
bool prev_has_tex;
|
||||
u32 prev_atlas_index;
|
||||
|
||||
UIBuffer[FO] buffers;
|
||||
|
||||
@ -280,6 +290,8 @@ struct UICtx
|
||||
f32 animation_rate;
|
||||
f32 fade_rate;
|
||||
|
||||
Stack!(UIItem*)* key_item_stack;
|
||||
|
||||
mixin UICtxParameter!(Vec4, "bg_col");
|
||||
mixin UICtxParameter!(Vec4, "bg_col_end");
|
||||
mixin UICtxParameter!(Vec4, "bg_hl_col");
|
||||
@ -440,8 +452,7 @@ struct Vertex
|
||||
f32 border_thickness;
|
||||
f32 edge_softness;
|
||||
f32 raised;
|
||||
u32 texture;
|
||||
u32 atlas_index;
|
||||
u32 has_texture;
|
||||
}
|
||||
|
||||
enum SettingType
|
||||
@ -452,22 +463,18 @@ enum SettingType
|
||||
Toggle,
|
||||
}
|
||||
|
||||
Attribute[15] attributes = [
|
||||
{ binding: 0, location: 0, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof },
|
||||
{ binding: 0, location: 1, format: FMT.RGBA_F32, offset: Vertex.cols_end.offsetof },
|
||||
{ binding: 0, location: 2, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*0 },
|
||||
{ binding: 0, location: 3, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*1 },
|
||||
{ binding: 0, location: 4, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*2 },
|
||||
{ binding: 0, location: 5, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*3 },
|
||||
{ binding: 0, location: 6, format: FMT.RG_F32, offset: Vertex.dst_start.offsetof },
|
||||
{ binding: 0, location: 7, format: FMT.RG_F32, offset: Vertex.dst_end.offsetof },
|
||||
{ binding: 0, location: 8, format: FMT.RG_F32, offset: Vertex.src_start.offsetof },
|
||||
{ binding: 0, location: 9, format: FMT.RG_F32, offset: Vertex.src_end.offsetof },
|
||||
{ binding: 0, location: 10, format: FMT.R_F32, offset: Vertex.border_thickness.offsetof },
|
||||
{ binding: 0, location: 11, format: FMT.R_F32, offset: Vertex.edge_softness.offsetof },
|
||||
{ binding: 0, location: 12, format: FMT.R_F32, offset: Vertex.raised.offsetof },
|
||||
{ binding: 0, location: 13, format: FMT.R_U32, offset: Vertex.texture.offsetof },
|
||||
{ binding: 0, location: 14, format: FMT.R_U32, offset: Vertex.atlas_index.offsetof },
|
||||
Attribute[11] attributes = [
|
||||
{ binding: 0, location: 0, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof },
|
||||
{ binding: 0, location: 1, format: FMT.RGBA_F32, offset: Vertex.cols_end.offsetof },
|
||||
{ binding: 0, location: 2, format: FMT.RGBA_F32, offset: Vertex.corner_radius.offsetof },
|
||||
{ binding: 0, location: 3, format: FMT.RG_F32, offset: Vertex.dst_start.offsetof },
|
||||
{ binding: 0, location: 4, format: FMT.RG_F32, offset: Vertex.dst_end.offsetof },
|
||||
{ binding: 0, location: 5, format: FMT.RG_F32, offset: Vertex.src_start.offsetof },
|
||||
{ binding: 0, location: 6, format: FMT.RG_F32, offset: Vertex.src_end.offsetof },
|
||||
{ binding: 0, location: 7, format: FMT.R_F32, offset: Vertex.border_thickness.offsetof },
|
||||
{ binding: 0, location: 8, format: FMT.R_F32, offset: Vertex.edge_softness.offsetof },
|
||||
{ binding: 0, location: 9, format: FMT.R_F32, offset: Vertex.raised.offsetof },
|
||||
{ binding: 0, location: 10, format: FMT.R_U32, offset: Vertex.has_texture.offsetof },
|
||||
];
|
||||
|
||||
union Rect
|
||||
@ -486,7 +493,8 @@ struct UIKey
|
||||
u64 hash;
|
||||
}
|
||||
|
||||
enum bool StringType(T) = (is(T: string) || is(T: u8[]) || is(T: char[]));
|
||||
enum bool KeyType(T) = (StringType!(T) || is(T == UIKey) || is(T == const(UIKey)));
|
||||
enum bool ItemAndKeyType(T) = (KeyType!(T) || is(T == UIItem*));
|
||||
|
||||
void
|
||||
InitUICtx(PlatformWindow* window)
|
||||
@ -524,6 +532,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.transient_items = g_UI_NIL;
|
||||
ctx.font = OpenFont(cast(u8[])FONT_BYTES);
|
||||
ctx.tab_width = 2;
|
||||
@ -544,7 +553,7 @@ InitUICtx(PlatformWindow* window)
|
||||
];
|
||||
|
||||
ctx.desc_set_layout = CreateDescSetLayout(&ctx.rd, layout_bindings);
|
||||
ctx.pipeline_layout = CreatePipelineLayout(&ctx.rd, ctx.desc_set_layout, Mat4.sizeof);
|
||||
ctx.pipeline_layout = CreatePipelineLayout(&ctx.rd, ctx.desc_set_layout, PushConst.sizeof);
|
||||
|
||||
for(u64 i = 0; i < FRAME_OVERLAP; i += 1)
|
||||
{
|
||||
@ -614,6 +623,12 @@ GetFontAtlas(u32 size)
|
||||
return &GetFontGlyphs(size).abuf;
|
||||
}
|
||||
|
||||
f32
|
||||
GetLineHeight(u32 size)
|
||||
{
|
||||
return GetFontAtlas(size).atlas.line_height;
|
||||
}
|
||||
|
||||
FontGlyphs*
|
||||
GetFontGlyphs(u32 size)
|
||||
{
|
||||
@ -636,12 +651,10 @@ GetFontGlyphs(u32 size)
|
||||
|
||||
assert(ctx.font);
|
||||
|
||||
fg.abuf = CreateAtlas(&ctx.arena, ctx.font, cast(f32)size, ATLAS_DIMENSION);
|
||||
fg.abuf = CreateAtlas(&ctx.arena, ctx.font, size, UVec2(ATLAS_DIMENSION));
|
||||
fg.size = size;
|
||||
fg.loaded = false;
|
||||
|
||||
Logf("setting size %s to %s", size, i);
|
||||
|
||||
ctx.glyphs_to_load = true;
|
||||
ctx.glyph_sets_used += 1;
|
||||
}
|
||||
@ -660,7 +673,6 @@ LoadFontGlyphs()
|
||||
FontGlyphs* fg = ctx.glyph_sets.ptr + i;
|
||||
if(!fg.loaded[fi])
|
||||
{
|
||||
Logf("loading %s frame index %s", i, fi);
|
||||
Transfer(&ctx.rd, &ctx.font_descs[fi][i].view, fg.abuf.data, ATLAS_DIMENSION, ATLAS_DIMENSION);
|
||||
fg.loaded[fi] = true;
|
||||
}
|
||||
@ -712,7 +724,7 @@ MakeItem(Args...)(string str, Args args)
|
||||
}
|
||||
|
||||
UIItem*
|
||||
MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T)
|
||||
MakeItem(T)(T k, UIFlags flags = UIF.None) if(KeyType!(T))
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
UIItem* item = Get(k);
|
||||
@ -724,7 +736,7 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T)
|
||||
if(Nil(ctx.root_first))
|
||||
{
|
||||
ctx.root_first = ctx.root_last = item;
|
||||
Push!("parent")(item);
|
||||
Push!("parent")(item, false);
|
||||
}
|
||||
if(item.flags & (UIF.Window | UIF.FloatingWindow) || Nil(ctx.root_first))
|
||||
{
|
||||
@ -856,9 +868,54 @@ SetColorTransparency(UIItem* item, f32 v)
|
||||
item.border_col.a *= v;
|
||||
}
|
||||
|
||||
bool
|
||||
Ready(UIItem* item)
|
||||
static string
|
||||
AssignItem(T, alias p)()
|
||||
{
|
||||
import std.format : format;
|
||||
|
||||
enum string id = __traits(identifier, p);
|
||||
string result = "";
|
||||
static if(is(T == UIItem*))
|
||||
{
|
||||
result = id;
|
||||
}
|
||||
else static if(is(T == UIKey) || StringType!(T))
|
||||
{
|
||||
result = format("Get(%s)", id);
|
||||
}
|
||||
else static assert(false, "Unknown type for AssignItem");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static string
|
||||
AssignKey(T, alias p)()
|
||||
{
|
||||
import std.format : format;
|
||||
|
||||
enum string id = __traits(identifier, p);
|
||||
string result = "";
|
||||
static if(is(T == UIItem*))
|
||||
{
|
||||
result = format("%s.key", id);
|
||||
}
|
||||
else static if(is(T == UIKey) || is(T == const(UIKey)))
|
||||
{
|
||||
result = id;
|
||||
}
|
||||
else static if(StringType!(T))
|
||||
{
|
||||
result = format("MakeKey(%s)", id);
|
||||
}
|
||||
else static assert(false, "Unknown type for AssignKey");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
Ready(T)(T param) if(ItemAndKeyType!(T))
|
||||
{
|
||||
UIItem* item = mixin(AssignItem!(T, param));
|
||||
return item.ready_t > 0.0001;
|
||||
}
|
||||
|
||||
@ -880,14 +937,7 @@ Hovered(bool current_frame, T)(T param)
|
||||
UICtx* ctx = GetCtx();
|
||||
bool result;
|
||||
|
||||
static if(is(T == UIKey))
|
||||
{
|
||||
UIKey key = param;
|
||||
}
|
||||
else static if(is(T == UIItem*))
|
||||
{
|
||||
UIKey key = param.key;
|
||||
}
|
||||
UIKey key = mixin(AssignKey!(T, param));
|
||||
|
||||
if(!ZeroKey(ctx.hover_key))
|
||||
{
|
||||
@ -909,9 +959,11 @@ Signal(UIItem* item)
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
|
||||
if(item.signal != UIS.None)
|
||||
assert(!ZeroKey(item.key), "Zero key passed to Signal");
|
||||
|
||||
if(item.signal == UIS.None && !ZeroKey(item.key))
|
||||
{
|
||||
bool mouse_over = InBounds(ctx.mouse_pos, &item.rect);
|
||||
bool mouse_over = KeyEq(ctx.hover_key, item.key);
|
||||
|
||||
if(mouse_over)
|
||||
{
|
||||
@ -924,13 +976,13 @@ Signal(UIItem* item)
|
||||
{
|
||||
bool taken;
|
||||
|
||||
if(item.flags & UIF.Clickable && i.type == UIE.Click && InBounds(ctx.mouse_pos, &item.rect))
|
||||
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 && InBounds(i.pos, &item.rect))
|
||||
if(ZeroKey(ctx.drag_key) && item.flags & UIF.Draggable && i.type == UIE.DragStart && mouse_over)
|
||||
{
|
||||
item.signal |= UIS.Dragged;
|
||||
ctx.drag_key = item.key;
|
||||
@ -967,6 +1019,17 @@ PushUIEvent(UICtx* ctx, UIInput input)
|
||||
DLLPush(&ctx.events, ev, null);
|
||||
}
|
||||
|
||||
void
|
||||
DrawUI(UICtx* ctx, u32 atlas_index)
|
||||
{
|
||||
if(ctx.pc.atlas_index != atlas_index)
|
||||
{
|
||||
DrawUI(ctx);
|
||||
ctx.pc.atlas_index = atlas_index;
|
||||
PushConstants(&ctx.rd, ctx.pipeline, &ctx.pc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawUI(UICtx* ctx)
|
||||
{
|
||||
@ -1055,18 +1118,12 @@ BeginUI(Inputs* inputs)
|
||||
// Check current mouse target
|
||||
if(mouse_moved && !Nil(ctx.root_last))
|
||||
{
|
||||
UIItem* last = ctx.root_last;
|
||||
while(!Nil(last.last))
|
||||
{
|
||||
last = last.last;
|
||||
}
|
||||
|
||||
UIKey hovered = ZeroKey();
|
||||
for(UIItem* item = last; !Nil(item); item = Recurse!(false)(item, g_UI_NIL))
|
||||
for(Stack!(UIItem*)* node = ctx.key_item_stack; node; node = node.next)
|
||||
{
|
||||
if(InBounds(ctx.mouse_pos, &item.rect) && !ZeroKey(item.key))
|
||||
if(InBounds(ctx.mouse_pos, &node.value.rect))
|
||||
{
|
||||
hovered = item.key;
|
||||
hovered = node.value.key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1082,7 +1139,8 @@ BeginUI(Inputs* inputs)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.root_first = ctx.root_last = g_UI_NIL;
|
||||
ctx.key_item_stack = null;
|
||||
ctx.root_first = ctx.root_last = g_UI_NIL;
|
||||
|
||||
// Clean up items
|
||||
KVPair!(UIHash, UIItem*)*[] items = GetAllNodes(&ctx.temp_arena, &ctx.items);
|
||||
@ -1105,7 +1163,6 @@ BeginUI(Inputs* inputs)
|
||||
item = next;
|
||||
}
|
||||
|
||||
|
||||
// Ctx state
|
||||
ctx.transient_items = g_UI_NIL;
|
||||
ctx.frame = next_frame;
|
||||
@ -1145,10 +1202,10 @@ EndUI()
|
||||
if(ext != ctx.res)
|
||||
{
|
||||
ctx.res = ext;
|
||||
Ortho(&ctx.projection, 0.0, 0.0, ext.x, ext.y, -10.0, 10.0);
|
||||
Ortho(&ctx.pc.projection, 0.0, 0.0, ext.x, ext.y, -10.0, 10.0);
|
||||
}
|
||||
|
||||
PushConstants(&ctx.rd, ctx.pipeline, &ctx.projection);
|
||||
PushConstants(&ctx.rd, ctx.pipeline, &ctx.pc);
|
||||
Bind(&ctx.rd, ctx.pipeline, ctx.desc_sets[ctx.f_idx]);
|
||||
}
|
||||
else
|
||||
@ -1206,12 +1263,17 @@ EndUI()
|
||||
{
|
||||
if(item.size_info[axis].type == ST.Pixels)
|
||||
{
|
||||
item.size.v[axis] = AxisPadding!(axis)(item) + item.size_info[axis].value;
|
||||
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] = size + AxisPadding!(axis)(item);
|
||||
f32 size = axis == A2D.X ? item.max_text_width : GetFontAtlas(item.text_size).atlas.line_height * item.text_lines.length;
|
||||
if(axis == A2D.Y)
|
||||
{
|
||||
// Logf("line height %f %f %f", size, floor(size), AxisPadding!(axis)(item));
|
||||
|
||||
}
|
||||
item.size.v[axis] = floor(size) + AxisPadding!(axis)(item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1396,6 +1458,11 @@ EndUI()
|
||||
}
|
||||
}
|
||||
|
||||
if(!ZeroKey(item.key))
|
||||
{
|
||||
PushKeyedItem(item);
|
||||
}
|
||||
|
||||
RenderItem(ctx, item);
|
||||
}
|
||||
|
||||
@ -1434,17 +1501,9 @@ Clamp(UICtx* ctx, Vertex* v)
|
||||
}
|
||||
|
||||
void
|
||||
FocusItem(T)(T focus) if(is(T == UIKey) || StringType!T || is(T == UIItem*))
|
||||
FocusItem(T)(T focus) if(ItemAndKeyType!(T))
|
||||
{
|
||||
static if(is(T == UIItem*))
|
||||
{
|
||||
assert(!Nil(focus));
|
||||
g_ui_ctx.focus_item = focus;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ui_ctx.focus_item = Get(focus);
|
||||
}
|
||||
g_ui_ctx.focus_item = mixin(AssignItem(T, focus));
|
||||
}
|
||||
|
||||
pragma(inline) void
|
||||
@ -1513,9 +1572,16 @@ RenderItem(UICtx* ctx, UIItem* item)
|
||||
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)
|
||||
{
|
||||
y_pos += (item.rect.p1.y - item.rect.p0.y - line_height) / 2.0;
|
||||
f32 adj = floor((item.rect.p1.y - item.rect.p0.y - line_height) / 2.0);
|
||||
y_pos += adj;
|
||||
}
|
||||
else
|
||||
{
|
||||
y_pos += item.padding[A2D.Y].x;
|
||||
}
|
||||
|
||||
foreach(i; 0 .. item.text_lines.length)
|
||||
@ -1530,7 +1596,6 @@ RenderItem(UICtx* ctx, UIItem* item)
|
||||
else if(item.flags & UIF.CenterAlignText)
|
||||
{
|
||||
x_pos = ((item.rect.p1.x-item.rect.p0.x - CalcTextWidth(str, &fg.abuf)) / 2.0) + item.padding[A2D.X].x;
|
||||
Logf("%f", x_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1545,7 +1610,7 @@ RenderItem(UICtx* ctx, UIItem* item)
|
||||
{
|
||||
u8 ch = str[j];
|
||||
Glyph* g = ch < fg.abuf.atlas.glyphs.length ? fg.abuf.atlas.glyphs.ptr + ch : null;
|
||||
DrawGlyph(item, g, fg.index, &x_pos, y_pos, line_height, fg.index, syntax_cols[tks[j]]);
|
||||
DrawGlyph(item, g, &x_pos, y_pos, line_height, syntax_cols[tks[j]]);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1554,7 +1619,7 @@ RenderItem(UICtx* ctx, UIItem* item)
|
||||
{
|
||||
u8 ch = str[j];
|
||||
Glyph* g = ch < fg.abuf.atlas.glyphs.length ? fg.abuf.atlas.glyphs.ptr + ch : null;
|
||||
DrawGlyph(item, g, fg.index, &x_pos, y_pos, line_height, fg.index, item.text_col);
|
||||
DrawGlyph(item, g, &x_pos, y_pos, line_height, item.text_col);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1569,13 +1634,10 @@ RenderItem(UICtx* ctx, UIItem* item)
|
||||
{
|
||||
DrawUI(ctx);
|
||||
|
||||
Vec2 p0 = Clamp(item.rect.p0 - item.padding[A2D.X], Vec2(0.0), Vec2(ctx.res.x, ctx.res.y));
|
||||
Vec2 p1 = Clamp(item.rect.p1 + item.padding[A2D.Y], Vec2(0.0), Vec2(ctx.res.x, ctx.res.y));
|
||||
|
||||
u32 x = cast(u32)(scissor_x ? floor(p0.x) : 0);
|
||||
u32 y = cast(u32)(scissor_y ? floor(p0.y) : 0);
|
||||
u32 w = cast(u32)(scissor_x ? floor(p1.x) - x : ctx.res.x);
|
||||
u32 h = cast(u32)(scissor_y ? floor(p1.y) - y : ctx.res.y);
|
||||
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);
|
||||
|
||||
@ -1607,6 +1669,41 @@ GetExtent()
|
||||
version(ENABLE_RENDERER) return RendererGetExtent(&g_ui_ctx.rd); else return [1280, 720];
|
||||
}
|
||||
|
||||
void
|
||||
PushKeyedItem(UIItem* item)
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
|
||||
assert(!Nil(item));
|
||||
assert(!ZeroKey(item.key));
|
||||
|
||||
Stack!(UIItem*)* node = Alloc!(Stack!(UIItem*))(&ctx.key_stack_arena);
|
||||
|
||||
node.next = ctx.key_item_stack;
|
||||
node.value = item;
|
||||
|
||||
ctx.key_item_stack = node;
|
||||
}
|
||||
|
||||
void
|
||||
PushDisplayStringCopy(T)(T param, bool auto_pop = true)
|
||||
{
|
||||
PushDisplayString(ScratchAlloc(mixin(AssignStr!(T, param))), auto_pop);
|
||||
}
|
||||
|
||||
void
|
||||
PushDisplayString(Args...)(string fmt, Args args)
|
||||
{
|
||||
static if(is(Args[Args.length-1] == bool))
|
||||
{
|
||||
PushDisplayString(Scratchf(fmt, args[0 .. Args.length-1]), args[Args.length-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
PushDisplayString(Scratchf(fmt, args));
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
StackIDs(string stack, string ctx = "ctx")
|
||||
{
|
||||
@ -1623,7 +1720,13 @@ static string
|
||||
PushScope(string stack, string value)()
|
||||
{
|
||||
import std.conv;
|
||||
return i"Push!(\"$(stack)\")($(value)); scope(exit) Pop!(\"$(stack)\")();".text;
|
||||
return i"Push!(\"$(stack)\")($(value), false); scope(exit) Pop!(\"$(stack)\")();".text;
|
||||
}
|
||||
|
||||
struct UIPushInfo
|
||||
{
|
||||
string s; // stack
|
||||
string v; // value
|
||||
}
|
||||
|
||||
static string
|
||||
@ -1640,14 +1743,22 @@ PushOnce(UIPushInfo[] info)()
|
||||
return result;
|
||||
}
|
||||
|
||||
struct UIPushInfo
|
||||
void
|
||||
PushOnce(Args...)()
|
||||
{
|
||||
string s; // stack
|
||||
string v; // value
|
||||
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 = false)
|
||||
Push(string stack_str, T)(T value, bool auto_pop = true)
|
||||
{
|
||||
import std.string : replace;
|
||||
|
||||
@ -1668,10 +1779,17 @@ Push(string stack_str, T)(T value, bool auto_pop = false)
|
||||
}
|
||||
|
||||
node.next = stack.top;
|
||||
node.value = value;
|
||||
node.auto_pop = auto_pop;
|
||||
static if(is(ST == string) && StringType!(T))
|
||||
{
|
||||
node.value = Str(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
node.value = value;
|
||||
}
|
||||
|
||||
stack.top = node;
|
||||
stack.top = node;
|
||||
}
|
||||
|
||||
static string
|
||||
@ -1750,7 +1868,7 @@ GenPushFuncs()
|
||||
}
|
||||
}
|
||||
|
||||
funcs ~= "pragma(inline) void " ~ fn_name ~ "(T)(T value, bool auto_pop = false){ Push!(\"" ~ info.id ~ "\")(value, auto_pop); }\n";
|
||||
funcs ~= "pragma(inline) void " ~ fn_name ~ "(T)(T value, bool auto_pop = true){ Push!(\"" ~ info.id ~ "\")(value, auto_pop); }\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1953,8 +2071,9 @@ ZeroKey()
|
||||
}
|
||||
|
||||
bool
|
||||
ZeroKey(UIKey key)
|
||||
ZeroKey(T)(T param) if(is(T == UIItem*) || is(T == UIKey))
|
||||
{
|
||||
UIKey key = mixin(AssignKey!(T, param));
|
||||
return key.hash == 0 && key.hash_text.length == 0;
|
||||
}
|
||||
|
||||
@ -1982,19 +2101,11 @@ Get(Args...)(string str, Args args)
|
||||
}
|
||||
|
||||
pragma(inline) UIItem*
|
||||
Get(T)(T k) if(is(T: UIKey) || StringType!T)
|
||||
Get(T)(T k) if(KeyType!(T))
|
||||
{
|
||||
static if(is(T: UIKey))
|
||||
{
|
||||
UIKey key = k;
|
||||
}
|
||||
else
|
||||
{
|
||||
UIKey key = MakeKey(k);
|
||||
}
|
||||
|
||||
UIItem* item;
|
||||
UIKey key = mixin(AssignKey!(T, k));
|
||||
UICtx* ctx = GetCtx();
|
||||
UIItem* item;
|
||||
|
||||
if(ZeroKey(key))
|
||||
{
|
||||
@ -2062,7 +2173,7 @@ GlyphWidth(Glyph* g, FontAtlasBuf* abuf)
|
||||
}
|
||||
|
||||
pragma(inline) void
|
||||
DrawGlyph(UIItem* item, Glyph* glyph, u32 atlas_index, f32* x_pos, f32 y, f32 line_height, u32 index, Vec4 col = Vec4(1.0))
|
||||
DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y, f32 line_height, Vec4 col = Vec4(1.0))
|
||||
{
|
||||
if(glyph)
|
||||
{
|
||||
@ -2091,10 +2202,9 @@ DrawGlyph(UIItem* item, Glyph* glyph, u32 atlas_index, f32* x_pos, f32 y, f32 li
|
||||
v.dst_end = Vec2(*x_pos+glyph.plane_left+w, y_pos+h);
|
||||
v.cols = col;
|
||||
v.cols_end = col;
|
||||
v.texture = true;
|
||||
v.atlas_index = index;
|
||||
v.src_start = Vec2(glyph.atlas_left, glyph.atlas_top);
|
||||
v.src_end = Vec2(glyph.atlas_right, glyph.atlas_bottom);
|
||||
v.has_texture = true;
|
||||
|
||||
f32 end_x = *x_pos + advance;
|
||||
f32 width = end_x - *x_pos;
|
||||
|
||||
@ -14,18 +14,28 @@ __gshared const Editor g_nil_ed;
|
||||
__gshared Editor* g_NIL_ED;
|
||||
__gshared const UIKey ZERO = ZeroKey();
|
||||
|
||||
/******
|
||||
- Set up "themes" for different components (e.g. command palette window, editor view, status bar) then have the ability to create styles and apply them to different sections via a string lookup, e.g. start of function to draw cmd palette call ApplyTheme(selected_theme_name) then do code to draw things, get to options and call ApplyTheme(selected_theme_name_for_options), etc.
|
||||
- Move scrolling behaviour into ui.d and externally be oblivious to it, e.g. just feed it all lines of text in a text buffer, will have to specifically handle extreme cases later but initially i think it should be fine
|
||||
******/
|
||||
|
||||
Vec4 BG_COL = Vec4(0.18, 0.18, 0.18, 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);
|
||||
Vec4 CMD_COL = Vec4(0.22, 0.22, 0.22, 1.0);
|
||||
Vec4 CMD_BORDER_COL = Vec4(0.48, 0.48, 0.48, 1.0);
|
||||
Vec4 CMD_INPUT_COL = Vec4(0.130, 0.420, 0.640, 1.0);
|
||||
Vec4 GREY = Vec4(0.45, 0.45, 0.45, 1.0);
|
||||
Vec4 GREY = Vec4(0.80, 0.80, 0.80, 1.0);
|
||||
Vec4 WHITE = HexCol(0xFFFFFF);
|
||||
Vec4 BLUE = HexCol(0x4EA9FF);
|
||||
Vec4 RED = HexCol(0xFF3268);
|
||||
Vec4 YELLOW = HexCol(0xF7C443);
|
||||
|
||||
const f32 CMD_X_PAD = 8.0;
|
||||
const f32 CMD_Y_PAD = 4.0;
|
||||
const u32 CMD_TITLE_PX = 14;
|
||||
const u32 CMD_SUB_PX = 10;
|
||||
|
||||
shared static this()
|
||||
{
|
||||
g_NIL_PANEL = cast(Panel* )&g_nil_panel;
|
||||
@ -70,7 +80,7 @@ LineCounterView(FontAtlasBuf* abuf, u64 max_line, u64 lines, i64 line_offset, f3
|
||||
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), true);
|
||||
Push!("display_string")(Scratchf("%s", i));
|
||||
MakeItem(ZERO, UIF.DrawText);
|
||||
}
|
||||
}
|
||||
@ -80,7 +90,7 @@ EditorTextView(UIItem* editor, Panel* p, FontAtlasBuf* abuf, u64 lines, i64 line
|
||||
{
|
||||
Editor* ed = p.ed;
|
||||
|
||||
PushLayoutAxis(A2D.Y, true);
|
||||
PushLayoutAxis(A2D.Y);
|
||||
|
||||
f32 text_size = cast(f32)p.text_size;
|
||||
f32 clamp_y = cast(f32)(ed.buf.line_count-lines)*text_size;
|
||||
@ -129,16 +139,12 @@ EditorTextView(UIItem* editor, Panel* p, FontAtlasBuf* abuf, u64 lines, i64 line
|
||||
mixin(PushScope!("size_info", q{ UISY(ST.TextSize) } ));
|
||||
mixin(PushScope!("syntax_highlight", q{ UISH.D } ));
|
||||
|
||||
// Do a thing like the bottom 3 colours on lost trail (arknights) on highlighting but make it slide to the right one colour every time you scroll down
|
||||
|
||||
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))
|
||||
{
|
||||
enum UIPushInfo[] lc_info = [
|
||||
{ "display_string", q{ Str(lb.text) } },
|
||||
{ "syntax_tokens", q{ cast(u8[])(lb.style) } },
|
||||
];
|
||||
mixin(PushOnce!(lc_info));
|
||||
string txt = Str(lb.text);
|
||||
u8[] tokens = cast(u8[])(lb.style);
|
||||
PushOnce!("display_string", txt, "syntax_tokens", tokens);
|
||||
|
||||
UIItem* line = MakeItem(zero, UIF.DrawText);
|
||||
}
|
||||
@ -163,6 +169,8 @@ EditorView(Panel* p)
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(ed);
|
||||
|
||||
UIKey ed_key = MakeKey("###ed_%s", ed.editor_id);
|
||||
UIItem* editor = Get(ed_key);
|
||||
|
||||
@ -202,7 +210,7 @@ EditorView(Panel* p)
|
||||
}
|
||||
}
|
||||
|
||||
for(UIInput* i = ctx.events.first; !CheckNil(g_UI_NIL_INPUT, i) && g_ed_ctx.focused_editor == p.ed; i = i.next)
|
||||
for(UIInput* i = ctx.events.first; !CheckNil(g_UI_NIL_INPUT, i) && g_ed_ctx.focused_panel == p && !CmdModeActive(); i = i.next)
|
||||
{
|
||||
bool taken;
|
||||
|
||||
@ -229,6 +237,9 @@ EditorView(Panel* p)
|
||||
{
|
||||
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);
|
||||
@ -241,19 +252,12 @@ EditorView(Panel* p)
|
||||
ResetBuffer(&ed.buf);
|
||||
}
|
||||
|
||||
void
|
||||
CommandPalette(CmdPalette* cmd, bool active)
|
||||
UIItem*
|
||||
CommandWindow(f32 w, f32 h, f32 x, f32 y, bool active)
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
Vec2 ext = GetExtent();
|
||||
FontAtlasBuf* abuf = &g_ui_ctx.glyph_sets[0].abuf;
|
||||
|
||||
f32 w = ext.x*0.6;
|
||||
f32 h = ext.y*0.7;
|
||||
|
||||
enum UIPushInfo[] cmd_params = [
|
||||
{ "layout_axis", q{ A2D.Y } },
|
||||
{ "fixed_pos", q{ Vec2(ext.x*0.2, ext.y*0.1) } },
|
||||
{ "fixed_pos", q{ Vec2(x, y) } },
|
||||
{ "bg_col", q{ BG_COL } },
|
||||
{ "border_col", q{ HL_BORDER_COL } },
|
||||
{ "border_thickness", q{ 4.0 } },
|
||||
@ -268,109 +272,179 @@ CommandPalette(CmdPalette* cmd, bool active)
|
||||
cmd_flags |= UIF.SetReady;
|
||||
}
|
||||
|
||||
UIItem* cmd_item = MakeItem("###cmd_palette", cmd_flags);
|
||||
UIItem* window = MakeItem("###cmd_palette", cmd_flags);
|
||||
Push!("parent")(window, false);
|
||||
|
||||
f32 padding_y = 4.0;
|
||||
return window;
|
||||
}
|
||||
|
||||
mixin(PushScope!("parent", q{ cmd_item } ));
|
||||
mixin(PushScope!("padding", q{ Vec2(4.0, padding_y) }));
|
||||
UIItem*
|
||||
CommandInput(CmdPalette* cmd, string placeholder = "")
|
||||
{
|
||||
string input_str = cmd.icount ? Str(cmd.buffer[0 .. cmd.icount]) : "Search...";
|
||||
Vec4 input_text_col = cmd.icount ? WHITE : GREY;
|
||||
|
||||
enum UIPushInfo[] cmd_input_params = [
|
||||
{ "bg_col", q{ CMD_COL } },
|
||||
{ "border_col", q{ CMD_BORDER_COL } },
|
||||
{ "border_thickness", q{ 1.0 }},
|
||||
{ "text_size", q{ 18 }},
|
||||
{ "corner_radius", q{ Vec4(12.0, 12.0, 0.0, 0.0)}},
|
||||
{ "edge_softness", q{ 1.0 }},
|
||||
{ "text_size", q{ 14 }},
|
||||
{ "corner_radius", q{ Vec4(12.0, 12.0, 0.0, 0.0) } },
|
||||
{ "edge_softness", q{ 1.0 } },
|
||||
{ "size_info", q{ UISY(ST.TextSize) } },
|
||||
{ "padding", q{ Vec2A2(6.0, 6.0, 10.0, 10.0)} },
|
||||
{ "display_string", q{ Str(cmd.buffer[0 .. cmd.icount]) } },
|
||||
{ "padding", q{ Vec2A2(6.0, 6.0, 6.0, 6.0)} },
|
||||
{ "display_string", q{ input_str } },
|
||||
{ "text_col", q{ input_text_col } },
|
||||
];
|
||||
|
||||
mixin(PushOnce!(cmd_input_params));
|
||||
return MakeItem("###cmd_input", UIF.DrawBorder|UIF.DrawBackground|UIF.DrawText|UIF.Overflow);
|
||||
}
|
||||
|
||||
MakeItem(ZERO, UIF.DrawBorder|UIF.DrawBackground|UIF.DrawText|UIF.Overflow|UIF.VerticalAlignText);
|
||||
|
||||
// the two sizes seems to fuck this up somehow
|
||||
u32 title_px = 16;
|
||||
u32 sub_px = 16;
|
||||
f32 title_pad = 2.0f;
|
||||
f32 opt_y_pad = 4.0;
|
||||
f32 opt_x_pad = 8.0;
|
||||
f32 opt_height = cast(f32)(title_px + sub_px) + opt_y_pad*2.0 + title_pad;
|
||||
|
||||
enum UIPushInfo[] cmd_opts_box_params = [
|
||||
{ "layout_axis", q{ A2D.Y }},
|
||||
{ "border_col", q{ CMD_BORDER_COL } },
|
||||
{ "border_thickness", q{ 1.0 } },
|
||||
{ "corner_radius", q{ Vec4(0.0, 0.0, 12.0, 12.0) } },
|
||||
{ "edge_softness", q{ 1.0 }},
|
||||
{ "size_info", q{ UISY(ST.Pixels, h-opt_height) } },
|
||||
];
|
||||
|
||||
mixin(PushOnce!(cmd_opts_box_params));
|
||||
|
||||
UIItem* opt_box = MakeItem(ZERO, UIF.DrawBorder);
|
||||
|
||||
mixin(PushScope!("parent", q{ opt_box }));
|
||||
mixin(PushScope!("padding", q{ Vec2A2(opt_x_pad, opt_x_pad, opt_y_pad, opt_y_pad) } ));
|
||||
mixin(PushScope!("size_info", q{ UISY(ST.Pixels, opt_height) } ));
|
||||
|
||||
u64 max_opts = cast(u64)ceil(h/opt_height);
|
||||
|
||||
UIItem*
|
||||
CommandOpt(T)(CmdPalette* cmd, T opt, u64 i)
|
||||
{
|
||||
Vec4[2] opt_cols = [
|
||||
Vec4(0.22, 0.22, 0.22, 1.0),
|
||||
Vec4(0.35, 0.35, 0.35, 1.0),
|
||||
Vec4(0.31, 0.31, 0.31, 1.0),
|
||||
];
|
||||
|
||||
// Active should be highlights around the item like File Pilot (maybe not)
|
||||
UIFlags flags = UIF.DrawBackground|UIF.AnimateHot|UIF.Clickable;
|
||||
|
||||
bool opts = cast(bool)cmd.opt_strs.length;
|
||||
if(opts)
|
||||
PushBgCol(opt_cols[i%2]);
|
||||
PushLayoutAxis(A2D.Y);
|
||||
|
||||
static if(is(T == string))
|
||||
{
|
||||
for(u64 i = 0; i < cmd.opt_strs.length && i < max_opts; i += 1)
|
||||
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);
|
||||
PushPadding(Vec2A2(CMD_X_PAD, CMD_X_PAD, CMD_Y_PAD, 2.0));
|
||||
PushDisplayStringCopy(cmd.commands[i].name);
|
||||
|
||||
MakeItem(ZERO, UIF.DrawText);
|
||||
|
||||
PushTextSize(CMD_SUB_PX);
|
||||
PushTextCol(GREY);
|
||||
PushPadding(Vec2A2(CMD_X_PAD, CMD_X_PAD, 0.0, 0.0));
|
||||
PushDisplayStringCopy(cmd.commands[i].desc);
|
||||
|
||||
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 }},
|
||||
{ "border_col", q{ CMD_BORDER_COL } },
|
||||
{ "border_thickness", q{ 1.0 } },
|
||||
{ "corner_radius", q{ Vec4(0.0, 0.0, 12.0, 12.0) } },
|
||||
{ "edge_softness", q{ 1.0 }},
|
||||
{ "size_info", q{ UISY(ST.Pixels, h-opt_height) } },
|
||||
];
|
||||
|
||||
mixin(PushOnce!(cmd_opts_box_params));
|
||||
|
||||
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)
|
||||
{
|
||||
PushDisplayString(Str(cmd.opt_strs[i]), true);
|
||||
PushBgCol(opt_cols[i%2], true);
|
||||
mixin(PushScope!("padding", q{ Vec2A2(CMD_X_PAD, CMD_X_PAD, CMD_Y_PAD, CMD_Y_PAD) } ));
|
||||
|
||||
UIKey k = MakeKey("###opt_%s", i);
|
||||
Hovered!(true)(k, &cmd.selected, i);
|
||||
|
||||
MakeItem(k, UIF.DrawBackground|UIF.DrawText|UIF.AnimateHot|(cmd.selected == i ? UIF.SetHot : UIF.None));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
for(UIInput* i = ctx.events.first; !CheckNil(g_UI_NIL_INPUT, i); i = i.next)
|
||||
{
|
||||
for(u64 i = 0; i < cmd.commands.length && i < max_opts; i += 1)
|
||||
bool taken = HandleCmdMode(cmd, i);
|
||||
|
||||
if(taken)
|
||||
{
|
||||
PushBgCol(opt_cols[i%2], true);
|
||||
PushLayoutAxis(A2D.Y, true);
|
||||
|
||||
UIKey k = MakeKey("###optc_%s", i);
|
||||
Hovered!(true)(k, &cmd.selected, i);
|
||||
|
||||
UIItem* optc = MakeItem(k, UIF.DrawBackground|UIF.AnimateHot|(cmd.selected == i ? UIF.SetHot : UIF.None));
|
||||
PushParent(optc);
|
||||
|
||||
PushSizeInfo(UISY(ST.TextSize));
|
||||
|
||||
PushTextSize(title_px, true);
|
||||
PushTextCol(WHITE, true);
|
||||
PushPadding(Vec2A2(opt_x_pad, opt_x_pad, 0.0, title_pad), true);
|
||||
PushDisplayString(ScratchAlloc(cmd.commands[i].name), true);
|
||||
|
||||
MakeItem(ZERO, UIF.DrawText);
|
||||
|
||||
PushTextSize(sub_px, true);
|
||||
PushTextCol(GREY, true);
|
||||
PushPadding(Vec2A2(opt_x_pad, opt_x_pad, 0.0, 0.0), true);
|
||||
PushDisplayString(ScratchAlloc(cmd.commands[i].desc), true);
|
||||
|
||||
MakeItem(ZERO, UIF.DrawText);
|
||||
|
||||
Pop!("parent", "size_info");
|
||||
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*
|
||||
@ -387,7 +461,7 @@ Container(bool push = true)(Axis2D axis, UISize[2] size_info)
|
||||
|
||||
static if(push)
|
||||
{
|
||||
Push!("parent")(item);
|
||||
Push!("parent")(item, false);
|
||||
}
|
||||
|
||||
return item;
|
||||
@ -411,7 +485,7 @@ StatusBar(EditorCtx* ed_ctx)
|
||||
status = "Input";
|
||||
status_col = YELLOW;
|
||||
}
|
||||
else if(ed_ctx.state == ES.CmdOpen)
|
||||
else if(ed_ctx.state == ES.CmdPalette)
|
||||
{
|
||||
status = "Command";
|
||||
status_col = RED;
|
||||
|
||||
@ -66,7 +66,7 @@ void main()
|
||||
vec4 gamma = vec4(1.0/1.4);
|
||||
|
||||
vec4 tex_color = vec4(1.0);
|
||||
if(FDF.texture != 0)
|
||||
if(FDF.has_texture != 0)
|
||||
{
|
||||
tex_color = texture(sampler2D(SpriteAtlas, SamplerNearest), FD.uv);
|
||||
}
|
||||
|
||||
@ -6,9 +6,10 @@ layout (set = 1, binding = 1) uniform sampler SamplerNearest;
|
||||
|
||||
layout (push_constant) uniform Constants {
|
||||
mat4 projection;
|
||||
uint atlas_index;
|
||||
} PC;
|
||||
|
||||
#define SpriteAtlas SpriteAtlasArray[FDF.atlas_index]
|
||||
#define SpriteAtlas SpriteAtlasArray[PC.atlas_index]
|
||||
|
||||
#ifdef VERT_SHADER
|
||||
# define FragData out struct FragDataOut
|
||||
@ -22,11 +23,10 @@ layout (push_constant) uniform Constants {
|
||||
|
||||
layout (location = 0) FragDataFlat
|
||||
{
|
||||
uint texture;
|
||||
uint atlas_index;
|
||||
uint has_texture;
|
||||
} FDF;
|
||||
|
||||
layout (location = 2) FragData
|
||||
layout (location = 1) FragData
|
||||
{
|
||||
vec4 color;
|
||||
vec4 color_end;
|
||||
|
||||
@ -8,19 +8,15 @@
|
||||
|
||||
layout (location = 0) in vec4 in_col_start;
|
||||
layout (location = 1) in vec4 in_col_end;
|
||||
layout (location = 2) in float in_corner_radius_x0y0;
|
||||
layout (location = 3) in float in_corner_radius_x1y0;
|
||||
layout (location = 4) in float in_corner_radius_x0y1;
|
||||
layout (location = 5) in float in_corner_radius_x1y1;
|
||||
layout (location = 6) in vec2 in_dst_start;
|
||||
layout (location = 7) in vec2 in_dst_end;
|
||||
layout (location = 8) in vec2 in_src_start;
|
||||
layout (location = 9) in vec2 in_src_end;
|
||||
layout (location = 10) in float border_thickness;
|
||||
layout (location = 11) in float edge_softness;
|
||||
layout (location = 12) in float raised;
|
||||
layout (location = 13) in uint in_has_texture;
|
||||
layout (location = 14) in uint in_atlas_index;
|
||||
layout (location = 2) in vec4 in_corner_radius;
|
||||
layout (location = 3) in vec2 in_dst_start;
|
||||
layout (location = 4) in vec2 in_dst_end;
|
||||
layout (location = 5) in vec2 in_src_start;
|
||||
layout (location = 6) in vec2 in_src_end;
|
||||
layout (location = 7) in float border_thickness;
|
||||
layout (location = 8) in float edge_softness;
|
||||
layout (location = 9) in float raised;
|
||||
layout (location = 10) in uint has_texture;
|
||||
|
||||
vec2 Vertices[4] = vec2[4](
|
||||
vec2(-1.0, -1.0),
|
||||
@ -57,10 +53,10 @@ void main()
|
||||
);
|
||||
|
||||
float corner_radius[4] = float[4](
|
||||
in_corner_radius_x0y0,
|
||||
in_corner_radius_x0y1,
|
||||
in_corner_radius_x1y0,
|
||||
in_corner_radius_x1y1
|
||||
in_corner_radius.x,
|
||||
in_corner_radius.z,
|
||||
in_corner_radius.y,
|
||||
in_corner_radius.w
|
||||
);
|
||||
|
||||
vec2 dst_verts_pct = vec2(bool(gl_VertexIndex >> 1) ? 1.0f : 0.0f,
|
||||
@ -77,8 +73,7 @@ void main()
|
||||
FD.raised = raised;
|
||||
FD.border_thickness = border_thickness;
|
||||
FD.sdf_sample_pos = (2.0f * dst_verts_pct - 1.0f) * half_size;
|
||||
FDF.texture = in_has_texture;
|
||||
FDF.atlas_index = in_atlas_index;
|
||||
FDF.has_texture = has_texture;
|
||||
|
||||
vec4 v_pos = PC.projection * vec4(pos.x, pos.y, 0, 1);
|
||||
gl_Position = vec4(v_pos.x, v_pos.y, v_pos.z, 1);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user