ui/curses: implement game view widget focusing

This commit is contained in:
rr-
2019-01-04 00:22:29 +01:00
parent 4230c57e73
commit 9db61f7191
11 changed files with 204 additions and 67 deletions
+63 -7
View File
@@ -6,6 +6,7 @@ import typing as T
from pqcli.mechanic import Player, Simulation
from pqcli.roster import Roster
from pqcli.ui.curses.event_handler import EventHandler
from pqcli.ui.curses.widgets import Widget
from ..base_view import BaseView
from .character_sheet_window import CharacterSheetWindow
@@ -36,8 +37,47 @@ class GameView(BaseView):
self._last_tick = datetime.datetime.now()
def keypress(self, key: int) -> None:
focused = self.focused
if key in map(ord, "qQ"):
self.on_exit()
elif key in map(ord, "jJ"):
if focused == self._char_sheet_win:
self.focus(self._spell_book_win)
elif focused == self._equipment_win:
self.focus(self._inventory_win)
elif focused == self._plot_win:
self.focus(self._quest_book_win)
elif key in map(ord, "kK"):
if focused == self._spell_book_win:
self.focus(self._char_sheet_win)
elif focused == self._inventory_win:
self.focus(self._equipment_win)
elif focused == self._quest_book_win:
self.focus(self._plot_win)
elif key in map(ord, "hH"):
if focused == self._equipment_win:
self.focus(self._char_sheet_win)
elif focused == self._inventory_win:
self.focus(self._spell_book_win)
elif focused == self._plot_win:
self.focus(self._equipment_win)
elif focused == self._quest_book_win:
self.focus(self._inventory_win)
elif key in map(ord, "lL"):
if focused == self._char_sheet_win:
self.focus(self._equipment_win)
elif focused == self._spell_book_win:
self.focus(self._inventory_win)
elif focused == self._equipment_win:
self.focus(self._plot_win)
elif focused == self._inventory_win:
self.focus(self._quest_book_win)
else:
super().keypress(key)
@@ -135,14 +175,19 @@ class GameView(BaseView):
x=0,
)
self._children: T.List[Widget] = [
self._char_sheet_win,
self._spell_book_win,
self._equipment_win,
self._inventory_win,
self._plot_win,
self._quest_book_win,
self._task_win,
]
def stop(self) -> None:
self._char_sheet_win.stop()
self._spell_book_win.stop()
self._equipment_win.stop()
self._inventory_win.stop()
self._plot_win.stop()
self._quest_book_win.stop()
self._task_win.stop()
for child in self._children:
child.stop()
del self._col1_win
del self._col2_win
del self._col3_win
@@ -154,3 +199,14 @@ class GameView(BaseView):
self._last_tick = datetime.datetime.now()
if self._args.use_saves:
self._roster.save_periodically()
@property
def focused(self) -> Widget:
for widget in self._children:
if widget.focused:
return widget
return None
def focus(self, widget: Widget):
self.focused.focused = False
widget.focused = True
@@ -2,16 +2,20 @@ import typing as T
from pqcli.mechanic import Player, StatType
from .focusable import Focusable
from .progress_bar_window import DataTableProgressBarWindow
class CharacterSheetWindow(DataTableProgressBarWindow):
class CharacterSheetWindow(Focusable, DataTableProgressBarWindow):
def __init__(
self, player: Player, parent: T.Any, h: int, w: int, y: int, x: int
) -> None:
super().__init__(
parent, h, w, y, x, " Character Sheet ", align_right=False
)
self._on_focus_change += self._render
self._focused = True
self._player = player
self._player.connect("level_up", self._sync_traits)
@@ -47,7 +51,9 @@ class CharacterSheetWindow(DataTableProgressBarWindow):
self._render_data_table()
def _sync_exp(self) -> None:
cur = self._player.exp_bar.position
max_ = self._player.exp_bar.max_
text = f"Experience ({max_-cur:.0f} XP to go)"
self._render_progress_bar(cur, max_, text)
self._cur_pos = self._player.exp_bar.position
self._max_pos = self._player.exp_bar.max_
self._progress_title = (
f"Experience ({self._max_pos-self._cur_pos:.0f} XP to go)"
)
self._render_progress_bar()
@@ -3,12 +3,15 @@ import typing as T
from pqcli.mechanic import EquipmentType, Player
from pqcli.ui.curses.widgets import DataTable, WindowWrapper
from .focusable import Focusable
class EquipmentWindow(WindowWrapper):
class EquipmentWindow(Focusable, WindowWrapper):
def __init__(
self, player: Player, parent: T.Any, h: int, w: int, y: int, x: int
) -> None:
super().__init__(parent, h, w, y, x)
self._on_focus_change += self._render
self._data_table = DataTable(
self._win, h - 2, w - 2, 1, 1, align_right=False
@@ -44,9 +47,11 @@ class EquipmentWindow(WindowWrapper):
if not self._win:
return
with self._focus_standout(self._win):
self._win.box()
text = " Equipment "
x = max(0, (self.getmaxyx()[1] - len(text)) // 2)
self._win.addnstr(0, x, text, min(len(text), self.getmaxyx()[1]))
self._win.refresh()
self._data_table.render()
@@ -0,0 +1,28 @@
import contextlib
import typing as T
from pqcli.ui.curses.event_handler import EventHandler
class Focusable:
def __init__(self, *args: T.Any, **kwargs: T.Any) -> None:
self._focused = False
self._on_focus_change = EventHandler()
super().__init__(*args, **kwargs)
@property
def focused(self) -> bool:
return self._focused
@focused.setter
def focused(self, focused: bool) -> None:
self._focused = focused
self._on_focus_change()
@contextlib.contextmanager
def _focus_standout(self, win: T.Any) -> T.Generator:
if self._focused:
self._win.standout()
yield
if self._focused:
self._win.standend()
@@ -5,14 +5,16 @@ from pqcli.lingo import to_roman
from pqcli.mechanic import InventoryItem, Player
from pqcli.ui.curses.widgets import DataTable, ProgressBar, WindowWrapper
from .focusable import Focusable
from .progress_bar_window import DataTableProgressBarWindow
class InventoryWindow(DataTableProgressBarWindow):
class InventoryWindow(Focusable, DataTableProgressBarWindow):
def __init__(
self, player: Player, parent: T.Any, h: int, w: int, y: int, x: int
) -> None:
super().__init__(parent, h, w, y, x, " Inventory ", align_right=True)
self._on_focus_change += self._render
self._player = player
self._player.connect("new_task", self._on_new_task)
@@ -46,10 +48,12 @@ class InventoryWindow(DataTableProgressBarWindow):
self._sync_encumbrance()
def _sync_encumbrance(self) -> None:
cur = self._player.inventory.encum_bar.position
max_ = self._player.inventory.encum_bar.max_
text = f"Encumbrance ({cur:.0f}/{max_} cubits)"
self._render_progress_bar(cur, max_, text)
self._cur_pos = self._player.inventory.encum_bar.position
self._max_pos = self._player.inventory.encum_bar.max_
self._progress_title = (
f"Encumbrance ({self._cur_pos:.0f}/{self._max_pos} cubits)"
)
self._render_progress_bar()
def _sync_gold(self) -> None:
self._data_table.set("Gold", str(self._player.inventory.gold))
@@ -4,16 +4,18 @@ from pqcli.lingo import act_name
from pqcli.mechanic import Player
from pqcli.ui.curses.widgets import ListBox, WindowWrapper
from .focusable import Focusable
from .progress_bar_window import ListBoxProgressBarWindow
class PlotWindow(ListBoxProgressBarWindow):
class PlotWindow(Focusable, ListBoxProgressBarWindow):
cutoff = 100
def __init__(
self, player: Player, parent: T.Any, h: int, w: int, y: int, x: int
) -> None:
super().__init__(parent, h, w, y, x, " Plot Development ")
self._on_focus_change += self._render
self._player = player
self._player.quest_book.connect("start_act", self._sync_act_add)
@@ -51,8 +53,6 @@ class PlotWindow(ListBoxProgressBarWindow):
self._list_box.add("[ ] " + act_name(act_number))
def _sync_position(self) -> None:
self._render_progress_bar(
self._player.quest_book.plot_bar.position,
self._player.quest_book.plot_bar.max_,
"",
)
self._cur_pos = self._player.quest_book.plot_bar.position
self._max_pos = self._player.quest_book.plot_bar.max_
self._render_progress_bar()
@@ -8,6 +8,8 @@ from pqcli.ui.curses.widgets import (
WindowWrapper,
)
from .focusable import Focusable
class ProgressBarWindow(WindowWrapper):
def __init__(
@@ -16,6 +18,9 @@ class ProgressBarWindow(WindowWrapper):
super().__init__(parent, h, w, y, x)
self._title = title
self._cur_pos = 0
self._max_pos = 1
self._progress_title = ""
try:
self._progress_bar_win = (
@@ -34,11 +39,17 @@ class ProgressBarWindow(WindowWrapper):
del self._progress_bar_win
self._progress_bar_win = None
def _render_progress_bar(self, cur: float, max_: float, text: str) -> None:
def _render_progress_bar(self) -> None:
if not self._progress_bar_win:
return
self._progress_bar_win.erase()
if self._focused:
# with self._focus_standout(self._progress_bar_win):
self._progress_bar_win.standout()
if True:
self._progress_bar_win.border(
curses.ACS_VLINE,
curses.ACS_VLINE,
@@ -50,11 +61,19 @@ class ProgressBarWindow(WindowWrapper):
curses.ACS_LRCORNER,
)
text = self._progress_title
x = max(0, (self.getmaxyx()[1] - len(text)) // 2)
self._progress_bar_win.addnstr(
0, x, text, min(len(text), self._progress_bar_win.getmaxyx()[1])
0,
x,
text,
min(len(text), self._progress_bar_win.getmaxyx()[1]),
)
self._progress_bar.set_position(cur, max_)
if self._focused:
self._progress_bar_win.standend()
self._progress_bar.set_position(self._cur_pos, self._max_pos)
self._progress_bar_win.refresh()
@@ -83,14 +102,20 @@ class DataTableProgressBarWindow(ProgressBarWindow):
if not self._win:
return
with self._focus_standout(self._win):
self._win.box()
x = max(0, (self.getmaxyx()[1] - len(self._title)) // 2)
self._win.addnstr(
0, x, self._title, min(len(self._title), self.getmaxyx()[1])
)
self._win.refresh()
self._data_table.render()
def _render(self) -> None:
self._render_data_table()
self._render_progress_bar()
class ListBoxProgressBarWindow(ProgressBarWindow):
def __init__(
@@ -108,10 +133,16 @@ class ListBoxProgressBarWindow(ProgressBarWindow):
if not self._win:
return
with self._focus_standout(self._win):
self._win.box()
x = max(0, (self.getmaxyx()[1] - len(self._title)) // 2)
self._win.addnstr(
0, x, self._title, min(len(self._title), self.getmaxyx()[1])
)
self._win.refresh()
self._list_box.render()
def _render(self) -> None:
self._render_list_box()
self._render_progress_bar()
@@ -3,16 +3,18 @@ import typing as T
from pqcli.mechanic import Player
from pqcli.ui.curses.widgets import ListBox, WindowWrapper
from .focusable import Focusable
from .progress_bar_window import ListBoxProgressBarWindow
class QuestBookWindow(ListBoxProgressBarWindow):
class QuestBookWindow(Focusable, ListBoxProgressBarWindow):
cutoff = 100
def __init__(
self, player: Player, parent: T.Any, h: int, w: int, y: int, x: int
) -> None:
super().__init__(parent, h, w, y, x, " Quests ")
self._on_focus_change += self._render
self._player = player
self._player.quest_book.connect("start_quest", self._sync_quest_add)
@@ -49,8 +51,6 @@ class QuestBookWindow(ListBoxProgressBarWindow):
self._list_box.add("[ ] " + quest_name)
def _sync_position(self) -> None:
self._render_progress_bar(
self._player.quest_book.quest_bar.position,
self._player.quest_book.quest_bar.max_,
"",
)
self._cur_pos = self._player.quest_book.quest_bar.position
self._max_pos = self._player.quest_book.quest_bar.max_
self._render_progress_bar()
@@ -4,12 +4,15 @@ from pqcli.lingo import to_roman
from pqcli.mechanic import Player, Spell
from pqcli.ui.curses.widgets import DataTable, WindowWrapper
from .focusable import Focusable
class SpellBookWindow(WindowWrapper):
class SpellBookWindow(Focusable, WindowWrapper):
def __init__(
self, player: Player, parent: T.Any, h: int, w: int, y: int, x: int
) -> None:
super().__init__(parent, h, w, y, x)
self._on_focus_change += self._render
self._data_table = DataTable(
self._win, h - 2, w - 2, 1, 1, align_right=True
@@ -46,9 +49,11 @@ class SpellBookWindow(WindowWrapper):
if not self._win:
return
with self._focus_standout(self._win):
self._win.box()
text = " Spell Book "
x = max(0, (self.getmaxyx()[1] - len(text)) // 2)
self._win.addnstr(0, x, text, min(len(text), self.getmaxyx()[1]))
self._win.refresh()
self._data_table.render()
@@ -3,8 +3,10 @@ import typing as T
from pqcli.mechanic import Player
from pqcli.ui.curses.widgets import Label, ProgressBar, WindowWrapper
from .focusable import Focusable
class TaskProgressWindow(WindowWrapper):
class TaskProgressWindow(Focusable, WindowWrapper):
def __init__(
self, player: Player, parent: T.Any, h: int, w: int, y: int, x: int
) -> None:
+1 -1
View File
@@ -1,4 +1,4 @@
from .base import WindowWrapper
from .base import Widget, WindowWrapper
from .data_table import DataTable
from .label import Label
from .list_box import ListBox