From 9740eee555cac43cc27e08a39a38e09a96ecb002 Mon Sep 17 00:00:00 2001 From: Julian Hurst Date: Mon, 16 May 2022 00:35:21 +0200 Subject: Add layout and a common widget type --- libui/list/list.ha | 245 ----------------------------------------------------- 1 file changed, 245 deletions(-) delete mode 100644 libui/list/list.ha (limited to 'libui/list/list.ha') diff --git a/libui/list/list.ha b/libui/list/list.ha deleted file mode 100644 index 7b181c4..0000000 --- a/libui/list/list.ha +++ /dev/null @@ -1,245 +0,0 @@ -use libui; -use fmt; -use os; -use strings; -use io; -use strio; -use unix::tty; -use regex; -use fnmatch; -use wcwidth; -use set; - -export type listwidget = struct { - ui: libui::ttyui, - items: []str, - marked: set::set, - 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; - -// Create a new list with the given items. -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, - marked = set::set {...}, - cursor = 0z, - listeners = [], - frame = frame { - start = 0u16, - end = rows: u16, - }, - sz = ttysize { - rows = rows: u16, - cols = sz.columns, - }, - }; - return w; -}; - -// Add a listener to the given list. -export fn addlistener(list: *listwidget, l: listener) void = { - append(list.listeners, l); -}; - -// Print the list's items while truncating the items to not be wider than the -// list.sz.cols. -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 + list.sz.rows; - - 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, list.sz.cols); - 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 if (set::contains(list.marked, i) is size){ - strio::concat(&st, "\x1B[46;1m\x1B[30m")?; - strio::concat(&st, truncitem)?; - strio::concat(&st, "\x1B[0m")?; - //libui::print(list.ui, list.items[i]); - } else { - strio::concat(&st, truncitem)?; - }; - strio::concat(&st, "\r\n")?; - }; - let s = strio::string(&st); - defer free(s); - libui::print(list.ui, s); -}; - -// Notify (call) the listwidget's listeners with the listwidget and r as a -// parameter. -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; -}; - -// Move the list's cursor down one item. Returns the new cursor. -export fn down(l: *listwidget) size = { - if (l.cursor < len(l.items) - 1) { - l.cursor += 1; - }; - reframe(l); - return l.cursor; -}; - -// Move the list's cursor up one item. Returns the new cursor. -export fn up(l: *listwidget) size = { - if (l.cursor > 0) { - l.cursor -= 1; - }; - reframe(l); - return l.cursor; -}; - -// Reset the list's frame based on the cursor. Returns whether the frame was -// updated. -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; -}; - -// Move the list's cursor to the top (first item). Returns the new cursor. -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; -}; - -// Move the list's cursor to the bottom (last item). Returns the new 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; -}; - -// Forward search through the list's items for an item containing s. Returns the -// new cursor. -export fn search(l: *listwidget, s: str) size = { - for (let i = l.cursor + 1; i < len(l.items); i += 1) { - if (strings::contains(l.items[i], s)) { - l.cursor = i; - reframe(l); - return l.cursor; - }; - }; - return l.cursor; -}; - -// Backwards search through the list's items for an item containing s. Returns -// the new cursor. -export fn rsearch(l: *listwidget, s: str) size = { - // size wraps to max value for size when < 0 - for (let i = l.cursor: int - 1; i >= 0; i -= 1) { - if (strings::contains(l.items[i], s)) { - l.cursor = i: size; - reframe(l); - return l.cursor; - }; - }; - return l.cursor; -}; - -// Toggles marking the currently selected item. -export fn tmark(l: *listwidget) void = { - if (!set::add(&l.marked, l.cursor)) { - set::del(&l.marked, l.cursor); - }; -}; - -// Clears all marked items. -export fn clearmarked(l: *listwidget) void = { - set::clear(&l.marked); -}; - -// Marks items that contain s (case sensitive). -export fn containsmark(l: *listwidget, s: str) void = { - for (let i = 0z; i < len(l.items); i += 1) { - if (strings::contains(l.items[i], s)) { - set::add(&l.marked, i); - }; - }; -}; - -// Marks items based on fnmatch (globbing). -export fn fnmatchmark(l: *listwidget, s: str) void = { - for (let i = 0z; i < len(l.items); i += 1) { - if (fnmatch::fnmatch(s, l.items[i])) { - set::add(&l.marked, i); - }; - }; -}; - -// Marks items according to a regular expression (POSIX ERE). -export fn regexmark(l: *listwidget, re: *regex::regex) void = { - for (let i = 0z; i < len(l.items); i += 1) { - if (regex::test(re, l.items[i])) { - set::add(&l.marked, i); - }; - }; -}; - -// Returns the selected item or marked items if there are any. -export fn selected(l: listwidget) (str | []str) = { - if (len(l.marked.items) > 0) { - let result: []str = []; - for (let i = 0z; i < len(l.marked.items); i += 1) { - append(result, l.items[l.marked.items[i]]); - }; - return result; - } else { - return l.items[l.cursor]; - }; -}; -- cgit v1.2.3