diff options
| author | Julian Hurst <ark@mansus.space> | 2025-03-22 18:47:17 +0100 |
|---|---|---|
| committer | Julian Hurst <ark@mansus.space> | 2025-03-22 18:47:36 +0100 |
| commit | d531bc786a3da309d10f3bdf62ebebda345e5205 (patch) | |
| tree | 115784b094359369be2dea779cf9b34787477101 /tui/widget/list/list.ha | |
| parent | 4c3c071e7b8f34d3b77a0232ef907350a992a49e (diff) | |
| download | hare-tui-d531bc786a3da309d10f3bdf62ebebda345e5205.tar.gz | |
Remove list.ha and refactor scrolllist
Diffstat (limited to 'tui/widget/list/list.ha')
| -rw-r--r-- | tui/widget/list/list.ha | 180 |
1 files changed, 173 insertions, 7 deletions
diff --git a/tui/widget/list/list.ha b/tui/widget/list/list.ha index cbf83fa..05300ba 100644 --- a/tui/widget/list/list.ha +++ b/tui/widget/list/list.ha @@ -4,6 +4,14 @@ use io; use unix::tty; use memio; use strings; +use fmt; +use strconv; + +export def DEFAULTSTYLE = style { + style = void, + normal = widget::color::DEFAULTFG, + marked = widget::color::BLUEBG, +}; export type frame = struct { start: int, @@ -14,18 +22,30 @@ export type list = struct { widget: widget::widget, items: []str, frame: frame, + cursor: int, + marked: []int, + style: *style, +}; + +export type style = struct { + style: (void | *widget::style), + normal: widget::color, + marked: widget::color, + //normal: (void | widget::color), + //marked: (void | widget::color), }; // Return an instance of list. out is the tty file, pos the starting position, // 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(state: *tui::tui, pos: widget::coords, sz: widget::widgetsize, -style: (*widget::style | void), items: str...) (list | tty::error) = { +style: *style, items: str...) (list | tty::error) = { const tsz = tty::winsize(state.out)?; let end = match (sz) { case let sz: tty::ttysize => - yield if (tsz.rows < sz.rows) tsz.rows - 1 else sz.rows; + const rows = if (tsz.rows < sz.rows) tsz.rows - 1 else sz.rows; + yield rows; case void => yield tsz.rows - 1; }; @@ -43,31 +63,177 @@ style: (*widget::style | void), items: str...) (list | tty::error) = { finish = &finishlist, pos = pos, sz = sz, - style = style, + style = style.style, damage = widget::damageall, ... }, items = items, frame = frame { start = 0, - end = end: int, + end = end, }, + cursor = 0, + marked = [], + style = style, }; }; -export fn printlist(widget: *widget::widget) void = { +fn printlist(widget: *widget::widget) void = { const list = widget: *list; + assert(list.frame.start >= 0); + assert(list.frame.end <= len(list.items): int); list.widget.buf = widget::linesbuf { lines = list.items[list.frame.start..list.frame.end], - styles = null, + styles = &styleslist, }; widget::print(list); }; -export fn resizelist(widget: *widget::widget, ttysize: tty::ttysize) void = { +fn resizelist(widget: *widget::widget, ttysize: tty::ttysize) void = { return; }; fn finishlist(widget: *widget::widget) void = { + const list = widget: *list; widget::finish(widget); + free(list.marked); +}; + +export fn down(li: *list) void = { + if (li.cursor == li.frame.end - 1) { + framedown(li); + }; + if (li.cursor < len(li.items): int - 1) { + li.cursor += 1; + }; +}; + +export fn up(li: *list) void = { + if (li.cursor == li.frame.start) { + frameup(li); + }; + if (li.cursor > 0) { + li.cursor -= 1; + }; +}; + +export fn frameup(li: *list) void = { + if (li.frame.start > 0) { + li.frame.start -= 1; + li.frame.end -= 1; + }; +}; + +export fn framedown(li: *list) void = { + if (li.frame.end < len(li.items): int) { + li.frame.start += 1; + li.frame.end += 1; + }; +}; + +export fn top(li: *list) void = { + const sz = li.frame.end - li.frame.start; + li.cursor = 0; + li.frame.end = sz; + li.frame.start = 0; +}; + +export fn bottom(li: *list) void = { + const sz = li.frame.end - li.frame.start; + li.cursor = len(li.items): int - 1; + li.frame.end = len(li.items): int; + li.frame.start = len(li.items): int - sz; +}; + +export fn setcursor(li: *list, newpos: int) void = { + if (newpos < 0) { + li.cursor = 0; + } else if (newpos > len(li.items): int) { + li.cursor = len(li.items): int - 1; + } else { + li.cursor = newpos; + }; + reframe(li); +}; + +fn reframe(li: *list) void = { + if (li.cursor >= li.frame.end) { + const diff = li.frame.end - li.frame.start; + li.frame.end = li.cursor + 1; + li.frame.start = li.frame.end - diff; + } else if (li.cursor < li.frame.start) { + const diff = li.frame.end - li.frame.start; + li.frame.start = li.cursor; + li.frame.end = li.frame.start + diff; + }; + assert(li.frame.start >= 0); + assert(li.frame.end <= len(li.items): int); +}; + +fn styleslist(widget: *widget::widget, txt: str, idx: size) str = { + const list = widget: *list; + const idx = idx: int + list.frame.start; + let st = memio::dynamic(); + defer io::close(&st)!; + + const normalst = colorordefault(list.style.normal, widget::color::DEFAULTFG); + const markst = colorordefault(list.style.marked, widget::color::BLUEBG); + + //memio::concat(&st, widget::color_to_str(normalst))!; + const normalsts = widget::color_to_str(normalst); + defer free(normalsts); + memio::concat(&st, normalsts)!; + if (idx == list.cursor) { + memio::concat(&st, "\x1B[7m")!; + }; + if (ismarked(*list, idx) is size) { + const s = widget::color_to_str(markst); + defer free(s); + memio::concat(&st, s)!; + }; + memio::concat(&st, txt)!; + memio::concat(&st, "\x1B[0m")!; + //if (idx == list.cursor) { + // memio::concat(&st, "\x1B[27m")!; + //} else if (ismarked(*list, idx) is size) { + //}; + //if (idx == list.cursor) { + // memio::concat(&st, "\x1B[27m")!; + //}; + //if (ismarked(*list, idx) is size) { + // memio::concat(&st, "\x1B[49m")!; + //}; + return strings::dup(memio::string(&st)!); +}; + +fn colorordefault(col: (void | widget::color), d: widget::color) widget::color = { + const c = match (col) { + case let c: widget::color => + yield c; + case void => + yield d; + }; + return c; +}; + +fn ismarked(li: list, j: int) (size | void) = { + for (let i = 0z; i < len(li.marked); i += 1) { + const idx = li.marked[i]; + if (idx == j) { + return i; + }; + }; + return; +}; + +export fn mark(li: *list) bool = { + defer down(li); + match (ismarked(*li, li.cursor)) { + case let s: size => + delete(li.marked[s]); + return false; + case void => + append(li.marked, li.cursor); + return true; + }; }; |
