Add basic euphoria single-room application

This commit is contained in:
Joscha 2019-05-15 16:58:24 +00:00
parent 60d686bfce
commit 43af84a395
4 changed files with 195 additions and 0 deletions

View file

@ -0,0 +1,8 @@
from typing import List
from .palette import *
from .single_room_application import *
__all__: List[str] = []
__all__ += palette.__all__
__all__ += single_room_application.__all__

View file

@ -0,0 +1,11 @@
import enum
__all__ = ["Style", "PALETTE"]
@enum.unique
class Style(enum.Enum):
ROOM = "room"
PALETTE = [
(Style.ROOM, "light blue,bold", ""),
]

View file

@ -0,0 +1,79 @@
import asyncio
from typing import Any, List
import urwid
import yaboli
from .palette import Style
from ..markup import AT
from ..widgets import ATWidget
class CenteredTextWidget(urwid.WidgetWrap):
def __init__(self, lines: List[AT]):
max_width = max(map(len, lines))
text = AT("\n").join(lines)
filler = urwid.Filler(ATWidget(text, align="center"))
super().__init__(filler)
class RoomWidget(urwid.WidgetWrap):
"""
The RoomWidget connects to and displays a single yaboli room.
Its life cycle looks like this:
1. Create widget
2. Call connect() (while the event loop is running)
3. Keep widget around and occasionally display it
4. Call disconnect() (while the event loop is runnning)
5. When the room should be destroyed/forgotten about, it sends a "close"
event
"""
def __init__(self, roomname: str) -> None:
self._room = yaboli.Room(roomname)
super().__init__(self._connecting_widget())
self._room_view = self._connected_widget()
def _connecting_widget(self) -> Any:
lines = [AT("Connecting to ")
+ AT("&" + self.room.name, style=Style.ROOM)
+ AT("...")]
return CenteredTextWidget(lines)
def _connected_widget(self) -> Any:
lines = [AT("Connected to ")
+ AT("&" + self.room.name, style=Style.ROOM)
+ AT(".")]
return CenteredTextWidget(lines)
def _connection_failed_widget(self) -> Any:
lines = [AT("Could not connect to ")
+ AT("&" + self.room.name, style=Style.ROOM)
+ AT(".")]
return CenteredTextWidget(lines)
@property
def room(self) -> yaboli.Room:
return self._room
# Start up the connection and room
async def _connect(self) -> None:
success = await self._room.connect()
if success:
self._w = self._room_view
else:
self._w = self._connection_failed_widget()
urwid.emit_signal(self, "close")
def connect(self) -> None:
asyncio.create_task(self._connect())
# Handle input
def selectable(self) -> bool:
return True
urwid.register_signal(RoomWidget, ["close"])

View file

@ -0,0 +1,97 @@
from typing import Any, Optional
import urwid
from .palette import Style
from .room_widget import RoomWidget
__all__ = ["SingleRoomApplication"]
class ChooseRoomWidget(urwid.WidgetWrap):
def __init__(self) -> None:
self.text = urwid.Text("Choose a room:", align="center")
self.edit = urwid.Edit("&", align="center")
self.pile = urwid.Pile([
self.text,
urwid.AttrMap(self.edit, Style.ROOM),
])
self.filler = urwid.Filler(self.pile)
super().__init__(self.filler)
def set_error(self, text: Any) -> None:
self.error = urwid.Text(text, align="center")
self.pile = urwid.Pile([
self.error,
self.text,
urwid.AttrMap(self.edit, Style.ROOM),
])
self.filler = urwid.Filler(self.pile)
self._w = self.filler
def unset_error(self) -> None:
self.error = None
self.pile = urwid.Pile([
self.text,
urwid.AttrMap(self.edit, Style.ROOM),
])
self.filler = urwid.Filler(self.pile)
self._w = self.filler
def could_not_connect(self, roomname: str) -> None:
text = [
"Could not connect to ",
(Style.ROOM, "&" + roomname),
".\n",
]
self.set_error(text)
def invalid_room_name(self) -> None:
# TODO animate the invalid room name thingy?
text = ["Invalid room name.\n"]
self.set_error(text)
class SingleRoomApplication(urwid.WidgetWrap):
ALPHABET = "abcdefghijklmnopqrstuvwxyz"
ALLOWED_EDITOR_KEYS = {
"backspace", "delete",
"left", "right",
"home", "end",
}
def __init__(self) -> None:
self.choose_room = ChooseRoomWidget()
super().__init__(self.choose_room)
def selectable(self) -> bool:
return True
def switch_to_choose(self) -> None:
self.choose_room.could_not_connect(self.choose_room.edit.edit_text)
self._w = self.choose_room
def keypress(self, size: Any, key: str) -> Optional[str]:
if self._w == self.choose_room:
# This leads to the editor jumping around the screen.
#
# TODO Find a way for the editor to stay still.
self.choose_room.unset_error()
if key == "enter":
roomname = self.choose_room.edit.edit_text
if roomname:
room = RoomWidget(roomname)
urwid.connect_signal(room, "close", self.switch_to_choose)
room.connect()
self._w = room
# Make sure we only enter valid room names
elif key.lower() in self.ALPHABET:
return super().keypress(size, key.lower())
elif key in self.ALLOWED_EDITOR_KEYS:
return super().keypress(size, key)
return None
else:
return super().keypress(size, key)