API documentation (autogenerated)

ascii_designer package

ASCII Designer: Library to generate Forms from ASCII Art… and then some.

AutoFrame is the main workhorse class. Subclass it and set the f_body and maybe further attributes.

Package overview:

  • autoframe provides the AutoFrame class, which by itself contains the build logic and the automatic binding infrastructure.
  • toolkit provides the widget generators and actual value and event binding. The base ToolkitBase contains the parsing function and lots of abstract methods.
  • toolkit_tk and toolkit_qt provide actual implementations of the Toolkit interface.
  • ascii_slice contains the text slicing algorithm used to cut text into grid cells.
  • list_model contains the list-like value class for list view / tree view. The ObsList is toolkit-agnostic and has has lots of hooks where the GUI bindings (in the toolkit_ modules) connect to.
class ascii_designer.AutoFrame[source]

Automatic frame.

class name is converted to title. Override with f_title.

Set window icon by giving an icon file’s path in f_icon. Supported formats are OS-specific; recommended are .ico on Windows and .png on Unix.

Body definition with f_body, menu definition with f_menu.

To create own widgets or customize the autocreated ones, override f_on_build.

To add initialization code, override f_on_show.

Get at the created controls using AutoFrame[key].

close(), exit(), quit() provided for convenience.

Functions with same name as a control are autobound to the default handler (click or changed).

Attributes are autobound to the control value (get/set), except if they are explicitly overwritten.

close()[source]

Close the window.

This is also called when the window is closed using the x button. Be sure to call super().close() or your window won’t close.

exit()[source]
f_add_widgets(parent, sliced_grid=None, body=None, offset_row=0, offset_col=0, autoframe=None)[source]
f_build(parent, body=None)[source]
f_build_menu(parent, menu=None)[source]

Builds the menu from the given menu definition.

Menu definition is a list which can (currently) contain actions and submenus.

An Action is simply a string, which is converted to an identifier following the same rules as the other widgets. It triggers the self. method named as the identifier. The method must be defined.

A submenu is created by a string ending in “>”, followed by an item which is itself a list (the submenu content).

Example

>>> menu = [
        'File >', ['Open', 'Save', 'Quit'],
        'Help >', ['About'],
    ]
>>> autoframe.f_build_menu(autoframe.f_controls(''), menu)
f_on_build()[source]

Hook that is called after form has been built.

Override this to add custom initialization of widgets.

f_on_show()[source]

Hook that is called when form is about to be shown on screen.

In contrast to f_on_build, this is called again if the form is closed and reopened.

f_option_tk_autovalidate = False

If True, tk/ttk Entry and Combobox are set up for automatic update of widget state when validated.

I.e. when value is retrieved or handler is called, the widgets foreground color (tk) or invalid state (ttk) is updated.

Opt-in, because it might interfere with user code if not expected.

f_show()[source]

Bring the frame on the screen.

f_translations = {}

Translation dictionary.

This can be set per-form or globally on the AutoFrame class. We only actually need the .get(key, default) method.

Translation keys are formed as <Class name>.<Widget ID>.

Translations are used in f_build and f_build_menu functions. Currently there is no facility to retranslate after building the form.

quit()[source]
ascii_designer.set_toolkit(toolkit_name, toolkit_options=None)[source]

Set the toolkit to use and toolkit options.

Toolkit name can be tk, ttk, qt.

toolkit_options is a dictionary of toolkit specific global settings like font size or theme. See ToolkitTk, ToolkitQt.

class ascii_designer.EventSource[source]

Event dispatcher class

You can register / unregister handlers via += and -= methods.

Handlers may return a result. If multiple handlers return results, last one is returned to the event’s source.

exception ascii_designer.CancelEvent[source]

Raise this in an event handler to inhibit all further processing.

class ascii_designer.Invalid[source]

Sentinel object to signal that the read value was invalid.

Invalid will returned as itself (i.e. not as instance).

ascii_designer.nullable(convert)[source]

Creates a converter that returns None on empty string, otherwise applies given converter.

>>> generic_var = GenericVar(tkroot, convert=nullable(float))
>>> generic_var.set("1.0")
>>> generic_var.get()
1.0
>>> generic_var.set("")
>>> generic_var.get()
None
>>> generic_var.set("foo")
>>> generic_var.get()
<class Invalid>
ascii_designer.gt0(convert)[source]

Applies convert, then raises if value is not greater than 0.

convert must return something number-like.

>>> generic_var.convert = gt0(int)
ascii_designer.ge0(convert)[source]

Applies convert, then raises if value is not greater or equal to 0.

convert must return something number-like.

>>> generic_var.convert = ge0(int)
class ascii_designer.Translations[source]

Mostly off-the shelf python dict, except for two facilities to aid translation.

Translations should be retrieved via .get(key, default) method.

The class has the two additional properties recording and mark_missing.

  • If recording is set to True, calls of get will add missing entries (i.e. get does the same as setdefault). By setting it and opening all forms once, you can collect all translation keys and default strings.
  • If mark_missing is set and get finds a missing key, the given default value is prefixed with a $ sign.
get(key, default=None)[source]

Return the value for key if key is in the dictionary, else default.

mark_missing = False
recording = False
ascii_designer.load_translations_json(package_or_dir='locale', prefix='', language=None)[source]

