diff options
| author | Julian Hurst <ark@mansus.space> | 2025-03-19 23:53:56 +0100 |
|---|---|---|
| committer | Julian Hurst <ark@mansus.space> | 2025-03-19 23:53:58 +0100 |
| commit | 05794aae570fd3c2f6ed27937b785f3d086f57f4 (patch) | |
| tree | daadef54404131604bbda28cfa315f2d8eb5e522 /tui/widget/widget.ha | |
| parent | 0d8f330ccf366a2733bb6d5d1e51eef3579f04aa (diff) | |
| download | hare-tui-05794aae570fd3c2f6ed27937b785f3d086f57f4.tar.gz | |
Replace widget buf string with linesbuf
This allows the generic widget print code to iterate more easily on the
lines and to apply widget-specific styles without breaking them by
truncating the console codes.
Diffstat (limited to 'tui/widget/widget.ha')
| -rw-r--r-- | tui/widget/widget.ha | 114 |
1 files changed, 71 insertions, 43 deletions
diff --git a/tui/widget/widget.ha b/tui/widget/widget.ha index 8422932..eadc773 100644 --- a/tui/widget/widget.ha +++ b/tui/widget/widget.ha @@ -25,12 +25,23 @@ export type damageitem = damagerow; export type damage = (damagenone | damageall | []damageitem); +export type stylesfn = fn(w: *widget, txt: str, idx: size) str; + +//export type line = struct { +// txt: str, +//}; + +export type linesbuf = struct { + lines: []str, + styles: nullable *stylesfn, +}; + export type widget = struct { state: *tui::tui, print: *printfn, resize: *resizefn, finish: *finishfn, - buf: str, + buf: linesbuf, pos: coords, sz: widgetsize, style: (*style | void), @@ -153,15 +164,33 @@ export fn print(w: *widget) void = { defer free(clear); let s = truncate_to_size(w); - defer free(s); + defer strings::freeall(s); let sstyle = applystyles(w.style, s); - defer free(sstyle); + defer strings::freeall(sstyle); //const clear = if (w.state.clear) "\x1B[2J" else ""; + + let st = memio::dynamic(); + defer io::close(&st)!; + + for(let i = 0z; i < len(sstyle); i += 1) { + const line = match (w.buf.styles) { + case let f: *stylesfn => + yield f(w, sstyle[i], i); + case null => + yield strings::dup(sstyle[i]); + }; + defer free(line); + memio::concat(&st, line, NEWLINE)!; + }; + + const joined = memio::string(&st)!; + let seekpos = fmt::asprintf("{}\x1B[{};{}H", clear, w.pos.0, w.pos.1); defer free(seekpos); - const sout = strings::concat(seekpos, sstyle); + + const sout = strings::concat(seekpos, joined); defer free(sout); fmt::fprint(w.state.out, sout)!; @@ -169,36 +198,40 @@ export fn print(w: *widget) void = { w.state.clear = false; }; -// Applies styling (style) to the given string -fn applystyles(st: (*style | void), s: str) str = { +// Applies styling (style) to the given string. +fn applystyles(st: (*style | void), s: []str) []str = { return match (st) { case let st: *style => let sborder = if (st.border) { yield border(s); } else { - yield strings::dup(s); + yield strings::dupall(s); }; - defer free(sborder); + //defer strings::freeall(sborder); const scolor = color_to_str(st.colorfg); defer free(scolor); const defcolor = color_to_str(color::DEFAULTFG); defer free(defcolor); - yield strings::concat(scolor, sborder, defcolor); + const sb = strings::concat(scolor, sborder[0]); + free(sborder[0]); + sborder[0] = sb; + const endidx = len(sborder) - 1; + const sb = strings::concat(sborder[endidx], defcolor); + free(sborder[endidx]); + sborder[endidx] = sb; + yield sborder; case void => - yield strings::dup(s); + yield strings::dupall(s); }; }; // Truncates the text of the widget to the widget's size (rows and columns) and -// returns the resulting string. -fn truncate_to_size(w: *widget) str = { - let spl = splitstr(w.buf, NEWLINE); - defer free(spl); - const st = memio::dynamic(); - defer io::close(&st)!; - const nbrows = minrows(w.state.out, len(spl): u16, w.sz)!; +// returns the resulting lines. Must call [[strings::freeall]] on the result. +fn truncate_to_size(w: *widget) []str = { + let lines: []str = []; + const nbrows = minrows(w.state.out, len(w.buf.lines): u16, w.sz)!; for (let i = 0z; i < nbrows; i += 1) { - const line = spl[i]; + const line = w.buf.lines[i]; let item = match (w.sz) { case let sz: tty::ttysize => const s = if (len(line) > sz.columns) strings::sub(line, 0z, sz.columns) else line; @@ -206,39 +239,34 @@ fn truncate_to_size(w: *widget) str = { case void => yield strings::dup(line); }; + append(lines, item); //fmt::println(item)!; - defer free(item); - memio::concat(&st, item)!; - memio::concat(&st, NEWLINE)!; }; - return strings::dup(memio::string(&st)!); + return lines; }; -// Add a border around a string -fn border(s: str) str = { - let st = memio::dynamic(); - defer io::close(&st)!; - //let spl = strings::split(s, NEWLINE); - let spl = splitstr(s, NEWLINE); - defer free(spl); - for (let i = 0z; i < len(spl); i += 1) { - const s = strings::concat("|", spl[i], "|"); - //const s = strings::dup(spl[i]); - defer free(s); - if (i == 0) { - s = overline(s); +// Add a border around a slice of strings. Must call [[strings::freeall]] on the +// result. +fn border(s: []str) []str = { + let lines: []str = []; + for (let i = 0z; i < len(s); i += 1) { + const si = strings::concat("|", s[i], "|"); + si = if (i == 0) { + defer free(si); + yield overline(si); + } else { + yield si; }; - if (i == len(spl) - 1) { - s = underline(s); + si = if (i == len(s) - 1) { + defer free(si); + yield underline(si); + } else { + yield si; }; - //memio::concat(&st, "|", s, "|")!; - memio::concat(&st, s)!; - if (i < len(spl) - 1) { - memio::concat(&st, NEWLINE)!; - }; + append(lines, si); }; - return strings::dup(memio::string(&st)!); + return lines; }; export fn prints(out: io::file, s: str, pos: coords) void = { |
