summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--cmd/list.ha6
-rw-r--r--cmd/list_nostyle.ha16
-rw-r--r--cmd/list_strictsz.ha10
-rw-r--r--cmd/text.ha36
-rw-r--r--tui/widget/list/list.ha27
-rw-r--r--tui/widget/text/text.ha11
-rw-r--r--tui/widget/widget.ha151
8 files changed, 234 insertions, 24 deletions
diff --git a/.gitignore b/.gitignore
index 7b990ab..bed6140 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
/text
/list
/list_strictsz
+/list_nostyle
diff --git a/cmd/list.ha b/cmd/list.ha
index 8729dd9..0148adb 100644
--- a/cmd/list.ha
+++ b/cmd/list.ha
@@ -10,7 +10,11 @@ use time;
export fn main() void = {
const out = tui::init()!;
defer io::close(out)!;
- let li = list::newlist(out, (1, 1), widget::nosize, "hello", "world")!;
+ let li = list::newlist(out, (1, 1), void, &widget::style {
+ border = true,
+ colorfg = widget::color::REDFG,
+ colorbg = widget::color::REDBG,
+ },"hello", "world", "bye", "world")!;
let l = layout::newvlayout(&li);
l.layout.print(&l);
};
diff --git a/cmd/list_nostyle.ha b/cmd/list_nostyle.ha
new file mode 100644
index 0000000..4e77955
--- /dev/null
+++ b/cmd/list_nostyle.ha
@@ -0,0 +1,16 @@
+use tui;
+use tui::layout;
+use tui::widget;
+use tui::widget::list;
+use unix::tty;
+use io;
+use fmt;
+use time;
+
+export fn main() void = {
+ const out = tui::init()!;
+ defer io::close(out)!;
+ let li = list::newlist(out, (1, 1), void, void,"hello", "world", "bye", "world")!;
+ let l = layout::newvlayout(&li);
+ l.layout.print(&l);
+};
diff --git a/cmd/list_strictsz.ha b/cmd/list_strictsz.ha
index 1a7ea1c..13c2808 100644
--- a/cmd/list_strictsz.ha
+++ b/cmd/list_strictsz.ha
@@ -11,9 +11,13 @@ export fn main() void = {
const out = tui::init()!;
defer io::close(out)!;
let li = list::newlist(out, (1, 1), tty::ttysize {
- rows = 2,
- columns = 2,
- }, "hello", "world")!;
+ rows = 3,
+ columns = 4,
+ }, &widget::style {
+ border = true,
+ colorfg = widget::color::BLUEFG,
+ colorbg = widget::color::BLUEBG,
+ }, "hello", "world", "bye", "world")!;
let l = layout::newvlayout(&li);
l.layout.print(&l);
};
diff --git a/cmd/text.ha b/cmd/text.ha
index 6e6e102..3ec0f2a 100644
--- a/cmd/text.ha
+++ b/cmd/text.ha
@@ -1,5 +1,6 @@
use tui;
use tui::layout;
+use tui::widget;
use tui::widget::text;
use io;
use fmt;
@@ -8,10 +9,41 @@ use time;
export fn main() void = {
const out = tui::init()!;
defer io::close(out)!;
- let txt = text::newtext(out, "hello world", (50, 20));
+ let txt = text::newtext(out, "hello world", (50, 20), &widget::style {
+ border = true,
+ colorfg = widget::color::REDFG,
+ colorbg = widget::color::REDBG,
+ });
let l = layout::newvlayout(&txt);
l.layout.print(&l);
- time::sleep(5 * time::SECOND);
+
+ time::sleep(1 * time::SECOND);
+ let st = txt.widget.style as *widget::style;
+ st.colorfg = widget::color::GREENFG;
text::settext(&txt, "bye world");
l.layout.print(&l);
+
+ time::sleep(1 * time::SECOND);
+ st.colorfg = widget::color::BROWNFG;
+ l.layout.print(&l);
+
+ time::sleep(1 * time::SECOND);
+ st.colorfg = widget::color::BLUEFG;
+ l.layout.print(&l);
+
+ time::sleep(1 * time::SECOND);
+ st.colorfg = widget::color::MAGENTAFG;
+ l.layout.print(&l);
+
+ time::sleep(1 * time::SECOND);
+ st.colorfg = widget::color::CYANFG;
+ l.layout.print(&l);
+
+ time::sleep(1 * time::SECOND);
+ st.colorfg = widget::color::WHITEFG;
+ l.layout.print(&l);
+
+ time::sleep(1 * time::SECOND);
+ st.colorfg = widget::color::DEFAULTFG;
+ l.layout.print(&l);
};
diff --git a/tui/widget/list/list.ha b/tui/widget/list/list.ha
index 7e60299..50fb8df 100644
--- a/tui/widget/list/list.ha
+++ b/tui/widget/list/list.ha
@@ -16,15 +16,16 @@ export type list = struct {
};
// Return an instance of list. out is the tty file, pos the starting position,
-// sz is the size of the widget (if [[widget::nosize]] is used, the maximum possible
+// sz is the size of the widget (if void is used, the maximum possible
// size is used), items is the slice of items of the list.
-export fn newlist(out: io::file, pos: widget::coords, sz: widget::widgetsize, items: str...) (list | tty::error) = {
+export fn newlist(out: io::file, pos: widget::coords, sz: widget::widgetsize,
+style: (*widget::style | void), items: str...) (list | tty::error) = {
const tsz = tty::winsize(out)?;
let end = match (sz) {
case let sz: tty::ttysize =>
yield if (tsz.rows < sz.rows) tsz.rows else sz.rows;
- case widget::nosize =>
+ case void =>
yield tsz.rows;
};
@@ -39,6 +40,8 @@ export fn newlist(out: io::file, pos: widget::coords, sz: widget::widgetsize, it
resize = &resizelist,
pos = pos,
sz = sz,
+ style = style,
+ ...
},
items = items,
frame = frame {
@@ -53,18 +56,20 @@ export fn printlist(widget: *widget::widget) void = {
let st = memio::dynamic();
defer io::close(&st)!;
for (let i = list.frame.start; i < list.frame.end; i += 1) {
- let item = match (list.widget.sz) {
- case let sz: tty::ttysize =>
- yield strings::sub(list.items[i], 0z, sz.columns);
- case widget::nosize =>
- yield list.items[i];
- };
- memio::concat(&st, item)!;
+ //let item = match (list.widget.sz) {
+ //case let sz: tty::ttysize =>
+ // yield strings::sub(list.items[i], 0z, sz.columns);
+ //case widget::nosize =>
+ // yield list.items[i];
+ //};
+ //memio::concat(&st, item)!;
+ memio::concat(&st, list.items[i])!;
if (i != list.frame.end - 1) {
memio::concat(&st, "\n")!;
};
};
- widget::print(list.widget.out, memio::string(&st)!, (1, 1));
+ list.widget.buf = memio::string(&st)!;
+ widget::print(list);
};
export fn resizelist(widget: *widget::widget, ttysize: tty::ttysize) void = {
diff --git a/tui/widget/text/text.ha b/tui/widget/text/text.ha
index 5cd8da7..ecb5c2c 100644
--- a/tui/widget/text/text.ha
+++ b/tui/widget/text/text.ha
@@ -1,20 +1,23 @@
use io;
use unix::tty;
use tui::widget;
+use strings;
export type text = struct {
widget: widget::widget,
txt: str,
};
-export fn newtext(out: io::file, txt: str, pos: widget::coords) text = {
+export fn newtext(out: io::file, txt: str, pos: widget::coords, style: (*widget::style | void)) text = {
return text {
widget = widget::widget {
out = out,
print = &printtext,
resize = &resizetext,
pos = pos,
- sz = widget::nosize,
+ sz = void,
+ style = style,
+ ...
},
txt = txt,
};
@@ -22,7 +25,9 @@ export fn newtext(out: io::file, txt: str, pos: widget::coords) text = {
fn printtext(widget: *widget::widget) void = {
const widget = widget: *text;
- widget::print(widget.widget.out, widget.txt, widget.widget.pos);
+ widget.widget.buf = strings::dup(widget.txt);
+ defer free(widget.widget.buf);
+ widget::print(widget);
};
fn resizetext(widget: *widget::widget, ttysize: tty::ttysize) void = {
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)!;
};