Source code for conntextual.curses.base

"""
A module implementing a base application.
"""

# built-in
import asyncio
import curses

# third-party
from runtimepy.net.arbiter import AppInfo
from runtimepy.net.arbiter.task import ArbiterTask
from runtimepy.tui.cursor import Cursor
from runtimepy.tui.mixin import CursesWindow


[docs] class AppBase(ArbiterTask): """A base TUI application.""" app: AppInfo input_queue: asyncio.Queue[int]
[docs] async def init(self, app: AppInfo) -> None: """Initialize this task with application information.""" self.app = app self.input_queue = asyncio.Queue() cursor = self.cursor with self.env.names_pushed("cursor"): self.env.channel("x", cursor.x) self.env.channel("y", cursor.y) with self.env.names_pushed("window"): self.env.channel("width", cursor.max_x) self.env.channel("height", cursor.max_y) self._handle_resize()
def _handle_resize(self) -> None: """Handle the application getting re-sized.""" self.cursor.poll_max()
[docs] async def handle_char(self, char: int) -> None: """Handle user input.""" if char == curses.KEY_RESIZE: self._handle_resize() else: # pragma: nocover # trigger this with 'q' self.app.stop.set()
# Handle this at some point. # elif char == curses.KEY_MOUSE: # pass
[docs] def draw(self) -> None: """Draw the application."""
[docs] async def dispatch(self) -> bool: """Dispatch an iteration of this task.""" window = self.window # Check for user input. keep_reading = True while keep_reading: data = window.getch() keep_reading = data != -1 if keep_reading: self.input_queue.put_nowait(data) # Process inputs. while not self.input_queue.empty(): await self.handle_char(self.input_queue.get_nowait()) # Update state. self.draw() # Not sure what's going on with coverage. window.noutrefresh() # pragma: nocover curses.doupdate() # pragma: nocover return True # pragma: nocover
@property def cursor(self) -> Cursor: """Get this instance's cursor.""" return self.app.tui.cursor @property def window(self) -> CursesWindow: """Get this instance's window.""" return self.app.tui.window