summaryrefslogtreecommitdiff
path: root/tui/widget/widget.ha
diff options
context:
space:
mode:
authorJulian Hurst <ark@mansus.space>2025-03-19 23:53:56 +0100
committerJulian Hurst <ark@mansus.space>2025-03-19 23:53:58 +0100
commit05794aae570fd3c2f6ed27937b785f3d086f57f4 (patch)
treedaadef54404131604bbda28cfa315f2d8eb5e522 /tui/widget/widget.ha
parent0d8f330ccf366a2733bb6d5d1e51eef3579f04aa (diff)
downloadhare-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.ha114
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 = {