Mini Shell
import os
from .screen import Screen
from .defs import KEYMAP as _KEYMAP
# Standard widget result actions (as return from .loop())
ACTION_OK = 1000
ACTION_CANCEL = 1001
ACTION_NEXT = 1002
ACTION_PREV = 1003
class Widget(Screen):
def __init__(self):
self.kbuf = b""
self.signals = {}
def set_xy(self, x, y):
self.x = x
self.y = y
def inside(self, x, y):
return self.y <= y < self.y + self.h and self.x <= x < self.x + self.w
def signal(self, sig):
if sig in self.signals:
self.signals[sig](self)
def on(self, sig, handler):
self.signals[sig] = handler
@staticmethod
def longest(items):
if not items:
return 0
return max((len(t) for t in items))
def set_cursor(self):
# By default, a widget doesn't use text cursor, so disables it
self.cursor(False)
def get_input(self):
if self.kbuf:
key = self.kbuf[0:1]
self.kbuf = self.kbuf[1:]
else:
key = os.read(0, 32)
if key[0] != 0x1b:
key = key.decode()
self.kbuf = key[1:].encode()
key = key[0:1].encode()
key = _KEYMAP.get(key, key)
if isinstance(key, bytes) and key.startswith(b"\x1b[M") and len(key) == 6:
if key[3] != 32:
return None
row = key[5] - 33
col = key[4] - 33
return [col, row]
return key
def handle_input(self, inp):
if isinstance(inp, list):
res = self.handle_mouse(inp[0], inp[1])
else:
res = self.handle_key(inp)
return res
def loop(self):
self.redraw()
while True:
key = self.get_input()
if key is None:
continue
res = self.handle_input(key)
if res is not None and res is not True:
return res
class FocusableWidget(Widget):
# If set to non-False, pressing Enter on this widget finishes
# dialog, with Dialog.loop() return value being this value.
finish_dialog = False
class EditableWidget(FocusableWidget):
def get(self):
raise NotImplementedError
class ChoiceWidget(EditableWidget):
def __init__(self, choice):
super().__init__()
self.choice = choice
def get(self):
return self.choice
# Widget with few internal selectable items
class ItemSelWidget(ChoiceWidget):
def __init__(self, items):
super().__init__(0)
self.items = items
def move_sel(self, direction):
self.choice = (self.choice + direction) % len(self.items)
self.redraw()
self.signal("changed")
Zerion Mini Shell 1.0