mirror of
https://github.com/rr-/pq-cli.git
synced 2026-11-12 22:40:36 -07:00
ty reported 20 diagnostics, and 0.0.89 adds a few more; this clears them all without suppressions. - The quest monster is held in a local before being stored on the quest book, so its name no longer reads from an Optional. - PgUp/PgDn narrow the focused window with isinstance against a runtime-checkable PageScrollable protocol instead of hasattr. - The ^t cheat used to monkeypatch SignalMixin.emit. SignalMixin now has a muted() context manager that emit() checks, and it restores emission even if a tick raises. - GameView keeps its children as GameWindow, a protocol declaring stop() and sync(), so the cheat's resync type-checks. - curses.ascii is imported explicitly where it is used. - ProgressBarWindow is now Focusable itself, instead of calling Focusable.focus_standout() on a class that is not Focusable. Its four subclasses drop the duplicate Focusable base; the MRO and initialisation order are unchanged. - MainMenu narrows the Optional pad before colouring the logo. - The tests that record tasks assert player.task is set. - Context managers are annotated as Generator rather than Iterator, which ty flags as deprecated for @contextmanager. - The redundant cast() around getch() is gone. - The frozen GameData test assigns through setattr(), since the direct assignment is an error by design. Bug fixes: - ListBox.select(None) crashed on `None < 0`; it now clears the selection, as DataTable.select(None) already does. - ListBox.get() caught ValueError, which indexing never raises; it now catches IndexError, so an out-of-range index returns None as intended.
51 lines
1.5 KiB
Python
51 lines
1.5 KiB
Python
import curses
|
|
from typing import Any
|
|
|
|
from pqcli.ui.curses.colors import COLOR_HIGHLIGHT, has_colors
|
|
|
|
from .scrollable import Scrollable
|
|
|
|
|
|
class ListBox(Scrollable):
|
|
_items: list[str]
|
|
|
|
def __init__(self, parent: Any, h: int, w: int, y: int, x: int) -> None:
|
|
super().__init__(parent, h, w, y, x)
|
|
self._selected: int | None = None
|
|
|
|
def add(self, text: str) -> None:
|
|
self._items.append(text)
|
|
self.scroll_to_item(-1)
|
|
|
|
def set(self, idx: int, value: str) -> None:
|
|
if idx < 0:
|
|
idx %= len(self._items)
|
|
self._items[idx] = value
|
|
|
|
def get(self, idx: int) -> str | None:
|
|
if not self._items:
|
|
return None
|
|
if idx < 0:
|
|
idx %= len(self._items)
|
|
try:
|
|
return self._items[idx]
|
|
except IndexError:
|
|
return None
|
|
|
|
def delete(self, idx: int, count: int = 1) -> None:
|
|
del self._items[idx : idx + count]
|
|
|
|
def select(self, idx: int | None) -> None:
|
|
if idx is not None and idx < 0 and self._items:
|
|
idx %= len(self._items)
|
|
self._selected = idx
|
|
|
|
def _render_impl(self, h: int, w: int) -> None:
|
|
assert self._pad
|
|
for y, item in enumerate(self._items):
|
|
if y == self._selected and has_colors():
|
|
self._pad.attron(curses.color_pair(COLOR_HIGHLIGHT))
|
|
self._pad.addnstr(y, 0, item, min(len(item), w))
|
|
if y == self._selected and has_colors():
|
|
self._pad.attroff(curses.color_pair(COLOR_HIGHLIGHT))
|