From ec601478dc4196764c543321ce76fd38461718b0 Mon Sep 17 00:00:00 2001 From: rr- Date: Sun, 4 Nov 2018 14:46:05 +0100 Subject: [PATCH] ui+roster: implement removing players --- pqcli/roster.py | 3 ++ pqcli/ui/__init__.py | 46 +++++++++++++++----- pqcli/ui/{exit_view.py => confirm_dialog.py} | 20 +++++---- pqcli/ui/roster_view.py | 38 ++++++++++++---- 4 files changed, 77 insertions(+), 30 deletions(-) rename pqcli/ui/{exit_view.py => confirm_dialog.py} (60%) diff --git a/pqcli/roster.py b/pqcli/roster.py index 6429ad0..f370a39 100644 --- a/pqcli/roster.py +++ b/pqcli/roster.py @@ -12,6 +12,9 @@ class Roster: def add_player(self, player: Player) -> None: self.players.append(player) + def delete_player_at(self, player_idx: int) -> None: + del self.players[player_idx] + @staticmethod def load(path: Path) -> "Roster": if path.exists(): diff --git a/pqcli/ui/__init__.py b/pqcli/ui/__init__.py index 03f4803..1d0df2e 100644 --- a/pqcli/ui/__init__.py +++ b/pqcli/ui/__init__.py @@ -2,9 +2,10 @@ import typing as T import urwid +from pqcli import random from pqcli.mechanic import Player from pqcli.roster import Roster -from pqcli.ui.exit_view import ExitView +from pqcli.ui.confirm_dialog import ConfirmDialog from pqcli.ui.new_game_view import NewGameView from pqcli.ui.roster_view import RosterView @@ -19,6 +20,11 @@ PALETTE: T.List[T.Tuple[str, str, str]] = [ ] +class ConfirmExitDialog(ConfirmDialog): + def __init__(self, old_view: urwid.Widget) -> None: + super().__init__("Really quit?", old_view) + + def bind_commands() -> None: for key, direction in { "k": "up", @@ -40,7 +46,7 @@ class Ui: self.loop = urwid.MainLoop( None, PALETTE, unhandled_input=self.unhandled_input ) - self.old_view: T.Optional[urwid.Widget] = None + self.old_views: T.List[urwid.Widget] = [] self.switch_to_roster_view() @@ -53,7 +59,6 @@ class Ui: return True if key == "ctrl q": - self.old_view = self.loop.widget self.switch_to_exit_view() return True @@ -63,13 +68,16 @@ class Ui: self.loop.widget = RosterView(self.roster) self._connect("load_game", self.switch_to_game_view) self._connect("new_game", self.switch_to_new_game_view) + self._connect("delete_game", self.switch_to_delete_player_view) self._connect("exit", self.switch_to_exit_view) def switch_to_exit_view(self) -> None: - self.old_view = self.loop.widget - self.loop.widget = ExitView(self.old_view) - self._connect("exit", self.exit) - self._connect("cancel", self.cancel_exit) + if isinstance(self.loop.widget, ConfirmExitDialog): + return + self.old_views.append(self.loop.widget) + self.loop.widget = ConfirmExitDialog(self.old_views[-1]) + self._connect("confirm", self.exit) + self._connect("cancel", self.cancel_dialog) def switch_to_new_game_view(self) -> None: self.loop.widget = NewGameView() @@ -80,16 +88,30 @@ class Ui: self.roster.add_player(player) self.switch_to_roster_view() - def switch_to_game_view(self, player_name: str) -> None: + def delete_player(self, player_idx: int) -> None: + self.roster.delete_player_at(player_idx) + self.switch_to_roster_view() + + def switch_to_game_view(self, player_idx: int) -> None: raise NotImplementedError("not implemented") + def switch_to_delete_player_view(self, player_idx: int) -> None: + adjective = random.choice(["faithful", "noble", "loyal", "brave"]) + player_name = self.roster.players[player_idx].name + + self.old_views.append(self.loop.widget) + self.loop.widget = ConfirmDialog( + f"Terminate {adjective} {player_name}?", self.old_views[-1] + ) + self._connect("confirm", lambda: self.delete_player(player_idx)) + self._connect("cancel", self.cancel_dialog) + def exit(self) -> None: raise urwid.ExitMainLoop() - def cancel_exit(self) -> None: - assert self.old_view is not None - self.loop.widget = self.old_view - self.old_view = None + def cancel_dialog(self) -> None: + assert len(self.old_views) + self.loop.widget = self.old_views.pop() def _connect(self, signal_name: str, callback: T.Callable) -> None: urwid.signals.connect_signal( diff --git a/pqcli/ui/exit_view.py b/pqcli/ui/confirm_dialog.py similarity index 60% rename from pqcli/ui/exit_view.py rename to pqcli/ui/confirm_dialog.py index 696fb74..1476996 100644 --- a/pqcli/ui/exit_view.py +++ b/pqcli/ui/confirm_dialog.py @@ -5,13 +5,13 @@ import urwid from pqcli.ui.button import MenuButton -class ExitView(urwid.Overlay): - signals = ["exit", "cancel"] +class ConfirmDialog(urwid.Overlay): + signals = ["confirm", "cancel"] - def __init__(self, parent: urwid.Widget) -> None: - question = urwid.Text(("bold", "Really quit?"), "center") + def __init__(self, label: str, parent: urwid.Widget) -> None: + question = urwid.Text(("bold", label), "center") yes_btn = MenuButton( - "Yes", hint="Y", on_press=lambda _user_data: self.exit() + "Yes", hint="Y", on_press=lambda _user_data: self.confirm() ) no_btn = MenuButton( "No", hint="N", on_press=lambda _user_data: self.cancel() @@ -23,19 +23,21 @@ class ExitView(urwid.Overlay): ) ) - super().__init__(line_box, parent, "center", 20, "middle", 5) + super().__init__( + line_box, parent, "center", len(label) + 6, "middle", 5 + ) def keypress(self, size: T.Any, key: str) -> T.Optional[str]: if key in {"y", "Y"}: - self.exit() + self.confirm() return None if key in {"n", "N"}: self.cancel() return None return T.cast(T.Optional[str], super().keypress(size, key)) - def exit(self) -> None: - self._emit("exit") + def confirm(self) -> None: + self._emit("confirm") def cancel(self) -> None: self._emit("cancel") diff --git a/pqcli/ui/roster_view.py b/pqcli/ui/roster_view.py index e0ee508..0c010de 100644 --- a/pqcli/ui/roster_view.py +++ b/pqcli/ui/roster_view.py @@ -7,7 +7,7 @@ from pqcli.ui.button import MenuButton class RosterView(urwid.Filler): - signals = ["load_game", "new_game", "exit"] + signals = ["load_game", "new_game", "delete_game", "exit"] def __init__(self, roster: Roster) -> None: self.roster = roster @@ -15,12 +15,24 @@ class RosterView(urwid.Filler): logo = urwid.BigText("ProgressQuest", urwid.HalfBlock5x4Font()) buttons = [] - for player in self.roster.players: + for player_idx, player in enumerate(self.roster.players): buttons.append( - MenuButton( - label=player.name, - on_press=self.on_resume_game_press, - user_data=player.name, + urwid.Columns( + [ + MenuButton( + label=player.name, + on_press=self.on_resume_game_press, + user_data=player_idx, + ), + ( + 10, + MenuButton( + label="Delete", + on_press=self.on_delete_game_press, + user_data=player_idx, + ), + ), + ] ) ) @@ -51,9 +63,17 @@ class RosterView(urwid.Filler): ) ) - def on_resume_game_press(self, user_data: T.Any) -> None: - player_name = T.cast(str, user_data) - self._emit("load_game", player_data) + def on_resume_game_press( + self, _widget: urwid.Widget, user_data: T.Any + ) -> None: + player_idx = T.cast(int, user_data) + self._emit("load_game", player_idx) + + def on_delete_game_press( + self, _widget: urwid.Widget, user_data: T.Any + ) -> None: + player_idx = T.cast(int, user_data) + self._emit("delete_game", player_idx) def on_new_game_press(self, _user_data: T.Any) -> None: self._emit("new_game")