py_cui Examples

There are several examples of simple py_cui programs you can find in the examples directory of the github repository. In addition, a larger python module pyautogit was written with py_cui, and is available for download using pip or from github. In this section of the documentation we will explain the source code for some of the supplied examples in more detail.

Hello py_cui!

As is tradition with programming, we start with our Hello World example. Here we simply create a PyCUI object with a grid size of 3 x 3, and we add a Label into the center grid space. This is the most basic py_cui you can create.

# Import the lib
import py_cui

# create the CUI object. Will have a 3 by 3 grid with indexes from 0,0 to 2,2
root = py_cui.PyCUI(3,3)

# Add a label to the center of the CUI in the 1,1 grid position
root.add_label('Hello py_cui!!!', 1, 1)

# Start/Render the CUI
root.start()

Simple Todo List

A simple usage of py_cui for creating a terminal todo list. We use keybindings to get control of each of our lists as well as our text entry

import py_cui

class SimpleTodoList:

    def __init__(self, master):

        self.master = master

        # The scrolled list cells that will contain our tasks in each of the three categories
        self.todo_scroll_cell =         self.master.add_scroll_menu('TODO',         0, 0, row_span=6, column_span=2)
        self.in_progress_scroll_cell =  self.master.add_scroll_menu('In Progress',  0, 2, row_span=7, column_span=2)
        self.done_scroll_cell =         self.master.add_scroll_menu('Done',         0, 4, row_span=7, column_span=2)

        # Textbox for entering new items
        self.new_todo_textbox = self.master.add_text_box('TODO Item', 6, 0, column_span=2)

        # Keybindings for controlling our CUI.
        # We bind the enter key for each of the widgets
        self.new_todo_textbox.add_key_command(          py_cui.keys.KEY_ENTER, self.add_item)
        self.todo_scroll_cell.add_key_command(          py_cui.keys.KEY_ENTER, self.mark_as_in_progress)
        self.in_progress_scroll_cell.add_key_command(   py_cui.keys.KEY_ENTER, self.mark_as_done)
        self.done_scroll_cell.add_key_command(          py_cui.keys.KEY_ENTER, self.remove_item)

    def add_item(self):
        """ Add a todo item """

        self.todo_scroll_cell.add_item(f'{self.new_todo_textbox.get()}')
        self.new_todo_textbox.clear()

    def mark_as_in_progress(self):
        """ Mark a todo item as inprogress. Remove it from todo scroll list, add it to in progress list, or show error popup if no tasks """

        in_prog = self.todo_scroll_cell.get()
        if in_prog is None:
            self.master.show_error_popup('No Item', 'There is no item in the list to mark as in progress')
            return
        self.todo_scroll_cell.remove_selected_item()
        self.in_progress_scroll_cell.add_item(in_prog)

    def mark_as_done(self):
        """ Mark a inprogress item as done. Remove it from inprogress scroll list, add it to done list, or show error popup if no tasks """

        done = self.in_progress_scroll_cell.get()
        if done is None:
            self.master.show_error_popup('No Item', 'There is no item in the list to mark as done')
            return
        self.in_progress_scroll_cell.remove_selected_item()
        self.done_scroll_cell.add_item(done)

    def remove_item(self):
        """ Remove a todo item """

        self.done_scroll_cell.remove_selected_item()

# Create the CUI with 7 rows 6 columns, pass it to the wrapper object, and start it
root = py_cui.PyCUI(7, 6)
root.set_title('CUI TODO List')
s = SimpleTodoList(root)
root.start()

Popups Example

This example will demonstrate the usage for using all supported popups.

# imports
import py_cui
import time
import os
import threading    # We will need the threading library when we want to use the loading popups