Locate and load translations from JSON file.

JSON file format is a simple key value store.

If given a package name, use the resource loading system. If given a dir, use file access.

The argument is interpreted as dir if:

  • the string contains / or \
  • the argument is a pathlib.PurePath instance.

Resource name is formed by the rule “<prefix>.<language>.json” (first dot is ommited if one of both is empty). If both prefix and language are empty, we look for default.json.

If the language is not given, the OS’s UI language is used.

With the given or guessed language we look for an existing file:

  • First we look for the exact language string (e.g. “de_DE.json”)
  • then we look for the first two letters of the language string (“de.json”)
  • then we look for emtpy language (i.e. default set).

If none of these exists, empty Translations object is returned.

ascii_designer.save_translations_json(translations, path)[source]

Save translations to JSON file.

OVERWRITES existing file!

In contrast to load_translations_json, we only accept a path here.

ascii_designer.autoframe module

Warning

module ‘ascii_designer.autoframe’ undocumented

class ascii_designer.autoframe.AutoFrame[source]

Automatic frame.

class name is converted to title. Override with f_title.

Set window icon by giving an icon file’s path in f_icon. Supported formats are OS-specific; recommended are .ico on Windows and .png on Unix.

Body definition with f_body, menu definition with f_menu.

To create own widgets or customize the autocreated ones, override f_on_build.

To add initialization code, override f_on_show.

Get at the created controls using AutoFrame[key].

close(), exit(), quit() provided for convenience.

Functions with same name as a control are autobound to the default handler (click or changed).

Attributes are autobound to the control value (get/set), except if they are explicitly overwritten.

close()[source]

Close the window.

This is also called when the window is closed using the x button. Be sure to call super().close() or your window won’t close.

exit()[source]
f_add_widgets(parent, sliced_grid=None, body=None, offset_row=0, offset_col=0, autoframe=None)[source]
f_build(parent, body=None)[source]
f_build_menu(parent, menu=None)[source]

Builds the menu from the given menu definition.

Menu definition is a list which can (currently) contain actions and submenus.

An Action is simply a string, which is converted to an identifier following the same rules as the other widgets. It triggers the self. method named as the identifier. The method must be defined.

A submenu is created by a string ending in “>”, followed by an item which is itself a list (the submenu content).

Example

>>> menu = [
        'File >', ['Open', 'Save', 'Quit'],
        'Help >', ['About'],
    ]
>>> autoframe.f_build_menu(autoframe.f_controls(''), menu)
f_on_build()[source]

Hook that is called after form has been built.

Override this to add custom initialization of widgets.

f_on_show()[source]

Hook that is called when form is about to be shown on screen.

In contrast to f_on_build, this is called again if the form is closed and reopened.

f_option_tk_autovalidate = False

If True, tk/ttk Entry and Combobox are set up for automatic update of widget state when validated.

I.e. when value is retrieved or handler is called, the widgets foreground color (tk) or invalid state (ttk) is updated.

Opt-in, because it might interfere with user code if not expected.

f_show()[source]

Bring the frame on the screen.

f_translations = {}

Translation dictionary.

This can be set per-form or globally on the AutoFrame class. We only actually need the .get(key, default) method.

Translation keys are formed as <Class name>.<Widget ID>.

Translations are used in f_build and f_build_menu functions. Currently there is no facility to retranslate after building the form.

quit()[source]

ascii_designer.ascii_slice module

Functions to slice up a fixed-column-width ASCII grid.

slice_grid splits up lines according to a header row with | separators.

merged_cells iterates over this grid and returns merge areas.

Columns are merged if there is something different from | or space below the separator in the header row.

