Source code for runtimepy.tui.cursor
"""
A basic cursor implementation for TUIs.
"""
# built-in
from typing import Any
# internal
from runtimepy.primitives import Uint32
# Typing for something like '_curses.window' isn't supported yet.
CursesWindow = Any
[docs]
class Cursor:
"""A simple cursor implementation."""
def __init__(self, window: CursesWindow) -> None:
"""Initialize this cursor."""
self.window = window
self.x = Uint32()
self.y = Uint32()
self.max_x = Uint32()
self.max_y = Uint32()
self.reset()
[docs]
def move(self, new_y: int = None, new_x: int = None) -> bool:
"""Perform the underlying cursor move."""
if new_y is None:
new_y = self.y.value
if new_x is None:
new_x = self.x.value
result = new_y < self.height and new_x < self.width
if result:
self.window.move(new_y, new_x)
self.y.value = new_y
self.x.value = new_x
return result
[docs]
def poll_max(self) -> bool:
"""Update the min and max cursor positions."""
curr_width = self.width
curr_height = self.height
# Update underlying values.
self.max_y.value, self.max_x.value = self.window.getmaxyx()
changed = curr_width != self.width or curr_height != self.height
if changed:
self.window.resize(self.height, self.width)
return changed
@property
def width(self) -> int:
"""Get the width of this cursor's window."""
return self.max_x.value
@property
def height(self) -> int:
"""Get the height of this cursor's window."""
return self.max_y.value
[docs]
def reset(self) -> None:
"""Reset this cursor."""
self.x.value = 0
self.y.value = 0
self.poll_max()
assert self.move()
[docs]
def inc_x(self, amount: int = 1) -> bool:
"""Increment the cursor's X coordinate."""
return self.move(new_x=self.x.value + amount)
[docs]
def inc_y(self, amount: int = 1) -> bool:
"""Increment the cursor's Y coordinate."""
return self.move(new_y=self.y.value + amount)