Ejemplo n.º 1
0
class InputBox(UI):
    _PADDING = 3
    _BORDER = 2
    _TITLE_COLOR = (47, 30)
    _BODY_COLOR = (47, 30)
    _INPUT_AREA_COLOR = (40, 37)

    def __init__(self, title :str, prompt :str):
        self.__title = title
        self.__activated = False
        self.__input_start_y = 0
        self.__prompt = prompt

        self.__start_x = self._PADDING + 1

        self.__buffer = []
        self.__reader = KeyReader(None)

        self.__cursor_offset = 0

    @property
    def __input_length(self):
        return col() - self._PADDING * 2 - self._BORDER * 2

    @property
    def __cursor_start_x(self):
        return self._PADDING + self._BORDER

    @property
    def __max_width(self):
        return col() - self._PADDING * 2

    def __com_buffer(self, comcmd :str, ch :str):
        if comcmd == 'a' and len(self.__buffer) < self.__input_length - 1:  
            # append
            self.__buffer.insert(self.__cursor_offset, ch)
            self.__update_cursor(1)

        elif comcmd == 'd' and self.__buffer:  # delete
            self.__buffer.pop(self.__cursor_offset - 1)
            self.__update_cursor(-1)

    def __do_key(self, k):
        if k == keys.KEY_ENTER:
            puts(0, 0, '')
            self.__activated = False

        elif k in (b'\x1b[D', b'\x1b[C'):
            ofs = {b'\x1b[D' : -1, b'\x1b[C' : 1}[k]

            self.__update_cursor(ofs)

        elif k in (b'\x1b[H', b'\x1b[F'):
            ofs = {b'\x1b[H' : -self.__cursor_offset, b'\x1b[F' : len(self.__buffer) - self.__cursor_offset}[k]

            self.__update_cursor(ofs)

        elif len(k) == 1: # ascii input
            ok = ord(k)

            if k == b'\x7f':  # backspace
                self.__com_buffer('d', '')
                self.__rm_ch()
                self.__update_cursor()

            elif ok in range(33, 127) or k == b' ':
                self.__com_buffer('a', chr(ord(k)))

        else:
            for ch in k:
                self.__do_key(ch.to_bytes(1, 'big'))

    def __refresh(self):
        tprint(self.__cursor_start_x + 1, 
                self.__input_start_y, 
                bgstr(''.join(self.__buffer), *self._INPUT_AREA_COLOR))

        tprint(self.__cursor_start_x + 1 + len(self.__buffer) + 1, 
                self.__input_start_y, 
                bgstr('_' * (self.__input_length - len(self.__buffer) - 1), 
                    *self._INPUT_AREA_COLOR))

    def __update_cursor(self, ofs=0):
        if self.__cursor_offset + ofs in range(0, len(self.__buffer) + 1):
            self.__cursor_offset += ofs

        puts(self.__cursor_start_x + self.__cursor_offset + 1,
             self.__input_start_y, '')

    def __rm_ch(self):
        tprint(self.__cursor_start_x + len(self.__buffer) + 1,
               self.__input_start_y, ' ')

    def __key_loop(self):
        try:
            while self.__activated:
                    k = self.__reader.get_key()
                    self.__do_key(k.key)
                    self.__update_cursor()
                    self.__refresh()
        except KeyboardInterrupt:
            self.__activated = False
            self.__buffer = ['']

    def get_input(self):
        self.draw()
        # v = tinput(self.__start_x + self._BORDER, self.__input_start_y, '')
        
        self.__update_cursor()
        self.__key_loop()

        self.__activated = False
        ui_manager.destroy_ui(self)

        return ''.join(self.__buffer)

    def activate(self):
        title = self.__title
        start = int(ln() / 2) - 1
        
        tx = int(col() / 2 - len(title) / 2) - 1

        tbc, txc = self._TITLE_COLOR
        bc, tc = self._BODY_COLOR

        t1 = bgstr('=' * self.__max_width, bc)
        t2 = bgstr(' ' * self.__max_width, bc)
        t3 = '{0}{1}{0}'.format(bgstr(' ' * self._BORDER, bc),
                ' ' * (self.__max_width - self._BORDER * 2))
        t4 = t1

        for i, v in enumerate((t1, t2, t3, t4)):
            tprint(self.__start_x, start + i, v)

        tprint(self.__start_x + self._BORDER, 
                start + 1, bgstr(self.__prompt, tbc))

        tprint(tx, start, bgstr(' %s ' % title, tbc, txc))

        self.__activated = True
        self.__input_start_y = start + 2

        self.__refresh()
        self.__update_cursor()
    
    draw = activate
Ejemplo n.º 2
0
class _UIManager:
    def __init__(self):
        self.__ui_stack = []
        self.__queue = KeyEventQueue()
        self.__kreader = KeyReader(self.__queue)
    
    @property
    def __current_ui(self) -> UI:
        return self.__ui_stack[-1]  \
                if self.__ui_stack else None

    def __check_and_append_ui(self, ui):
        if not isinstance(ui, UI):
            raise exceptions.NotAnUIException('%s is not an UI instance' % ui)
        self.__ui_stack.append(ui)

    def __check_resolution(self):
        oc, ol = col(), ln()

        while True:
            if (oc != col() or ol != ln()) and not ui_share.CMD_MODE:
                oc, ol = col(), ln()
                self.__draw()

            time.sleep(1 / _RESOLUTION_CHECK_FREQ)

    def __do_key(self):
        k = self.__kreader.get_key()
        self.__current_ui.do_key(k)

    def __draw_current_ui(self):
        self.__current_ui.draw()

    def __draw(self):
        if _DRAW_ALL_UI_EACH_REFRESH:
            self.draw_all_ui()
        else:
            self.__draw_current_ui()

    def draw_all_ui(self):
        clear()
        for ui in self.__ui_stack:
            ui.draw()

    def get_current_ui(self):
        return self.__current_ui.cur_ui

    def activate_ui(self, ui):
        self.draw_all_ui()
        self.__check_and_append_ui(ui)
        ui.activate()

    def destroy_ui(self, ui):
        if ui in self.__ui_stack:
            self.__ui_stack.remove(ui)
            self.__draw_current_ui()

    def main_loop(self):
        t = threading.Thread(target=self.__check_resolution)
        t.setDaemon(True)
        t.start()

        try:
            while True:
                self.__do_key()
                self.__draw_current_ui()
        except KeyboardInterrupt:
            main_loop()  # ignore

        except Exception:
            handle_exception(*sys.exc_info())

    def get_key(self) -> KeyEvent:
        return self.__kreader.get_key()

    def exit(self, exit_code=0):
        clear()
        sys.exit(exit_code)