add text line widget, add text wrapping
This commit is contained in:
parent
de90479aa7
commit
9f8e4aff59
2
src/dlib
2
src/dlib
@ -1 +1 @@
|
||||
Subproject commit f30edc3bbe9fdfda5eb429a214fdf050a0012af0
|
||||
Subproject commit 29a98de0e05cb04001b42a55b1ae094ab42f2ab1
|
||||
@ -4,6 +4,7 @@ import dlib.alloc;
|
||||
import dlib.util;
|
||||
import core.stdc.stdio : EOF;
|
||||
import parsing;
|
||||
import std.format : sformat;
|
||||
|
||||
struct FlatBuffer
|
||||
{
|
||||
@ -25,7 +26,6 @@ struct LineBuffers
|
||||
{
|
||||
Arena arena;
|
||||
u8[][] lines;
|
||||
u32[] lengths;
|
||||
}
|
||||
|
||||
FlatBuffer
|
||||
@ -108,15 +108,15 @@ Insert(FlatBuffer* buffer, u8[] insert, u64 length, Range pos)
|
||||
|
||||
// TODO: handle case for when lines are longer than line buffer
|
||||
void
|
||||
GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length)
|
||||
GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length, bool add_hash = false)
|
||||
{
|
||||
assert(start_line < buffer.line_count, "GetLines failure: start is not less than line_count");
|
||||
assert(linebufs != null, "GetLines failure: linebufs is null");
|
||||
length = length > buffer.line_count ? buffer.line_count : length;
|
||||
|
||||
Reset(&linebufs.arena);
|
||||
linebufs.lines = AllocArray!(u8[])(&linebufs.arena, length);
|
||||
linebufs.lengths = AllocArray!(u32)(&linebufs.arena, length);
|
||||
|
||||
u64 extra_buffer = add_hash ? 10 : 0;
|
||||
i64 start = -1;
|
||||
u64 line = 0;
|
||||
u64 current_line = 0;
|
||||
@ -136,9 +136,8 @@ GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length)
|
||||
|
||||
if (start < 0 && new_line)
|
||||
{
|
||||
linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, 1);
|
||||
linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, 1 + extra_buffer);
|
||||
linebufs.lines[current_line][0] = '\n';
|
||||
linebufs.lengths[current_line] = 1;
|
||||
current_line += 1;
|
||||
continue;
|
||||
}
|
||||
@ -151,9 +150,8 @@ GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length)
|
||||
|
||||
if (new_line)
|
||||
{
|
||||
linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, i-start);
|
||||
linebufs.lines[current_line][0 .. $] = buffer.data[start .. i];
|
||||
linebufs.lengths[current_line] = cast(u32)(i-start);
|
||||
linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, (i-start) + extra_buffer);
|
||||
linebufs.lines[current_line][0 .. i-start] = buffer.data[start .. i];
|
||||
current_line += 1;
|
||||
start = -1;
|
||||
continue;
|
||||
@ -161,9 +159,21 @@ GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length)
|
||||
|
||||
if (i == buffer.length-1)
|
||||
{
|
||||
linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, buffer.length-start);
|
||||
linebufs.lines[current_line][0 .. $] = buffer.data[start .. buffer.length];
|
||||
linebufs.lengths[current_line] = cast(u32)(buffer.length-start);
|
||||
linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, (buffer.length-start) + extra_buffer);
|
||||
linebufs.lines[current_line][0 .. buffer.length-start] = buffer.data[start .. buffer.length];
|
||||
}
|
||||
}
|
||||
|
||||
if (add_hash)
|
||||
{
|
||||
for (u64 i = 0; i < linebufs.lines.length; i += 1)
|
||||
{
|
||||
if (linebufs.lines[i].length > 0)
|
||||
{
|
||||
u8[10] buf = 0;
|
||||
(cast(char[])buf).sformat("##%08s", i);
|
||||
linebufs.lines[i][linebufs.lines[i].length - extra_buffer .. $] = buf[0 .. $];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,16 +29,16 @@ struct Editor
|
||||
Arena temp_arena;
|
||||
PlatformWindow* window;
|
||||
|
||||
Renderer rd;
|
||||
ImageView font_atlas;
|
||||
Pipeline pipeline;
|
||||
DescSetLayout desc_set_layout;
|
||||
DescSet desc_set;
|
||||
PipelineLayout pipeline_layout;
|
||||
PushConst pc;
|
||||
Renderer rd;
|
||||
ImageView font_atlas;
|
||||
Pipeline pipeline;
|
||||
DescSetLayout desc_set_layout;
|
||||
DescSet desc_set;
|
||||
PipelineLayout pipeline_layout;
|
||||
PushConst pc;
|
||||
|
||||
FlatBuffer[] buffers;
|
||||
Tokenizer[] tokenizers;
|
||||
FlatBuffer[] buffers;
|
||||
Tokenizer[] tokenizers;
|
||||
u8[][] buffer_names;
|
||||
u32 buffer_count;
|
||||
FlatBuffer* active_buffer;
|
||||
@ -48,7 +48,7 @@ struct Editor
|
||||
FontFace font;
|
||||
FontAtlasBuf atlas_buf;
|
||||
|
||||
UVec2 res;
|
||||
Vec2 res;
|
||||
}
|
||||
|
||||
struct PushConst
|
||||
@ -70,6 +70,82 @@ struct Vertex
|
||||
u32 texture;
|
||||
}
|
||||
|
||||
void
|
||||
Cycle(Editor* ed, Inputs* inputs)
|
||||
{
|
||||
Reset(&ed.temp_arena);
|
||||
ResetScratch(MB(4));
|
||||
|
||||
BeginBuild(inputs);
|
||||
|
||||
static UIPanel panel = {
|
||||
id: CastStr!(u8)("##main_panel"),
|
||||
pct: 1.0,
|
||||
axis: A2D.X,
|
||||
color: Vec4(0.2, 0.4, 0.8, 1.0),
|
||||
};
|
||||
|
||||
static UIPanel panel_l = {
|
||||
id: CastStr!(u8)("##panel_l"),
|
||||
pct: 0.5,
|
||||
axis: A2D.Y,
|
||||
color: Vec4(0.2, 0.4, 0.8, 1.0),
|
||||
};
|
||||
|
||||
static UIPanel panel_r = {
|
||||
id: CastStr!(u8)("##panel_r"),
|
||||
pct: 0.5,
|
||||
axis: A2D.Y,
|
||||
color: Vec4(0.4, 0.3, 0.7, 1.0),
|
||||
};
|
||||
|
||||
BeginFrame(&ed.rd);
|
||||
|
||||
Vec2 ext = GetExtent(&ed.rd);
|
||||
if (ext != ed.res)
|
||||
{
|
||||
ed.res = ext;
|
||||
Ortho(&ed.pc.projection, 0.0, 0.0, ext.x, ext.y, 1000.0, 0.1);
|
||||
}
|
||||
|
||||
u32 rows = cast(u32)(ext.y / ed.atlas_buf.atlas.size) + 5;
|
||||
Panel(&panel);
|
||||
{
|
||||
Panel(&panel_l);
|
||||
{
|
||||
if (ed.active_buffer != null)
|
||||
{
|
||||
GetLines(&ed.buffers[0], &ed.linebufs, 0, rows);
|
||||
|
||||
for(u64 i = 0; i < ed.linebufs.lines.length; i += 1)
|
||||
{
|
||||
TextLine(ed.linebufs.lines[i], ed.atlas_buf.atlas.size, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
EndPanel();
|
||||
|
||||
Panel(&panel_r);
|
||||
{
|
||||
|
||||
}
|
||||
EndPanel();
|
||||
}
|
||||
EndPanel();
|
||||
|
||||
BeginRendering(&ed.rd);
|
||||
|
||||
PushConstants(&ed.rd, ed.pipeline, &ed.pc);
|
||||
|
||||
Bind(&ed.rd, ed.pipeline, ed.desc_set);
|
||||
|
||||
EndBuild();
|
||||
|
||||
FinishRendering(&ed.rd);
|
||||
|
||||
SubmitAndPresent(&ed.rd);
|
||||
}
|
||||
|
||||
Editor
|
||||
CreateEditor(PlatformWindow* window, u8[] buffer_data, u8[] buffer_name)
|
||||
{
|
||||
@ -175,140 +251,6 @@ CreateEditor(PlatformWindow* window, u8[] buffer_data, u8[] buffer_name)
|
||||
return editor;
|
||||
}
|
||||
|
||||
void
|
||||
Cycle(Editor* ed, Inputs* inputs)
|
||||
{
|
||||
Reset(&ed.temp_arena);
|
||||
|
||||
BeginBuild(inputs);
|
||||
|
||||
static UIPanel[11] panels = [
|
||||
{
|
||||
id: CastStr!(u8)("##panel_1"),
|
||||
pct: 0.3,
|
||||
axis: A2D.X,
|
||||
color: Vec4(0.2, 0.5, 0.8, 1.0),
|
||||
},
|
||||
{
|
||||
id: CastStr!(u8)("##sub_panel_1"),
|
||||
pct: 0.125,
|
||||
axis: A2D.X,
|
||||
color: Vec4(0.2, 0.4, 0.5, 1.0),
|
||||
},
|
||||
{
|
||||
id: CastStr!(u8)("##sub_panel_2"),
|
||||
pct: 0.675,
|
||||
axis: A2D.X,
|
||||
color: Vec4(0.9, 0.6, 0.5, 1.0),
|
||||
},
|
||||
{
|
||||
id: CastStr!(u8)("##sub_panel_3"),
|
||||
pct: 0.2,
|
||||
axis: A2D.X,
|
||||
color: Vec4(1.0, 0.4, 0.5, 1.0),
|
||||
},
|
||||
{
|
||||
id: CastStr!(u8)("##panel_2"),
|
||||
pct: 0.3,
|
||||
axis: A2D.X,
|
||||
color: Vec4(0.5, 0.2, 0.45, 1.0),
|
||||
},
|
||||
{
|
||||
id: CastStr!(u8)("##panel_3"),
|
||||
pct: 0.4,
|
||||
axis: A2D.X,
|
||||
color: Vec4(0.3, 0.7, 0.6, 1.0),
|
||||
},
|
||||
{
|
||||
id: CastStr!(u8)("##sub_panel_4"),
|
||||
pct: 0.25,
|
||||
axis: A2D.Y,
|
||||
color: Vec4(0.33, 0.4, 0.8, 1.0),
|
||||
},
|
||||
{
|
||||
id: CastStr!(u8)("##sub_sub_panel_1"),
|
||||
pct: 0.4,
|
||||
axis: A2D.X,
|
||||
color: Vec4(1.0, 0.0, 0.0, 1.0),
|
||||
},
|
||||
{
|
||||
id: CastStr!(u8)("##sub_sub_panel_2"),
|
||||
pct: 0.6,
|
||||
axis: A2D.X,
|
||||
color: Vec4(1.0, 1.0, 0.0, 1.0),
|
||||
},
|
||||
{
|
||||
id: CastStr!(u8)("##sub_panel_5"),
|
||||
pct: 0.55,
|
||||
axis: A2D.X,
|
||||
color: Vec4(0.9, 0.2, 0.3, 1.0),
|
||||
},
|
||||
{
|
||||
id: CastStr!(u8)("##sub_panel_6"),
|
||||
pct: 0.2,
|
||||
axis: A2D.X,
|
||||
color: Vec4(0.2, 0.76, 0.5, 1.0),
|
||||
},
|
||||
];
|
||||
|
||||
Panel(&panels[0]);
|
||||
{
|
||||
Panel(&panels[1]);
|
||||
EndPanel();
|
||||
|
||||
Panel(&panels[2]);
|
||||
EndPanel();
|
||||
|
||||
Panel(&panels[3]);
|
||||
EndPanel();
|
||||
}
|
||||
EndPanel();
|
||||
|
||||
Panel(&panels[4]);
|
||||
EndPanel();
|
||||
|
||||
Panel(&panels[5]);
|
||||
{
|
||||
Panel(&panels[6]);
|
||||
{
|
||||
Panel(&panels[7]);
|
||||
EndPanel();
|
||||
|
||||
Panel(&panels[8]);
|
||||
EndPanel();
|
||||
}
|
||||
EndPanel();
|
||||
|
||||
Panel(&panels[9]);
|
||||
EndPanel();
|
||||
|
||||
Panel(&panels[10]);
|
||||
EndPanel();
|
||||
}
|
||||
EndPanel();
|
||||
|
||||
BeginFrame(&ed.rd);
|
||||
|
||||
UVec2 ext = UVec2(GetExtent(&ed.rd));
|
||||
if (ext != ed.res)
|
||||
{
|
||||
ed.res = ext;
|
||||
Ortho(&ed.pc.projection, 0.0, 0.0, cast(f32)(ext.x), cast(f32)(ext.y), 1000.0, 0.1);
|
||||
}
|
||||
|
||||
BeginRendering(&ed.rd);
|
||||
|
||||
PushConstants(&ed.rd, ed.pipeline, &ed.pc);
|
||||
|
||||
Bind(&ed.rd, ed.pipeline, ed.desc_set);
|
||||
|
||||
EndBuild();
|
||||
|
||||
FinishRendering(&ed.rd);
|
||||
|
||||
SubmitAndPresent(&ed.rd);
|
||||
}
|
||||
|
||||
void
|
||||
DrawText(Editor* ed, f32 x, f32 y, f32 px, string str)
|
||||
{
|
||||
|
||||
259
src/editor/ui.d
259
src/editor/ui.d
@ -7,6 +7,9 @@ import dlib.fonts;
|
||||
import vulkan;
|
||||
import widgets;
|
||||
import std.stdio;
|
||||
import std.math.rounding : ceil;
|
||||
import std.format : sformat;
|
||||
import core.stdc.string : memset;
|
||||
|
||||
import editor;
|
||||
|
||||
@ -31,8 +34,9 @@ enum UIFlags
|
||||
{
|
||||
None = 0x00,
|
||||
DrawBackground = 0x01,
|
||||
Clickable = 0x02,
|
||||
Draggable = 0x04,
|
||||
DrawText = 0x02,
|
||||
Clickable = 0x04,
|
||||
Draggable = 0x08,
|
||||
}
|
||||
|
||||
alias UIF = UIFlags;
|
||||
@ -60,8 +64,10 @@ struct UICtx
|
||||
Arena arena;
|
||||
Renderer* rd;
|
||||
Inputs* inputs;
|
||||
u64 frame;
|
||||
u64 f_idx;
|
||||
|
||||
UIBuffer buffer;
|
||||
UIBuffer[FRAME_OVERLAP] buffers;
|
||||
|
||||
UIItem* root;
|
||||
UIItemNode* top_parent;
|
||||
@ -77,6 +83,8 @@ struct UICtx
|
||||
Vec4 text_color;
|
||||
Axis2D layout_axis;
|
||||
Vec2 adjustment;
|
||||
u32 tab_width;
|
||||
f32 text_size;
|
||||
}
|
||||
|
||||
struct UIItemStackList
|
||||
@ -125,8 +133,8 @@ struct UISize
|
||||
|
||||
struct UIBuffer
|
||||
{
|
||||
MappedBuffer!(Vertex) mapped_vtx;
|
||||
MappedBuffer!(u32) mapped_idx;
|
||||
MappedBuffer!(Vertex) m_vtx;
|
||||
MappedBuffer!(u32) m_idx;
|
||||
Vertex[] vtx;
|
||||
u32[] idx;
|
||||
u32 count;
|
||||
@ -166,9 +174,17 @@ InitUICtx(Renderer* rd, FontAtlas atlas)
|
||||
g_UI_NIL_NODE = cast(UIItemNode*)&g_ui_nil_item_node;
|
||||
|
||||
Arena arena = CreateArena(MB(4));
|
||||
|
||||
UIBuffer[FRAME_OVERLAP] buffers;
|
||||
|
||||
MappedBuffer!(Vertex) m_vtx = CreateMappedBuffer!(Vertex)(rd, BT.Vertex, 5000);
|
||||
MappedBuffer!(u32) m_idx = CreateMappedBuffer!(u32)(rd, BT.Index, 15000);
|
||||
u64 vertex_size = 10000;
|
||||
for(u64 i = 0; i < FRAME_OVERLAP; i += 1)
|
||||
{
|
||||
buffers[i].m_vtx = CreateMappedBuffer!(Vertex)(rd, BT.Vertex, vertex_size);
|
||||
buffers[i].m_idx = CreateMappedBuffer!(u32)(rd, BT.Index, cast(u64)(ceil(vertex_size * 1.5)));
|
||||
buffers[i].vtx = buffers[i].m_vtx.data;
|
||||
buffers[i].idx = buffers[i].m_idx.data;
|
||||
}
|
||||
|
||||
UICtx ctx = {
|
||||
rd: rd,
|
||||
@ -179,12 +195,9 @@ InitUICtx(Renderer* rd, FontAtlas atlas)
|
||||
top_parent: g_UI_NIL_NODE,
|
||||
prev_sibling: g_UI_NIL_NODE,
|
||||
drag_item: g_UI_NIL,
|
||||
buffer: {
|
||||
mapped_vtx: m_vtx,
|
||||
mapped_idx: m_idx,
|
||||
vtx: m_vtx.data,
|
||||
idx: m_idx.data,
|
||||
},
|
||||
text_size: 14.0,
|
||||
tab_width: 2,
|
||||
buffers: buffers,
|
||||
};
|
||||
|
||||
g_ui_ctx = ctx;
|
||||
@ -361,13 +374,25 @@ SetLayoutAxis(Axis2D axis)
|
||||
ctx.layout_axis = axis;
|
||||
}
|
||||
|
||||
void
|
||||
SetTextSize(f32 size)
|
||||
{
|
||||
g_ui_ctx.text_size = size;
|
||||
}
|
||||
|
||||
void
|
||||
BeginBuild(Inputs* inputs)
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
|
||||
ctx.f_idx = ctx.frame%FRAME_OVERLAP;
|
||||
|
||||
ctx.inputs = inputs;
|
||||
ctx.buffer.count = 0;
|
||||
|
||||
memset(ctx.buffers[ctx.f_idx].vtx.ptr, 0, Vertex.sizeof * ctx.buffers[ctx.f_idx].count);
|
||||
memset(ctx.buffers[ctx.f_idx].idx.ptr, 0, u32.sizeof * ctx.buffers[ctx.f_idx].count);
|
||||
ctx.buffers[ctx.f_idx].count = 0;
|
||||
|
||||
ctx.panel_level = 0;
|
||||
|
||||
ctx.root = Root();
|
||||
@ -400,8 +425,10 @@ EndBuild()
|
||||
first = true;
|
||||
}
|
||||
|
||||
BindBuffers(g_ui_ctx.rd, &g_ui_ctx.buffer.mapped_idx, &g_ui_ctx.buffer.mapped_vtx);
|
||||
DrawIndexed(g_ui_ctx.rd, 6, g_ui_ctx.buffer.count, 0);
|
||||
BindBuffers(ctx.rd, &ctx.buffers[ctx.f_idx].m_idx, &ctx.buffers[ctx.f_idx].m_vtx);
|
||||
DrawIndexed(ctx.rd, 6, ctx.buffers[ctx.f_idx].count, 0);
|
||||
|
||||
ctx.frame += 1;
|
||||
}
|
||||
|
||||
void
|
||||
@ -473,7 +500,15 @@ DrawUI(UICtx* ctx, UIItem* item)
|
||||
{
|
||||
if (!Nil(item))
|
||||
{
|
||||
DrawRect(ctx, item);
|
||||
if (item.flags & UIF.DrawBackground)
|
||||
{
|
||||
DrawRect(ctx, item);
|
||||
}
|
||||
|
||||
if (item.flags & UIF.DrawText)
|
||||
{
|
||||
DrawLine(item);
|
||||
}
|
||||
|
||||
DrawUI(ctx, item.first);
|
||||
DrawUI(ctx, item.next);
|
||||
@ -567,20 +602,33 @@ RootSize()
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
UIKey
|
||||
MakeKey(u8[] text, u8[] hash)
|
||||
{
|
||||
UIKey key;
|
||||
|
||||
key.text = text;
|
||||
key.hash = Hash(text, hash);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
UIKey
|
||||
MakeKey(u8[] id)
|
||||
{
|
||||
UIKey key;
|
||||
|
||||
u32 pos = 0;
|
||||
i64 pos = 0;
|
||||
u32 hash_count = 0;
|
||||
for(u32 i = 0; i < id.length; i += 1)
|
||||
for(i64 i = id.length-1; i >= 0; i -= 1)
|
||||
{
|
||||
if (hash_count == 2)
|
||||
{
|
||||
if (id[i] == '#')
|
||||
{
|
||||
hash_count += 1;
|
||||
pos = i;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -588,11 +636,7 @@ MakeKey(u8[] id)
|
||||
|
||||
if (id[i] == '#')
|
||||
{
|
||||
if (hash_count == 0)
|
||||
{
|
||||
pos = i;
|
||||
}
|
||||
|
||||
pos = i;
|
||||
hash_count += 1;
|
||||
}
|
||||
}
|
||||
@ -616,6 +660,21 @@ MakeKey(u8[] id)
|
||||
return key;
|
||||
}
|
||||
|
||||
pragma(inline) UIItem*
|
||||
Get(UIKey key)
|
||||
{
|
||||
Result!(UIItem*) result = g_ui_ctx.items[key.hash];
|
||||
if (!result.ok)
|
||||
{
|
||||
result.value = Alloc!(UIItem)(&g_ui_ctx.arena);
|
||||
Push(&g_ui_ctx.items, key.hash, result.value);
|
||||
}
|
||||
|
||||
result.value.key = key;
|
||||
|
||||
return result.value;
|
||||
}
|
||||
|
||||
UIItem*
|
||||
Get(string id)
|
||||
{
|
||||
@ -627,48 +686,132 @@ UIItem*
|
||||
Get(u8[] id)
|
||||
{
|
||||
UIKey key = MakeKey(id);
|
||||
|
||||
Result!(UIItem*) result = g_ui_ctx.items[key.hash];
|
||||
if (!result.ok)
|
||||
{
|
||||
result.value = Alloc!(UIItem)(&g_ui_ctx.arena);
|
||||
Push(&g_ui_ctx.items, key.hash, result.value);
|
||||
result.value.key = key;
|
||||
}
|
||||
|
||||
return result.value;
|
||||
return Get(key);
|
||||
}
|
||||
|
||||
f32
|
||||
CalcTextWidth(u8[] str)
|
||||
{
|
||||
u32 tab_width = 2; //g_ui_ctx.tab_width;
|
||||
u32 tab_width = g_ui_ctx.tab_width;
|
||||
Glyph* space = g_ui_ctx.atlas.glyphs.ptr + ' ';
|
||||
|
||||
f32 width;
|
||||
f32 width = 0.0;
|
||||
for(u64 i = 0; i < str.length; i += 1)
|
||||
{
|
||||
Glyph* g = g_ui_ctx.atlas.glyphs.ptr + str.ptr[i];
|
||||
width += GlyphWidth(g_ui_ctx.atlas.glyphs.ptr + str.ptr[i]);
|
||||
}
|
||||
|
||||
if (g.ch == '\t')
|
||||
return width;
|
||||
}
|
||||
|
||||
pragma(inline) f32
|
||||
GlyphWidth(Glyph* g)
|
||||
{
|
||||
f32 width = 0.0;
|
||||
if (g.ch == '\t')
|
||||
{
|
||||
width += g_ui_ctx.atlas.glyphs[' '].advance * cast(f32)(g_ui_ctx.tab_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
width += g.advance;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
Node!(u8[])*
|
||||
MakeMultiline(u8[] text, f32 width, u64 line_no)
|
||||
{
|
||||
f32 scaled_width = width * (g_ui_ctx.atlas.size/g_ui_ctx.text_size);
|
||||
f32 text_width = CalcTextWidth(text);
|
||||
|
||||
u64 line_count = cast(u64)(ceil(text_width/scaled_width));
|
||||
Node!(u8[])* node = null;
|
||||
if (line_count > 0)
|
||||
{
|
||||
f32 w = 0.0;
|
||||
u64 line = 0;
|
||||
u64 start = 0;
|
||||
const u64 extra_buf = 10;
|
||||
for(u64 i = 0; i < text.length; i += 1)
|
||||
{
|
||||
width += space.advance * cast(f32)(tab_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
width += g.advance;
|
||||
f32 ch_w = GlyphWidth(g_ui_ctx.atlas.glyphs.ptr + text[i]);
|
||||
|
||||
if (ch_w + w > scaled_width || i == text.length-1)
|
||||
{
|
||||
u64 len = i-start+1;
|
||||
u8[10] buf = 0;
|
||||
(cast(char[])buf).sformat("##%04s%04s", line_no, line);
|
||||
|
||||
u8[] str = ScratchAlloc!(u8)(len+extra_buf);
|
||||
str[0 .. len] = text[start .. start+len];
|
||||
str[len .. len+extra_buf] = buf[0 .. $];
|
||||
|
||||
Node!(u8[])* n = node;
|
||||
for(;;)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
node = ScratchAlloc!(Node!(u8[]))();
|
||||
node.value = str;
|
||||
node.next = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n.next == null)
|
||||
{
|
||||
n.next = ScratchAlloc!(Node!(u8[]))();
|
||||
n.next.value = str;
|
||||
n.next.next = null;
|
||||
break;
|
||||
}
|
||||
|
||||
n = n.next;
|
||||
}
|
||||
|
||||
line += 1;
|
||||
start = i;
|
||||
w = 0.0;
|
||||
}
|
||||
|
||||
w += ch_w;
|
||||
}
|
||||
}
|
||||
|
||||
return width; // * g_ui_ctx.text_scale;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DrawLine(UIItem* item)
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
f32 y = item.rect.y0 + ctx.text_size;
|
||||
f32 x = item.rect.x0;
|
||||
FontAtlas* atlas = &ctx.atlas;
|
||||
|
||||
for(u64 i = 0; i < item.key.text.length && item.key.text[i] != '\0'; i += 1)
|
||||
{
|
||||
u8 ch = item.key.text.ptr[i];
|
||||
if (ch < 128)
|
||||
{
|
||||
DrawGlyph(&atlas.glyphs[ch], atlas.size/ctx.text_size, &x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pragma(inline) void
|
||||
DrawGlyph(Glyph* glyph, f32 scale, f32* x_pos, f32 y, Vec4 col = Vec4(1.0))
|
||||
{
|
||||
if (glyph.atlas_left != glyph.atlas_right)
|
||||
if (glyph.ch == '\t')
|
||||
{
|
||||
Vertex* v = g_ui_ctx.buffer.vtx.ptr + g_ui_ctx.buffer.count;
|
||||
*x_pos += glyph.advance * (GetCtx().tab_width - 1);
|
||||
}
|
||||
else if (glyph.atlas_left != glyph.atlas_right && glyph.ch != '\n')
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
Vertex* v = ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count;
|
||||
|
||||
f32 r = glyph.plane_right * scale;
|
||||
f32 l = glyph.plane_left * scale;
|
||||
@ -693,7 +836,7 @@ DrawGlyph(Glyph* glyph, f32 scale, f32* x_pos, f32 y, Vec4 col = Vec4(1.0))
|
||||
|
||||
v.texture = 1;
|
||||
|
||||
AddUIIndices();
|
||||
AddUIIndices(ctx);
|
||||
}
|
||||
|
||||
*x_pos += glyph.advance * scale;
|
||||
@ -703,7 +846,7 @@ pragma(inline) void
|
||||
DrawRect(UICtx* ctx, UIItem* item)
|
||||
{
|
||||
// Y reversed
|
||||
Vertex* v = ctx.buffer.vtx.ptr + ctx.buffer.count;
|
||||
Vertex* v = ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count;
|
||||
v.dst_start = item.rect.vec0;
|
||||
v.dst_end = item.rect.vec1;
|
||||
v.cols = item.color;
|
||||
@ -712,20 +855,20 @@ DrawRect(UICtx* ctx, UIItem* item)
|
||||
v.edge_softness = 0.0;
|
||||
v.raised = 0.0;
|
||||
|
||||
AddUIIndices();
|
||||
AddUIIndices(ctx);
|
||||
}
|
||||
|
||||
void
|
||||
AddUIIndices()
|
||||
pragma(inline) void
|
||||
AddUIIndices(UICtx* ctx)
|
||||
{
|
||||
g_ui_ctx.buffer.idx[0] = 0;
|
||||
g_ui_ctx.buffer.idx[1] = 1;
|
||||
g_ui_ctx.buffer.idx[2] = 2;
|
||||
g_ui_ctx.buffer.idx[3] = 2;
|
||||
g_ui_ctx.buffer.idx[4] = 1;
|
||||
g_ui_ctx.buffer.idx[5] = 3;
|
||||
ctx.buffers[ctx.f_idx].idx[0] = 0;
|
||||
ctx.buffers[ctx.f_idx].idx[1] = 1;
|
||||
ctx.buffers[ctx.f_idx].idx[2] = 2;
|
||||
ctx.buffers[ctx.f_idx].idx[3] = 2;
|
||||
ctx.buffers[ctx.f_idx].idx[4] = 1;
|
||||
ctx.buffers[ctx.f_idx].idx[5] = 3;
|
||||
|
||||
g_ui_ctx.buffer.count += 1;
|
||||
ctx.buffers[ctx.f_idx].count += 1;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@ -114,8 +114,8 @@ Panel(UIPanel* panel)
|
||||
parent_end = parent.rect.vec1.y;
|
||||
}
|
||||
|
||||
u8[128] buf = 0;
|
||||
(cast(char[])buf).sformat("sep_%s", cast(char[])panel.id);
|
||||
u8[] buf = ScratchAlloc!(u8)(panel.id.length + 5);
|
||||
(cast(char[])buf).sformat("%s_sep", cast(char[])panel.id);
|
||||
|
||||
separator = Get(buf);
|
||||
|
||||
@ -127,12 +127,11 @@ Panel(UIPanel* panel)
|
||||
if (separator.signal & UIS.Dragged && pos != 0.0)
|
||||
{
|
||||
f32 pct = Remap(pos, 0.0, parent_start-parent_end, 0.0, 1.0);
|
||||
panel.pct -= pct;
|
||||
panel.prev.pct += pct;
|
||||
|
||||
Logf("%f", pct);
|
||||
|
||||
Logf("%s %f %s %f", cast(char[])panel.id, panel.pct, cast(char[])panel.prev.id, panel.prev.pct);
|
||||
if (CheckPanelBounds(panel.pct - pct) && CheckPanelBounds(panel.prev.pct + pct))
|
||||
{
|
||||
panel.pct -= pct;
|
||||
panel.prev.pct += pct;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,6 +150,12 @@ Panel(UIPanel* panel)
|
||||
return item;
|
||||
}
|
||||
|
||||
bool
|
||||
CheckPanelBounds(f32 pct)
|
||||
{
|
||||
return pct >= 0.0 && pct <= 1.0;
|
||||
}
|
||||
|
||||
void
|
||||
Separator(UIItem* item, f32 x_size, f32 y_size, Axis2D axis)
|
||||
{
|
||||
@ -162,6 +167,25 @@ Separator(UIItem* item, f32 x_size, f32 y_size, Axis2D axis)
|
||||
BuildItem(item, UISize(x_t, x_size), UISize(y_t, y_size), UIF.DrawBackground|UIF.Draggable);
|
||||
}
|
||||
|
||||
void
|
||||
TextLine(u8[] text, f32 text_size, u64 line_no)
|
||||
{
|
||||
UIItem* parent = PeekParent();
|
||||
|
||||
if (!Nil(parent) && parent.size.x > 0.0)
|
||||
{
|
||||
SetColor(Vec4(1.0));
|
||||
SetTextSize(text_size);
|
||||
|
||||
Node!(u8[])* lines = MakeMultiline(text, parent.size.x, line_no);
|
||||
for(Node!(u8[])* line = lines; line != null; line = line.next)
|
||||
{
|
||||
UIItem* item = Get(line.value);
|
||||
BuildItem(item, UISize(ST.Percentage, 1.0), UISize(ST.Pixels, text_size), UIF.DrawText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EndPanel()
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user