diff options
Diffstat (limited to 'libui/list/list.ha')
| -rw-r--r-- | libui/list/list.ha | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/libui/list/list.ha b/libui/list/list.ha new file mode 100644 index 0000000..6b11b75 --- /dev/null +++ b/libui/list/list.ha @@ -0,0 +1,155 @@ +use libui; +use fmt; +use os; +use strings; +use io; +use strio; +use unix::tty; +use wcwidth; + +export type listwidget = struct { + ui: libui::ttyui, + items: []str, + cursor: size, + listeners: []listener, + frame: frame, + sz: ttysize, +}; + +export type frame = struct { + start: u16, + // largest value is nb of items + end: u16, +}; + +export type ttysize = struct { + rows: u16, + cols: u16, +}; + +export type listener = *fn(l: *listwidget, r: rune) bool; + +export fn newlist(ui: libui::ttyui, items: str...) listwidget = { + let sz = libui::getwinsize(ui)!; + let rows: (u16 | size) = if (sz.rows - 2 < len(items)) { + yield sz.rows - 2; + } else { + yield len(items); + }; + let w = listwidget { + ui = ui, + items = items, + cursor = 0z, + listeners = [], + frame = frame { + start = 0u16, + end = rows: u16, + }, + sz = ttysize { + rows = rows: u16, + cols = sz.columns, + }, + }; + return w; +}; + +export fn addlistener(list: *listwidget, l: listener) void = { + append(list.listeners, l); +}; + +export fn print(list: *listwidget) (void | io::error | tty::error) = { + let sz = libui::getwinsize(list.ui)?; + let rows: (u16 | size) = if (sz.rows - 2 < len(list.items)) { + yield sz.rows - 2; + } else { + yield len(list.items); + }; + + //fmt::fprintln(os::stderr, rows)!; + + list.frame.end = list.frame.start + rows: u16; + + let st = strio::dynamic(); + strio::concat(&st, "\r")?; + for (let i = list.frame.start; i < list.frame.end: u16; i += 1) { + let item = list.items[i]; + let truncitem = wcwidth::truncate(item, sz.columns); + if (list.cursor == i) { + strio::concat(&st, "\x1B[104;1m\x1B[30m")?; + strio::concat(&st, truncitem)?; + strio::concat(&st, "\x1B[0m")?; + //libui::print(list.ui, strings::concat("\x1B[31;1m> ", list.items[i], "\x1B[0m")); + } else { + strio::concat(&st, truncitem)?; + //libui::print(list.ui, list.items[i]); + }; + strio::concat(&st, "\r\n")?; + }; + let s = strio::string(&st); + defer free(s); + libui::print(list.ui, s); +}; + +export fn notify(l: *listwidget, r: rune) bool = { + for (let i = 0z; i < len(l.listeners); i += 1) { + if (l.listeners[i](l, r)) { + return true; + }; + }; + return false; +}; + +export fn down(l: *listwidget) size = { + if (l.cursor < len(l.items) - 1) { + l.cursor += 1; + }; + reframe(l); + return l.cursor; +}; + +export fn up(l: *listwidget) size = { + if (l.cursor > 0) { + l.cursor -= 1; + }; + reframe(l); + return l.cursor; +}; + +fn reframe(l: *listwidget) bool = { + let reframed: bool = false; + if (l.cursor < l.frame.start) { + l.frame.end -= l.frame.start - l.cursor: u16; + l.frame.start = l.cursor: u16; + reframed = true; + }; + if (l.cursor >= l.frame.end) { + l.frame.start += l.cursor: u16 - l.frame.end + 1; + l.frame.end = l.cursor: u16; + reframed = true; + }; + return reframed; +}; + +export fn top(l: *listwidget) size = { + l.cursor = 0; + l.frame.start = 0; + l.frame.end = l.frame.start + l.sz.rows; + return l.cursor; +}; + +export fn bottom(l: *listwidget) size = { + l.cursor = len(l.items) - 1; + l.frame.end = len(l.items): u16; + l.frame.start = l.frame.end - l.sz.rows; + return l.cursor; +}; + +export fn search(l: *listwidget, s: str) size = { + for (let i = 0z; i < len(l.items); i += 1) { + if (strings::contains(l.items[i], s)) { + l.cursor = i; + reframe(l); + }; + }; + return l.cursor; +}; |
