diff --git a/src/editor/editor.d b/src/editor/editor.d index af8671b..a46714a 100644 --- a/src/editor/editor.d +++ b/src/editor/editor.d @@ -156,7 +156,7 @@ Cycle(EditorCtx* ctx, Inputs* inputs) UIItem* p0 = MakeItem("###p0", UIF.DrawBackground|UIF.Resizeable|UIF.DrawBorder); Push!("layout_axis", true)(ui_ctx, A2D.Y); - Push!("parent", true)(ui_ctx, p0); + Push!("parent")(ui_ctx, p0); Push!("size_info", true)(ui_ctx, MakeUISize(UISize(ST.ChildrenSum, 1.0), UISize(ST.Percentage, 1.0))); Push!("bg_col", true)(ui_ctx, blue); UIItem* ln = MakeItem("###ln", UIF.DrawBackground); @@ -173,11 +173,25 @@ Cycle(EditorCtx* ctx, Inputs* inputs) Pop!("padding", "size_info", "parent", "bg_col")(ui_ctx); - Push!("size_info", true)(ui_ctx, MakeUISize(UISize(ST.Pixels, 200.0), UISize(ST.Pixels, 80.0))); - Push!("parent", true)(ui_ctx, p0); + Push!("size_info", true)(ui_ctx, MakeUISizeX(ST.Percentage, 1.0)); + Push!("layout_axis", true)(ui_ctx, A2D.Y); + UIItem* t_box = MakeItem("###t_box"); + + Push!("parent")(ui_ctx, t_box); + + Push!("size_info", true)(ui_ctx, MakeUISize(UISize(ST.Pixels, 350.0, 1.0), UISize(ST.TextSize, 1.0, 1.0))); Push!("bg_col", true)(ui_ctx, green); Push!("padding", true)(ui_ctx, Vec2(4.0)); - UIItem* text = MakeItem("Haha0##text", UIF.DrawBackground|UIF.DrawText|UIF.RightAlignText|UIF.TextWrap); + UIItem* text = MakeItem("Test line of text##text", UIF.DrawBackground|UIF.DrawText|UIF.RightAlignText|UIF.TextWrap); + + Push!("size_info", true)(ui_ctx, MakeUISize(UISize(ST.Percentage, 1.0, 1.0), UISize(ST.TextSize, 1.0, 1.0))); + Push!("bg_col", true)(ui_ctx, white); + Push!("text_col", true)(ui_ctx, black[0]); + Push!("padding", true)(ui_ctx, Vec2(8.0)); + UIItem* text2 = MakeItem("A different line of text for testing purposes##text", UIF.DrawBackground|UIF.DrawText|UIF.TextWrap); + + Pop!("parent")(ui_ctx); + Pop!("parent")(ui_ctx); Push!("size_info", true)(ui_ctx, MakeUISizeX(ST.Pixels, 2.0)); Push!("bg_col", true)(ui_ctx, black); diff --git a/src/editor/ui.d b/src/editor/ui.d index f1cd137..2d1b02b 100644 --- a/src/editor/ui.d +++ b/src/editor/ui.d @@ -64,6 +64,8 @@ UISize[2] g_size_info_default = [UISize(ST.Percentage, 1.0), UISize(ST.P Axis2D g_layout_axis_default = A2D.X; Vec2 g_padding_default = Vec2(0.0); f32 g_text_scale_default = 1.0; +Vec2 g_scroll_target_default = Vec2(0.0); +Vec2 g_scroll_clamp_default = Vec2(0.0); alias g_parent_default = g_UI_NIL; const UI_COUNT = 5000; @@ -237,6 +239,8 @@ struct UICtx mixin UICtxParameter!(UISize[2], "size_info"); mixin UICtxParameter!(Vec4, "text_col"); mixin UICtxParameter!(Vec4, "text_hl_col"); + mixin UICtxParameter!(Vec2[2], "scroll_clamp"); + mixin UICtxParameter!(Vec2, "scroll_target"); mixin UICtxParameter!(Vec2, "padding"); mixin UICtxParameter!(UIItem*, "parent"); mixin UICtxParameter!(Axis2D, "layout_axis"); @@ -303,9 +307,11 @@ struct UIItem Rect rect; Vec2 size; - f32 resize_pct; string display_string; string[] text_lines; + f32 max_text_width; + f32 resize_pct; + Vec2 scroll_offset; mixin UIItemParameters!(); } @@ -342,13 +348,26 @@ struct GlyphBounds f32 atlas_r = 0.0, atlas_l = 0.0, atlas_t = 0.0, atlas_b = 0.0; } +struct VPos +{ + Vec2 start; + Vec2 end; +} + struct Vertex { Vec4[4] cols; - Vec2 dst_start; - Vec2 dst_end; - Vec2 src_start; - Vec2 src_end; + union + { + VPos[2] pos; + struct + { + Vec2 dst_start; + Vec2 dst_end; + Vec2 src_start; + Vec2 src_end; + }; + }; f32 border_thickness; f32 corner_radius; f32 edge_softness; @@ -587,7 +606,9 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T) } } - string str = item.display_string.length ? item.display_string : item.key.text; + 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; @@ -595,8 +616,8 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T) if(text_width < width || width == 0.0) goto InitSingleLine; - u64 lines = cast(u64)(ceil(text_width/width)); - item.text_lines = ScratchAlloc!(string)(lines); + u64 lines = cast(u64)(ceil(text_width/width)); + item.text_lines = ScratchAlloc!(string)(lines); f32 w = 0.0; u64 line = 0; @@ -613,9 +634,14 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T) item.text_lines[line++] = str[ch_start .. i]; ch_start = i; + item.max_text_width = item.max_text_width < w ? w : item.max_text_width; + if(line == lines-1) { item.text_lines[line] = str[ch_start .. $]; + w = CalcTextWidth(item.text_lines[line]); + item.max_text_width = item.max_text_width < w ? w : item.max_text_width; + break; } @@ -628,21 +654,33 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T) else { InitSingleLine: - item.text_lines = ScratchAlloc!(string)(1); - item.text_lines[0] = str; + item.text_lines = ScratchAlloc!(string)(1); + item.text_lines[0] = str; + item.max_text_width = CalcTextWidth(item.text_lines[0]); + } + + f32 scroll_speed = 1 - pow(2, (-60.0f * g_delta)); + static foreach(axis; A2D.min .. A2D.max) + { + 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]) < 2.0) + { + item.scroll_offset.v[axis] = item.scroll_target.v[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.last_frame = ctx.frame; item.padding += item.border_thickness; - if(item.text_lines.length > 1) - { - foreach(i; 0 .. item.text_lines.length) - { - Logf("line %s: %s", i, item.text_lines[i]); - } - } - return item; } @@ -867,11 +905,11 @@ EndUI() { static if(axis == A2D.X) { - item.size.v[axis] = item.padding.x*2.0 + CalcTextWidth(item.display_string.length ? item.display_string : item.key.text); + item.size.v[axis] = item.max_text_width + item.padding.x*2.0; } else { - item.size.v[axis] = item.padding.y*2.0 + TEXT_SIZE; + item.size.v[axis] = item.padding.y*2.0 + TEXT_SIZE*item.text_lines.length; } } } @@ -1089,8 +1127,6 @@ RenderItems(UIItem* root) if(item.flags & UIF.DrawText || item.display_string) { - string str = item.display_string ? item.display_string : item.key.text; - if(item.flags & UIF.CenterAlignText) { // TODO @@ -1099,15 +1135,23 @@ RenderItems(UIItem* root) { FontAtlas* atl = &ctx.atlas_buf.atlas; - f32 x_pos = item.flags & UIF.RightAlignText ? item.rect.p1.x - item.padding.x - CalcTextWidth(str) : - item.rect.p0.x + item.padding.x; - f32 y_pos = item.rect.p0.y + item.padding.y; - foreach(i; 0 .. str.length) + + foreach(i; 0 .. item.text_lines.length) { - u8 ch = str[i]; - Glyph* g = ch < atl.glyphs.length ? atl.glyphs.ptr + ch : null; - DrawGlyph(item, g, &x_pos, y_pos); + string str = item.text_lines[i]; + + f32 x_pos = item.flags & UIF.RightAlignText ? item.rect.p1.x - item.padding.x - CalcTextWidth(str) : + item.rect.p0.x + item.padding.x; + + foreach(j; 0 .. str.length) + { + u8 ch = str[j]; + Glyph* g = ch < atl.glyphs.length ? atl.glyphs.ptr + ch : null; + DrawGlyph(item, g, &x_pos, y_pos); + } + + y_pos += TEXT_SIZE; } } } @@ -1538,6 +1582,14 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y) v.src_end.y -= (v.src_end.y - v.src_start.y) * cull_pct; } + static foreach(axis; A2D.min .. A2D.max) + { + static foreach(i; 0 .. v.pos.length) + { + v.pos[i].end[axis] = v.pos[i].start.v[axis] > v.pos[i].end.v[axis] ? v.pos[i].start.v[axis] : v.pos[i].end.v[axis]; + } + } + AddVertexCount(ctx); *x_pos += advance;