bt-gui-lolevel
[module] bt-gui-lolevel
Low level GUI abstractions and helper procedures.
Utilities
[syntax] tk/bind*
Thread-safe version of tk/bind. Wraps the procedure PROC in a thunk that is safe to execute as a callback from Tk.
[procedure] (bind-key WIDGET GROUP ACTION PROC)
Bind the keypress event for WIDGET to PROC. ACTION must be a mapping listed in the group GROUP of the active keymap.
[procedure] (recolor-png FILENAME COLOR)
[procedure] (tk/icon FILENAME #!optional (ICON-COLOR (colors 'text)))
Create a tk image resource from a given PNG file.
[procedure] (make-separator PARENT ORIENT)
[procedure] (add-size-grip)
[procedure] (stylize-text-widget WIDGET)
Change the style of the Tk text WIDGET so it matches Bintracker's look.
[procedure] (wait-for-treeview-item TREE ITEM #!optional (TRIES 0))
Work-around for Tk wonkyness when referencing treeview items. Call this
procedure before calling focus
or selection set
on a treeview. TREE
shall be a ttk::treeview widget, and ITEM is the Tk identifier of item
that is referenced. TRIES is for internal use only.
[procedure] (get-treeview-selection TREE #!optional (TRIES 0))
Work-around for Tk wonkyness when querying a treeview's selection. Call
this instead of using a raw ttk::treeview 'selection
command.
[procedure] (focus-first-treeview-item TREE)
Focus and select the first item in the ttk::treeview TREE. The treeview must contain at least one item.
[procedure] (tk-true? TK-EVAL-RESULT)
Convert Tk's "0" and "1" responses to conditional queries to #f
/#t
.
Accessibility
[procedure] (sanitize-string-for-speech STR)
Translate the string STR so that it will make more sense when read by a text-to-speech utility.
[procedure] (text-to-speech TEXT)
Output TEXT on the active text-to-speech utility, if any.
Dialogues
This section provides abstractions over Tk dialogues and pop-ups.
tk/safe-dialogue
is potentially the most useful entry points for
creating native dialogues from user code.
[procedure] (tk/safe-dialogue TYPE . ARGS)
Used to provide safe variants of tk/message-box, tk/get-open-file, and tk/get-save-file that block the main application window while the pop-up is alive. This is a work-around for tk dialogue procedures getting stuck once they lose focus. tk-with-lock does not help in these cases.
[procedure] (tk/message-box* . ARGS)
Crash-safe variant of tk/message-box
.
[procedure] (tk/get-open-file* . ARGS)
Crash-safe variant of tk/get-open-file
.
[procedure] (tk/get-save-file* . ARGS)
Crash-safe variant of tk/get-save-file
.
[procedure] (about-message)
Display the "About Bintracker" message.
[procedure] (report-exception EXN PROLOGUE)
Display a message box for the given EXN, and output a summary of the error on the active text-to-speech utility, if any. PROLOGUE will be prepended to the exception message.
[procedure] (exit-with-unsaved-changes-dialog EXIT-OR-CLOSING)
Display a message box that asks the user whether to save unsaved changes
before exiting or closing. EXIT-OR-CLOSING should be the string
"exit"
or "closing"
, respectively.
Widget Style
[procedure] (default-theme-generator)
Generates the default Bintracker Tk theme and saves it as
resources/bt-theme.tcl
.
[procedure] (update-ttk-style)
Configure ttk widget styles.
Menus
[procedure] (add-menu-item! MENU ITEM-SPEC)
Destructively add an item to menu-struct menu
according to
item-spec
. item-spec
must be a list containing either
- ('separator)
- ('command id label underline accelerator command)
- ('submenu id label underline items-list)
where id is a unique identifier symbol; label and underline are the
name that will be shown in the menu for this item, and its underline
position; accelerator is a string naming a keyboard shortcut for the
item, command is a procedure to be associated with the item, and
items-list is a list of item-specs.
[procedure] (construct-menu ITEMS)
Events
[procedure] (disable-keyboard-traversal)
Disable automatic keyboard traversal. Needed because it messes with key binding involving Tab.
[procedure] (create-virtual-events)
Create default virtual events for Bintracker. This procedure only needs to be called on startup, or after updating key bindings.
[procedure] (reverse-binding-eval-order WIDGET)
Reverse the evaluation order for tk bindings, so that global bindings are evaluated before the local bindings of WIDGET. This is necessary to prevent keypresses that are handled globally being passed through to the widget.
TextGrid
TextGrids are Tk Text widgets with default bindings removed and/or
replaced with Bintracker-specific bindings. TextGrids form the basis of
Bintrackers
[procedure] (textgrid-configure-tags TG)
Configure TextGrid widget tags.
[procedure] (textgrid-do-tags METHOD TG TAGS FIRST-ROW #!optional (FIRST-COL 0) (LAST-COL 'end) (LAST-ROW #f))
Abstraction over Tk's textwidget tag add
command.
Contrary to Tk's convention, ROW uses 0-based indexing.
TAGS may be a single tag, or a list of tags.
[procedure] (textgrid-add-tags . ARGS)
[procedure] (textgrid-remove-tags . ARGS)
[procedure] (textgrid-remove-tags-globally TG TAGS)
[procedure] (textgrid-position->tk-index ROW CHAR)
Convert the row
, char
arguments into a Tk Text index string.
row
is adjusted from 0-based indexing to 1-based indexing.
[procedure] (textgrid-xy->char-pos TG X Y)
Convert the mouse position (relativ pixel offset in widget) to the nearest character position. The result is adjusted to 0-based indexing.
[procedure] (textgrid-create-basic PARENT)
Create a TextGrid as slave of the Tk widget parent
. Returns a Tk Text
widget with class bindings removed.
[procedure] (textgrid-create PARENT)
UI Element Base Classes
[class] <ui-element>
slot | initform | accessor |
---|---|---|
initialized |
#f |
|
setup |
||
parent |
tk |
ui-parent |
packing-args |
'() |
|
box |
ui-box |
|
children |
'() |
ui-children |
where |
"unknown UI element" |
A <ui-element>
represents a GUI metawidget consisting of one or more
Tk widgets. The metawidget is self-contained, meaning all it's child
widgets are wrapped in a
ttk::frame.
A <ui-element>
instance may contain other <ui-elements>
as child
elements.
Any instance of <ui-element>
or a derived class contains the following
fields:
-
setup
- an expression specifying how to construct the UI element. Details depend on the specific class type of the element. For standard<ui-element>
s, this is the only mandatory field. Provides a reader namedui-setup
. -
parent
- the Tk parent widget, typically a tk::frame. Defaults totk
if not specified. Provides an accessor namedui-parent
. -
packing-args
- additional arguments that are passed to tk/pack when the UI element's main widget container is packed to the display. -
children
- an alist of child UI elements, where keys are symbols and values are instances of<ui-element>
or a descendant class. Children are derived automatically from thesetup
field, so the user normally does not need to interact with thechildren
field directly. Provides an accessor namedui-children
.
The generic procedures ui-show
, ui-hide
, and ui-ref
are implemented
for all UI element classes. UI elements commonly also provide
ui-set-state
and ui-set-callbacks
methods.
To implement your own custom UI elements, you should create a class
that inherits from <ui-element>
or one of its descendants. You probably
want to define at least the initialize-instance
method for your class,
which should be an after:
method. Note that <ui-element>
's constructor
does not initialize the child elements. ui-show
, however, will
recursively apply ui-show
on an <ui-element>
. Therefore the children
slot must not contain anything but named instances of <ui-element>
,
unless you override ui-show
with your own primary method. The
recommended way is to add new slots to your derived class for any custom
widgets not derived from <ui-element>
.
[method] (initialize-instance after: (ELEM <ui-element>))
[method] (ui-show primary: (ELEM <ui-element>))
Map the GUI element to the display.
[method] (ui-hide primary: (ELEM <ui-element>))
Remove the GUI element from the display.
[method] (ui-where primary: (ELEM <ui-element>))
[method] (ui-what primary: (ELEM <ui-element>))
[method] (ui-destroy primary: (ELEM <ui-element>))
Remove the GUI element ELEM from the display and destroy it. Destroying an
element will recursively call ui-destroy
on ELEM's child elements,
before destroying its associated Tk widgets. You cannot resurrect ELEM
after calling this method.
[method] (ui-ref primary: (ELEM <ui-element>) CHILD-ELEMENT)
Returns ELEMs child UI element with the identifier CHILD-ELEMENT. The
requested element may be a direct descendant of ELEM, or an indirect
descendant in the tree of UI elements represented by ELEM.
[class] <ui-wrapper>
inherits from: <ui-element>
slot | initform |
---|---|
yscroll |
#f |
orient |
'horizontal |
packing-args |
'(padx: 4 pady: 4 side: top fill: x) |
Class-based container for one or more Tk widgets. This is essentially an adapter for using raw Tk widgets from within Bintracker's class-based UI system. Create instances as follows:
where ID1 is a unique child element identifier, WIDGET-TYPE1 is the name
of a Tk widget element, and ARGS... are the arguments passed to the
widget's consructor. ORIENT specifies the orientation in which the widgets
will be packed. It must be either 'horizontal
or 'vertical
, defaults
to 'horizontal
. YS may be a boolean. If #t
, setup may contain only a
single child element, and ORIENT must be 'horizontal
. A vertical
scrollbar will be added for the child element.
[method] (initialize-instance after: (ELEM <ui-wrapper>))
[method] (ui-show primary: (ELEM <ui-wrapper>))
[method] (ui-ref primary: (ELEM <ui-wrapper>) CHILD-ELEMENT)
[class] <ui-modeline>
inherits from: <ui-element>
slot | initform |
---|---|
packing-args |
'(expand: 0 fill: x side: bottom) |
segments |
[method] (initialize-instance after: (BUF <ui-modeline>))
A modeline (aka status bar) widget. Create instances with
(make <ui-modeline> 'setup ((ID TEXT [COLOR]) ...))
where ID is a unique identifier of a modeline segment, and TEXT is the
string that will be displayed in the modeline segment. An empty string
means the segment is not displayed. If COLOR is given, it must be an
integer referencing one of the application colors text-1
... text-7
.
If COLOR is omitted, the color text
will be used.
[method] (ui-show before: (BUF <ui-modeline>))
[method] (ui-modeline-set primary: (BUF <ui-modeline>) SEGMENT TEXT)
Set the TEXT string of the modeline segment identifier SEGMENT.
[class] <ui-setting>
inherits from: <ui-element>
slot | initform |
---|---|
packing-args |
'(side: left) |
label |
|
spinbox |
|
statevar |
A class representing a labelled Tk spinbox. Create instances with
where PARENT is the parent Tk widget, LABEL is the text of the label,
INFO is a short description of the element's function, DEFAULT-VAR is a
symbol denoting an entry in (settings)
, FROM and TO are integers
describing the range of permitted values, and CALLBACK may optionally a
procedure of no arguments that will be invoked when the user selects a new
value.
[method] (initialize-instance after: (BUF <ui-setting>))
[method] (ui-set-state primary: (BUF <ui-setting>) STATE)
Set the state of the UI element buf
. state
can be either 'disabled
or 'enabled
.
[class] <ui-settings-group>
inherits from: <ui-element>
slot | initform |
---|---|
packing-args |
'(expand: 0 fill: x) |
A wrapper for one or more <ui-setting>
s. Create instances with
where ID1 is a unique child element identifier, and CHILD-SPEC ... are the
remaining arguments that will be passed to <ui-setting>
's constructor
the 'setup
argument.
[method] (initialize-instance after: (BUF <ui-settings-group>))
[method] (ui-set-state primary: (BUF <ui-settings-group>) STATE)
Enable or disable BUF. STATE must be either 'enabled
or 'disabled
.
[class] <ui-button-group>
inherits from: <ui-element>
slot | initform |
---|---|
packing-args |
'(expand: 0 side: left) |
orient |
'horizontal |
buttons |
A class representing a group of button widgets. Create instances with
where PARENT is the parent Tk widget, ID is a unique identifier, INFO is a string of text to be displayed in the status bar when the user hovers the button, ICON-FILE is the name of a file in resources/icons/. You may optionally set the initial state of the button (enabled/disabled) by specifying INIT-STATE.
[method] (initialize-instance after: (BUF <ui-button-group>))
[method] (ui-set-state primary: (BUF <ui-button-group>) STATE #!optional BUTTON-ID)
Enable or disable BUF or one of it's child elements. STATE must be either
'enabled
or 'disabled
. When passing a BUTTON-ID is specified, only the
corresponding child element's state changes, otherwise, the change affects
all buttons in the group.
[method] (ui-set-callbacks primary: (BUF <ui-button-group>) CALLBACKS #!optional MODELINE SEGMENT-ID)
Set callback procedures for buttons in the button group. callbacks
must be a list constructed as follows:
((ID THUNK) ...)
where ID is a button identifier, and THUNK is a callback procedure that takes no arguments. Optionally, ENTER-BINDING may be a callback procedure with no arguments that will be invoked when the user starts hovering over the button with the mouse, and LEAVE-BINDING may be a callback procedure with no arguments that is invoked when the mouse leaves the button area. You would typically use this to display some information about the button in a modeline.
[class] <ui-toolbar>
inherits from: <ui-element>
slot | initform |
---|---|
packing-args |
'(expand: 0 fill: x) |
A class representing a toolbar metawidget, consisting of
<ui-button-group>
s. Create instances with
where PARENT is the parent Tk widget, ID1 is a unique identifier, and
BUTTON-SPEC1 is a setup expression passed to
[method] (initialize-instance after: (BUF <ui-toolbar>))
[method] (ui-set-callbacks primary: (BUF <ui-toolbar>) CALLBACKS #!optional MODELINE SEGMENT-ID)
Set callback procedures for buttons in the toolbar. callbacks
must be
a list constructed as follows:
(ID BUTTON-GROUP-CALLBACK-SPEC ...)
where ID is a button group identifier and BUTTON-GROUP-CALLBACK-SPEC is
a callback specification as required by the ui-set-callbacks
method of
<ui-button-group>
.
[class] <ui-buffer-decorations>
slot | initform |
---|---|
toolbar |
#f |
settings-bar |
#f |
modeline |
#f |
An auxiliary class used to add toolbars, settings-bars, and modelines
(status bars) to classes derived from <ui-element>
.
Classes inheriting from this must initialize the slots to an instance of
<ui-toolbar>
, <ui-settings-bar>
, and/or <ui-modeline>
, for the
toolbar, settings-bar, and modeline slots, respectively.
You can then call ui-show-decorations
on instances of your derived class
to map the decorations to a chosen parent Tk frame).
[method] (ui-show-decorations (D <ui-buffer-decorations>) PARENT #!optional AFTER)
Pack the decorations to the PARENT Tk frame window (usually (ui-buf)
of
the class that inherits from this and <ui-element>
).
[class] <ui-selectable>
slot | initform | accessor |
---|---|---|
selection |
#f |
ui-selection |
[class] <ui-multibuffer>
inherits from: <ui-element>
<ui-buffer-decorations>
slot | initform |
---|---|
packing-args |
'(expand: 1 fill: both) |
orient |
'vertical |
setup |
'() |
panes |
|
state |
A class representing a container widget that wraps multiple resizable ui-buffers in a ttk panedwindow.
Create instances with
where PARENT is the parent Tk widget (defaults to tk
), ID1 is a unique
identifier for a child buffer, VISIBLE is a boolean specifying if the
child widget should initially be mapped to the display, WEIGHT is an
integer specifying how large the child buffer should be in relation to the
remaining child buffers, and CHILD-SPEC ... is the name of a UI buffer
class, followed by the arguments that shall be passed to make
when
creating the child buffer instance.
The optional ORIENT argument specifies the orientation of the metabuffer;
it shall be one of the symbols 'vertical
or 'horizontal
. By default,
metabuffers are oriented vertically, meaning new child buffers will be
added below the current ones.
The state
slot contains an alist with the child identifiers as keys.
alist-ref
will return a list in the form (INDEX VISIBLE WEIGHT), where
INDEX is an integer representing the position of the child element in the
multibuffer, VISIBLE is #t
if the child element is currently controlled
by the display manager and #f
otherwise, and WEIGHT is an integer
specifying the initial size of the child element in relation to the other
children (not taking into account resizes by the user),
[method] (initialize-instance after: (BUF <ui-multibuffer>))
[method] (multibuffer-active+sorted-children primary: (BUF <ui-multibuffer>))
Returns the actively managed children of BUF sorted by position.
[method] (ui-show primary: (BUF <ui-multibuffer>))
[method] (multibuffer-add primary: (BUF <ui-multibuffer>) CHILD-SPEC #!key BEFORE)
Add a new child buffer. CHILD-SPEC shall have the same form as the
elements in the 'setup
argument to (make <ui-multibuffer ...)
.
The new child buffer will be added before the child named BEFORE, or at
the end if BEFORE is not specified.
[method] (multibuffer-show primary: (BUF <ui-multibuffer>) CHILD)
Map the child element CHILD to the display. Does nothing if CHILD is
already visible.
[method] (multibuffer-hide primary: (BUF <ui-multibuffer>) CHILD)
Remove the child element CHILD from the display. Does nothing if CHILD is
currently not hidden. You can add back CHILD at a later point with
multibuffer-show
. If CHILD is no longer needed at all, use
multibuffer-destroy
instead.
[method] (multibuffer-delete primary: (BUF <ui-multibuffer>) CHILD)
Remove the child element CHILD from the multibuffer display and delete it.
If you just want to remove the child from the display, use
multibuffer-hide
instead.
[class] <ui-buffer>
inherits from: <ui-element>
<ui-buffer-decorations>
slot | initform |
---|---|
title |
"" |
default-state |
'expanded |
collapse-icon |
(tk/icon "collapse.png") |
expand-icon |
(tk/icon "expand.png") |
collapse-button |
|
content-box |
|
collapsible |
#f |
collapsed |
#f |
This class commonly acts as a superclass for UI classes that represent
user data. <ui-buffer>
's are collapsible. This means child elements are
wrapped in a frame that the user can fold and unfold by clicking a button,
or through a key binding. `
The constructor of this class does not evaluate 'setup
expressions, so
derived classes should provide their own setup reader. A plain
where ID is a unique child element identifier, and ELEMENT1 is an
instance of a <ui-element>
.
[method] (initialize-instance after: (BUF <ui-buffer>))
[method] (ui-show after: (BUF <ui-buffer>))
[method] (ui-collapse primary: (BUF <ui-buffer>))
[method] (ui-expand primary: (BUF <ui-buffer>))
[class] <ui-dialog>
slot | initform | accessor |
---|---|---|
initialized |
#f |
|
visible |
#f |
|
parent |
tk |
ui-parent |
packing-args |
'() |
|
box |
ui-box |
|
title |
"" |
|
initializers |
(make-hooks) |
|
finalizers |
(make-hooks) |
|
footer |
||
cancel-button |
||
confirm-button |
||
cancel-text |
"Cancel" |
|
confirm-text |
"Confirm" |
|
children |
'() |
ui-children |
traverse |
'() |
A class representing a popup dialog. Dialogs are automatically constructed
with two buttons labelled "Confirm" and "Cancel", and <Escape>
and
<Return>
keypress events are always bound. Construct instances with:
(make <ui-dialog>
['title TITLE]
['children CHILD-SPECS]
['traverse CHILD-IDS]
['initializers INIT-HOOKS]
['finalizers FINAL-HOOKS]
['parent PARENT])
TITLE may be a string that will be displayed as the dialog window name.
CHILD-SPECS may be an associative list of named child elements, which must
be <ui-element>
s.
If all child elements are <ui-wrapper>
instances, you can implement
automatic Tab/Backtab traversal by listing the CHILD-IDS of focussable child
elements.
Widgets in a dialog are not created until the dialog is shown. This means you cannot bind events or apply procedures to child elements of the dialog directly after initialization. To apply bindings and/or procedures, provide a hook set as INIT-HOOKS.
FINALIZERS may be a hook set that will be executed when the user clicks the "Confirm" button or hits the Return key. Procedures in the hook set must be stubs, ie. they may not take any arguments.
PARENT may be a Tk toplevel window. The dialog window acts as a transient
on the PARENT. PARENT defaults to the root window tk
. You normally do
not need to set this explicitly, except when creating dialogs acting on
behalf of other dialogs.
As long as the dialog is not destroyed (by calling ui-destroy
on it or
manually destroying its ui-box
), it preserves state between invocations.
Note that <ui-dialog>
is not a descendant of <ui-element>
. In practice
this hardly matters, as <ui-dialog>
supports all of the basic methods
defined on <ui-element>
. However, note the caveat regarding applying
bindings and procedures to sub-widgets above.
[method] (ui-show primary: (D <ui-dialog>) #!key INITIALIZER-ARGS)
[method] (ui-hide primary: (D <ui-dialog>))
[method] (ui-destroy primary: (D <ui-dialog>))
[method] (ui-ref primary: (ELEM <ui-dialog>) CHILD-ELEMENT)
Toolbar Sets
Toolbar Sets can be used to create customizable <ui-toolbar>
objects
Their main purpose is to provide a possibility for plug-ins to extend
the toolbars of existing UI classes.
[procedure] (create-toolbar-set GROUP-SPECS CALLBACK-SPECS)
Create a toolbar set. GROUP-SPECS shall be a setup list as required by
<ui-toolbar>
. CALLBACK-SPECS shall be a list of callback procedures,
similar to <ui-toolbar>
's ui-set-callbacks
method.
Returns a closure. When called without arguments, the closure returns a list containing the group specifications in car, and the callback specifications in cadr. Otherwise, the closure can be called as follows:
(TS 'add 'button GROUP-ID BUTTON-SPEC1...)
Add the button specification(s) BUTTON-SPEC1... to the button group GROUP-ID. If GROUP-ID does not exist in the toolbar set's groups, a new group is created. If the button given in BUTTON-SPEC1 already exists, its specification is updated instead.
(TS 'add 'callback GROUP-ID CALLBACK-SPEC1...)
Add or replace the callback specification(s) CALLBACK-SPEC1... for the button group GROUP-ID, where CALLBACK-SPEC1 is a list containing a valid button ID in car, and a procedure in cadr.
(TS 'callbacks)
Returns the current callback specifications.
(TS 'groups)
Returns the button group specifications.