diff options
| author | Julian Hurst <ark@mansus.space> | 2025-03-17 16:58:07 +0100 |
|---|---|---|
| committer | Julian Hurst <ark@mansus.space> | 2025-03-17 16:58:07 +0100 |
| commit | 0d0186d63712472a037cf510812e68774c73c12f (patch) | |
| tree | 48ec90686ede65cb8a9cb126bdc2cacfd9a202a8 /tui | |
| parent | e074c936bb99ccfce311445f4dbf42ba964b44a4 (diff) | |
| download | hare-tui-0d0186d63712472a037cf510812e68774c73c12f.tar.gz | |
Add initial support for damage tracking
This also fixes a styling issue when the widget styles its own text.
Diffstat (limited to 'tui')
| -rw-r--r-- | tui/layout/layout.ha | 5 | ||||
| -rw-r--r-- | tui/layout/vlayout.ha | 2 | ||||
| -rw-r--r-- | tui/widget/list/list.ha | 6 | ||||
| -rw-r--r-- | tui/widget/text/text.ha | 6 | ||||
| -rw-r--r-- | tui/widget/widget.ha | 76 |
5 files changed, 91 insertions, 4 deletions
diff --git a/tui/layout/layout.ha b/tui/layout/layout.ha index d425891..7a64221 100644 --- a/tui/layout/layout.ha +++ b/tui/layout/layout.ha @@ -10,5 +10,8 @@ export type layout = struct { }; fn finish(l: *layout) void = { - free(l.widgets); + for (let w .. l.widgets) { + w.finish(w); + }; + //free(l.widgets); }; diff --git a/tui/layout/vlayout.ha b/tui/layout/vlayout.ha index 0381a9f..8a6a0a6 100644 --- a/tui/layout/vlayout.ha +++ b/tui/layout/vlayout.ha @@ -20,7 +20,7 @@ fn printvlayout(l: *layout) void = { }; }; -fn finishvlayout(l: *layout) void = { +export fn finishvlayout(l: *layout) void = { let vl = l: *vlayout; finish(&vl.layout); }; diff --git a/tui/widget/list/list.ha b/tui/widget/list/list.ha index ca7571b..d741a4d 100644 --- a/tui/widget/list/list.ha +++ b/tui/widget/list/list.ha @@ -39,9 +39,11 @@ style: (*widget::style | void), items: str...) (list | tty::error) = { state = state, print = &printlist, resize = &resizelist, + finish = &finishlist, pos = pos, sz = sz, style = style, + damage = widget::all, ... }, items = items, @@ -76,3 +78,7 @@ export fn printlist(widget: *widget::widget) void = { export fn resizelist(widget: *widget::widget, ttysize: tty::ttysize) void = { return; }; + +fn finishlist(widget: *widget::widget) void = { + widget::finish(widget); +}; diff --git a/tui/widget/text/text.ha b/tui/widget/text/text.ha index d849661..0a30eb0 100644 --- a/tui/widget/text/text.ha +++ b/tui/widget/text/text.ha @@ -15,9 +15,11 @@ export fn newtext(state: *tui::tui, txt: str, pos: widget::coords, style: (*widg state = state, print = &printtext, resize = &resizetext, + finish = &finishtext, pos = pos, sz = void, style = style, + damage = widget::all, ... }, txt = txt, @@ -38,3 +40,7 @@ fn resizetext(widget: *widget::widget, ttysize: tty::ttysize) void = { export fn settext(text: *text, txt: str) void = { text.txt = txt; }; + +fn finishtext(widget: *widget::widget) void = { + widget::finish(widget); +}; diff --git a/tui/widget/widget.ha b/tui/widget/widget.ha index a56203a..426d844 100644 --- a/tui/widget/widget.ha +++ b/tui/widget/widget.ha @@ -11,17 +11,30 @@ export type coords = (u16, u16); export type printfn = fn(w: *widget) void; export type resizefn = fn(w: *widget, ttysize: tty::ttysize) void; +export type finishfn = fn(w: *widget) void; export type widgetsize = (tty::ttysize | void); +export type none = void; +export type all = void; +export type row = uint; +export type col = uint; + +//export type damageitem = (row | col | coords); +export type damageitem = row; + +export type damage = (none | all | []damageitem); + export type widget = struct { state: *tui::tui, print: *printfn, resize: *resizefn, + finish: *finishfn, buf: str, pos: coords, sz: widgetsize, style: (*style | void), + damage: damage, }; export type color = enum uint { @@ -66,6 +79,9 @@ def NOUNDERLINE: str = "\x1B[0m"; def OVERLINE: rune = '\u0305'; def NOOVERLINE: str = "\x1B[0m"; +def CLEAR: str = "\x1B[2J"; +def CLEARROW: str = "\x1B[2K"; + // Must free return value fn underline(s: str) str = { return strings::concat(UNDERLINE, s, NOUNDERLINE); @@ -76,10 +92,19 @@ fn overline(s: str) str = { const st = memio::dynamic(); defer io::close(&st)!; let iter = strings::iter(s); + let iscolorcode = false; for (let r: rune => strings::next(&iter)) { - const char = strings::fromrunes([r, OVERLINE]); + if (r == '\x1B') { + iscolorcode = true; + }; + const char = if (!iscolorcode) { + yield strings::fromrunes([r, OVERLINE]); + } else { + yield strings::fromrunes([r]); + }; defer free(char); memio::concat(&st, char)!; + if (iscolorcode && r == 'm') iscolorcode = false; }; return strings::dup(memio::string(&st)!); }; @@ -97,21 +122,46 @@ fn minrows(out: io::file, x: u16, y: widgetsize) (u16 | tty::error) = { // Must free return string fn color_to_str(color: color) str = fmt::asprintf("\x1B[{}m", strconv::utos(color)); +fn clearrow(row: uint) str = fmt::asprintf("\x1B[{}d{}", row, CLEARROW); + export fn print(w: *widget) void = { + const clear = match (w.damage) { + case all => + yield strings::dup(CLEAR); + case none => + yield strings::dup(""); + case let dam: []damageitem => + let st = memio::dynamic(); + defer io::close(&st)!; + for (let item: damageitem .. dam) { + memio::concat(&st, clearrow(item))!; + //match (item) { + //case let r: row => + // yield clearrow(r); + ////case let c: col => + ////case let co: coords => + //}; + }; + yield strings::dup(memio::string(&st)!); + }; + defer free(clear); + let s = truncate_to_size(w); defer free(s); let sstyle = applystyles(w.style, s); defer free(sstyle); - const clear = if (w.state.clear) "\x1B[2J" else ""; + //const clear = if (w.state.clear) "\x1B[2J" else ""; let seekpos = fmt::asprintf("{}\x1B[{};{}H", clear, w.pos.0, w.pos.1); defer free(seekpos); const sout = strings::concat(seekpos, sstyle); defer free(sout); fmt::fprint(w.state.out, sout)!; + + w.state.clear = false; }; // Applies styling (style) to the given string @@ -187,3 +237,25 @@ export fn prints(out: io::file, s: str, pos: coords) void = { fmt::fprintf(out, "\x1B[{};{}H", pos.0, pos.1)!; fmt::fprint(out, s)!; }; + +export fn finish(w: *widget) void = { + match (w.damage) { + case let dam: []damageitem => + free(dam); + case all => + return; + case all => + return; + }; +}; + +export fn cleardamage(w: *widget) void = { + let dam = if (w.damage is all) { + return; + } else { + yield w.damage as []damageitem; + }; + for (let i = 0z; i < len(dam); i += 1) { + delete(dam[i]); + }; +}; |
