Command Line User Interface¶
Warning
This library is very experimental. Handle with care and expect interface changes with the next update.
The Command Line User Interface (CLUI) is an unicode based “graphical” user interface library. It provides some primitive UI elements documented in this section of the documentation.
Text¶
- class lib.clui.text.Text[source]¶
This class handles the shell output. It sets color and cursor settings and handles the screen.
The default color is gray text on black background (
0;37;40
).Whenever a parameter is a color, the ANSI escape format for colors as strings were expected. These strings were sent to the terminal as shown in the following code example:
def SetColor(color): print("\033[%sm" % color, end="") SetColor("1;32") # bright green text SetColor("44") # blue background
- ClearScreen()[source]¶
This method clears the screen using the ANSI escape squence
[2J
.- Returns
Nothing
- FlushScreen()[source]¶
This method forces the shell to flush the stdout buffer. After calling this method, everything written into the output buffer will be visible on the screen.
- Returns
Nothing
- GetKey()[source]¶
This method returns the name of the pressed key. The key input gets not printed to the screen.
Until now, the following keys will be recognized:
The usual prinable keys
escape
(Must be hit twice)enter
,backspace
,delete
backtab
(shift+tab)up
,down
,left
,right
,end
,home
page down
,page up
Ctrl-D
(Quit),Ctrl-W
(Delete Word),Ctrl-U
(Delete Line)
In case you want to get other keys, it is easy to add them by editing the code of this method. I just implemented the one I need for the
ListView
UI element.- Returns
The pressed key. If it is a special key, then the name of the key gets returnd as string.
None
will be returnd for unknown keys.
- GetRawKey()[source]¶
This method reads a raw key input from the input buffer without printing it on the screen.
Usually you want to use the more abstract method
GetKey()
- Returns
The key from the input buffer
- GetScreenSize()[source]¶
This method returns the screen size as columns and rows. For detecting the screen size, the tool
stty
gets called:stty size
- Returns
columns, rows (as integer)
- PrintText(text)[source]¶
This method simply prints text to the screen. It does nothing more than:
print(text, end="")
So instead of the “normal” print, there will be no line break at the end.
- Returns
Nothing
- SetBGColor(color=None)[source]¶
This method sets the background color. If the color argument is
None
, then the default background color gets used. If the color argument is a color, then a new default backgound color gets defined and set. Next time this method gets called without an argument, this new color will be used as default.- Parameters
color (str) – New background color
- Returns
Nothing
- Raises
TypeError – When argument is set and not a string
- SetColor(fgcolor=None, bgcolor=None)[source]¶
This method calls
SetFGColor()
andSetBGColor()
.
- SetCursor(x, y)[source]¶
This method sets the position of the curser. The top left corner is at position x=0; y=0. y represents the rows and x the columns.
For setting the cursor the ANSI escape sequence
[y;xH
gets used.- Parameters
x (int) – Column position of the cursor
y (int) – Row position of the cursor
- Returns
Nothing
- Raises
TypeError – When x or y are not of type integer
ValueError – When x or y are negative
- SetFGColor(color=None)[source]¶
This method sets the foreground (text) color. If the color argument is
None
, then the default foreground color gets used. If the color argument is a color, then a new default foreground color gets defined and set. Next time this method gets called without an argument, this new color will be used as default.- Parameters
color (str) – New foreground (text) color
- Returns
Nothing
- Raises
TypeError – When argument is set and not a string
Frame¶
- class lib.clui.frame.Frame(linestyle=0)[source]¶
This class provides an unicode based frame that gets printed around a certain area.
There are the following styles available:
LINESTYLE_NORMAL
:┌─┐ │ │ └─┘
LINESTYLE_BOLD
:┏━┓ ┃ ┃ ┗━┛
LINESTYLE_ASCII
:+-+ | | +-+
LINESTYLE_DOUBLE
:╔═╗ ║ ║ ╚═╝
LINESTYLE_ROUND
:╭─╮ │ │ ╰─╯
- Parameters
linestyle – The style used to draw the lines. The default linestyle is
LINESTYLE_NORMAL
.
- Draw(x, y, w, h)[source]¶
This method draws the frame around a certain area.
The upper left corner of the frame will be at (x;y), the bottom right corner at (x+w;y+h)
Only the frame characters gets drawn. Every character inside the frame stays. So this method can also be called to draw a frame around already printed content.
- Parameters
x (int) – Start position of the frame (top left corner)
y (int) – Start position of the frame (top left corner)
w (int) – width of the frame
h (int) – height of the frame
- Returns
Nothing
- Raises
TypeError – When one of the arguments is not of type integer.
ValueError – When x or y is negative.
Pane¶
- class lib.clui.pane.Pane(title=None, x=0, y=0, w=0, h=0)[source]¶
This class can be used to define a whole, filled are in the shell. The area consist of spaces in the defined color. Around the area, a
Frame
gets printed.If a title is set, then this title gets printed in the top left corner of the frame. The title gets surrounded by a space character.
The coordinates define the placement of the frame, the usable area starts with an offset of one.
- Parameters
title (str) – Optional title for the area.
x (int) – Start position of the frame (top left corner) of this area
y (int) – Start position of the frame (top left corner) of this area
w (int) – width of the frame
h (int) – height of the frame
ListView¶
- class lib.clui.listview.ListView(title=None, x=0, y=0, w=0, h=0)[source]¶
This class provides a ListView that shows a list the user can scroll through using the arrow keys.
The data shown in the list must be a string. For derived classes, they can be considered abstract and contain any kind of type as long as you adopt the
onDrawElement()
method.An example on how to use this class with complex data structures:
class MusicView(ListView): def __init__(self, title): ListView.__init__(self, title) def SetData(self, artists, albums, songs): artistdata = [("artist", name) for name in artists] albumdata = [("album", name) for name in albums ] songdata = [("song", name) for name in songs ] data = [] data.extend(artistdata) data.extend(albumdata ) data.extend(songdata ) ListView.SetData(self, data) def onDrawElement(self, element, number, maxwidth): tag = element[0] path = element[1] maxnamelen = maxwidth - 6 # - "[xxx] " string = "\033[1;30m[" if tag == "artist": string += "art" elif tag == "album": string += "alb" elif tag == "song": string += "sng" else: string += "INV" string += "] \033[1;34m" string += path[:(maxnamelen)].ljust(maxpathlen) return string artists = ["Artist A", "Brtist B"] albums = ["An album", "And Another Album"] songs = ["This is a song name"] sv = MusicView("Music", 2, 2, 10, 5) sv.SetData(artists, albums, songs) sv.Draw()
The elements in the list are stored in a variable
elements
. This list can be maintained usingSetData()
.A second variable
linemarker
points (in form of an index) to the selected element in this list. The element the linemarker points to can be accessed viaGetSelectedData()
andSetSelectedData()
When the list of element exceeds the height of the list, a scroll bar will be printed in place of the right frame edge.
- Parameters
title (str) – Title of the list view
x (int) – Position of the list view
y (int) – Position of the list view
w (int) – Width and height
h (int) – Width and height
- Draw()[source]¶
This method draws the list of elements. If the list exceeds the height of the list view, a scroll bar gets added and the user can scroll though the data.
The background of the list view will be black. The surrounding frame is red. The lines in the list will be printed in blue. The selected line gets a cyan background color.
- Returns
Nothing
- GetSelectedData()[source]¶
This method returns the selected element from the list.
- Returns
The selected element
- HandleKey(key)[source]¶
This method must be called whenever a key was pressed and this list view is “active”. It expects the key name returned by
lib.clui.text.Text.GetKey()
.If the key is
"up"
the element above the current selected element gets selected. If the key is"down"
the one below will be selected. Any other key gets passed to theonAction()
method. Read the documentation of theonAction()
method to see how the return value of that method gets processed.After handling an key, the
Draw()
method gets called to refresh the view.- Parameters
key (str) – Key name that shall be handled
- Returns
Nothing
- SetData(elements)[source]¶
This method can be used to initialize the list of data that will be shown in the list view If the
onDrawElement()
method is not overloaded, the list must contain strings.After setting the new
elements
list, thelinemarker
gets set to the begin of the list.- Parameters
elements (list) – A list of data
- Returns
Nothing
- SetSelectedData(element)[source]¶
Replaces the selected element with a new one. This method can be used to interact with the list without triggering the
onAction()
callback.- Parameters
element – An element that replaces the selected element
- Returns
Nothing
- onAction(element, key)[source]¶
This method gets called when a key gets passed to the
HandleKey()
method. It is supposed to process the selected line in the list of elements. In this class, nothing will be done with the data.This function must return the processed element back to the list. It is also possible to return a new element to replace the old one. When a line shall not be updated, return None. A case where this may be useful will be presented in the following example:
def onAction(self, element, key): # this method manipulates a list of numbers if key == "r": # remove element self.elements.remove(element) return None elif key == "a": # append number to list self.elements.append("0") elif key == "0": # reset number return "0" elif key == "+": # increment number element = str(int(element) + 1) elif key == "-": # decrement number element = str(int(element) - 1) return element
When the last element gets removed, the
linemarker
variable gets moved to the previous line. Otherwise it stays at its position that will now be the element next after the removed one.- Parameters
element – The selected element in the list
key (str) – The key that was pressed while the element was selected
- Returns
The modified element that will be put back in the list of elements.
- onDrawElement(element, number, maxwidth)[source]¶
This method gets called when an element gets printed into the list view. To customize how elements will appear in the list, overload this method.
The returned string can contain ANSI Escape Sequences for coloring. The number of printable character should not exceed the maximum width
maxwidth
. Furthermore the string should be exactmaxwidth
wide.An example how to implement a custom
onDrawElement
method can be seen in the following code example:def onDrawElement(self, element, number, maxwidth): # Print the element number in front of each entry. # Alternate the text color with each line. Odd lines in white, even in blue. num = "%2d: "%(number) # start list entry with the index of the element val = element[:maxwidth-4] # Limit string to max width. 4 Characters are consumed for the num variable # Alternating colors with each line # Colors do not count to the width of the string because they are not printable if num % 2: color = "\033[1;37m" # Set color to white for odd lines else: color = "\033[1;34m" # Set color to blue for even lines return color + num + val
- Parameters
element – The element that shall be printed.
number (int) – The index of the element in the list of all elements
maxwidth (int) – The maximum number of characters that can be printed in one line of the list view
- Returns
The string that will be printed in one line of the list view
Dialog¶
- class lib.clui.dialog.Dialog(title=None, x=0, y=0, w=0, h=0)[source]¶
This class provides a dialog box that is organized like a list view.
It provides one input element per line over several lines. The lines can be selected using the up (↑) and down (↓) key. Pressing the space bar on an
BoolInput
toggles its value. On enter (↵), the changes shoud be committed, on escape (␛) they should be rejected.Beside the list of input elements a
ButtonView
gets printed at the bottom of the dialog view telling the user about the key mentioned above.The dialog works on a list with each element beeing a tuple of a label, the control itself and a hint for the user.
Example on using a Dialog:
dialog = Dialog("Add Unicode Icon", 1, 1, 40, 10) nameinput = TextInput() iconinput = TextInput() varselector= BoolInput() dialog.AddInput("Name:", self.nameinput, "Visibly for user") dialog.AddInput("Icon:", self.iconinput, "Unicode char") dialog.AddInput("U+FE0E:",self.varselector, "Do not replace with emoji")
- Parameters
title (str) – Title of the list view
x (int) – Position of the list view
y (int) – Position of the list view
w (int) – Width and height
h (int) – Width and height
- AddInput(label, control, hint=None)[source]¶
This method adds a new control to the list of controls. The input control element must provide a
Draw
and aHandleKey
method. Position and width of the control element will be calculated when they get printed. The label gets printed in front of the control element, the hint at the end of the list entry.- The following inputs are suitable for the dialog:
lib.clui.textinbut.TextInput
- Parameters
label (str) – Label of the input element
control – The input element itself
hint (str) – An additional hint to the input element.
None
for no hint.
- Returns
Nothing
- HandleKey(key)[source]¶
This method must be called whenever a key was pressed and this dialog is “active”. It expects the key name returned by
lib.clui.text.Text.GetKey()
.If the key is
"up"
the element above the current selected element gets selected. If the key is"down"
the one below will be selected. This will be done by passing the up and down key to theHandleKey
method of the base class.Any other key gets passed to the
onAction()
method of this class.After handling an key, the
Draw()
method gets called to refresh the view.- Parameters
key (str) – Key name that shall be handled
- Returns
Nothing
- onAction(element, key)[source]¶
This method gets called when a key gets passed to the
HandleKey()
method. It is supposed to get passed to the selected control element.- Parameters
element – The selected element in the list
key (str) – The key that was pressed while the element was selected
- Returns
Nothing
- onDrawElement(element, number, maxwidth)[source]¶
This method gets called when an element gets printed into the dialog view. Keep in mind that the dialog element is not able to scroll.
The
element
is a tuple containing the label, the control element and the hint. If the number of characters is too high, the hints will not be printed. The number of printable characters gets calculated by the with of the label and hint of each row. It should be at least 10 characters be left for the control, and 2 for spaces around the control.- Parameters
element – The element that shall be printed.
number (int) – The index of the element in the list of all elements and at the same time the y coordinate
maxwidth (int) – Will be ignored
- Returns
Nothing
- Raises
ValueError – In case the with of the dialog is to small to print at least the label and the input control
TextInput¶
- class lib.clui.textinput.TextInput(x=0, y=0, w=0)[source]¶
This class provides a simple one-line text input element.
The cursor mentioned in this class documentation is not related to the cursor of the terminal! Each TextInput maintain its own cursor.
- Parameters
x (int) – Position of the list view
y (int) – Position of the list view
w (int) – Width
- Draw()[source]¶
This method draws the input control and the cursor. The input elements color are white text on blue background. The element the cursor points to has a cyan background.
- Returns
Nothing
- HandleKey(key)[source]¶
This method handled the users input. The keys are expected as the method
lib.clui.text.Text.GetKey()
returns. With the"right"
and"left"
key, the user can navigate through the text. With"backspace"
the character left to the cursor gets removed. With"delete"
the character right below the cursor. Each printable character gets inserted left to the cursor.- Parameters
key (str) – Key name that shall be handled
- Returns
Nothing
- SetData(string)[source]¶
This method sets the data of the input element. The cursor points to the end of the input data.
Note
The string gets normalized (NFC). All further manipulations of the string won’t be normalized.
- Parameters
string (str) – String that will be used as the input
- Returns
Nothing
- Raises
TypeError – When string is not of type string
BoolInput¶
- class lib.clui.boolinput.BoolInput(x=0, y=0, data=None)[source]¶
This class provides a simple boolean input element.
None
is also allowed!Default representation is:
[✔]
True[✘]
False[❓]
None
- Parameters
x (int) – Position of the list view
y (int) – Position of the list view
data (bool) –
True
,False
orNone
representing the input of the BoolInput element
- HandleKey(key)[source]¶
Space key toggles the value of the input element. When the previos value was
None
,True
will be the next. Then it alters betweenTrue
andFalse
- Parameters
key (str) – Key name that shall be handled
- Returns
Nothing
- SetData(data)[source]¶
This method sets the data of the input element
- Parameters
data (bool) –
True
,False
orNone
representing the input of the BoolInput element- Returns
Nothing
- SetRepresentation(true=None, false=None, none=None)[source]¶
Define the representation of True, False and None in form of an Unicode character.
- Parameters
true (str) – Unicode to represent one of the three states
false (str) – Unicode to represent one of the three states
none (str) – Unicode to represent one of the three states
- Returns
Nothing
- Raises
TypeError – when an argument is not
None
and not of type stringValueError – when the string is larger than one character
TabGroup¶
- class lib.clui.tabgroup.TabGroup[source]¶
This class can be used to group multiple UI elements. They can be selected by pressing tab (
" "
). All other keys get passed to the selected UI element. The selected element gets highlighted by setting its frame line-style toFrame.LINESTYLE_BOLD
.