implement scrolling, various fixes
This commit is contained in:
parent
39ab34ebeb
commit
ace749228d
2
src/dlib
2
src/dlib
@ -1 +1 @@
|
|||||||
Subproject commit 7f4c109106eaabda180158a8f7a92c9d2e60d3db
|
Subproject commit 809814577db807d5911e79216d6e114a2d5a2dfd
|
||||||
278
src/editor/ui.d
278
src/editor/ui.d
@ -154,7 +154,11 @@ struct UIInput
|
|||||||
UIInput* next, prev;
|
UIInput* next, prev;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
Input key;
|
struct
|
||||||
|
{
|
||||||
|
Input key;
|
||||||
|
string text;
|
||||||
|
};
|
||||||
IVec2 rel;
|
IVec2 rel;
|
||||||
IVec2 pos;
|
IVec2 pos;
|
||||||
}
|
}
|
||||||
@ -168,8 +172,8 @@ UICtxParameter(T, string name)
|
|||||||
{
|
{
|
||||||
import std.traits, std.array;
|
import std.traits, std.array;
|
||||||
|
|
||||||
string stack_top = "\tStackTop!("~T.stringof~") "~name~";\n";
|
string stack_top = "\tStackTop!("~T.stringof~") "~name~";\n";
|
||||||
string stack = "\tStack!("~T.stringof~")* "~name~"_top;\n";
|
string stack = "\tStack!("~T.stringof~")* "~name~"_top;\n";
|
||||||
|
|
||||||
return stack_top~stack;
|
return stack_top~stack;
|
||||||
}
|
}
|
||||||
@ -177,7 +181,8 @@ UICtxParameter(T, string name)
|
|||||||
mixin(CtxParameterGen!(T, name)());
|
mixin(CtxParameterGen!(T, name)());
|
||||||
}
|
}
|
||||||
|
|
||||||
template CtxMemberInfo(int i)
|
template
|
||||||
|
CtxMemberInfo(int i)
|
||||||
{
|
{
|
||||||
import std.string : endsWith, startsWith;
|
import std.string : endsWith, startsWith;
|
||||||
import std.traits : isInstanceOf, isPointer;
|
import std.traits : isInstanceOf, isPointer;
|
||||||
@ -274,31 +279,32 @@ struct StackTop(T)
|
|||||||
Stack!(T)* free;
|
Stack!(T)* free;
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin template UIItemParameters()
|
static string
|
||||||
|
UIItemParameterGen()
|
||||||
{
|
{
|
||||||
static string
|
string fields = "";
|
||||||
UIItemParameterGen()
|
static foreach(i, m; UICtx.tupleof)
|
||||||
{
|
{
|
||||||
string fields = "";
|
|
||||||
static foreach(i, m; UICtx.tupleof)
|
|
||||||
{
|
{
|
||||||
|
enum info = CtxMemberInfo!(i);
|
||||||
|
static if(info.is_stack)
|
||||||
{
|
{
|
||||||
enum info = CtxMemberInfo!(i);
|
fields ~= typeof(UICtx.tupleof[i].top.value).stringof ~ " " ~ info.id;
|
||||||
static if(info.is_stack)
|
static if(is(typeof(UICtx.tupleof[i]): f32))
|
||||||
{
|
{
|
||||||
fields ~= typeof(UICtx.tupleof[i].top.value).stringof ~ " " ~ info.id;
|
fields ~= " = 0.0";
|
||||||
static if(is(typeof(UICtx.tupleof[i]): f32))
|
|
||||||
{
|
|
||||||
fields ~= " = 0.0";
|
|
||||||
}
|
|
||||||
fields ~= ";\n";
|
|
||||||
}
|
}
|
||||||
|
fields ~= ";\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fields;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin template
|
||||||
|
UIItemParameters()
|
||||||
|
{
|
||||||
mixin(UIItemParameterGen());
|
mixin(UIItemParameterGen());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,17 +683,21 @@ InitSingleLine:
|
|||||||
{
|
{
|
||||||
if(item.flags & (UIF.ScrollX << axis))
|
if(item.flags & (UIF.ScrollX << axis))
|
||||||
{
|
{
|
||||||
item.scroll_offset.v[axis] += scroll_speed * (item.scroll_target.v[axis] - item.scroll_offset.v[axis]);
|
if(fabsf(item.scroll_offset.v[axis] - item.scroll_target.v[axis]) > 0.0009)
|
||||||
|
|
||||||
if(fabsf(item.scroll_offset.v[axis] - item.scroll_target.v[axis]) < 2.0)
|
|
||||||
{
|
{
|
||||||
item.scroll_offset.v[axis] = item.scroll_target.v[axis];
|
f32 v = scroll_speed * (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))
|
if(item.flags & (UIF.ClampX << axis))
|
||||||
{
|
{
|
||||||
item.scroll_offset = clamp(item.scroll_offset.v[axis], item.scroll_clamp[axis].x, item.scroll_clamp[axis].y);
|
item.scroll_offset.v[axis] = clamp(item.scroll_offset.v[axis], item.scroll_clamp[axis].x, item.scroll_clamp[axis].y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -822,7 +832,7 @@ BeginUI(Inputs* inputs)
|
|||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
PushUIEvent(ctx, UIInput(type: UIE.Press, key: i.key));
|
PushUIEvent(ctx, UIInput(type: UIE.Press, key: i.key, text: i.pressed ? i.text : []));
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -851,7 +861,7 @@ BeginUI(Inputs* inputs)
|
|||||||
// Ctx state
|
// Ctx state
|
||||||
ctx.f_idx = ctx.frame%FRAME_OVERLAP;
|
ctx.f_idx = ctx.frame%FRAME_OVERLAP;
|
||||||
ctx.inputs = inputs;
|
ctx.inputs = inputs;
|
||||||
ctx.char_width = GlyphWidth(&ctx.atlas_buf.atlas.glyphs['0']);
|
ctx.char_width = GlyphWidth(&ctx.atlas_buf.atlas.glyphs[' ']);
|
||||||
|
|
||||||
ResetStacks(ctx);
|
ResetStacks(ctx);
|
||||||
|
|
||||||
@ -880,13 +890,13 @@ BeginUI(Inputs* inputs)
|
|||||||
|
|
||||||
// Root Item
|
// Root Item
|
||||||
UISize[2] sizes = [UISize(ST.Pixels, ctx.res.x), UISize(ST.Pixels, ctx.res.y)];
|
UISize[2] sizes = [UISize(ST.Pixels, ctx.res.x), UISize(ST.Pixels, ctx.res.y)];
|
||||||
Push!("size_info")(ctx, sizes);
|
Push!("size_info")(sizes);
|
||||||
|
|
||||||
ctx.root = MakeItem("###root");
|
ctx.root = MakeItem("###root");
|
||||||
ctx.window_root = MakeItem("###window_root");
|
ctx.window_root = MakeItem("###window_root");
|
||||||
|
|
||||||
Pop!("size_info")(ctx);
|
Pop!("size_info");
|
||||||
Push!("parent")(ctx, ctx.root);
|
Push!("parent")(ctx.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -999,7 +1009,7 @@ EndUI()
|
|||||||
{
|
{
|
||||||
f32 size = InnerSize!(axis)(item);
|
f32 size = InnerSize!(axis)(item);
|
||||||
|
|
||||||
if(item.flags & (UIF.PortalX << axis))
|
if(item.flags & (UIF.PortalViewX << axis))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1067,7 +1077,7 @@ EndUI()
|
|||||||
}
|
}
|
||||||
else if(item == item.parent.first)
|
else if(item == item.parent.first)
|
||||||
{
|
{
|
||||||
pos += item.parent.padding.v[axis];
|
pos += item.parent.padding.v[axis] + item.parent.view_offset.v[axis];
|
||||||
}
|
}
|
||||||
|
|
||||||
f32 inner_pos = pos;
|
f32 inner_pos = pos;
|
||||||
@ -1082,6 +1092,7 @@ EndUI()
|
|||||||
assert(!isNaN(item.rect.p0.v[axis]));
|
assert(!isNaN(item.rect.p0.v[axis]));
|
||||||
assert(!isNaN(item.rect.p1.v[axis]));
|
assert(!isNaN(item.rect.p1.v[axis]));
|
||||||
|
|
||||||
|
/*
|
||||||
debug
|
debug
|
||||||
{
|
{
|
||||||
bool portal = cast(bool)(item.parent.flags & (UIF.PortalViewX << axis));
|
bool portal = cast(bool)(item.parent.flags & (UIF.PortalViewX << axis));
|
||||||
@ -1103,6 +1114,7 @@ EndUI()
|
|||||||
assert(in_bounds_start && in_bounds_end);
|
assert(in_bounds_start && in_bounds_end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
if(!Nil(item.first))
|
if(!Nil(item.first))
|
||||||
{
|
{
|
||||||
@ -1169,8 +1181,8 @@ RenderItem(UICtx* ctx, UIItem* item)
|
|||||||
{
|
{
|
||||||
DrawUI(ctx);
|
DrawUI(ctx);
|
||||||
|
|
||||||
u32 x = cast(u32)(scissor_x ? floor(item.rect.p0.x) : ctx.res.x);
|
u32 x = cast(u32)(scissor_x ? floor(item.rect.p0.x) : 0);
|
||||||
u32 y = cast(u32)(scissor_y ? floor(item.rect.p0.y) : ctx.res.y);
|
u32 y = cast(u32)(scissor_y ? floor(item.rect.p0.y) : 0);
|
||||||
u32 w = cast(u32)(scissor_x ? floor(item.rect.p1.x) - x : ctx.res.x);
|
u32 w = cast(u32)(scissor_x ? floor(item.rect.p1.x) - x : ctx.res.x);
|
||||||
u32 h = cast(u32)(scissor_y ? floor(item.rect.p1.y) - y : ctx.res.y);
|
u32 h = cast(u32)(scissor_y ? floor(item.rect.p1.y) - y : ctx.res.y);
|
||||||
SetScissor(&ctx.rd, x, y, w, h);
|
SetScissor(&ctx.rd, x, y, w, h);
|
||||||
@ -1178,7 +1190,6 @@ RenderItem(UICtx* ctx, UIItem* item)
|
|||||||
|
|
||||||
if(item.flags & UIF.DrawBackground)
|
if(item.flags & UIF.DrawBackground)
|
||||||
{
|
{
|
||||||
// DrawRect
|
|
||||||
Vertex* v = GetVertex(ctx);
|
Vertex* v = GetVertex(ctx);
|
||||||
v.dst_start = item.rect.p0 + item.border_thickness;
|
v.dst_start = item.rect.p0 + item.border_thickness;
|
||||||
v.dst_end = item.rect.p1 - item.border_thickness;
|
v.dst_end = item.rect.p1 - item.border_thickness;
|
||||||
@ -1284,23 +1295,117 @@ GetExtent(Renderer* rd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template
|
template
|
||||||
StackIDs(string stack)
|
StackIDs(string stack, string ctx = "ctx")
|
||||||
{
|
{
|
||||||
import std.string : replace;
|
import std.string : replace;
|
||||||
struct Identifiers { string stack, stack_top_node; }
|
struct Identifiers { string stack, stack_top_node; }
|
||||||
|
|
||||||
enum Identifiers StackIDs = {
|
enum Identifiers StackIDs = {
|
||||||
stack: replace("ctx.@", "@", stack),
|
stack: replace(ctx~".@", "@", stack),
|
||||||
stack_top_node: replace("ctx.@_top", "@", stack),
|
stack_top_node: replace(ctx~".@_top", "@", stack),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Push(string stack_str, bool auto_pop = false, T)(UICtx* ctx, T value)
|
PushSizeInfoVec(int i)(SizeType type, f32 value, f32 strictness = 1.0, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
UISize[2] size_info = g_size_info_default;
|
||||||
|
|
||||||
|
size_info[i].type = type;
|
||||||
|
size_info[i].value = value;
|
||||||
|
size_info[i].strictness = strictness;
|
||||||
|
|
||||||
|
Push!("size_info")(size_info, auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushSizeInfoX(SizeType type, f32 value, f32 strictness = 1.0, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
PushSizeInfoVec!(0)(type, value, strictness, auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushSizeInfoY(SizeType type, f32 value, f32 strictness = 1.0, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
PushSizeInfoVec!(1)(type, value, strictness, auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushScrollClampVec(int i)(Vec2 clamp, bool auto_pop)
|
||||||
|
{
|
||||||
|
Vec2[2] scroll_clamp = g_scroll_clamp_default;
|
||||||
|
scroll_clamp[i] = clamp;
|
||||||
|
Push!("scroll_clamp")(scroll_clamp, auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushScrollClampX(f32 start, f32 end, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
PushScrollClampVec!(0)(Vec2(start, end), auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushScrollClampY(f32 start, f32 end, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
PushScrollClampVec!(1)(Vec2(start, end), auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushBorderCol(Vec4 col, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
Vec4[4] arr = col;
|
||||||
|
PushBorderCol(arr, auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushBgCol(Vec4 col, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
Vec4[4] arr = col;
|
||||||
|
PushBgCol(arr, auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushPaddingX(f32 padding, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
PushPadding(Vec2(padding, 0.0), auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushPaddingY(f32 padding, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
PushPadding(Vec2(0.0, padding), auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushViewOffsetX(f32 offset, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
PushViewOffset(Vec2(offset, 0.0), auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushViewOffsetY(f32 offset, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
PushViewOffset(Vec2(0.0, offset), auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushScrollTargetX(f32 target, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
PushScrollTarget(Vec2(target, 0.0), auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushScrollTargetY(f32 target, bool auto_pop = false)
|
||||||
|
{
|
||||||
|
PushScrollTarget(Vec2(0.0, target), auto_pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Push(string stack_str, T)(T value, bool auto_pop = false)
|
||||||
{
|
{
|
||||||
import std.string : replace;
|
import std.string : replace;
|
||||||
|
|
||||||
enum ids = StackIDs!(stack_str);
|
enum ids = StackIDs!(stack_str, "g_ui_ctx");
|
||||||
|
|
||||||
auto stack = &mixin(ids.stack);
|
auto stack = &mixin(ids.stack);
|
||||||
auto top = mixin(ids.stack_top_node);
|
auto top = mixin(ids.stack_top_node);
|
||||||
@ -1312,7 +1417,7 @@ Push(string stack_str, bool auto_pop = false, T)(UICtx* ctx, T value)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
node = Alloc!(Stack!(T))(&ctx.temp_arena);
|
node = Alloc!(Stack!(T))(&g_ui_ctx.temp_arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
node.next = stack.top;
|
node.next = stack.top;
|
||||||
@ -1322,12 +1427,29 @@ Push(string stack_str, bool auto_pop = false, T)(UICtx* ctx, T value)
|
|||||||
stack.top = node;
|
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
|
auto
|
||||||
Pop(string stack_str)(UICtx* ctx)
|
Pop(string stack_str)()
|
||||||
{
|
{
|
||||||
import std.string : replace;
|
import std.string : replace;
|
||||||
|
|
||||||
enum ids = StackIDs!(stack_str);
|
enum ids = StackIDs!(stack_str, "g_ui_ctx");
|
||||||
|
|
||||||
auto stack = &mixin(ids.stack);
|
auto stack = &mixin(ids.stack);
|
||||||
auto top = mixin(ids.stack_top_node);
|
auto top = mixin(ids.stack_top_node);
|
||||||
@ -1345,14 +1467,52 @@ Pop(string stack_str)(UICtx* ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Pop(stack_strs...)(UICtx* ctx)
|
Pop(stack_strs...)()
|
||||||
{
|
{
|
||||||
static foreach(stack; stack_strs)
|
static foreach(stack; stack_strs)
|
||||||
{
|
{
|
||||||
Pop!(stack)(ctx);
|
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 = false){ Push!(\"" ~ info.id ~ "\")(value, auto_pop); }\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return funcs;
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin(GenPushFuncs());
|
||||||
|
|
||||||
void
|
void
|
||||||
AutoPopStacks(UICtx* ctx)
|
AutoPopStacks(UICtx* ctx)
|
||||||
{
|
{
|
||||||
@ -1368,7 +1528,7 @@ AutoPopStacks(UICtx* ctx)
|
|||||||
if(ctx.tupleof[i].top.auto_pop)
|
if(ctx.tupleof[i].top.auto_pop)
|
||||||
{
|
{
|
||||||
ctx.tupleof[i].top.auto_pop = false;
|
ctx.tupleof[i].top.auto_pop = false;
|
||||||
Pop!(member_info.id)(ctx);
|
Pop!(member_info.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1595,8 +1755,6 @@ NewItem(UICtx* ctx)
|
|||||||
item = Alloc!(UIItem)(&ctx.arena);
|
item = Alloc!(UIItem)(&ctx.arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
item.last_frame = ctx.frame-2;
|
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1666,8 +1824,7 @@ CalcTextWidth(string str)
|
|||||||
pragma(inline) f32
|
pragma(inline) f32
|
||||||
GlyphWidth(Glyph* g)
|
GlyphWidth(Glyph* g)
|
||||||
{
|
{
|
||||||
f32 width = 0.0;
|
f32 width = g.ch == '\t' ? (g_ui_ctx.atlas_buf.atlas.glyphs[' '].advance*cast(f32)(g_ui_ctx.tab_width)) : g.advance;
|
||||||
width += g.ch == '\t' ? (g_ui_ctx.atlas_buf.atlas.glyphs[' '].advance*cast(f32)(g_ui_ctx.tab_width)) : g.advance;
|
|
||||||
|
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
@ -1962,11 +2119,22 @@ Dragged(UIItem* item, Rect* rect)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma(inline) Vec4[4]
|
static Vec4[4]
|
||||||
Vec4Arr(Vec4 col)
|
Vec4Arr(Vec4 vec)
|
||||||
{
|
{
|
||||||
Vec4[4] arr = col;
|
return [vec, vec, vec, vec];
|
||||||
return arr;
|
}
|
||||||
|
|
||||||
|
static Vec2[2]
|
||||||
|
Vec2ArrX(alias Vec2 vec)()
|
||||||
|
{
|
||||||
|
return [vec, Vec2(0.0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static Vec2[2]
|
||||||
|
Vec2ArrY(alias Vec2 vec)()
|
||||||
|
{
|
||||||
|
return [Vec2(0.0), vec];
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
@ -1995,7 +2163,7 @@ unittest
|
|||||||
Vec4 w = Vec4(1.0);
|
Vec4 w = Vec4(1.0);
|
||||||
Vec4[4] col = w;
|
Vec4[4] col = w;
|
||||||
|
|
||||||
Push!("bg_col")(ctx, col);
|
Push!("bg_col")(col);
|
||||||
assert(ctx.bg_col.top.value == col);
|
assert(ctx.bg_col.top.value == col);
|
||||||
|
|
||||||
EndUI();
|
EndUI();
|
||||||
@ -2011,7 +2179,7 @@ unittest
|
|||||||
{
|
{
|
||||||
BeginUI(&inputs);
|
BeginUI(&inputs);
|
||||||
|
|
||||||
Push!("size_info")(ctx, MakeUISizeX(ST.Percentage, 0.5));
|
Push!("size_info")(MakeUISizeX(ST.Percentage, 0.5));
|
||||||
UIItem* root = ctx.root;
|
UIItem* root = ctx.root;
|
||||||
|
|
||||||
UIItem* i0 = MakeItem("###i0");
|
UIItem* i0 = MakeItem("###i0");
|
||||||
|
|||||||
@ -14,6 +14,93 @@ Nil(UIPanel* panel)
|
|||||||
return panel == null || panel == g_UI_NIL_PANEL;
|
return panel == null || panel == g_UI_NIL_PANEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LineCounterView(u64 max_line, u64 lines, u64 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)*ctx.char_width; // Should figure out how to accurately measure text width
|
||||||
|
|
||||||
|
PushLayoutAxis(A2D.Y, true);
|
||||||
|
PushViewOffsetY(view_offset, true);
|
||||||
|
PushPaddingX(4.0, true);
|
||||||
|
PushSizeInfoX(ST.Pixels, lc_width, 1.0, true);
|
||||||
|
|
||||||
|
UIItem* line_count = MakeItem(zero, UIF.DrawBorder|UIF.PortalViewY);
|
||||||
|
|
||||||
|
PushTextCol(Vec4(1.0));
|
||||||
|
PushSizeInfoY(ST.Pixels, TEXT_SIZE);
|
||||||
|
PushParent(line_count);
|
||||||
|
|
||||||
|
u64 end_line = lines+line_offset;
|
||||||
|
for(u64 i = line_offset; i < end_line; i += 1)
|
||||||
|
{
|
||||||
|
char[] buf = ScratchAlloc!(char)(ch_width);
|
||||||
|
Push!("display_string")(ConvToStr(sformat(buf, "%s", i)), true);
|
||||||
|
MakeItem(zero, UIF.DrawText);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pop!("text_col", "size_info", "parent");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditorTextView(UIItem* editor, Editor* ed, u64 lines, u64 line_offset, f32 view_offset)
|
||||||
|
{
|
||||||
|
PushLayoutAxis(A2D.Y, true);
|
||||||
|
|
||||||
|
f32 clamp_y = cast(f32)(ed.buf.line_count-lines)*TEXT_SIZE;
|
||||||
|
f32 scroll_pos = cast(f32)(ed.line_offset)*TEXT_SIZE;
|
||||||
|
|
||||||
|
PushLayoutAxis(A2D.Y, true);
|
||||||
|
PushScrollClampY(0.0, clamp_y, true);
|
||||||
|
PushSizeInfo(g_size_info_default, true);
|
||||||
|
PushBorderCol(Vec4(1.0), true);
|
||||||
|
PushScrollTargetY(scroll_pos, true);
|
||||||
|
PushViewOffsetY(view_offset, true);
|
||||||
|
|
||||||
|
static bool end;
|
||||||
|
static f32 count = 0.0;
|
||||||
|
|
||||||
|
if(!end)
|
||||||
|
{
|
||||||
|
ed.cursor_pos.y = 500;
|
||||||
|
count += g_delta;
|
||||||
|
if(count > 0.5)
|
||||||
|
{
|
||||||
|
end = !end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ed.cursor_pos.y = 0;
|
||||||
|
count -= g_delta;
|
||||||
|
if(count <= 0.0)
|
||||||
|
{
|
||||||
|
end = !end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
editor = MakeItem(editor.key, UIF.DrawBorder|UIF.ScrollY|UIF.ClampY);
|
||||||
|
|
||||||
|
u64 end_line = line_offset+lines;
|
||||||
|
|
||||||
|
UIKey zero = ZeroKey();
|
||||||
|
|
||||||
|
PushSizeInfoY(ST.TextSize, 1.0);
|
||||||
|
PushParent(editor);
|
||||||
|
|
||||||
|
scope(exit) Pop!("size_info", "parent");
|
||||||
|
|
||||||
|
u64 i = line_offset;
|
||||||
|
for(LineBuffer* lb = GetLine(&ed.buf, i); !CheckNil(g_NIL_LINE_BUF, lb) && i < line_offset+lines; i += 1, lb = GetLine(&ed.buf, i))
|
||||||
|
{
|
||||||
|
PushDisplayString(ConvToStr(lb.text), true);
|
||||||
|
UIItem* line = MakeItem(zero, UIF.DrawText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
EditorView(Editor* ed)
|
EditorView(Editor* ed)
|
||||||
{
|
{
|
||||||
@ -23,83 +110,44 @@ EditorView(Editor* ed)
|
|||||||
UIItem* editor = Get(ed_key);
|
UIItem* editor = Get(ed_key);
|
||||||
|
|
||||||
u64 frame_line_offset = ed.line_offset;
|
u64 frame_line_offset = ed.line_offset;
|
||||||
f32 frame_view_offset = editor.scroll_offset.y%TEXT_SIZE;
|
f32 frame_view_offset = -(editor.scroll_offset.y%TEXT_SIZE);
|
||||||
|
|
||||||
|
PushBgCol(Vec4(0.2, 0.3, 0.8, 1.0), true);
|
||||||
|
PushSizeInfoX(ST.Percentage, 1.0, 1.0, true);
|
||||||
|
|
||||||
Push!("bg_col", true)(ctx, Vec4Arr(Vec4(0.2, 0.3, 0.8, 1.0)));
|
|
||||||
Push!("size_info", true)(ctx, MakeUISizeX(ST.Percentage, 1.0));
|
|
||||||
UIItem* container = MakeItem(zero, UIF.DrawBackground);
|
UIItem* container = MakeItem(zero, UIF.DrawBackground);
|
||||||
|
|
||||||
Push!("parent")(ctx, container);
|
PushParent(container);
|
||||||
|
PushBorderCol(Vec4(1.0));
|
||||||
|
|
||||||
Push!("border_col")(ctx, Vec4Arr(Vec4(1.0)));
|
scope(exit) Pop!("parent", "border_col");
|
||||||
|
|
||||||
// Line Counter
|
|
||||||
f32 lc_width = ed.buf.line_count.toChars().length*ctx.char_width;
|
|
||||||
|
|
||||||
Push!("layout_axis", true)(ctx, A2D.Y);
|
|
||||||
Push!("view_offset" )(ctx, Vec2(0.0, frame_view_offset));
|
|
||||||
Push!("padding", true)(ctx, Vec2(4.0, 0.0));
|
|
||||||
Push!("size_info", true)(ctx, MakeUISizeX(ST.Pixels, lc_width));
|
|
||||||
|
|
||||||
UIItem* line_count = MakeItem(zero, UIF.DrawBorder);
|
|
||||||
|
|
||||||
// Editor
|
|
||||||
f32 scroll_pos = cast(f32)(ed.line_offset)*TEXT_SIZE;
|
|
||||||
|
|
||||||
Push!("layout_axis", true)(ctx, A2D.Y);
|
|
||||||
Push!("scroll_clamp", true)(ctx, cast(Vec2[2])[Vec2(0.0), Vec2(0.0, cast(f32)(ed.buf.line_count)*TEXT_SIZE)]);
|
|
||||||
Push!("size_info", true)(ctx, MakeUISize(UISize(ST.Percentage, 1.0), UISize(ST.Percentage, 1.0)));
|
|
||||||
Push!("border_col", true)(ctx, Vec4Arr(Vec4(1.0)));
|
|
||||||
Push!("scroll_target", true)(ctx, Vec2(0.0, scroll_pos));
|
|
||||||
|
|
||||||
editor = MakeItem(ed_key, UIF.DrawBorder|UIF.ScrollY|UIF.ClampY);
|
|
||||||
|
|
||||||
Pop!("view_offset")(ctx);
|
|
||||||
|
|
||||||
u64 view_lines;
|
u64 view_lines;
|
||||||
if(editor.size.y > 0.0)
|
if(editor.size.y > 0.0)
|
||||||
{
|
{
|
||||||
view_lines = cast(u64)ceil(editor.size.y/TEXT_SIZE);
|
view_lines = cast(u64)ceil(editor.size.y/TEXT_SIZE)+1;
|
||||||
|
|
||||||
const u64 SCROLL_BUFFER = 2;
|
const u64 SCROLL_BUFFER = 4;
|
||||||
|
|
||||||
u64 start = ed.line_offset;
|
u64 start = ed.line_offset;
|
||||||
u64 end = start+view_lines;
|
u64 end = start+view_lines;
|
||||||
|
|
||||||
if(ed.cursor_pos.y < start)
|
if(ed.cursor_pos.y < start)
|
||||||
{
|
{
|
||||||
ed.line_offset = clamp(ed.cursor_pos.y - SCROLL_BUFFER, 0, ed.buf.line_count);
|
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)
|
else if(ed.cursor_pos.y > end)
|
||||||
{
|
{
|
||||||
ed.line_offset = clamp(ed.cursor_pos.y + SCROLL_BUFFER - view_lines, 0, ed.buf.line_count);
|
ed.line_offset = clamp(ed.cursor_pos.y + SCROLL_BUFFER - view_lines, 0, ed.buf.line_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Push!("size_info")(ctx, MakeUISizeY(ST.Pixels, TEXT_SIZE));
|
u64 start = cast(u64)floor(editor.scroll_offset.y/TEXT_SIZE);
|
||||||
Push!("parent" )(ctx, line_count);
|
|
||||||
Push!("text_col" )(ctx, Vec4(1.0));
|
|
||||||
|
|
||||||
u64 end_line = frame_line_offset+view_lines;
|
LineCounterView(ed.buf.line_count, view_lines, start, frame_view_offset);
|
||||||
|
|
||||||
for(u64 i = frame_line_offset; i < end_line; i += 1)
|
EditorTextView(editor, ed, view_lines, start, frame_view_offset);
|
||||||
{
|
|
||||||
MakeItem("%s##ed_%s", i, ed.editor_id, UIF.DrawText);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pop!("parent", "size_info")(ctx);
|
|
||||||
|
|
||||||
Push!("size_info")(ctx, MakeUISizeY(ST.TextSize, 1.0));
|
|
||||||
Push!("parent")(ctx, editor);
|
|
||||||
|
|
||||||
u64 i = frame_line_offset;
|
|
||||||
for(LineBuffer* lb = GetLine(&ed.buf, i); !CheckNil(g_NIL_LINE_BUF, lb) && i < end_line; i += 1, lb = GetLine(&ed.buf, i))
|
|
||||||
{
|
|
||||||
Push!("display_string", true)(ctx, ConvToStr(lb.text));
|
|
||||||
UIItem* line = MakeItem(zero, UIF.DrawText);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pop!("parent", "parent", "text_col")(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user