Module gonioimsoft.libtui

A terminal user interface library. Small, custom.

Classes

class NBlock

Non-blocking read of key pressess using threading and stdin read

Expand source code
class NBlock:
    '''Non-blocking read of key pressess using threading and stdin read
    '''
    def __init__(self):
        self.input = []
        self.exit = False
        self.t = threading.Thread(target=self.target)

    def run(self):
        self.t.start()

    def target(self):
        while not self.exit:
            char = sys.stdin.read(1)
            self.input.append(char)

    def stop(self):
        self.exit = True
        self.t.join()

Methods

def run(self)
def stop(self)
def target(self)
class SimpleTUI

A terminal user interface (TUI) library.

Attributes

header : string or None
Text shown on on the top of the screen.
Expand source code
class SimpleTUI:
    '''A terminal user interface (TUI) library.
    
    Attributes
    ----------
    header : string or None
        Text shown on on the top of the screen.
    '''
    
    def __init__(self):
        self.header = None
        
        if OS != 'Windows':
            self.nblock = NBlock()
            self.nblock.run()

    def read_key(self):
        if OS == 'Windows':
            if msvcrt.kbhit():
                key = ord(msvcrt.getwch())
                return chr(key)
        else:
            if not self.nblock.input:
                return ''
            button = self.nblock.input.pop(0)
            return button
        return ''

    def clear_screen(self):
        '''Empties the screen and prints the header if any.
        '''
        if os.name == 'posix':
            os.system('clear')
        elif os.name == 'nt':
            os.system('cls')

        if self.header is not None:
            self.print(self.header)


    @staticmethod
    def print_lines(lines):
        for text in lines:
            print(text)
        
    @staticmethod
    def print(value=''):
        print(value)


    def _convert_selection(self, selection):
        '''
        selection : string
            Raw string typed by the user.
        '''
        selection = selection.strip('\r\n')
        selection = selection.split(',')

        # Raises ValueError if fails
        selection = [int(string) for string in selection]
        
        return selection


    def item_select(self, items, message=None, multiselect=False):
        '''Makes the user to select an item

        Arguments
        ---------
        items : iterable
            An iterable (eg. list) that returns printable items.
            If the item is newline, then prints a space and this
            space cannot be selected.
        message : string
            Printed before the selection table as an instruction
        multiselect : bool
            If True, 

        Returns
        -------
        item : ?
            The selected item. If multiselect is True, returns a
            list of selected items

        Empty string items are converted to a space
        '''
        
        if message is not None:
            self.print(message)

        real_items = []
        i = 0
        for item in items:
            if item != '\n':
                self.print('{}) {}'.format(i+1, item))
                real_items.append(item)
                i += 1
            else:
                self.print()

        self.print()
        
        if multiselect:
            self.print('# Multiple selections possible, separate by commas (,)')
        else:
            self.print('# Select by number and hit enter')

        self.print()

        selection = ''
        while True:
            new_char = self.read_key()
            if new_char:
                if new_char == '\b':
                    # Backspace
                    selection = selection[:-1]
                elif new_char in "0123456789\n\r":
                    selection += new_char
                self.print(selection)
            if selection.endswith('\r') or selection.endswith('\n'):
                
                try:
                    selection = self._convert_selection(selection)
                except ValueError:
                    self.print('Invalid input (non-numbers inputted)')
                    selection = ''
                    continue
                
                try:
                    # Test that we can get the item; -1 comes from
                    # the difference between Python first index (0)
                    # and this selection program first index (1) 
                    [real_items[number-1] for number in selection]
                except IndexError:
                    self.print('Invalid input (index out of range)')
                    selection = ''
                    continue

                break


        to_return = [real_items[int(number)-1] for number in selection]
        if not multiselect:
            to_return = to_return[0]

        return to_return

    def bool_select(self, message=None, true='yes', false='no'):
        '''Ask the user yes/no.

        Uses input so it blocks.
        '''
        
        if message is not None:
            self.print(message)

        while True:
            sel = self.input('(yes/no) >> ').lower()
            if sel.startswith('yes') or sel == 'y':

                return True
            elif sel.startswith('no') or sel == 'n':
                return False
            
            self.print('What? Please try again')
            time.sleep(1)



    def input(self, message=None, cancels=None):
        '''Ask the user for text input.

        A blocking call.
        
        Arguments
        ---------
        message : string
            The on-line message shown to the user.
        cancels: string
            If user inputs this string then returns None

        Returns
        -------
        user_input : string or None if cancels
        '''
        if OS == 'Windows':
            if message is not None:
                uinput = input(f'{message} >> ')
            else:
                uinput = input('>> ')
            
        else:
            if message is not None:
                self.print(f'{message} >> ')
            else:
                self.print('>> ')
            uinput = ''
            while True:
                if self.nblock.input:
                    char = self.nblock.input.pop(0)
                    if char in ['\n', '\r']:
                        break
                    uinput += char
                else:
                    time.sleep(0.1)

        if isinstance(cancels, str) and uinput == cancels:
            return None
        return uinput

Static methods

def print(value='')
def print_lines(lines)

Methods

def bool_select(self, message=None, true='yes', false='no')

Ask the user yes/no.

Uses input so it blocks.

def clear_screen(self)

Empties the screen and prints the header if any.

def input(self, message=None, cancels=None)

Ask the user for text input.

A blocking call.

Arguments

message : string
The on-line message shown to the user.
cancels : string
If user inputs this string then returns None

Returns

user_input : string or None if cancels
 
def item_select(self, items, message=None, multiselect=False)

Makes the user to select an item

Arguments

items : iterable
An iterable (eg. list) that returns printable items. If the item is newline, then prints a space and this space cannot be selected.
message : string
Printed before the selection table as an instruction
multiselect : bool
If True,

Returns

item : ?
The selected item. If multiselect is True, returns a list of selected items
Empty string items are converted to a space
 
def read_key(self)