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")