From e3ffe51979f0ad9c24719ef5b94f066fa6810e31 Mon Sep 17 00:00:00 2001 From: rr- Date: Fri, 4 Jan 2019 16:59:24 +0100 Subject: [PATCH] ui/curses: let user scroll game view windows --- pqcli/ui/curses/views/game_view/__init__.py | 10 ++++++- .../views/game_view/inventory_window.py | 8 +++++ .../ui/curses/views/game_view/plot_window.py | 8 +++++ .../views/game_view/quest_book_window.py | 8 +++++ .../views/game_view/spell_book_window.py | 8 +++++ pqcli/ui/curses/widgets/__init__.py | 1 + pqcli/ui/curses/widgets/scrollable.py | 30 ++++++++++++++----- 7 files changed, 64 insertions(+), 9 deletions(-) diff --git a/pqcli/ui/curses/views/game_view/__init__.py b/pqcli/ui/curses/views/game_view/__init__.py index 3ee744c..97f7d9d 100644 --- a/pqcli/ui/curses/views/game_view/__init__.py +++ b/pqcli/ui/curses/views/game_view/__init__.py @@ -7,7 +7,7 @@ from pqcli.mechanic import Player, Simulation from pqcli.roster import Roster from pqcli.ui.curses.event_handler import EventHandler from pqcli.ui.curses.util import KEYS_DOWN, KEYS_LEFT, KEYS_RIGHT, KEYS_UP -from pqcli.ui.curses.widgets import Widget +from pqcli.ui.curses.widgets import Scrollable, Widget from ..base_view import BaseView from .character_sheet_window import CharacterSheetWindow @@ -43,6 +43,14 @@ class GameView(BaseView): if key in map(ord, "qQ"): self.on_exit() + elif key in {curses.KEY_PPAGE}: + if hasattr(focused, "scroll_page_up"): + focused.scroll_page_up() + + elif key in {curses.KEY_NPAGE}: + if hasattr(focused, "scroll_page_down"): + focused.scroll_page_down() + elif key in KEYS_DOWN: if focused == self._char_sheet_win: self.focus(self._spell_book_win) diff --git a/pqcli/ui/curses/views/game_view/inventory_window.py b/pqcli/ui/curses/views/game_view/inventory_window.py index a315b31..86d128b 100644 --- a/pqcli/ui/curses/views/game_view/inventory_window.py +++ b/pqcli/ui/curses/views/game_view/inventory_window.py @@ -51,6 +51,14 @@ class InventoryWindow(Focusable, DataTableProgressBarWindow): "change", self._sync_encumbrance ) + def scroll_page_up(self) -> None: + self._data_table.scroll_page_up() + self._render() + + def scroll_page_down(self) -> None: + self._data_table.scroll_page_down() + self._render() + def _sync(self) -> None: self._sync_gold() self._sync_items() diff --git a/pqcli/ui/curses/views/game_view/plot_window.py b/pqcli/ui/curses/views/game_view/plot_window.py index 9cb591b..fc54439 100644 --- a/pqcli/ui/curses/views/game_view/plot_window.py +++ b/pqcli/ui/curses/views/game_view/plot_window.py @@ -34,6 +34,14 @@ class PlotWindow(Focusable, ListBoxProgressBarWindow): "change", self._sync_position ) + def scroll_page_up(self) -> None: + self._list_box.scroll_page_up() + self._render() + + def scroll_page_down(self) -> None: + self._list_box.scroll_page_down() + self._render() + def _sync(self) -> None: self._sync_acts() self._sync_position() diff --git a/pqcli/ui/curses/views/game_view/quest_book_window.py b/pqcli/ui/curses/views/game_view/quest_book_window.py index 69d125c..df93e99 100644 --- a/pqcli/ui/curses/views/game_view/quest_book_window.py +++ b/pqcli/ui/curses/views/game_view/quest_book_window.py @@ -33,6 +33,14 @@ class QuestBookWindow(Focusable, ListBoxProgressBarWindow): "change", self._sync_position ) + def scroll_page_up(self) -> None: + self._list_box.scroll_page_up() + self._render() + + def scroll_page_down(self) -> None: + self._list_box.scroll_page_down() + self._render() + def _sync(self) -> None: self._sync_quests() self._sync_position() diff --git a/pqcli/ui/curses/views/game_view/spell_book_window.py b/pqcli/ui/curses/views/game_view/spell_book_window.py index 4237ee0..8146063 100644 --- a/pqcli/ui/curses/views/game_view/spell_book_window.py +++ b/pqcli/ui/curses/views/game_view/spell_book_window.py @@ -31,6 +31,14 @@ class SpellBookWindow(Focusable, WindowWrapper): self._player.spell_book.disconnect("add", self._sync_spell_add) self._player.spell_book.disconnect("change", self._sync_spell_change) + def scroll_page_up(self) -> None: + self._data_table.scroll_page_up() + self._render() + + def scroll_page_down(self) -> None: + self._data_table.scroll_page_down() + self._render() + def _sync(self) -> None: self._data_table.clear() for spell in self._player.spell_book: diff --git a/pqcli/ui/curses/widgets/__init__.py b/pqcli/ui/curses/widgets/__init__.py index f2c86f1..ed56237 100644 --- a/pqcli/ui/curses/widgets/__init__.py +++ b/pqcli/ui/curses/widgets/__init__.py @@ -4,3 +4,4 @@ from .label import Label from .list_box import ListBox from .menu import Menu from .progress_bar import ProgressBar +from .scrollable import Scrollable diff --git a/pqcli/ui/curses/widgets/scrollable.py b/pqcli/ui/curses/widgets/scrollable.py index 2305966..3057cf0 100644 --- a/pqcli/ui/curses/widgets/scrollable.py +++ b/pqcli/ui/curses/widgets/scrollable.py @@ -7,7 +7,7 @@ from .base import WindowWrapper class Scrollable(WindowWrapper): 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._scroll_pos = 0 self._pad: T.Optional[T.Any] = curses.newpad(1, 1) self._items: T.List[T.Any] = [] @@ -15,13 +15,27 @@ class Scrollable(WindowWrapper): self._items = [] self.scroll_to_item(0) + def scroll_page_up(self) -> None: + self.scroll_to_item(max(0, self._scroll_pos - self.getmaxyx()[0])) + + def scroll_page_down(self) -> None: + self.scroll_to_item( + min( + len(self._items) - 1, + self._scroll_pos + self.getmaxyx()[0] * 2 - 1, + ) + ) + def scroll_to_item(self, y: int) -> None: if not self._items or not self._win: return if y < 0: y %= len(self._items) - while not (self._scroll_y <= y < self._scroll_y + self.getmaxyx()[0]): - self._scroll_y += 1 if self._scroll_y < y else -1 + + h = self.getmaxyx()[0] + delta = 1 if self._scroll_pos < y else -1 + while not self._scroll_pos <= y < self._scroll_pos + h: + self._scroll_pos += delta def stop(self) -> None: super().stop() @@ -50,9 +64,9 @@ class Scrollable(WindowWrapper): y, x = self.getbegyx() try: - if self._scroll_y > 0 or self._scroll_y + h < len(self._items): - y1 = self._scroll_y - y2 = self._scroll_y + h + if self._scroll_pos > 0 or self._scroll_pos + h < len(self._items): + y1 = self._scroll_pos + y2 = self._scroll_pos + h thumb_y1 = int(y1 * h // len(self._items)) thumb_y2 = int(y2 * h // len(self._items)) for win_y in range(h): @@ -67,12 +81,12 @@ class Scrollable(WindowWrapper): self._render_impl(h, w - 1) self._pad.noutrefresh( - self._scroll_y, 0, y, x, y + h - 1, x + w - 2 + self._scroll_pos, 0, y, x, y + h - 1, x + w - 2 ) else: self._render_impl(h, w) self._pad.noutrefresh( - self._scroll_y, 0, y, x, y + h - 1, x + w - 1 + self._scroll_pos, 0, y, x, y + h - 1, x + w - 1 ) except curses.error: