fixes & improvements

This commit is contained in:
Matthew 2025-12-30 17:29:51 +11:00
parent 07f72ac41e
commit 80b454914a
4 changed files with 225 additions and 117 deletions

@ -1 +1 @@
Subproject commit e77c1790f7eb5d18d8d84596025c53b2caaca18c
Subproject commit 1160d747ccb550b72a60cd68aa22a14f6dcb1ab1

View File

@ -161,7 +161,18 @@ Cycle(Inputs* inputs)
}
}
UIItem* container = Container(A2D.Y, UIS2());
Push!("parent")(container);
UIItem* ed_container = Container(A2D.X, UISY(ST.Percentage, 0.98));
Push!("parent")(ed_container);
EditorView(g_ed_ctx.base_panel);
Pop!("parent");
assert(ui_ctx.parent.top.value == container);
StatusBar(&g_ed_ctx);
if(g_ed_ctx.state == ES.CmdOpen)
{
@ -283,7 +294,7 @@ ToAbsolutePath(u8[] file_name)
version(Windows)
{
name_buf.sformat("%s/%s", wd, cast(char[])file_name);
name_buf.sformat("%s/%s", wd, cast(char[])file_name);
}
char[] path_buf = ScratchAlloc!(char)(strlen(name_buf.ptr)+1);

View File

@ -127,6 +127,7 @@ enum UIFlags
OverflowX = 1<<21,
OverflowY = 1<<22,
Gradient = 1<<23,
VerticalAlignText = 1<<24,
Clamp = UIFlags.ClampX | UIFlags.ClampY,
PortalView = UIFlags.PortalViewX | UIFlags.PortalViewY,
@ -258,7 +259,6 @@ struct UICtx
u32 tab_width;
Vec4[TS.max][UISH.max] syntax_colors;
UIItem* window_root;
UIItem* root;
UIItem* drag_item;
UIItem* focus_item;
@ -423,6 +423,14 @@ struct Vertex
u32 atlas_index;
}
enum SettingType
{
Value,
Slider,
Dropdown,
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 },
@ -638,11 +646,11 @@ MakeItem(Args...)(string str, Args args)
UIFlags flags = has_flag ? args[args.length-1] : UIF.None;
enum len = has_flag ? Args.length-1 : Args.length;
char[] key = sformat(ScratchAlloc!(char)(cast(u64)(str.length*1.5)), str, args[0 .. len]);
string key = Scratchf(str, args[0 .. len]);
}
else
{
char[] key = CastStr(char)(str);
string key = str;
UIFlags flags = UIF.None;
}
@ -667,6 +675,7 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T)
}
next.next = item;
item.prev = next;
}
else if(!Nil(item.parent))
{
@ -689,8 +698,8 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T)
}
FontAtlasBuf* abuf = GetFontAtlas(item.text_size);
item.max_text_width = 0.0;
string str = item.display_string.length ? item.display_string : item.key.text;
item.max_text_width = cast(f32)(str.length)*abuf.atlas.max_advance;
if(item.flags & UIF.TextWrap)
{
@ -698,8 +707,6 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T)
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);
u32 max_chars = str.length > ch_per_line ? ch_per_line : cast(u32)str.length;
item.max_text_width = cast(f32)(max_chars)*abuf.atlas.max_advance;
item.text_lines = ScratchAlloc!(string)(lines);
u64 start;
@ -707,6 +714,11 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T)
{
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)
@ -723,6 +735,7 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T)
{
item.text_lines = ScratchAlloc!(string)(1);
item.text_lines[0] = str;
item.max_text_width = CalcTextWidth(str, abuf);
if(item.syntax_tokens.length)
{
@ -761,8 +774,6 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T)
item.last_frame = ctx.frame;
item.rendered = false;
//item.padding[A2D.X] += item.border_thickness;
//item.padding[A2D.Y] += item.border_thickness;
return item;
}
@ -916,6 +927,7 @@ BeginUI(Inputs* inputs)
UIItem* item = items[i].value;
if(item.last_frame != ctx.frame)
{
Delete(&ctx.items, items[i].key);
memset(item, 0, UIItem.sizeof);
DLLPush(ctx.free_items, item, g_UI_NIL);
}
@ -966,7 +978,6 @@ BeginUI(Inputs* inputs)
Push!("size_info")(sizes);
ctx.root = MakeItem("###root");
ctx.window_root = MakeItem("###window_root");
Pop!("size_info");
Push!("parent")(ctx.root);
@ -1169,7 +1180,7 @@ EndUI()
{
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.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);
}
@ -1186,7 +1197,6 @@ EndUI()
// Render Items
RenderItems(ctx.root);
RenderItems(ctx.window_root);
version(ENABLE_RENDERER)
{
@ -1235,14 +1245,17 @@ RenderItem(UICtx* ctx, UIItem* item)
if(item.rendered) return;
if(!(item.flags & DRAW_FLAGS)) return;
Vertex* v = null;
if(item.flags & UIF.DrawBackground)
{
Vertex* v = GetVertex(ctx);
v = GetVertex(ctx);
v.dst_start = item.rect.p0;
v.dst_end = item.rect.p1;
v.cols = item.bg_col;
v.cols_end = item.flags & UIF.Gradient ? item.bg_col_end : item.bg_col;
v.corner_radius = item.flags & UIF.DrawBorder ? item.corner_radius*0.5 : item.corner_radius;
v.edge_softness = item.edge_softness;
v.bounds = ItemBounds(item.parent);
AddVertexCount(ctx);
@ -1250,7 +1263,7 @@ RenderItem(UICtx* ctx, UIItem* item)
if(item.flags & UIF.DrawBorder)
{
Vertex* v = GetVertex(ctx);
v = GetVertex(ctx);
v.dst_start = item.rect.p0 - Vec2(InnerOffset!(A2D.X, true )(item), InnerOffset!(A2D.Y, true )(item));
v.dst_end = item.rect.p1 + Vec2(InnerOffset!(A2D.X, false)(item), InnerOffset!(A2D.Y, false)(item));
v.cols = item.border_col;
@ -1263,25 +1276,42 @@ RenderItem(UICtx* ctx, UIItem* item)
AddVertexCount(ctx);
}
if(item.flags & UIF.DrawText || item.display_string)
if(v)
{
if(item.flags & UIF.CenterAlignText)
{
// TODO
v.dst_start = Clamp(v.dst_start, Vec2(0.0), Vec2(ctx.res));
v.dst_end = Clamp(v.dst_end, Vec2(0.0), Vec2(ctx.res));
}
else
if(item.flags & UIF.DrawText || item.display_string)
{
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;
if(item.flags & UIF.VerticalAlignText)
{
y_pos += (item.rect.p1.y - item.rect.p0.y - line_height) / 2.0;
}
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 = item.flags & UIF.RightAlignText ? item.rect.p1.x - item.padding[A2D.X].x - CalcTextWidth(str, &fg.abuf) :
item.rect.p0.x + item.padding[A2D.X].x;
f32 x_pos = 0.0;
if(item.flags & UIF.RightAlignText)
{
x_pos = item.rect.p1.x - item.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) + item.padding[A2D.X].x;
Logf("%f", x_pos);
}
else
{
x_pos = item.rect.p0.x + item.padding[A2D.X].x;
}
x_pos = clamp(x_pos, item.rect.p0.x, item.rect.p1.x);
@ -1307,7 +1337,6 @@ RenderItem(UICtx* ctx, UIItem* item)
y_pos += line_height;
}
}
}
// Doesn't really support nesting scissors, will maybe change this later.
bool scissor_x = cast(bool)(item.flags & UIF.PortalViewX);
@ -1732,7 +1761,7 @@ MakeKey(T)(T str) if(StringType!T)
}
else
{
string id = ConvToStr(str);
string id = Str(str);
}
UIKey key;
@ -1784,7 +1813,18 @@ MakeKey(T)(T str) if(StringType!T)
return key;
}
UIKey
static Vec4
HexCol(u64 col)
{
return Vec4(
cast(f32)((col >> 16) & 0xFF) / 255.0,
cast(f32)((col >> 8 ) & 0xFF) / 255.0,
cast(f32)((col >> 0 ) & 0xFF) / 255.0,
1.0
);
}
static UIKey
ZeroKey()
{
return UIKey();
@ -1862,7 +1902,7 @@ Get(T)(T k) if(is(T: UIKey) || StringType!T)
}
f32
CalcTextWidth(bool fast = true, T, U)(T text, U param) if((is(T == string) || StringType!T) && (is(U: u32) || is(U == FontAtlasBuf*) ))
CalcTextWidth(T, U)(T text, U param) if((is(T == string) || StringType!T) && (is(U: u32) || is(U == FontAtlasBuf*) ))
{
static if(is(T == string))
{
@ -1870,7 +1910,7 @@ CalcTextWidth(bool fast = true, T, U)(T text, U param) if((is(T == string) || St
}
else
{
string str = ConvToStr(text);
string str = Str(text);
}
static if(is(U: u32))
@ -1884,19 +1924,11 @@ CalcTextWidth(bool fast = true, T, U)(T text, U param) if((is(T == string) || St
u32 tab_width = g_ui_ctx.tab_width;
static if(fast)
{
f32 width = str.length * abuf.atlas.max_advance;
assert(abuf.atlas.max_advance > 0.0009);
}
else
{
f32 width = 0.0;
for(u64 i = 0; i < str.length; i += 1)
{
width += GlyphWidth(abuf.atlas.glyphs.ptr + str.ptr[i], abuf);
}
}
return width;
}
@ -1992,19 +2024,19 @@ AxisPadding(Axis2D axis)(UIItem* item)
pragma(inline) f32
InnerSize(Axis2D axis)(UIItem* item)
{
return clamp(item.size[axis] - (item.padding[axis].x + item.padding[axis].y) - item.border_thickness*2.0, 0.0, f32.max);
return clamp(item.size[axis] - item.border_thickness*2.0, 0.0, f32.max);
}
pragma(inline) f32
InnerSize(UIItem* item, Axis2D axis)
{
return clamp(item.size[axis] - (item.padding[axis].x + item.padding[axis].y) - item.border_thickness*2.0, 0.0, f32.max);
return clamp(item.size[axis] - item.border_thickness*2.0, 0.0, f32.max);
}
pragma(inline) f32
InnerOffset(Axis2D axis, bool start)(UIItem* item)
{
return item.padding[axis].v[start] + item.border_thickness;
return item.border_thickness;
}
pragma(inline) Vertex*

View File

@ -12,12 +12,16 @@ __gshared const Panel g_nil_panel;
__gshared Panel* g_NIL_PANEL;
__gshared const Editor g_nil_ed;
__gshared Editor* g_NIL_ED;
__gshared const UIKey ZERO = ZeroKey();
Vec4 BG_COL = Vec4(0.18, 0.18, 0.18, 1.0);
Vec4 CMD_COL = Vec4(0.22, 0.22, 0.22, 1.0);
Vec4 HL_BG_COL = Vec4(0.160, 0.533, 0.803, 1.0);
Vec4 HL_BORDER_COL = Vec4(0.172, 0.643, 0.988, 1.0);
Vec4 BLUE = HexCol(0x4EA9FF);
Vec4 RED = HexCol(0xFF3268);
Vec4 YELLOW = HexCol(0xF7C443);
shared static this()
{
@ -38,7 +42,6 @@ void
LineCounterView(FontAtlasBuf* abuf, u64 max_line, u64 lines, i64 line_offset, f32 view_offset)
{
UICtx* ctx = GetCtx();
UIKey zero = ZeroKey();
u64 ch_width = max_line.toChars().length;
f32 lc_width = cast(f32)(ch_width+1)*abuf.atlas.max_advance;
@ -47,14 +50,14 @@ LineCounterView(FontAtlasBuf* abuf, u64 max_line, u64 lines, i64 line_offset, f3
{ "layout_axis", q{ A2D.Y } },
{ "view_offset", q{ Vec2(0.0, view_offset) } },
{ "padding", q{ Vec2(4.0) } },
{ "size_info", q{ UIS2(ST.Pixels, ST.Percentage, lc_width, 1.0) }},
{ "size_info", q{ UIS2(ST.Pixels, ST.Percentage, lc_width, 1.0) } },
{ "edge_softness", q{ 0.0 } },
{ "border_thickness", q{ 1.0 } },
];
mixin(PushOnce!(lc_params));
UIItem* line_count = MakeItem("###lc", UIF.DrawBorder|UIF.PortalViewY);
UIItem* line_count = MakeItem(ZERO, UIF.DrawBorder|UIF.PortalViewY);
mixin(PushScope!("text_col", q{ Vec4(1.0) } ));
mixin(PushScope!("size_info", q{ UISY(ST.Pixels, abuf.atlas.line_height) } ));
@ -64,8 +67,8 @@ 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")(ConvToStr(sformat(ScratchAlloc!(char)(ch_width), "%s", i)), true);
MakeItem(zero, UIF.DrawText);
Push!("display_string")(Scratchf("%s", i), true);
MakeItem(ZERO, UIF.DrawText);
}
}
@ -106,7 +109,7 @@ EditorTextView(UIItem* editor, Panel* p, FontAtlasBuf* abuf, u64 lines, i64 line
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!(false)(lb.text[0 .. ed.cursor_pos.x], abuf);
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 + ' ';
@ -129,7 +132,7 @@ EditorTextView(UIItem* editor, Panel* p, FontAtlasBuf* abuf, u64 lines, i64 line
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{ ConvToStr(lb.text) } },
{ "display_string", q{ Str(lb.text) } },
{ "syntax_tokens", q{ cast(u8[])(lb.style) } },
];
mixin(PushOnce!(lc_info));
@ -266,7 +269,7 @@ CommandPalette(CmdPalette* cmd)
enum UIPushInfo[] cmd_input_params = [
{ "bg_col", q{ HL_BG_COL } },
{ "size_info", q{ UISY(ST.TextSize) } },
{ "display_string", q{ ConvToStr(cmd.buffer[0 .. cmd.icount]) } },
{ "display_string", q{ Str(cmd.buffer[0 .. cmd.icount]) } },
];
mixin(PushOnce!(cmd_input_params));
@ -295,9 +298,71 @@ CommandPalette(CmdPalette* cmd)
for(u64 i = 0; i < cmd.opt_strs.length && i < max_opts; i += 1)
{
PushDisplayString(ConvToStr(cmd.opt_strs[i]), true);
PushDisplayString(Str(cmd.opt_strs[i]), true);
PushBgCol(cmd.selected == i ? HL_BG_COL : opt_cols[i%2], true);
MakeItem(zero, UIF.DrawBackground|UIF.DrawText);
}
}
UIItem*
Container(Axis2D axis, UISize[2] size_info)
{
enum UIPushInfo[] container_info = [
{ "layout_axis", q{ axis } },
{ "size_info", q{ size_info }},
];
mixin(PushOnce!(container_info));
return MakeItem(ZeroKey());
}
void
StatusBar(EditorCtx* ed_ctx)
{
mixin(PushScope!("edge_softness", q{ 0.6 }));
enum UIPushInfo[] bar_info = [
{ "size_info", q{ UISY(ST.Percentage, 0.02)} },
{ "layout_axis", q{ A2D.X} },
];
mixin(PushOnce!(bar_info));
Vec4 status_col = BLUE;
string status = "Normal";
if(ed_ctx.state == ES.InputMode)
{
status = "Input";
status_col = YELLOW;
}
else if(ed_ctx.state == ES.CmdOpen)
{
status = "Command";
status_col = RED;
}
UIItem* bar = MakeItem(ZERO);
mixin(PushScope!("parent", q{ bar }));
enum UIPushInfo[] status_info = [
{ "bg_col", q{ status_col } },
{ "corner_radius", q{ Vec4(8.0) } },
{ "text_size", q{ 16 }},
{ "padding", q{ Vec2A2(8.0, 8.0, 0.0, 0.0) } },
{ "size_info", q{ UISX(ST.TextSize) } },
{ "display_string", q{ status } },
];
mixin(PushOnce!(status_info));
MakeItem(ZERO, UIF.DrawBackground|UIF.DrawText|UIF.VerticalAlignText);
enum UIPushInfo[] rest_info = [
{ "bg_col", q{ BG_COL }},
{ "corner_radius", q{ Vec4(0.0, 0.0, 0.0, 8.0) }},
{ "size_info", q{ UIS2() }},
];
MakeItem(ZERO, UIF.DrawBackground);
}