Files
ProgressQuest-cli/pqcli/ui/curses/__init__.py
T

125 lines
3.7 KiB
Python

import argparse
import signal
import curses
import os
import time
import typing as T
from pqcli import lingo
from pqcli.mechanic import Player
from pqcli.roster import Roster
from pqcli.ui.curses.views import (
BaseView,
ChooseCharacterView,
ConfirmView,
CreateCharacterView,
GameView,
RosterView,
)
from ..base import BaseUserInterface
class StopMainLoop(Exception):
pass
class CursesUserInterface(BaseUserInterface):
def __init__(self, roster: Roster, args: argparse.Namespace) -> None:
super().__init__(roster, args)
os.environ.setdefault("ESCDELAY", "25")
self.screen = curses.initscr()
self.screen.nodelay(True)
self.screen.keypad(True)
curses.noecho()
curses.curs_set(0)
def signal_handler(sig, frame):
print("Quitting")
if self.args.use_saves:
self.roster.save()
exit(0)
signal.signal(signal.SIGINT, signal_handler)
self.roster_view = RosterView(self.screen)
self.roster_view.on_create += self.switch_to_create_character_view
self.roster_view.on_delete += self.switch_to_delete_character_view
self.roster_view.on_play += self.switch_to_play_view
self.roster_view.on_quit += self.quit
self.view: BaseView = self.roster_view
self.view.start()
def run(self) -> None:
try:
self.switch_to_roster_view()
while True:
key = T.cast(int, self.screen.getch())
if key == curses.ERR:
time.sleep(0.1)
self.view.idle()
continue
if key == curses.KEY_RESIZE:
self.view.stop()
self.view.start()
else:
try:
self.view.keypress(key)
except StopMainLoop:
break
finally:
curses.endwin()
curses.curs_set(1)
def switch_to_roster_view(self) -> None:
self.switch_view(self.roster_view)
def switch_to_create_character_view(self) -> None:
view = CreateCharacterView(self.screen)
view.on_cancel += self.switch_to_roster_view
view.on_confirm += self.switch_to_game_view
self.switch_view(view)
def switch_to_delete_character_view(self) -> None:
view = ChooseCharacterView(
self.screen, self.roster, "Choose character to delete"
)
view.on_cancel += self.switch_to_roster_view
view.on_confirm += self.switch_to_confirm_delete_character_view
self.switch_view(view)
def switch_to_confirm_delete_character_view(self, player: Player) -> None:
view = ConfirmView(self.screen, lingo.terminate_message(player.name))
view.on_cancel += self.switch_to_delete_character_view
view.on_confirm += lambda: self.delete_character(player)
self.switch_view(view)
def switch_to_play_view(self) -> None:
view = ChooseCharacterView(
self.screen, self.roster, "Choose character to play"
)
view.on_cancel += self.switch_to_roster_view
view.on_confirm += self.switch_to_game_view
self.switch_view(view)
def switch_to_game_view(self, player: Player) -> None:
view = GameView(self.screen, player)
view.on_exit += self.switch_to_roster_view
self.switch_view(view)
def switch_view(self, view: BaseView) -> None:
self.view.stop()
self.view = view
self.view.start()
def delete_character(self, player: Player) -> None:
self.roster.players.remove(player)
self.switch_to_roster_view()
def quit(self) -> None:
raise StopMainLoop