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:
autoframeprovides theAutoFrameclass, which by itself contains the build logic and the automatic binding infrastructure.
toolkitprovides the widget generators and actual value and event binding. The baseToolkitBasecontains the parsing function and lots of abstract methods.
toolkit_tkandtoolkit_qtprovide actual implementations of the Toolkit interface.
ascii_slicecontains the text slicing algorithm used to cut text into grid cells.
list_modelcontains the list-like value class for list view / tree view. TheObsListis toolkit-agnostic and has has lots of hooks where the GUI bindings (in thetoolkit_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.icoon Windows and.pngon Unix.Body definition with
f_body, menu definition withf_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: str | None = 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_controls: dict[str, Any]
Dictionary of controls created by the form.
You can also access the controls by indexing the AutoFrame instance.
- 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: bool = 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
invalidstate (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_toolkit: ToolkitBase
The toolkit used to create widgets, e.g ToolkitTk or ToolkitQt instance.
- f_translations: 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_buildandf_build_menufunctions. Currently there is no facility to retranslate after building the form.
- property f_translations_get_prefixed: Callable[[str, str | None], str]
Returns a getter for translations with own form name as prefix.
I.e. identical to
self.f_translations.get_prefix(self.__class__.__name__)Supports the usual case that you want additional translations keyed with the form name as prefix.
Example:
# Somewhere in class MyForm(AutoFrame) tr = self.f_translations_get_prefixed # Retrieves translation key MyForm.msg_wait self.label1 = tr(".msg_wait", "Please wait")
- quit()[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.
Invalidwill returned as itself (i.e. not as instance).
- class ascii_designer.ObsList(iterable: Iterable[ItemType] | None = None, binding: _BindingLike | None = None, toolkit_parent_id: Any = 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_sourcesetting (see there).
If configured as tree, indexing happens via tuples:
mylist[8]returns the 8th item at toplevel, as usualmylist[3, 2]returns the 2nd item of the 3rd items’ children.mylist[3, 2, 12, 0]goes 4 levels deepmylist[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:
Note
Events are defined with positional args for backwards-compat reasons.
on_insert(idx, item, toolkit_parent_id) -> toolkit_id: function to call for each inserted itemon_replace(toolkit_id, item): function to call for replaced itemReplacement of item implies that children are “collapsed” again.
on_remove(toolkit_id): function to call for each removed itemon_load_children(sublist): function when children of a node are retrieved.on_get_selection(): return the items selected in the GUIMust 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 forfind_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.- property binding: _BindingLike | None
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: str | list[str] | tuple[str | list[str] | tuple[SourceDef, str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], has_children_source: str | list[str] | tuple[str | list[str] | tuple[SourceDef, str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]] | None = None)[source]
Sets the source for children of each list item, turning the list into a tree.
children,has_childrenfollow the same semantics as other sources.Resolving
childrenshould return an iterable that will be turned into anObsListof its own.has_childrenshould 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_childrenis usually evaluated immediately, because the treeview needs to decide whether to display an expander icon.
- find(item: ItemType) tuple[ObsList, int][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: ItemType) tuple[int][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: Any) tuple[ObsList, int][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(toolkit_id: Any) tuple[int][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: tuple[int | None, ...] | int | None) ObsList[source]
Get childlist of item at given idx, loading it if not already loaded.
- has_children(item: ItemType) bool[source]
- insert(idx_tuple: int | tuple[int], item: ItemType) tuple[int, ItemType][source]
Returns the index of the inserted item and the item itself.
- item_mutated(item: ItemType)[source]
Call this when you mutated the item (which must be in this list) and want to update the GUI.
- load_children(idx_tuple: tuple[int | None, ...] | int | None)[source]
Retrieves the childlist of item at given idx.
- on_get_selection() list[ItemType] | None[source]
Event: .selection property is retrieved
Meaning that we need the selection from the GUI.
Handler must return the items selected in the GUI. Must return a List of (original) items.
- on_insert(item: ItemType, toolkit_parent_id: Any, /) Any | None[source]
Event: An item was inserted.
- Parameters:
idx (int) – insertion position
item – Inserted item
toolkit_parent_id – In case of tree structure, the toolkit id of the lists’s parent in the view.
The handler must return the “Toolkit ID” of the inserted item, which is is stored in the
toolkit_idlist. Toolkit ID can be of any type (e.g string or QModelIndex).
- on_load_children()[source]
Event: children of a node were retrieved.
- on_remove()[source]
Event: item with the given toolkit_id was removed.
- on_replace(item: ItemType, /)[source]
Event: Item with the associated toolkit ID was replaced by the given one.
Replacement of item implies that children are “collapsed” again.
- on_sort(info: dict, /)[source]
Indicates that the given
sublistwas sorted.infois a dictionary of sort settings (key, direction).
- property selection
returns the sublist of all currently-selected items.
Returns empty list if no handler is attached.
- sort(key=None, reverse=False, info: dict | None = None, restore=False)[source]
Sort the list.
infois optional information to be passed on to on_sort.Set
restoreto reuse key and info from lastsortcall.
- sources(_text: str | list[str] | tuple[str | list[str] | tuple[SourceDef, str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]] = '', **kwargs: str | list[str] | tuple[str | list[str] | tuple[SourceDef, str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]])[source]
Forwards to
ListBinding.sources- see there.
- class ascii_designer.Translations[source]
Mostly off-the shelf python dict, except for some facilities to aid translation.
Translations should be retrieved via
.get(key, default)method.The class has the two additional properties
recordingandmark_missing.If
recordingis set to True, calls ofgetwill add missing entries (i.e.getdoes the same assetdefault). By setting it and opening all forms once, you can collect all translation keys and default strings.If
mark_missingis set andgetfinds a missing key, the given default value is prefixed with a$sign.
Additionally, it sports the convenience methods
get_prefixandget_exception.- get(key: str, default=None) str[source]
Return the value for key if key is in the dictionary, else default.
- get_exception(exc, prefix: str = 'exc.') str[source]
Return translation for the given exception.
Translation is retrieved using they key
<prefix><exc. class>. E.g.exc.ValueError.The translated string MAY contain placeholders corresponding to attributes of the exception object. Additionally,
{exc}can be used to insert the original string representation of the exception.Fallback text is str(exc).
- get_prefix(prefix: str) Callable[[str, str | None], str][source]
Returns a getter function like
getthat augments keys with the given prefix.I.e.:
tr.get("prefix.name", "..")is equivalent totr.get_prefix("prefix")(".name", "..").
- mark_missing: bool = False
- recording: bool = False
- ascii_designer.event(prototype: Callable[[P], R] | None = None, *, strict: bool | None = None, exceptions: Literal['log', 'print', 'raise', 'group'] = 'log') Event[P, R] | Callable[[Callable[[P], R]], Event[P, R]][source]
Turn the decorated method into an Event.
See
Event. The@eventdecorator allows to pass arguments:@event(strict=False, exeptions=”print”) def some_event(arg1: bool, /): …
- ascii_designer.ge0(convert)[source]
Applies
convert, then raises if value is not greater or equal to 0.convertmust return something number-like.>>> generic_var.convert = ge0(int)
- ascii_designer.gt0(convert)[source]
Applies
convert, then raises if value is not greater than 0.convertmust return something number-like.>>> generic_var.convert = gt0(int)
- ascii_designer.load_translations_json(package_or_dir: str | PurePath = 'locale', prefix: str = '', language: str | None = None) Translations[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.PurePathinstance.
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
Translationsobject is returned.
- ascii_designer.nullable(convert)[source]
Creates a converter that returns
Noneon 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.save_translations_json(translations: dict[str, str], path: str | PurePath) 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.icoon Windows and.pngon Unix.Body definition with
f_body, menu definition withf_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.
- f_add_widgets(parent, sliced_grid=None, body=None, offset_row=0, offset_col=0, autoframe=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_controls: dict[str, Any]
Dictionary of controls created by the form.
You can also access the controls by indexing the AutoFrame instance.
- 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: bool = 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
invalidstate (ttk) is updated.Opt-in, because it might interfere with user code if not expected.
- f_toolkit: ToolkitBase
The toolkit used to create widgets, e.g ToolkitTk or ToolkitQt instance.
- f_translations: 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_buildandf_build_menufunctions. Currently there is no facility to retranslate after building the form.
- property f_translations_get_prefixed: Callable[[str, str | None], str]
Returns a getter for translations with own form name as prefix.
I.e. identical to
self.f_translations.get_prefix(self.__class__.__name__)Supports the usual case that you want additional translations keyed with the form name as prefix.
Example:
# Somewhere in class MyForm(AutoFrame) tr = self.f_translations_get_prefixed # Retrieves translation key MyForm.msg_wait self.label1 = tr(".msg_wait", "Please wait")
ascii_designer.ascii_slice module
Functions to slice up a fixed-column-width ASCII grid.
slice_grids 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.
- class ascii_designer.ascii_slice.MCell(row: int = 0, col: int = 0, text: str = '', rowspan: int = 1, colspan: int = 1)[source]
Warning
class ‘ascii_designer.ascii_slice.MCell’ undocumented
- col: int = 0
Cell’s column, counting from 0
- colspan: int = 1
Spanned columns, at least 1
- row: int = 0
Cell’s row, counting from 0
- rowspan: int = 1
Spanned rows, at least 1
- text: str = ''
Merged-area text
- class ascii_designer.ascii_slice.SlicedGrid(column_heads: list[str] = <factory>, body_lines: list[list[str]] = <factory>, subgrids: dict[str, 'SlicedGrid'] = <factory>)[source]
Warning
class ‘ascii_designer.ascii_slice.SlicedGrid’ undocumented
- body_lines: list[list[str]]
- column_heads: list[str]
- subgrids: dict[str, SlicedGrid]
- 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.
- ascii_designer.ascii_slice.slice_grids(grid_text) SlicedGrid[source]
slice grids 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.
A grid can be followed by subgrids. Start of a subgrid is indicated by the text
:subgridid:on a separate line, wheresubgrididcan be any text. The first:MUST be on the same indentation level as the first|(which is required).- 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.
subgrid: Dictionary of subgrids, keyed by subgridid.
ascii_designer.toolkit module
Warning
module ‘ascii_designer.toolkit’ undocumented
- 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
sortedtoFalse.- 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.
- allow_sorting
Enable / disable sorting by clicking on a column header
- on_sort(sublist, info)[source]
reorder rows in GUI
Base implementation remembers sort_key, sort_ascending entries from info, and sets
sortedflag if both are there.Subclasses should call the base, and then update header formatting if appropriate.
- sort(key=None, ascending: bool = None, restore=False)[source]
Sort the list using one of the columns.
keycan be a string, refering to the particular column of the listview. Use Empty String to refer to the anonymous column.If
keyis a callable, the list is sorted in normal fashion.Instead of specifying
keyandascending, you can setrestore=Trueto reuse the last applied sorting, if any.If
allow_sortingis set toFalse, nothing happens.
- sort_ascending
sorted ascending yes/no
- sort_key
column by which list is currently sorted
- sorted
List is currently sorted by GUI interaction
- 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 attributenamefrom the source object (on attribute error, try to get as item)
- String
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
_textargument, if given, is used to set the source for the “default” (anynomous-column) value.
- 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_idis the user-given id value, as opposed toid(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.
- 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: dict[str, str] = {'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.
- 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"')]
Append command labeled
textto menuparent.Handler:
func() -> None, is immediately connected.shortcutfollows the syntax(modifier)-(key), wheremodifieris one or more ofC,S,Afor Ctrl, Shift, Alt respectively.
Create menu object and set as parent’s menu.
Append submenu labeled
textto menuparent.
- 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_"+ idThe 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_prefixis 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 originaltext.For treelist, we will also look up
<translation_prefix><id>.<column_id>and use it as column name, if found.
Parse menu definition list and attach to the handlers.
Translations work the same as for
parse.
- 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.
- 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: dict[str, Any] = {'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.
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_stylethis 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_ttkisFalse; otherwise,winnativeis used if available, otherwiseclam.autovalidate (bool) – If True, generated widgets using
GenericVarwill set themselves up for automatic update of widget state when validated. This usesGenericVar.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
.variableproperty is added just like for the other controls.
- 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.
Append command labeled
textto menuparent.Handler:
func() -> None, is immediately connected.
Create menu object and set as parent’s menu.
Append submenu labeled
textto menuparent.
- option(parent, id=None, text='', checked=None)[source]
Option button. Prefix ‘O’ for unchecked, ‘0’ for checked.
- 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.
- 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
TreeEditis 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
ToolkitQt-specific notes:
Alignment / Stretch not 100% reliable so far, if using row/col-span.
Tree / List widget not available so far
- closing of form with X button cannot be stopped in the default handler. If
you need to do this, replace (root).closeEvent function.
- class ascii_designer.toolkit_qt.ToolkitQt(**kwargs)[source]
Warning
class ‘ascii_designer.toolkit_qt.ToolkitQt’ 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]
Creates a QWidget or QGroupBox.
A
_valueproperty is created, to hold AutoFrame-reassigned value.
- col_stretch(container, col, proportion)[source]
set the given col to stretch according to the proportion.
- 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: dict[str, str] = {'copy': qtpy.QtGui.QKeySequence.Copy, 'cut': qtpy.QtGui.QKeySequence.Cut, 'delete': qtpy.QtGui.QKeySequence.Delete, 'find': qtpy.QtGui.QKeySequence.Find, 'new': qtpy.QtGui.QKeySequence.New, 'open': qtpy.QtGui.QKeySequence.Open, 'paste': qtpy.QtGui.QKeySequence.Paste, 'preferences': qtpy.QtGui.QKeySequence.Preferences, 'quit': qtpy.QtGui.QKeySequence.Quit, 'redo': qtpy.QtGui.QKeySequence.Redo, 'refresh': qtpy.QtGui.QKeySequence.Refresh, 'save': qtpy.QtGui.QKeySequence.Save, 'save_as': qtpy.QtGui.QKeySequence.SaveAs, 'undo': qtpy.QtGui.QKeySequence.Undo}
- dropdown(parent, id=None, text='', values=None, _clskey='dropdown')[source]
dropdown box; values is the raw string between the parens. Only preset choices allowed.
Append command labeled
textto menuparent.Handler:
func() -> None, is immediately connected.
Create menu object and set as parent’s menu.
Append submenu labeled
textto menuparent.
- option(parent, id=None, text='', checked=None)[source]
Option button. Prefix ‘O’ for unchecked, ‘0’ for checked.
- 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.
- treelist(parent, id=None, text='', columns=None, first_column_editable=False)[source]
treeview (also usable as plain list)
Qt notes: The model does no caching on its own, but retrieves item data all the time. I.e. if your columns are costly to calculate, roll your own caching please.
- widget_classes: dict[str, Any] = {'box': qtpy.QtWidgets.QWidget, 'box_labeled': qtpy.QtWidgets.QGroupBox, 'button': qtpy.QtWidgets.QPushButton, 'checkbox': qtpy.QtWidgets.QCheckBox, 'combo': qtpy.QtWidgets.QComboBox, 'dropdown': qtpy.QtWidgets.QComboBox, 'label': qtpy.QtWidgets.QLabel, 'multiline': qtpy.QtWidgets.QPlainTextEdit, 'option': qtpy.QtWidgets.QRadioButton, 'slider': qtpy.QtWidgets.QSlider, 'textbox': qtpy.QtWidgets.QLineEdit, 'treelist': qtpy.QtWidgets.QTreeView}
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.
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 some facilities to aid translation.
Translations should be retrieved via
.get(key, default)method.The class has the two additional properties
recordingandmark_missing.If
recordingis set to True, calls ofgetwill add missing entries (i.e.getdoes the same assetdefault). By setting it and opening all forms once, you can collect all translation keys and default strings.If
mark_missingis set andgetfinds a missing key, the given default value is prefixed with a$sign.
Additionally, it sports the convenience methods
get_prefixandget_exception.- get(key: str, default=None) str[source]
Return the value for key if key is in the dictionary, else default.
- get_exception(exc, prefix: str = 'exc.') str[source]
Return translation for the given exception.
Translation is retrieved using they key
<prefix><exc. class>. E.g.exc.ValueError.The translated string MAY contain placeholders corresponding to attributes of the exception object. Additionally,
{exc}can be used to insert the original string representation of the exception.Fallback text is str(exc).
- get_prefix(prefix: str) Callable[[str, str | None], str][source]
Returns a getter function like
getthat augments keys with the given prefix.I.e.:
tr.get("prefix.name", "..")is equivalent totr.get_prefix("prefix")(".name", "..").
- mark_missing: bool = False
- recording: bool = False
- ascii_designer.i18n.load_translations_json(package_or_dir: str | PurePath = 'locale', prefix: str = '', language: str | None = None) Translations[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.PurePathinstance.
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
Translationsobject is returned.
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(byToolkitBase.setval)The “code-side” of the
ObsListquacks (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
retrievefunction 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: Iterable[ItemType] | None = None, binding: _BindingLike | None = None, toolkit_parent_id: Any = 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_sourcesetting (see there).
If configured as tree, indexing happens via tuples:
mylist[8]returns the 8th item at toplevel, as usualmylist[3, 2]returns the 2nd item of the 3rd items’ children.mylist[3, 2, 12, 0]goes 4 levels deepmylist[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:
Note
Events are defined with positional args for backwards-compat reasons.
on_insert(idx, item, toolkit_parent_id) -> toolkit_id: function to call for each inserted itemon_replace(toolkit_id, item): function to call for replaced itemReplacement of item implies that children are “collapsed” again.
on_remove(toolkit_id): function to call for each removed itemon_load_children(sublist): function when children of a node are retrieved.on_get_selection(): return the items selected in the GUIMust 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 forfind_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
- property binding: _BindingLike | None
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: str | list[str] | tuple[str | list[str] | tuple[SourceDef, str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], has_children_source: str | list[str] | tuple[str | list[str] | tuple[SourceDef, str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]] | None = None)[source]
Sets the source for children of each list item, turning the list into a tree.
children,has_childrenfollow the same semantics as other sources.Resolving
childrenshould return an iterable that will be turned into anObsListof its own.has_childrenshould 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_childrenis 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: ItemType) tuple[ObsList, int][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: ItemType) tuple[int][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: Any) tuple[ObsList, int][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(toolkit_id: Any) tuple[int][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: tuple[int | None, ...] | int | None) ObsList[source]
Get childlist of item at given idx, loading it if not already loaded.
- 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: int | tuple[int], item: ItemType) tuple[int, ItemType][source]
Returns the index of the inserted item and the item itself.
- item_mutated(item: ItemType)[source]
Call this when you mutated the item (which must be in this list) and want to update the GUI.
- load_children(idx_tuple: tuple[int | None, ...] | int | None)[source]
Retrieves the childlist of item at given idx.
- on_get_selection() list[ItemType] | None[source]
Event: .selection property is retrieved
Meaning that we need the selection from the GUI.
Handler must return the items selected in the GUI. Must return a List of (original) items.
- on_insert(item: ItemType, toolkit_parent_id: Any, /) Any | None[source]
Event: An item was inserted.
- Parameters:
idx (int) – insertion position
item – Inserted item
toolkit_parent_id – In case of tree structure, the toolkit id of the lists’s parent in the view.
The handler must return the “Toolkit ID” of the inserted item, which is is stored in the
toolkit_idlist. Toolkit ID can be of any type (e.g string or QModelIndex).
- on_replace(item: ItemType, /)[source]
Event: Item with the associated toolkit ID was replaced by the given one.
Replacement of item implies that children are “collapsed” again.
- on_sort(info: dict, /)[source]
Indicates that the given
sublistwas sorted.infois a dictionary of sort settings (key, direction).
- 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
- property selection
returns the sublist of all currently-selected items.
Returns empty list if no handler is attached.
- sort(key=None, reverse=False, info: dict | None = None, restore=False)[source]
Sort the list.
infois optional information to be passed on to on_sort.Set
restoreto reuse key and info from lastsortcall.
- sources(_text: str | list[str] | tuple[str | list[str] | tuple[SourceDef, str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]] = '', **kwargs: str | list[str] | tuple[str | list[str] | tuple[SourceDef, str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]])[source]
Forwards to
ListBinding.sources- see there.
- ascii_designer.list_model.retrieve(obj, source: str | list[str] | tuple[str | list[str] | tuple[SourceDef, str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]]) Any[source]
Automagic retrieval of object properties.
If
sourceis empty string, returnstr(obj).If
sourceis a plain string (identifier), usegetattronobj; on error, trygetitem.If
sourceis a list with a single string-valued item, usegetitemonobj.If
sourceis a callable, returnsource(obj).If
sourceis a 2-tuple, use the first item (“getter”) as above.
- ascii_designer.list_model.store(obj, val, source: str | list[str] | tuple[str | list[str] | tuple[SourceDef, str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]], str] | Callable[[Any], Any] | _SourceCallable | tuple[Callable[[Any], Any], Callable[[Any, Any], None]])[source]
Automagic storing of object properties.
If ‘’source`` is a plain string (identifier), use
setattronobj.If
sourceis a list with a single string-valued item, usesetitemonobj.If
sourceis a callable, call it asfn(obj, val).If
sourceis a 2-tuple of things, use the second item (“setter”) as above.Note
storeis not fully symmetric to its counterpartretrieve.Empty source can not be used for
storePlain string source will always use
setitemwithout 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_treeview module
Functions related to Tk List / Tree View setup and behavior.
- class ascii_designer.tk_treeview.ListBindingTk(treeview, keys, **kwargs)[source]
Use
getto return the ObsList;setto replace the value using a new list.All the
on_*methods are internal event handlers.- property allow_reorder
- sort_asc_icon
header icon for ascending column
- sort_desc_icon
header icon for descending column
- ascii_designer.tk_treeview.make_treelist(parent, id=None, text='', columns=None, first_column_editable=False, widget_classes=None, sort_asc_icon=None, sort_desc_icon=None)[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
TreeEditis generated instead of the TreeView.Returns the treeview widget (within the frame).
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:
addto allow adding new items (anywhere)
addchildto allow insertion of child items
removeto 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: Literal['left', 'right', 'up', 'down'] = 'right')[source]
switch to next cell.
directioncan be left, right, up, down.If going left/right beyond the first or last cell, edit box moves to the previous/next row.
- property allow
Allowed structural edits (add, delete, addchild).
Pass the allowed actions as list of strings or comma-separated string.
Can be updated during operation.
- property autoedit_added: bool
Automatically begin editing added items yes/no
- 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')]
- 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')]
- on_add() bool | None[source]
Event: Item is about to be added.
after_iidgives the currently-selected item.A handler may return
Falseto indicate that it already took care about inserting item in the view.
ascii_designer.tk_generic_var module
Tkinter generic variable.
Comes with tools:
Invalidspecial valuegt0,ge0,nullableconverter 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.
mastercan be given as master widget.valueis an optional value (defaults to “”)nameis an optional Tcl name (defaults to PY_VARnum). Ifnamematches an existing variable andvalueis omitted then the existing value is retained.- convert
Gives the conversion to apply when
get-ting the value.converttakes the string (widget content) as single argument and returns a converted value. Any Exceptions will be caught (seeget).
- convert_set
Gives the function to apply to a value passed in to
set.In most cases the default (
str) will be sufficient.
- property validated_hook: Callable[[bool], None]
If set, adds a side-effect to
getdepending 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 whetherconvertraised an exception.If you set
validated_hookto 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 onvalid.For a Ttk widget,
invalidstate 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.
Invalidwill 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.convertmust 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.convertmust return something number-like.>>> generic_var.convert = gt0(int)
- ascii_designer.tk_generic_var.nullable(convert)[source]
Creates a converter that returns
Noneon 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
@event decorator for methods, to make them into subscribable events.
- exception ascii_designer.event.CancelEvent[source]
Raise this in an event handler to inhibit all further processing.
- class ascii_designer.event.Event(prototype: Callable[[P], R], strict: bool | None = None, exceptions: Literal['log', 'print', 'raise', 'group'] = 'log')[source]
Notifies a number of “listeners” (functions) when called.
The principle is well-known under many names:
Define the event as member of a class that wants to tell the world about changes.
Arbitrary listeners can subscribe the event.
In the class’s implementation, the event is called when the trigger condition occurs. Listeners will be called in the order they subscribed.
Defining events
In contrast to other adhoc event systems, this one enforces well-defined signatures and documentation. An event is created by decorating a method (the so-called “prototype”) with
@event.The
eventwill take over the method’s signature, annotations and docstring. IDE tools and Sphinx documentation should (mostly) “see” the Event like any other method.The prototype method is executed every time the event is triggered. Usually it does not need any code except for a docstring or
passstatement.Restrictions apply:
In
strictmode, only positional-only and/or keyword-only args are allowed. This is to make clear to the user how the arguments will be given (by position or by name).Yes:
prototype(a: int, b: str, /)Yes:
prototype(*, a: int, b: str)No:
prototype(a:int, b:str)(but allowed in non-strict mode)
strictmode is disabled for backwards compatibility, but will become the default in the future.Arguments with default values are forbidden, since their meaning would be ambiguous for the user of the class.
The prototype does not get an automatic
selfargument. I.e. it works like astaticmethod. You can define aselfargument, but it must be given explicitly upon calling.
Listeners
A listener is a Callable whose signature fits the event specification. Event listeners can be subscribed/unsubscribed using the
+=and-=operators. Listener signature is not checked at the time of subscription.There is some freedom in listener signature. E.g. you can have extra parameters with default values, or you can catch the event data via
*args/**kwargs.Triggering the event
The event is triggered by calling the
eventinstance. Usually this happens within the class containing the Event.First, the wrapped protoype is executed, in order to verify correct arguments. Note that adherence to annotated types is not checked, in line with standard Python behavior.
Any handler can raise
CancelEventto gracefully abort the processing of further listeners.Return values
At most one listener is expected to return a value. If multiple listeners return a value, an exception is raised.
The return type must always be Optional.
Exceptions
Listeners may raise exceptions that are unexpected for the event’s origin site.
Eventhas the “exceptions” parameter to control how they are handled:"log"(default) emits alogging.errormessage with the traceback."print"prints the exception (usingtraceback.print_exception)."raise"raises any exception immediately. No subsequent listeners are called."group"calls all listeners, then raises anExceptionGroupif any failed. The error is always anExceptionGroup, even in case of a single error.
When using
raise, code that triggers an event must be prepared for any exception being thrown at it.CancelEventis obviously exempt from this exception handling.Unbound/Bound distinction
Analogous to unbound methods, the class will contain the event as “unbound” event. You can in principle subscribe to it, and trigger it using
Class.event(). There is only one, global list of subscribers.A class instance will have a “bound” copy of the
Event, meaning that it has its own list of subscribers independent from all other instances. It does not inherit listeners from the unbound event. Typically, the bound event is the one you want to subscribe to.Lastly, you can also apply
@eventto a module-level function. There will be only one, global list of subscribers, same as for an unbound event.Example:
# Class definition class MyCounter: @event def counter_changed_to(self, new_value:int): '''Event: counter changed to given value''' def my_timer_function(self): # ... self.counter_changed(123) # ... # User code class MyGUI: def __init__(self, counter_instance:MyCounter): self.counter_instance = counter_instance self.counter_instance.counter_changed_to += self.on_counter_changed def on_counter_changed(self, new_value): self.update_display(new_value)
- ascii_designer.event.event(prototype: Callable[[P], R], *, strict: bool | None = None, exceptions: Literal['log', 'print', 'raise', 'group'] = 'log') Event[P, R][source]
- ascii_designer.event.event(prototype: None = None, *, strict: bool | None = None, exceptions: Literal['log', 'print', 'raise', 'group'] = 'log') Callable[[Callable[[P], R]], Event[P, R]]
Turn the decorated method into an Event.
See
Event. The@eventdecorator allows to pass arguments:@event(strict=False, exeptions=”print”) def some_event(arg1: bool, /): …