Welcome to cursed!
This is a simplified wrapper around the curses library to provide an easy API to create a curses application, with easy concurrency across windows. It provides a simple menu implementation as well.
The best way to get started is to look at an example. Here’s the examples/menu.py example from the main repository, with extra comments to explain the various parts:
from cursed import CursedApp, CursedWindow, CursedMenu
# You instanciate the application through instanciating a CursedApp
app = CursedApp()
# The way to create windows is by creating classes derived from the
# CursedWindow class. These must have X, Y, WIDTH, and HEIGHT specified
# as class variables. 'max' or an integer value are valid for WIDTH and
# HEIGHT.
# A new gevent thread will be spawned for each window class.
# These act like singletons, and all functions should be class methods.
# The class itself will never be instanciated.
class MainWindow(CursedWindow):
X, Y = (0, 0)
WIDTH, HEIGHT = 'max', 23
# To create a menubar, you create a CursedMenu instance in a MENU
# class variable.
# You add a menu to it with the add_menu function, and specify the
# title, optional hotkey, and a list of menu items in the form of
# (name, hotkey, callback) or (name, callback).
# Menu items can be chosen by hotkeys or by the arrow keys and enter.
MENU = CursedMenu()
MENU.add_menu('File', key='f', items=[
('Save', 's', 'save'),
('Quit', 'q', 'quit'),
])
MENU.add_menu('Edit', key='e', items=[
('Copy', 'c', 'copy'),
('Delete', 'delete')
])
# Decorate your methods with @classmethod since no instance will ever
# be instanciated.
@classmethod
def save(cls):
# cls.addstr will write a string to x and y location (5, 5)
cls.addstr('File->Save', 5, 5)
@classmethod
def quit(cls):
# The quit function will run before the window exits.
# Killing the window is triggered with cls.trigger('quit'),
# which is the same way to trigger any other function in the
# CursedWindow.
cls.addstr('Quitting', 5, 5)
@classmethod
def copy(cls):
cls.addstr('edit->copy', 5, 5)
@classmethod
def delete(cls):
cls.addstr('edit->delete', 5, 5)
@classmethod
def update(cls):
# The update function will be looped upon, so this is where you
# want to put the main logic. This is what will check for key
# presses, as well as trigger other functions through
# cls.trigger.
# Handle input here, other than what the menu will handle through
# triggering callbacks itself.
cls.addstr('x=10, y=12', 10, 12)
# Press spacebar to open menu
k = cls.getch()
if k == 32:
cls.openmenu()
class FooterWindow(CursedWindow):
# This window will appear on the bottom, print the string
# "Press f then q to exit", then quit. The message will stay on the
# screen.
# All windows must have called 'quit' to exit out of the program, or
# simply ctrl-C could be pressed.
X, Y = (0, 23)
WIDTH, HEIGHT = 'max', 1
@classmethod
def init(cls):
cls.addstr('Press f then q to exit')
cls.refresh()
cls.trigger('quit')
# You need to call app.run() to start the application, which handles
# setting up the windows.
result = app.run()
print(result)
# This checks if ctrl-C or similar was pressed to kill the application.
if result.interrupted():
print('Ctrl-C pressed.')
else:
# This will reraise exceptions that were raised in windows.
result.unwrap()
That’s the essentials of it. Just remember to trigger(‘quit’) to all your windows if you want it to exit cleanly.
Added pads!
Now, you can specify a pad CursedWindow like so:
class MyPad(CursedWindow):
X, Y = 0, 0
WIDTH, HEIGHT = 40, 40
# set PAD to True
PAD = True
# the top left of the region to display
PAD_X, PAD_Y = 0, 0
# the virtual width and height, which you can scroll around to
PAD_WIDTH, PAD_HEIGHT = 500, 500
@classmethod
def update(cls):
...
# get new coordinates for top left of region
...
cls.PAD_X, cls.PAD_Y = top_left_x, top_left_y
...
# will now display the correct region in a smaller 40x40 display
cls.refresh()
This is useful for when you might want to do something like scroll through a map. See examples/pad.py for an example which scrolls through text using the arrow keys.
Bases: object
The CursedApp is the main class which is used to track windows that are created and finally run the application.
The CursedApp is initialized then run in the main function to build the windows.
Example:
from cursed import CursedApp, CursedWindow
app = CursedApp()
class MainWindow(CursedWindow):
X, Y = (0, 0)
WIDTH, HEIGHT = ('max', 'max')
...
result = app.run()
result.unwrap()
Runs all the windows added to the application, and returns a Result object.
Bases: object
Result represents the object returned by app.run(), which may contain exception information.
Returns the exception or None.
Returns True if the application was interrupted, like through Ctrl-C.
Return True if no exception occurred.
Prints the exception traceback.
Unwraps the Result, raising an exception if one exists.
cursed.window
This contains the core logic used by cursed to create the window and offer the ncurses interface to display everything.
Bases: object
The CursedWindow should be the parent class of all Window classes you declare. Each should have class variables X, Y, WIDTH, and HEIGHT declared. WIDTH and HEIGHT can be integers or ‘max’.
Each function in a class derived from CursedWindow should be a classmethod, since no instances of the class will be created. The code will run as the single class, like a singleton.
Add a character to a position on the screen or at cursor.
Parameters: |
|
---|
write at most n characters at specified position or cursor.
Parameters: |
|
---|
write the string onto specified position or cursor, overwriting anything already at position.
Parameters: |
|
---|
Either the x position of cursor, or sets the x position. Example:
# gets the x position of cursor
my_x = cls.cx()
# set the x position to 20
cls.cx(20)
# moves right 2 spots
cls.cx(cls.cx() + 2)
Parameters: | x – optional x position to move to |
---|---|
Returns: | if x not specified, returns the x position of cursor |
Either the y position of cursor, or sets the y position. Example:
# gets the y position of cursor
my_y = cls.cy()
# set the y position to 20
cls.cy(20)
# moves down 2 spots
cls.cy(cls.cy() + 2)
Parameters: | y – optional y position to move to |
---|---|
Returns: | if y not specified, returns the y position of cursor |
Delete a character at position, at cursor or specified position.
Parameters: |
|
---|
Get the integer value for the keypress, such as 27 for escape.
Returns: | integer keycode of keypress |
---|
Get the key that was pressed, or None. This is useful to simply check what key was pressed on the keyboard, ignoring special keys like the arrow keys.
Returns: | character specifying key pressed, like ‘a’ or ‘C’ |
---|
Get string input from user at position, with optional prompt message.
Parameters: |
|
---|---|
Returns: | the string the user input |
Get the width and height of a window.
Returns: | (width, height) |
---|
Get the x and y position of the cursor.
Returns: | (x, y) |
---|
Insert a horizontal line at position, at most n characters or width of window.
Parameters: |
|
---|
Return the character and attributes of the character at the specified position in the window or cursor.
Parameters: |
|
---|---|
Returns: | (character, attributes) |
Write a character at specified position or cursor, with attributes.
Parameters: |
|
---|
Insert a string at cursor or specified position, at most n characters. Cursor is not moved and characters to the right are shifted right. If n is zero, all characters are inserted.
Parameters: |
|
---|
Insert a string at cursor or specified position. Cursor is not moved and characters to the right are shifted right.
Parameters: |
|
---|
Return a string at cursor or specified position. If n is specified, returns at most n characters.
Parameters: |
|
---|---|
Returns: | string at position |
Moves cursor to x and y specified.
Parameters: |
|
---|
Goes to the next line like a carriage return.
Opens the menu, if menu is specified for the window.
Reorients where the top left of the PAD should be, so it knows which region to display to the user.
Parameters: |
|
---|
Redraws the window.
Tell the CursedWindow’s greenlet to sleep for seconds. This should be used to allow other CursedWindow’s greenlets to execute, especially if you have long running code in your update classmethod.
This is purely a restriction imposed by gevent, the concurrency library used for cursed. It is not truly parallel, so one long running greenlet can lock up execution of other windows. Calling cls.sleep() even with zero seconds (default) will allow other greenlets to start execution again.
There is no benefit to calling sleep with a number other than zero. Zero will allow other greenlets to take over just fine.
Parameters: | seconds – seconds to sleep. default zero is fine. |
---|
Triggers a class function to be run by that window. This can be run across gevent coroutines to trigger other CursedWindow classes to run functions in their context.
This is also used to cause a window to “quit” by running something like:
MainWindow.trigger('quit')
Parameters: |
---|
Insert a vertical line at position, at most n characters or height of window.
Parameters: |
|
---|
Writes a msg to the screen, with optional x and y values. If newlines are present, it goes to the next line.
Parameters: |
|
---|
cursed.exceptions
Base exceptions used by cursed.
Bases: exceptions.RuntimeError
Raised when a callback issue occurs, such as triggering a callback that doesn’t exist, example:
cls.trigger('typo_in_nmae')
Bases: exceptions.RuntimeError
Raised when menus aren’t initialized correctly. Check in the CursedMenu documentation or the example projects for examples of proper creation of menus.
Bases: exceptions.ValueError
Raised when you screw up setting up a PAD type CursedWindow, either by not specifying the PAD_WIDTH or PAD_HEIGHT.
Bases: exceptions.RuntimeError
Raised when a terminal size issue occurs, such as the menu not fitting in the width of the screen, or writing text outside of the window.
Bases: exceptions.ValueError
Raised when you screw up with the initial CursedWindow class variables, like not setting WIDTH or HEIGHT.
cursed.meta
This contains the metaclass used to decorate all user classes that subclass CursedWindow, crucial for the curses interface to work.
cursed
Simplified curses interface with concurrency, for quick and sane curses apps. Allows easy creation of windows and menus. Code for each window runs concurrently.
Bases: object
The CursedApp is the main class which is used to track windows that are created and finally run the application.
The CursedApp is initialized then run in the main function to build the windows.
Example:
from cursed import CursedApp, CursedWindow
app = CursedApp()
class MainWindow(CursedWindow):
X, Y = (0, 0)
WIDTH, HEIGHT = ('max', 'max')
...
result = app.run()
result.unwrap()
Runs all the windows added to the application, and returns a Result object.
Bases: object
The CursedWindow should be the parent class of all Window classes you declare. Each should have class variables X, Y, WIDTH, and HEIGHT declared. WIDTH and HEIGHT can be integers or ‘max’.
Each function in a class derived from CursedWindow should be a classmethod, since no instances of the class will be created. The code will run as the single class, like a singleton.
Add a character to a position on the screen or at cursor.
Parameters: |
|
---|
write at most n characters at specified position or cursor.
Parameters: |
|
---|
write the string onto specified position or cursor, overwriting anything already at position.
Parameters: |
|
---|
Either the x position of cursor, or sets the x position. Example:
# gets the x position of cursor
my_x = cls.cx()
# set the x position to 20
cls.cx(20)
# moves right 2 spots
cls.cx(cls.cx() + 2)
Parameters: | x – optional x position to move to |
---|---|
Returns: | if x not specified, returns the x position of cursor |
Either the y position of cursor, or sets the y position. Example:
# gets the y position of cursor
my_y = cls.cy()
# set the y position to 20
cls.cy(20)
# moves down 2 spots
cls.cy(cls.cy() + 2)
Parameters: | y – optional y position to move to |
---|---|
Returns: | if y not specified, returns the y position of cursor |
Delete a character at position, at cursor or specified position.
Parameters: |
|
---|
Get the integer value for the keypress, such as 27 for escape.
Returns: | integer keycode of keypress |
---|
Get the key that was pressed, or None. This is useful to simply check what key was pressed on the keyboard, ignoring special keys like the arrow keys.
Returns: | character specifying key pressed, like ‘a’ or ‘C’ |
---|
Get string input from user at position, with optional prompt message.
Parameters: |
|
---|---|
Returns: | the string the user input |
Get the width and height of a window.
Returns: | (width, height) |
---|
Get the x and y position of the cursor.
Returns: | (x, y) |
---|
Insert a horizontal line at position, at most n characters or width of window.
Parameters: |
|
---|
Return the character and attributes of the character at the specified position in the window or cursor.
Parameters: |
|
---|---|
Returns: | (character, attributes) |
Write a character at specified position or cursor, with attributes.
Parameters: |
|
---|
Insert a string at cursor or specified position, at most n characters. Cursor is not moved and characters to the right are shifted right. If n is zero, all characters are inserted.
Parameters: |
|
---|
Insert a string at cursor or specified position. Cursor is not moved and characters to the right are shifted right.
Parameters: |
|
---|
Return a string at cursor or specified position. If n is specified, returns at most n characters.
Parameters: |
|
---|---|
Returns: | string at position |
Moves cursor to x and y specified.
Parameters: |
|
---|
Goes to the next line like a carriage return.
Opens the menu, if menu is specified for the window.
Reorients where the top left of the PAD should be, so it knows which region to display to the user.
Parameters: |
|
---|
Redraws the window.
Tell the CursedWindow’s greenlet to sleep for seconds. This should be used to allow other CursedWindow’s greenlets to execute, especially if you have long running code in your update classmethod.
This is purely a restriction imposed by gevent, the concurrency library used for cursed. It is not truly parallel, so one long running greenlet can lock up execution of other windows. Calling cls.sleep() even with zero seconds (default) will allow other greenlets to start execution again.
There is no benefit to calling sleep with a number other than zero. Zero will allow other greenlets to take over just fine.
Parameters: | seconds – seconds to sleep. default zero is fine. |
---|
Triggers a class function to be run by that window. This can be run across gevent coroutines to trigger other CursedWindow classes to run functions in their context.
This is also used to cause a window to “quit” by running something like:
MainWindow.trigger('quit')
Parameters: |
---|
Insert a vertical line at position, at most n characters or height of window.
Parameters: |
|
---|
Writes a msg to the screen, with optional x and y values. If newlines are present, it goes to the next line.
Parameters: |
|
---|
Bases: object
The CursedMenu is the class which is used to initialize all the menus and items.
This creates a full menu with a title, an optional hotkey, and a list of items inside the menu, with their name, hotkey and callback.
Example:
MENU = CursedMenu('File', key='f', items=[
('Save', 's', 'save_callback'),
('Open', 'open_callback'),
('Quit', 'q', 'quit'),
])