From 871144bf0c5ea4093f473b0d32a6ea4c09bb85b2 Mon Sep 17 00:00:00 2001 From: rr- Date: Thu, 3 Jan 2019 23:23:47 +0100 Subject: [PATCH] ui/curses: add scrollbars --- pqcli/ui/curses/widgets/data_table.py | 6 +----- pqcli/ui/curses/widgets/list_box.py | 6 +----- pqcli/ui/curses/widgets/scrollable.py | 29 +++++++++++++++++++++++---- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/pqcli/ui/curses/widgets/data_table.py b/pqcli/ui/curses/widgets/data_table.py index 31b06be..f2ee2cc 100644 --- a/pqcli/ui/curses/widgets/data_table.py +++ b/pqcli/ui/curses/widgets/data_table.py @@ -44,9 +44,8 @@ class DataTable(Scrollable): return idx return None - def _render_impl(self) -> None: + def _render_impl(self, h: int, w: int) -> None: assert self._pad - h, w = self.getmaxyx() if self._align_right: for y, row in enumerate(self._items): self._pad.move(y, 0) @@ -64,8 +63,5 @@ class DataTable(Scrollable): y, col2_x, row[1], min(len(row[1]), w - col2_x) ) - y, x = self.getbegyx() - self._pad.refresh(self._scroll_y, 0, y, x, y + h - 1, x + w - 1) - def _get_col_width(self, x: int) -> int: return max([len(row[0]) for row in self._items] + [0]) diff --git a/pqcli/ui/curses/widgets/list_box.py b/pqcli/ui/curses/widgets/list_box.py index 3abfe33..a757d73 100644 --- a/pqcli/ui/curses/widgets/list_box.py +++ b/pqcli/ui/curses/widgets/list_box.py @@ -30,11 +30,7 @@ class ListBox(Scrollable): def delete(self, idx: int, count: int = 1) -> None: del self._items[idx : idx + count] - def _render_impl(self) -> None: + def _render_impl(self, h: int, w: int) -> None: assert self._pad - h, w = self.getmaxyx() for y, item in enumerate(self._items): self._pad.addnstr(y, 0, item, min(len(item), w)) - - y, x = self.getbegyx() - self._pad.refresh(self._scroll_y, 0, y, x, y + h - 1, x + w - 1) diff --git a/pqcli/ui/curses/widgets/scrollable.py b/pqcli/ui/curses/widgets/scrollable.py index f37652b..e833fd0 100644 --- a/pqcli/ui/curses/widgets/scrollable.py +++ b/pqcli/ui/curses/widgets/scrollable.py @@ -5,8 +5,8 @@ from .base import WindowWrapper class Scrollable(WindowWrapper): - def __init__(self, *args: T.Any, **kwargs: T.Any) -> None: - super().__init__(*args, **kwargs) + def __init__(self, parent: T.Any, h: int, w: int, y: int, x: int) -> None: + super().__init__(parent, h, w, y, x) self._scroll_y = 0 self._pad: T.Optional[T.Any] = curses.newpad(1, 1) self._items: T.List[T.Any] = [] @@ -32,7 +32,7 @@ class Scrollable(WindowWrapper): return len(self._items) def render(self) -> None: - if not self._pad: + if not self._pad or not self._win: return if self._items: @@ -43,8 +43,29 @@ class Scrollable(WindowWrapper): self._pad.resize(1, 1) self._pad.erase() + h, w = self.getmaxyx() + y, x = self.getbegyx() + try: - self._render_impl() + if self._scroll_y > 0 or self._scroll_y + h < len(self._items): + y1 = self._scroll_y + y2 = self._scroll_y + h + win_y1 = int(y1 * h // len(self._items)) + win_y2 = int(y2 * h // len(self._items)) + for win_y in range(win_y1, win_y2): + self._win.chgat(win_y, 0, curses.A_REVERSE) + self._win.refresh() + + self._render_impl(h, w - 1) + self._pad.refresh( + self._scroll_y, 0, y, x, y + h - 1, x + w - 2 + ) + else: + self._render_impl(h, w) + self._pad.refresh( + self._scroll_y, 0, y, x, y + h - 1, x + w - 1 + ) + except curses.error: pass