Rows are merged by prefixing the cells with {. The symbols must be in the same text column.

ascii_designer.ascii_slice.slice_grid(grid_text)[source]

slice a grid up by the first (nonempty) row.

Before slicing, empty lines before/after are removed, and the text is dedented.

The first row is split by | characters. The first column can contain a | character or not.

Returns a SlicedGrid with Properties:
  • column_heads: the split up parts of the first line (not including the separators).
  • body_lines: list of following lines; each item is a list of strings, where each string is the grid “cell” including the preceding separator column. I.e. if you join the cell list without separator, you regain the text line.
class ascii_designer.ascii_slice.SlicedGrid(column_heads=NOTHING, body_lines=NOTHING)[source]

Warning

class ‘ascii_designer.ascii_slice.SlicedGrid’ undocumented

ascii_designer.ascii_slice.merged_cells(sliced_grid)[source]

Generator: takes the sliced grid, and returns merged cells one by one.

Cells are merged by the following logic:

  • If the first character of a (stripped) cell is ‘{’, cells of the following row(s) are merged while they also start with ‘{’ in the same column.
  • Then, columns are merged if the following (column’s) cell starts neither with space nor with ‘|’.

Yields MCell instances with:

  • row, col: cell position (int, 0-based)
  • rowspan, colspan: spanned rows/cols, at least 1
  • text: merged area text, as sliced out from the text editor; not including the leading ‘{’; “ragged” linebreaks retained.

Iteration order is row-wise.

Merge areas must not overlap. (However this should rarely happen on accident).

Note: If you need two row-merge ranges above each other, indent the ‘{’ differently.

class ascii_designer.ascii_slice.MCell(row, col, text='', rowspan=1, colspan=1)[source]

Warning

class ‘ascii_designer.ascii_slice.MCell’ undocumented

ascii_designer.toolkit module

Warning

module ‘ascii_designer.toolkit’ undocumented

ascii_designer.toolkit.set_toolkit(toolkit_name, toolkit_options=None)[source]

Set the toolkit to use and toolkit options.

Toolkit name can be tk, ttk, qt.

toolkit_options is a dictionary of toolkit specific global settings like font size or theme. See ToolkitTk, ToolkitQt.

ascii_designer.toolkit.get_toolkit()[source]

Get toolkit instance as previously set.

class ascii_designer.toolkit.ToolkitBase[source]

Warning

class ‘ascii_designer.toolkit.ToolkitBase’ undocumented

anchor(widget, left=True, right=True, top=True, bottom=True)[source]

anchor the widget. Depending on the anchors, widget will be left-, right-, center-aligned or stretched.

box(parent, id=None, text='', given_id='')[source]

An empty panel (frame, widget, however you call it) or group box that you can fill with own widgets.

given_id is the user-given id value, as opposed to id (the autogenerated one). A Group box is created if text AND given_id are set.

The virtual attribute value is the panel itself, or in case of groupbox the contained panel.

button(parent, id=None, text='')[source]
checkbox(parent, id=None, text='', checked=None)[source]

Checkbox

close(frame)[source]

close the frame

col_stretch(container, col, proportion)[source]

set the given col to stretch according to the proportion.

combo(parent, id=None, text='', values=None)[source]

combo box; values is the raw string between the parens. Free-text allowed.

connect(widget, function)[source]

bind the widget’s default event to function.

Default event is:
  • click() for a button
  • value_changed(new_value) for value-type controls;
    usually fired after focus-lost or Return-press.
default_shortcuts = {'copy': 'C-C', 'cut': 'C-X', 'find': 'C-F', 'new': 'C-N', 'open': 'C-O', 'paste': 'C-P', 'redo': 'C-S-Z', 'refresh': 'F5', 'save': 'C-S', 'undo': 'C-Z'}
dropdown(parent, id=None, text='', values=None)[source]

dropdown box; values is the raw string between the parens. Only preset choices allowed.

getval(widget)[source]

get python-type value from widget.

grammar = [('box', '\\<(?:\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:)?\\s*(?P<text>[^(]*?)?\\s*\\>', '"<Text>"'), ('option', '\\((?P<checked> |x)\\)\\s+(?:\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:)?\\s*(?P<text>[^(]*?)?\\s*$', '"( ) text" or "(x) text"'), ('checkbox', '\\[(?P<checked> |x)\\]\\s+(?:\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:)?\\s*(?P<text>[^(]*?)?\\s*$', '"[ ] Text" or "[x] Text"'), ('slider', '\\[\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:\\s*(?P<min>\\d+)\\s*\\-\\+\\-\\s*(?P<max>\\d+)\\s*\\]', '[id: 0 -+- 100]'), ('multiline', '\\[(?:\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:)?\\s*(?P<text>[^(]*?)?\\s*__\\s*\\]', '"[Text__]"'), ('textbox', '\\[(?:\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:)?\\s*(?P<text>[^(]*?)?\\s*_\\s*\\]', '"[Text_]"'), ('treelist', '\\[\\s*=(?:\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:)?\\s*(?P<text>[^(]*?)?\\s*(?:\\((?P<columns>.*?)\\))?\\s*\\]', '"[= Text]" or [= Text (column1, column2, ..)]'), ('combo', '\\[(?:\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:)?\\s*(?P<text>[^(]*?)?\\s*_\\s*(?:\\((?P<values>.*?)\\))?\\s+v\\s*\\]', '"[Text_ v]" or "[Text_ (val1, val2, ...) v]'), ('dropdown', '\\[(?:\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:)?\\s*(?P<text>[^(]*?)?\\s*(?:\\((?P<values>.*?)\\))?\\s+v\\s*\\]', '"[Text v]" or "[Text (val1, val2, ...) v]'), ('button', '\\[(?:\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:)?\\s*(?P<text>[^(]*?)?\\s*\\]', '"[Text]"'), ('label', '(?x)\n (?: # Optional prefix:\n \\s*(?P<id>[a-zA-Z0-9_]+)\\s*:(?=.+) # Identifier followed by : followed by something\n | \\. # OR single .\n )?\n (?P<text>.*?)$ # Any text up to end of string\n ', '"Text" or ".Text"')]
label(parent, id=None, label_id=None, text='')[source]
menu_command(parent, id, text, shortcut, handler)[source]

Append command labeled text to menu parent.

Handler: func() -> None, is immediately connected.

shortcut follows the syntax (modifier)-(key), where modifier is one or more of C, S, A for Ctrl, Shift, Alt respectively.

menu_grammar = [('sub', '(?:\\s*(?P<id>[a-zA-Z0-9_]+)\\s*\\:)?\\s*(?P<text>[^(]*?)?\\s*>', '"text >"'), ('command', '(?ix)\\s*\n (?P<id>[a-zA-Z0-9_]+\\s*\\:)?\n (?P<text>[^#]+)\n (?:\\#(?P<shortcut>[a-zA-Z0-9-]*))?\n ', '"text :C-A-S-x"')]
menu_root(parent)[source]

Create menu object and set as parent’s menu.

menu_sub(parent, id, text)[source]

Append submenu labeled text to menu parent.

multiline(parent, id=None, text='')[source]

multiline text entry box

option(parent, id=None, text='', checked=None)[source]

Option button. Prefix ‘O’ for unchecked, ‘0’ for checked.

parse(parent, text, translations=None, translation_prefix='')[source]

Returns the widget id and widget generated from the textual definition.

Autogenerates id:

  • If given, use it
  • else, try to use text (extract all a-z0-9_ chars)
  • else, use ‘x123’ with 123 being a globally unique number

For label type, id handling is special:

  • The label’s id will be "label_" + id
  • The id will be remembered and used on the next widget, if it has no id.

If nothing matched, return None, None.

Supports automatic translation of widgets.

  • translations is a dict-like object. We will use .get(key, default) to retrieve values.
  • translation_prefix is a global prefix, so that you can use the same dict for multiple forms.
  • For each widget that has text, we look up <translation_prefix><id> in the dict. If present, the content will be used instead of original text.
  • For treelist, we will also look up <translation_prefix><id>.<column_id> and use it as column name, if found.
parse_menu(parent, menudef, handlers, translations=None, translation_prefix='')[source]

Parse menu definition list and attach to the handlers.

Translations work the same as for parse.

place(widget, row=0, col=0, rowspan=1, colspan=1)[source]

place widget

root(title='Window', icon='', on_close=None)[source]

make a root (window) widget. Optionally you can give a close handler.

row_stretch(container, row, proportion)[source]

set the given row to stretch according to the proportion.

setval(widget, value)[source]

update the widget from given python-type value.

value-setting must not interfere with, i.e. not happen when the user is editing the widget.

show(frame)[source]

do what is necessary to make frame appear onscreen.

This should start the event loop if necessary.

slider(parent, id=None, min=None, max=None)[source]

slider, integer values, from min to max

textbox(parent, id=None, text='')[source]

single-line text entry box

treelist(parent, id=None, text='', columns=None, first_column_editable=False)[source]

treeview (also usable as plain list) Column is a list of column definitions: something with .id, .text, .editable attrs.

widget_classes = {'box': None, 'box_labeled': None, 'button': None, 'checkbox': None, 'combo': None, 'dropdown': None, 'label': None, 'multiline': None, 'option': None, 'slider': None, 'textbox': None, 'treelist': None, 'treelist_editable': None}

Actual class to use for each widget type.

This allows you to override the actual widget with a custom subclass, if desired.

Obviously, this should be done before building the frame, e.g. in __init__.

The replacement must have the same init signature as the original widget class.

class ascii_designer.toolkit.ListBinding(keys, **kwargs)[source]

Glue code to connect an ObsList to a GUI List widget.

Takes care of:

  • Extracting column values from list items
  • Remembering/applying GUI-sorting
  • Mapping “model” events to GUI actions and vice-versa.
Properties:
keys (list of str)
column keys
list (ObsList)
the bound list
sort_key (str)
column sorted by
sort_ascending (bool)
sort order
sorted (bool)
whether list is currently sorted by one of the list columns. Sorting the list with a key function (“Python way”) resets sorted to False.
factory (function() -> Any)
Factory function for new items (on add). Signature might change in future releases. I am not sure right now what parameters might be useful.

Abstract base class. Override methods where noted.

list
on_get_selection()[source]

ABSTRACT: query selected nodes from GUI

on_insert(idx, item, toolkit_parent_id)[source]

ABSTRACT: Insert item in tree, return toolkit_id

on_load_children(children)[source]

ABSTRACT: insert children into GUI tree

on_remove(iid)[source]

ABSTRACT: remove item in GUI

on_replace(iid, item)[source]

ABSTRACT: update GUI with changed item

on_sort(sublist, info)[source]

reorder rows in GUI

Base implementation remembers sort_key, sort_ascending entries from info, and sets sorted flag if both are there.

Subclasses should call the base, and then update header formatting if appropriate.

retrieve(item, column='')[source]
sort(key=None, ascending: bool = None, restore=False)[source]

Sort the list using one of the columns.

key can be a string, refering to the particular column of the listview. Use Empty String to refer to the anonymous column.

If key is a callable, the list is sorted in normal fashion.

Instead of specifying key and ascending, you can set restore=True to reuse the last applied sorting, if any.

sources(_text=None, **kwargs)[source]

Alter the data binding for each column.

Takes the column names as kwargs and the data source as value; which can be:

  • Empty string to retrieve str(obj)
  • String "name" to retrieve attribute name from the source object
    (on attribute error, try to get as item)
  • list of one item ['something'] to get item 'something' (think of it as index without object)
  • Callable lambda obj: .. to do a custom computation.

The _text argument, if given, is used to set the source for the “default” (anynomous-column) value.

store(item, val, column='')[source]
ascii_designer.toolkit.auto_id(id, text=None, last_label_id='')[source]

for missing id, calculate one from text.

ascii_designer.toolkit_tk module

TK Toolkit implementation

class ascii_designer.toolkit_tk.ToolkitTk(*args, prefer_ttk: bool = False, setup_style=None, add_setup=None, font_size: int = 10, ttk_theme: str = '', autovalidate: bool = False, **kwargs)[source]

Builds Tk widgets.

Returns the raw Tk widget (no wrapper).

For each widget, a Tk Variable is generated. It is stored in <widget>.variable (attached as additional property).

If you create Radio buttons, they will all share the same variable.

The multiline widget is a tkinter.scrolledtext.ScrolledText and has no variable.

The ComboBox / Dropdown box is taken from ttk.

Parameters:
  • prefer_ttk (bool) – Prefer ttk widgets before tk widgets. This means that you need to use the Style system to set things like background color etc.
  • setup_style (fn(root_widget) -> None) – custom callback for setting up style of the Tk windows (font size, themes). If not set, some sensible defaults are applied; see the other options, and source of setup_style().
  • add_setup (fn(root_widget) -> None) – custom callback for additional setup. In contrast to setup_style this will not replace but extend the default setup function.
  • font_size (int) – controls default font size of all widgets.
  • ttk_theme (str) – explicit choice of theme. Per default, no theme is set if prefer_ttk is False; otherwise, winnative is used if available, otherwise clam.
  • autovalidate (bool) – If True, generated widgets using GenericVar will set themselves up for automatic update of widget state when validated. This uses GenericVar.validated_hook. Affects Entry and Combobox. Can be changed afterwards.

Box variable (placeholder): If you replace the box by setting its virtual attribute, the replacement widget must have the same master as the box: in case of normal box the frame root, in case of group box the group box. Recommendation: new_widget = tk.Something(master=autoframe.the_box.master)

anchor(widget, left=True, right=True, top=True, bottom=True)[source]

anchor the widget. Depending on the anchors, widget will be left-, right-, center-aligned or stretched.

box(parent, id=None, text='', given_id='')[source]

Creates a TKinter frame or label frame.

A .variable property is added just like for the other controls.

button(parent, id=None, text='')[source]
checkbox(parent, id=None, text='', checked=None)[source]

Checkbox

close(frame)[source]

close the frame

col_stretch(container, col, proportion)[source]

set the given col to stretch according to the proportion.

combo(parent, id=None, text='', values=None)[source]

combo box; values is the raw string between the parens. Free-text allowed.

connect(widget, function)[source]

bind the widget’s default event to function.

Default event is:
  • click() for a button
  • value_changed(new_value) for value-type controls;
    usually fired after focus-lost or Return-press.
dropdown(parent, id=None, text='', values=None)[source]

dropdown box; values is the raw string between the parens. Only preset choices allowed.

getval(widget)[source]

get python-type value from widget.

label(parent, id=None, label_id=None, text='')[source]
menu_command(parent, id, text, shortcut, handler)[source]

Append command labeled text to menu parent.

Handler: func() -> None, is immediately connected.

menu_root(parent)[source]

Create menu object and set as parent’s menu.

menu_sub(parent, id, text)[source]

Append submenu labeled text to menu parent.

multiline(parent, id=None, text='')[source]

multiline text entry box

option(parent, id=None, text='', checked=None)[source]

Option button. Prefix ‘O’ for unchecked, ‘0’ for checked.

place(widget, row=0, col=0, rowspan=1, colspan=1)[source]

place widget

root(title='Window', icon='', on_close=None)[source]

make a root (window) widget

row_stretch(container, row, proportion)[source]

set the given row to stretch according to the proportion.

setup_style(root)[source]

Setup some default styling (dpi, font, ttk theme).

For details, refer to the source.

setval(widget, value)[source]

update the widget from given python-type value.

value-setting must not interfere with, i.e. not happen when the user is editing the widget.

show(frame)[source]

do what is necessary to make frame appear onscreen.

slider(parent, id=None, min=None, max=None)[source]

slider, integer values, from min to max

textbox(parent, id=None, text='')[source]

single-line text entry box

treelist(parent, id=None, text='', columns=None, first_column_editable=False)[source]

treeview (also usable as plain list)

Implementation note: Uses a ttk.TreeView, and wraps it into a frame together with a vertical scrollbar. For correct placement, the .place, .grid, .pack methods of the returned tv are replaced by that of the frame.

Columns can be marked editable by appending “_” to the name. If any column is editable, a TreeEdit is generated instead of the TreeView.

Returns the treeview widget (within the frame).

widget_classes_tk = {'box': <class 'tkinter.Frame'>, 'box_labeled': <class 'tkinter.LabelFrame'>, 'button': <class 'tkinter.Button'>, 'checkbox': <class 'tkinter.Checkbutton'>, 'combo': <class 'tkinter.ttk.Combobox'>, 'dropdown': <class 'tkinter.ttk.Combobox'>, 'label': <class 'tkinter.Label'>, 'multiline': <class 'tkinter.scrolledtext.ScrolledText'>, 'option': <class 'tkinter.Radiobutton'>, 'scrollbar': <class 'tkinter.Scrollbar'>, 'slider': <class 'tkinter.Scale'>, 'textbox': <class 'tkinter.Entry'>, 'treelist': <class 'tkinter.ttk.Treeview'>, 'treelist_editable': <class 'ascii_designer.tk_treeedit.TreeEdit'>}
widget_classes_ttk = {'box': <class 'tkinter.ttk.Frame'>, 'box_labeled': <class 'tkinter.ttk.Labelframe'>, 'button': <class 'tkinter.ttk.Button'>, 'checkbox': <class 'tkinter.ttk.Checkbutton'>, 'combo': <class 'tkinter.ttk.Combobox'>, 'dropdown': <class 'tkinter.ttk.Combobox'>, 'label': <class 'tkinter.ttk.Label'>, 'multiline': <class 'tkinter.scrolledtext.ScrolledText'>, 'option': <class 'tkinter.ttk.Radiobutton'>, 'scrollbar': <class 'tkinter.ttk.Scrollbar'>, 'slider': <class 'tkinter.ttk.Scale'>, 'textbox': <class 'tkinter.ttk.Entry'>, 'treelist': <class 'tkinter.ttk.Treeview'>, 'treelist_editable': <class 'ascii_designer.tk_treeedit.TreeEdit'>}

ascii_designer.toolkit_qt module

ascii_designer.i18n module

I18n support for ASCII Designer or other purposes.

Provides the working-data structure Translations, and functions to load and save translation files.

class ascii_designer.i18n.Translations[source]

Mostly off-the shelf python dict, except for two facilities to aid translation.

Translations should be retrieved via .get(key, default) method.

The class has the two additional properties recording and mark_missing.

  • If recording is set to True, calls of get will add missing entries (i.e. get does the same as setdefault). By setting it and opening all forms once, you can collect all translation keys and default strings.
  • If mark_missing is set and get finds a missing key, the given default value is prefixed with a $ sign.
get(key, default=None)[source]

Return the value for key if key is in the dictionary, else default.

mark_missing = False
recording = False
ascii_designer.i18n.load_translations_json(package_or_dir='locale', prefix='', language=None)[source]

Locate and load translations from JSON file.

JSON file format is a simple key value store.

If given a package name, use the resource loading system. If given a dir, use file access.

The argument is interpreted as dir if:

  • the string contains / or \
  • the argument is a pathlib.PurePath instance.

Resource name is formed by the rule “<prefix>.<language>.json” (first dot is ommited if one of both is empty). If both prefix and language are empty, we look for default.json.

If the language is not given, the OS’s UI language is used.

With the given or guessed language we look for an existing file:

  • First we look for the exact language string (e.g. “de_DE.json”)
  • then we look for the first two letters of the language string (“de.json”)
  • then we look for emtpy language (i.e. default set).

If none of these exists, empty Translations object is returned.

ascii_designer.i18n.save_translations_json(translations, path)[source]

Save translations to JSON file.

OVERWRITES existing file!

In contrast to load_translations_json, we only accept a path here.

ascii_designer.list_model module

Pythonic list and tree classes that can be used in a GUI.

The general concept for Lists is this:

  • List is wrapped into an ObsList (by ToolkitBase.setval)
  • The “code-side” of the ObsList quacks (mostly) like a regular list.
  • The “gui-side” of the ObsList
    • provides event callbacks for insert, replace, remove, sort.
  • a ListBinding:
    • provides COLUMNS (key-value items) dynamically retrieved from each list item (using retrieve function from here)
    • remembers column and order to be used when sorting
    • has a notion of “selection” (forwarded to a callback)
class ascii_designer.list_model.ObsList(iterable=None, binding=None, toolkit_parent_id=None)[source]

Base class for treelist values.

Behaves mostly like a list, except that:
  • it maintains a list of expected attributes (columns)
  • it provides notification when items are added or removed
  • it can be made into a tree by means of the children_source setting (see there).

If configured as tree, indexing happens via tuples:

  • mylist[8] returns the 8th item at toplevel, as usual
  • mylist[3, 2] returns the 2nd item of the 3rd items’ children.
  • mylist[3, 2, 12, 0] goes 4 levels deep
  • mylist[3, None] can be used to retreive the list of children of item 3, instead of a specific child item.
toolkit_ids

can be indexed in the same way as the nodelist, and gives the toolkit-specific identifier of the list/treeview node.

Events:

  • on_insert(idx, item, toolkit_parent_id) -> toolkit_id: function to call for each inserted item
  • on_replace(toolkit_id, item): function to call for replaced item
    Replacement of item implies that children are “collapsed” again.
  • on_remove(toolkit_id): function to call for each removed item
  • on_load_children(toolkit_parent_id, sublist): function when children of a node are retrieved.
  • on_get_selection(): return the items selected in the GUI
    Must return a List of (original) items.
  • on_sort(sublist, info): when list is reordered

For on_insert, the handler should return the toolkit_id. This is an unspecified, toolkit-native object identifier. It is used in the other events and for find_by_toolkit_id. Its purpose is to allow easier integration with toolkit-native events and methods.

on_sort: Info argument is a dict containing custom info, e.g. column that was sorted by.

append(value)

S.append(value) – append value to the end of the sequence

binding

Weak reference to the binding using this list.

If list is attached to multiple Bindings, last one wins. (TODO: make it a list)

children_source(children_source, has_children_source=None)[source]

Sets the source for children of each list item, turning the list into a tree.

children, has_children follow the same semantics as other sources.

Resolving children should return an iterable that will be turned into an ObsList of its own.

has_children should return a truthy value that is used to decide whether to display the expander. If omitted, all nodes get the expander initially if children_source is set.

Children source only applies when the list of children is initially retrieved. Once the children are retrieved, source changes do not affect already-retrieved children anymore.

has_children is usually evaluated immediately, because the treeview needs to decide whether to display an expander icon.

clear() → None -- remove all items from S
count(value) → integer -- return number of occurrences of value
extend(values)

S.extend(iterable) – extend sequence by appending elements from the iterable

find(item)[source]

Finds the sublist and index of the item.

Returns (sublist: ObsList, idx: int).

If not found, raises ValueError. Scans the whole tree for the item.

find2(item)[source]

Finds the tuple-index of the item.

Returns idx: Tuple[int].

If not found, raises ValueError. Scans the whole tree for the item.

find_by_toolkit_id(toolkit_id)[source]

finds the sublist and index of the item having the given toolkit id.

Returns (sublist: ObsList, idx: int).

If not found, raises ValueError. Scans the whole tree for the item.

find_by_toolkit_id2(item)[source]

Finds the tuple-index of the item having the given toolkit id.

Returns idx: Tuple[int].

If not found, raises ValueError. Scans the whole tree for the item.

get_children(idx_tuple)[source]

Get childlist of item at given idx, loading it if not already loaded.

has_children(item)[source]
index(value[, start[, stop]]) → integer -- return first index of value.

Raises ValueError if the value is not present.

Supporting start and stop arguments is optional, but recommended.

insert(idx_tuple, item)[source]

S.insert(index, value) – insert value before index

item_mutated(item)[source]

Call this when you mutated the item (which must be in this list) and want to update the GUI.

load_children(idx_tuple)[source]

Retrieves the childlist of item at given idx.

pop([index]) → item -- remove and return item at index (default last).

Raise IndexError if list is empty or index is out of range.

remove(value)

S.remove(value) – remove first occurrence of value. Raise ValueError if the value is not present.

reverse()

S.reverse() – reverse IN PLACE

selection

returns the sublist of all currently-selected items.

Returns empty list if no handler is attached.

sort(key=None, reverse=False, info=None, restore=False)[source]

Sort the list.

info is optional information to be passed on to on_sort.

Set restore to reuse key and info from last sort call.

sources(_text=None, **kwargs)[source]

Forwards to ListBinding.sources - see there.

ascii_designer.list_model.retrieve(obj, source)[source]

Automagic retrieval of object properties.

If source is empty string, return str(obj).

If source is a plain string (identifier), use getattr on obj; on error, try getitem.

If source is a list with a single string-valued item, use getitem on obj.

If source is a callable, return source(obj).

If source is a 2-tuple, use the first item (“getter”) as above.

ascii_designer.list_model.store(obj, val, source)[source]

Automagic storing of object properties.

If ‘’source`` is a plain string (identifier), use setattr on obj.

If source is a list with a single string-valued item, use setitem on obj.

If source is a callable, call it as fn(obj, val).

If source is a 2-tuple of things, use the second item (“setter”) as above.

Note

store is not fully symmetric to its counterpart retrieve.

  • Empty source can not be used for store
  • Plain string source will always use setitem without fallback.

If you use a single callable as source, it must be able to discern between “getter” and “setter” calls, e.g. by having a special default value for the second parameter.

ascii_designer.tk_treeedit module

ttk.TreeView control augmented by editing capabilities.

For basic information, see official Tkinter (ttk) docs.

The following additional functionality is provided:

  • Mark column as editable using TreeEdit.editable.
  • allow= parameter to specify legal structural operations.

allow is a list of strings or a comma-separated string. It can contain any of:

  • add to allow adding new items (anywhere)
  • addchild to allow insertion of child items
  • remove to allow deletion of items.

For each allowance, the corresponding control is shown, and the keybinding is activated.

The following bindings / behaviors are built-in. Generally, value is submitted on close, except if Escape key is used.

Treeview:

  • Dblclick: open edit on col
  • Scroll: Take focus (close edit)
  • Resize: close edit box
  • F2: open first edit of row
  • Ctrl+plus, Insert: add item (if enabled, see below)
  • Ctrl+asterisk: add child (if enabled)
  • Ctrl+minus,
  • Delete: remove item (if enabled)

Edit box:

  • Lose Focus: close
  • Return: close
  • Escape: close without submitting
  • Shift+enter,
  • Down arrow: Close + edit same column in next row
  • Tab,
  • Shift+Right arrow: close + edit next column (or 1st col in next row)
  • Shift+Tab,
  • Shift+Left arrow: like Tab but backwards
  • Up arrow: Close + edit same col in prev row

Events:

These are properties of the TreeeEdit control. Use treeedit.<property> += handler``to bind a handler, ``-= to unbind it.

  • on_cell_edit(iid, columnname, cur_value) when editor is opened
  • on_cell_modified(iid, columname, new_value) when editor is closed
  • on_add(iid): before item is inserted after (iid).
  • on_add_child(iid): before child is inserted under (iid).
  • on_remove(iid): before child is deleted

Note

on_cell_modified, on_add, on_add_child, on_remove are fired immediately before the respective action takes place in the widget.

Your handler can return False to indicate that the widget content shall not be modified; e.g. if the action is forbidden or you took care of updating the tree yourself. Note that None is counted as True result in this case.

# TODO: # reorder # custom editor types (button, checkbox, combo, … pass own widget(s)) # copy/paste # have a handler for after-item-insertion with the actual iid as param (we don’t need it currently)

class ascii_designer.tk_treeedit.TreeEdit(master, allow=None, *args, **kwargs)[source]

see module docs

advance(direction='right')[source]

switch to next cell.

direction can be left, right, up, down.

If going left/right beyond the first or last cell, edit box moves to the previous/next row.

advance_down(ev=None)[source]
advance_left(ev=None)[source]
advance_right(ev=None)[source]
advance_up(ev=None)[source]
allow

Allowed structural edits (add, delete, addchild).

Pass the allowed actions as list of strings or comma-separated string.

Can be updated during operation.

autoedit_added

Automatically begin editing added items yes/no

begin_edit(iid, column)[source]

Show edit widget for the specified cell.

begin_edit_row(ev)[source]

Start editing the first editable column of the focused row.

close_edit(ev=None, cancel=False)[source]

Close the currently open editor, if any.

del_item(ev=None)[source]

Trigger deletion of focused item.

editable(column, editable=None)[source]

Query or specify whether the column is editable.

Only accepts Column Name or '#0'.

editbox_bindings = [('<FocusOut>', 'close_edit'), ('<Return>', '_close_edit_refocus'), ('<KP_Enter>', '_close_edit_refocus'), ('<Escape>', '_cancel_edit_refocus'), ('<Shift-Right>', 'advance_right'), ('<Tab>', 'advance_right'), ('<Shift-Left>', 'advance_left'), ('<Shift-Tab>', 'advance_left'), ('<Shift-Return>', 'advance_down'), ('<Shift-KP_Enter>', 'advance_down'), ('<Down>', 'advance_down'), ('<Up>', 'advance_up'), ('<Control-plus>', 'ins_item'), ('<Control-asterisk>', 'ins_child_item'), ('<Control-minus>', 'del_item'), ('<Shift-ISO_Left_Tab>', 'advance_left')]
ins_child_item(ev=None)[source]

Trigger insertion of new child item

ins_item(ev=None, child=False)[source]

Trigger insertion of a new item.

list_bindings = [('<Double-Button-1>', '_dblclick'), ('<F2>', 'begin_edit_row'), ('<4>', '_close_edit_refocus'), ('<5>', '_close_edit_refocus'), ('<Control-plus>', 'ins_item'), ('<Insert>', 'ins_item'), ('<Control-asterisk>', 'ins_child_item'), ('<Control-minus>', 'del_item'), ('<Delete>', 'del_item')]

ascii_designer.tk_generic_var module

Tkinter generic variable.

Comes with tools:

  • Invalid special value
  • gt0, ge0, nullable converter compositors

Also, it sports the validated_hook property for all-in-one validation and conversion.

class ascii_designer.tk_generic_var.GenericVar(master=None, value=None, name=None, convert=<class 'str'>, convert_set=<class 'str'>, validated_hook=None)[source]

Generic variable.

A conversion function can be specified to get a “native” value from the string representation and vice-versa. By default, behaves like a StringVar.

master can be given as master widget. value is an optional value (defaults to “”) name is an optional Tcl name (defaults to PY_VARnum). If name matches an existing variable and value is omitted then the existing value is retained.

convert = None

Gives the conversion to apply when get-ting the value.

convert takes the string (widget content) as single argument and returns a converted value. Any Exceptions will be caught (see get).

convert_set = None

Gives the function to apply to a value passed in to set.

In most cases the default (str) will be sufficient.

get()[source]

Return converted value of variable.

If conversion failed, returns Invalid.

set(value)[source]

Set the variable to VALUE.

validated_hook

If set, adds a side-effect to get depending on whether the value was valid or not.

It shall be a callback taking a single bool argument valid; which is True or False depending on whether convert raised an exception.

If you set validated_hook to a Tk widget, we will automatically convert it into a callback:

  • For a Tk widget, foreground color will be set to red / original color depending on valid.
  • For a Ttk widget, invalid state will be set/reset. Note that in most themes, by default no visual change happens, unless you configured an appropriate style map.
class ascii_designer.tk_generic_var.Invalid[source]

Sentinel object to signal that the read value was invalid.

Invalid will returned as itself (i.e. not as instance).

ascii_designer.tk_generic_var.ge0(convert)[source]

Applies convert, then raises if value is not greater or equal to 0.

convert must return something number-like.

>>> generic_var.convert = ge0(int)
ascii_designer.tk_generic_var.gt0(convert)[source]

Applies convert, then raises if value is not greater than 0.

convert must return something number-like.

>>> generic_var.convert = gt0(int)
ascii_designer.tk_generic_var.nullable(convert)[source]

Creates a converter that returns None on empty string, otherwise applies given converter.

>>> generic_var = GenericVar(tkroot, convert=nullable(float))
>>> generic_var.set("1.0")
>>> generic_var.get()
1.0
>>> generic_var.set("")
>>> generic_var.get()
None
>>> generic_var.set("foo")
>>> generic_var.get()
<class Invalid>

ascii_designer.event module

Provides an event dispatcher class.

exception ascii_designer.event.CancelEvent[source]

Raise this in an event handler to inhibit all further processing.

class ascii_designer.event.EventSource[source]

Event dispatcher class

You can register / unregister handlers via += and -= methods.

Handlers may return a result. If multiple handlers return results, last one is returned to the event’s source.