diff options
Diffstat (limited to 'tui/widget/widget.ha')
| -rw-r--r-- | tui/widget/widget.ha | 151 |
1 files changed, 147 insertions, 4 deletions
diff --git a/tui/widget/widget.ha b/tui/widget/widget.ha index 77b6f88..dbbfa11 100644 --- a/tui/widget/widget.ha +++ b/tui/widget/widget.ha @@ -1,35 +1,178 @@ use fmt; use unix::tty; use io; +use strings; +use memio; +use os; +use strconv; export type coords = (u16, u16); export type printfn = fn(w: *widget) void; export type resizefn = fn(w: *widget, ttysize: tty::ttysize) void; -export type nosize = void; -export type widgetsize = (tty::ttysize | nosize); +export type widgetsize = (tty::ttysize | void); + +export type color = enum uint { + BLACKFG = 30, + REDFG = 31, + GREENFG = 32, + BROWNFG = 33, + BLUEFG = 34, + MAGENTAFG = 35, + CYANFG = 36, + WHITEFG = 37, + DEFAULTFG = 39, + + BLACKBG = 40, + REDBG = 41, + GREENBG = 42, + BROWNBG = 43, + BLUEBG = 44, + MAGENTABG = 45, + CYANBG = 46, + WHITEBG = 47, + DEFAULTBG = 49, +}; export type style = struct { border: bool, + colorfg: color, + colorbg: color, }; export def DEFAULT_STYLE: style = style { border = false, + colorfg = color::DEFAULTFG, + colorbg = color::DEFAULTBG, }; export type widget = struct { out: io::file, print: *printfn, resize: *resizefn, + buf: str, pos: coords, sz: widgetsize, - style: style, + style: (*style | void), }; def gotoroot: str = "\x1B[1;1H"; -export fn print(out: io::file, s: str, pos: coords) void = { +def UNDERLINE: str = "\x1B[4m"; +def NOUNDERLINE: str = "\x1B[0m"; + +def OVERLINE: rune = '\u0305'; +def NOOVERLINE: str = "\x1B[0m"; + +// Must free return value +fn underline(s: str) str = { + return strings::concat(UNDERLINE, s, NOUNDERLINE); +}; + +// Must free return value +fn overline(s: str) str = { + const st = memio::dynamic(); + defer io::close(&st)!; + let iter = strings::iter(s); + for (let r: rune => strings::next(&iter)) { + const char = strings::fromrunes([r, OVERLINE]); + defer free(char); + memio::concat(&st, char)!; + }; + return strings::dup(memio::string(&st)!); +}; + +fn minrows(out: io::file, x: u16, y: widgetsize) (u16 | tty::error) = { + const y = match (y) { + case let y: tty::ttysize => + yield y; + case void => + yield tty::winsize(out)?; + }; + return if (x < y.rows) x else y.rows; +}; + +// Must free return string +fn color_to_str(color: color) str = fmt::asprintf("\x1B[{}m", strconv::utos(color)); + +export fn print(w: *widget) void = { + fmt::fprintf(w.out, "\x1B[{};{}H", w.pos.0, w.pos.1)!; + + let s = truncate_to_size(w); + + let sstyle = match (w.style) { + case let st: *style => + defer free(s); + let sborder = if (st.border) { + yield border(s); + } else { + yield strings::dup(s); + }; + defer free(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); + case void => + yield s; + }; + + defer free(sstyle); + + fmt::fprint(w.out, sstyle)!; +}; + +// 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 = strings::split(w.buf, "\n"); + const st = memio::dynamic(); + defer io::close(&st)!; + for (let i = 0z; i < minrows(w.out, len(spl): u16, w.sz)!; i += 1) { + const line = spl[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; + yield strings::rpad(s, ' ', sz.columns); + case void => + yield strings::dup(line); + }; + defer free(item); + memio::concat(&st, item)!; + if (i < len(spl) - 1) { + memio::concat(&st, "\n")!; + }; + }; + return strings::dup(memio::string(&st)!); +}; + +fn border(s: str) str = { + let st = memio::dynamic(); + defer io::close(&st)!; + let spl = strings::split(s, "\n"); + 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); + }; + if (i == len(spl) - 1) { + s = underline(s); + }; + //memio::concat(&st, "|", s, "|")!; + memio::concat(&st, s)!; + + if (i < len(spl) - 1) { + memio::concat(&st, "\n")!; + }; + }; + return strings::dup(memio::string(&st)!); +}; + +export fn prints(out: io::file, s: str, pos: coords) void = { fmt::fprintf(out, "\x1B[{};{}H", pos.0, pos.1)!; fmt::fprint(out, s)!; }; |