class PopupExample:

    def __init__(self, master):

        # This is a reference to our top level CUI object
        self.master = master

        # buttons for control - each simply spawns the linked popup
        self.show_message_popup = self.master.add_button('Show Message Popup', 0, 0,            command=self.show_message)
        self.show_yes_no_popup  = self.master.add_button('Show Yes No Popup',  1, 0,            command=self.show_yes_no)
        self.show_loading_icon_popup = self.master.add_button('Show Loading Icon Popup', 2, 0,  command=self.show_loading_icon)
        self.show_loading_bar_popup = self.master.add_button('Show Loading Bar Popup', 0,1,     command = self.show_loading_bar)
        self.show_text_box_popup = self.master.add_button('Show Text Box Popup', 1,1,           command = self.show_text_box)
        self.show_menu_popup = self.master.add_button('Show Scroll Menu Popup', 2,1,            command = self.show_menu_popup_fun)


    def show_message(self):
        """ Displays a simple message popup """

        self.master.show_message_popup('Hello!', 'This is a message popup. You can also spawn warnings and errors.')

    ################################################
    # YES NO POPUP

    def quit_cui(self, to_quit):
        # THis is the function given to the yes no popup. The to_quit parameter will be true if y is pressed, or False if n is pressed
        if to_quit:
            exit()
        else:
            self.master.show_message_popup('Cancelled', 'The quit operation was cancelled.')


    def show_yes_no(self):
        """ Displays a yes no popup asking if the user would like to quit """

        # For the yes/no popup, the 'command' parameter must take a function that requires a single boolean parameter
        self.master.show_yes_no_popup('Are you sure you want to quit?', self.quit_cui)

    ################################################

    ################################################
    # TEXTBOX POPUP

    def reset_title(self, new_title):
        self.master.set_title(new_title)


    def show_text_box(self):
        """ Displays a textbox popup asking the user for a new window title """

        # A textbox popup requires a prompt and a function reference. The function must take a single string parameter that will return
        # whatever is within the text box when the ENTER key is pressed
        self.master.show_text_box_popup('Please enter a new window title', self.reset_title)

    ################################################

    ################################################
    # SCROLL MENU POPUP

    def change_button_color(self, new_color):
        """ Function called when ENTER pressed in menu popup. Takes string as parameter """

        color = py_cui.WHITE_ON_BLACK
        if new_color == "RED":
            color = py_cui.RED_ON_BLACK
        elif new_color == "CYAN":
            color = py_cui.CYAN_ON_BLACK
        elif new_color == "MAGENTA":
            color = py_cui.MAGENTA_ON_BLACK
        for key in self.master.get_widgets().keys():
            if isinstance(self.master.get_widgets()[key], py_cui.widgets.Button):
                self.master.get_widgets()[key].set_color(color)

    def show_menu_popup_fun(self):
        """ Opens scroll menu for selecting button colors """

        # Spawning a menu popup must recieve a list of strings as menu options, and a function reference that takes a string parameter
        menu_choices = ['RED', 'CYAN', 'MAGENTA']
        self.master.show_menu_popup('Please select a new button color', menu_choices, self.change_button_color)

    ################################################

    def show_loading_icon(self):
        """ Function that shows the usage for spwaning a loading icon popup """

        # The loading popup will remain onscreen until the stop loading function is called. Call this before a large operation, and call
        # stop after the operation is finished. Note that for these long operations, you must use a different thread
        # to not block the draw calls.
        self.master.show_loading_icon_popup('Please Wait', 'Loading')
        operation_thread = threading.Thread(target=self.long_operation)
        operation_thread.start()


    def show_loading_bar(self):
        """ Function that shows the usage for spawning a loading bar popup """

        self.master.show_loading_bar_popup('Incrementing a counter...', 100)
        operation_thread = threading.Thread(target=self.long_operation)
        operation_thread.start()


    def long_operation(self):
        """ A simple function that demonstrates a long callback operation performed while loading popup is open """

        counter = 0
        for i in range(0, 100):
            time.sleep(0.1)
            counter= counter +1
            self.master.status_bar.set_text(str(counter))
            # When using a bar indicator, we will increment the completed counter. Will be ignored for loading icon popup
            self.master.increment_loading_bar()
        # This is what stops the loading popup and reenters overview mode
        self.master.stop_loading_popup()


# Create the CUI, pass it to the wrapper object, and start it
root = py_cui.PyCUI(3, 2)
root.set_title('CUI Popups Example')
s = PopupExample(root)
root.start()

Other examples

Other examples are available in the examples directory in the repository on github. For a larger example of a project using py_cui, see pyautogit.