Skip to content

bt-gui

[module] bt-gui

Bintracker GUI abstractions.

Global Actions

[procedure] (update-window-title!)

update window title by looking at current file name and 'modified' property

[procedure] (do-proc-with-exit-dialogue DIALOGUE-STRING PROC)

If there are unsaved changes to the current module, ask user if they should be saved, then execute the procedure PROC unless the user cancelled the action. With no unsaved changes, simply execute PROC.

[procedure] (exit-bintracker)

Shut down the running application.

[variable] on-close-file-hooks

default:

(make-hooks
     `(delete-module-view . ,(lambda () (multibuffer-delete (ui) 'module-view)))
     `(show-welcome-buffer . ,(lambda () (multibuffer-show (ui) 'welcome)))
     `(update-window-title . ,update-window-title!))

[procedure] (close-file)

Close the currently opened module file.

[variable] after-load-file-hooks

default:

(make-hooks
     `(hide-welcome-buffer . ,(lambda args (multibuffer-hide (ui) 'welcome)))
     `(show-module
       . ,(lambda (mmod filename)
        (multibuffer-add (ui)
                 `(module-view #t 5 ,<ui-module-view>
                       mmod ,mmod filename ,filename)
                 before: 'repl)))
     `(focus-first-block
       . ,(lambda args
        (and-let* ((entry (find (lambda (entry)
                      (symbol-contains (car entry)
                               "block-view"))
                    (focus 'list))))
          (focus 'set (car entry))))))

[procedure] (load-file)

Prompt the user to load an MDAL module file.

[procedure] (create-new-module MDEF-NAME)

[variable] new-file-dialog

default:

(make <ui-dialog>
      'title "Select Engine"
      'children
      `((header ,<ui-wrapper> setup
        ((lbl1 label text: "Platform")
         (platform-selector combobox state: readonly)))
    (sf ,<ui-wrapper> setup
        ((mdef-selector treeview columns: (Name Version Platform)
                show: tree selectmode: browse))
        yscroll #t)
    (df ,<ui-wrapper> setup
        ((description text takefocus: 0 state: disabled bd: 0
              highlightthickness: 0 height: 10 wrap: word))
        yscroll #t))
      'initializers
      (make-hooks
       `(configure-text-style
     .
     ,(lambda ()
        ((ui-ref new-file-dialog 'description) 'configure
         bg: (colors 'background) fg: (colors 'text)
         font: (list family: (settings 'font-mono)
              size: (settings 'font-size)))))
       `(list-platforms
     .
     ,(lambda ()
        (let ((selected-pf (tk-var "selectedplatform")))
          ((ui-ref new-file-dialog 'platform-selector)
           'configure values: (cons "any" (btdb-list-platforms))
           textvariable: selected-pf)
          (tk-set-var! "selectedplatform" "any"))))
       `(list-mdefs
     .
     ,(lambda ()
        (for-each (lambda (mdef)
            ((ui-ref new-file-dialog 'mdef-selector)
             'insert '{} 'end text: (car mdef)
             values: (list (cadr mdef) (third mdef))))
              ;; TODO btdb-list-mdefs should always return a list!
              (btdb-list-mdefs))))
       `(do-bindings
     .
     ,(lambda ()
        (let* ((platform-selector (ui-ref new-file-dialog
                          'platform-selector))
           (mdef-selector (ui-ref new-file-dialog 'mdef-selector))
           (description-widget (ui-ref new-file-dialog 'description))
           (get-item-list (lambda ()
                    (string-split
                     (string-delete
                      (string->char-set "{}")
                      (->string
                       (mdef-selector 'children '{})))))))
          (tk/bind
           platform-selector
           '<<ComboboxSelected>>
           (lambda ()
         (let ((selected-platform
            (string->symbol (tk-get-var "selectedplatform"))))
           (mdef-selector 'delete (get-item-list))
           (for-each (lambda (mdef)
                   (mdef-selector 'insert '{} 'end
                          text: (car mdef)
                          values: (list (cadr mdef)
                                (third mdef))))
                 (btdb-list-mdefs selected-platform))
           (mdef-selector 'focus (car (get-item-list)))
           (mdef-selector 'selection 'set
                  (list (car (get-item-list)))))))
          (tk/bind
           mdef-selector
           '<<TreeviewSelect>>
           ;; TODO this fails when selection was set automatically,
           ;; because Tk delays execution of the selection too long.
           ;; Calling tk/update or tk/update 'idletasks hangs the app.
           ;; For now, use tk/after 100 as a (very brittle) work-around.
           (lambda ()
         (tk/after
          100
          (lambda ()
            (let* ((selected-engine
                (string->symbol
                 (mdef-selector
                  'item (mdef-selector 'selection) text:)))
               (description (->string (btdb-get-mdef-description
                           selected-engine))))
              (description-widget 'configure state: 'normal)
              (description-widget 'delete "0.0" 'end)
              (description-widget 'insert 'end description)
              (description-widget 'configure state: 'disabled))))))))))
      'finalizers
      (make-hooks
       `(ex
     .
     ,(lambda a
        (and-let*
        ((mdef-selector (ui-ref new-file-dialog 'mdef-selector))
         (item-list (string-split
                 (string-delete
                  (string->char-set "{}")
                  (->string (mdef-selector 'children '{})))))
         (_ (not (null? item-list)))
         (selected-def (mdef-selector 'item (mdef-selector 'focus)
                          text:)))
          (create-new-module (if (string-null? selected-def)
                     (mdef-selector 'item (car item-list)
                            text:)
                     selected-def)))))))

[procedure] (new-file)

[variable] on-save-file-hooks

default:

(make-hooks
     `(write-file
       . ,(lambda ()
        (mmod->file (ui-metastate (current 'module-view) 'mmod)
            (ui-metastate (current 'module-view) 'filename))
        (ui-metastate (current 'module-view) 'modified #f)))
     `(update-window-title . ,update-window-title!))

[procedure] (save-file)

Save the current MDAL module. If no file name has been specified yet, promt the user for one.

[procedure] (save-file-as)

Save the current MDAL module under a new, different name.

[procedure] (export-bin)

[procedure] (undo)

Calls undo on (current 'module-view).

[procedure] (redo)

Calls redo on (current 'module-view).

[procedure] (launch-help)

Launch the online help in the user's default system web browser.

Playback

[procedure] (play-from-start)

[procedure] (play-pattern)

[procedure] (stop-playback)

GUI Elements

A collection of classes and methods that make up Bintracker's internal GUI structure. All UI classes are derived from <ui-element>. The OOP system used is coops.

[procedure] (ui-eval-layout-expression EXPR)

"Evaluate" a GUI layout expression (as used in config/config.scm) by replacing class names with class instances. Note that this procedure is not recursive, ie. you cannot use it to create nested layouts.

Auxilliary procedures used by various BT meta-widgets

[procedure] (value-display-size COMMAND-CONFIG)

Determine how many characters are needed to print values of a given command.

[procedure] (replace-digit VAL DIGIT-IDX KEYSYM)

Takes the Tk keypress symbol KEYSYM and interprets it as a digit taking the nth postion in the integer VAL, using a radix corresponding to the result of (settings 'number-base). DIGIT-IDX is the digit position index.

[procedure] (replace-modifier-digit VAL DIGIT-IDX KEYSYM)

Takes the Tk keypress symbol KEYSYM and interprets it as a digit taking the nth postion in the modifier command value VAL, using a radix corresponding to the result of (settings 'number-base) for the integer part. DIGIT-IDX is the digit position index (right to left) or -1 for the prefix part.

[procedure] (normalize-field-value VAL FIELD-ID MDEF)

Transform an ifield value from MDAL format to tracker display format. Replaces empty values with dots, changes numbers depending on number format setting, and turns everything into a string.

[procedure] (get-field-color-tag FIELD-ID MDEF)

Get the color tag asscociated with the field's command type.

[procedure] (get-field-color FIELD-ID MDEF)

Get the RGB color string associated with the field's command type.

[procedure] (keypress->note KEY BASE-OCTAVE)

Convert a keysym (as returned by a tk-event %K placeholder) to an MDAL note name.

[procedure] (get-command-type-tag FIELD-ID MDEF)

Get the appropriate command type tag to set the item color.

[procedure] (node-id-abbreviate ID LEN)

Generate an abbrevation of len characters from the given MDAL inode identifier id. Returns the abbrevation as a string. The string is padded to len characters if necessary.

Block View Field Configurations

[record] bv-field-config

[constructor] (make-bv-field-config #!key TYPE-TAG WIDTH START CURSOR-WIDTH CURSOR-DIGITS)
[predicate] bv-field-config?
implementation: defstruct

field getter setter type
type-tag bv-field-config-type-tag bv-field-config-type-tag-set! symbol
width bv-field-config-width bv-field-config-width-set! fixnum
start bv-field-config-start bv-field-config-start-set! fixnum
cursor-width bv-field-config-cursor-width bv-field-config-cursor-width-set! fixnum
cursor-digits bv-field-config-cursor-digits bv-field-config-cursor-digits-set! fixnum

A record type used internally by and its descendants.

[procedure] (field-id->cursor-size FIELD-ID MDEF)

Returns the number of characters that the blockview cursor should span for the given field-id.

[procedure] (field-id->cursor-digits FIELD-ID MDEF)

Returns the number of cursor positions for the the field node field-id. For fields that are based on note/key/ukey commands, the result will be one, otherwise it will be equal to the number of characters needed to represent the valid input range for the field's source command.

[procedure] (blockview-make-field-configs BLOCK-IDS FIELD-IDS MDEF)

Generate the alist of bv-field-configs.

Bintracker-specific UI Classes

[class] <ui-welcome-buffer>

inherits from: <ui-element>

slot initform
ui-zone (gensym 'welcome)
packing-args '(expand: 1 fill: both)
focus-controller focus
buttons '()
commands `(,new-file ,load-file ,launch-help)

A welcome screen with two buttons for creating and opening an MDAL module, respectively. Create instances with (make <ui-welcome-buffer>).

[method] (initialize-instance after: (BUF <ui-welcome-buffer>) )

[method] (ui-show before: (BUF <ui-welcome-buffer>) )

[method] (ui-focus primary: (BUF <ui-welcome-buffer>) )

[class] <ui-repl>

inherits from: <ui-buffer>

slot initform
ui-zone (gensym 'repl)
focus-controller focus
repl
yscroll
prompt "repl> "
history '()

A class representing a read-evaluate-print-loop prompt. 'setup shall be the initial text to display on the prompt. To register the widget as focussable in the Bintracker main UI, specify a ui-zone identifier as initform to 'ui-zone. The methods repl-clear, repl-insert, and repl-get are provided for interaction with the prompt.

[method] (initialize-instance after: (BUF <ui-repl>) )

[method] (ui-show before: (BUF <ui-repl>) )

[method] (ui-hide after: (BUF <ui-repl>) )

[method] (ui-destroy before: (BUF <ui-repl>) )

[method] (ui-where primary: (BUF <ui-repl>) )

[method] (ui-what primary: (BUF <ui-repl>) )

[method] (repl-insert primary: (BUF <ui-repl>) STR)
Insert STR at the end of the prompt of the <ui-repl> instance BUF.

[method] (repl-insert-prompt primary: (BUF <ui-repl>) )

[method] (repl-clear primary: (BUF <ui-repl>) )
Clear the prompt of the <ui-repl> instance BUF.

[method] (repl-eval primary: (BUF <ui-repl>) )
Evaluate the latest command that the user entered into the repl prompt.

[method] (ui-focus primary: (BUF <ui-repl>) )

Get the text contents of the <ui-repl> instance BUF. The remaining args are evaluated as arguments to Tk:Text 'get. See Tk manual page.

Module View Widgets

The following classes are the components used to construct a graphical representation of an MDAL module (MMOD). The <ui-module-view> class defined at the end of this section combines these to create a display metabuffer of the module, and manage its state.

Given a class instance of any of these module view components (or an instance of the module view itself, you can interact with the (parent) module state through the ui-metastate method (see below).

You normally do not need to create instances of the child components yourself. If you do construct your own instances, then you must already have constructed a <ui-module-view>, and pass the value of its metastate-accessor slot to the constructor of the child component.

[class] <ui-group-field>

inherits from: <ui-element>

slot initform
label
entry
node-id (error '|make <ui-group-field>| "Missing 'node-id.")
parent-instance-path (error '|make <ui-group-field>| "Missing 'parent-instance-path.")
metastate-accessor (error '|make <ui-group-field>| "Missing 'metastate-accessor")
packing-args '(expand: 0 fill: x)

A widget representing an MDAL group field instance. Create instances of this class with

(make <ui-group-field>
      'node-id ID
      'parent-instance-path PATH
      'metastate-accessor ACCESSOR)

where ID is an MDAL field node identifier in the parent MMOD, and PATH is an MDAL node path string valid for (ACCESSOR 'mmod). where ID is an MDAL field node identifier, PATH is an MDAL node path string pointing to the parent group node instance, and ACCESSOR is a metastate accessor procedure as described in the` documentation below.

[method] (initialize-instance after: (BUF <ui-group-field>) )

[method] (ui-group-field-perform-edit primary: (BUF <ui-group-field>) ACTION)

[method] (ui-group-field-update-value primary: (BUF <ui-group-field>) )

[method] (ui-focus primary: (BUF <ui-group-field>) )

[method] (ui-unfocus primary: (BUF <ui-group-field>) )

See <ui-module-view> below.

[class] <ui-group-fields>

inherits from: <ui-buffer>

slot initform
ui-zone (gensym 'group-fields)
focus-controller focus
group-id (error '|make <ui-group-fields>| "Missing 'group-id.")
parent-instance-path (error '|make <ui-group-fields>| "Missing 'parent-instance-path.")
metastate-accessor (error '|make <ui-group-fields>| "Missing 'metastate-accessor.")
active-index 0
packing-args '(expand: 0 fill: x)

A wrapper for the group field nodes of an MDAL group instance. Create instances of this class with

(make <ui-group-fields>
      'group-id ID
      'parent-instance-path PATH
      'metastate-accessor ACCESSOR)

where ID is the MDAL node identifier of the parent group node, PATH is an MDAL node path string pointing to the parent group node instance, and ACCESSOR is a metastate accessor procedure as described in the <ui-module-view> documentation below.

[method] (initialize-instance after: (BUF <ui-group-fields>) )

[method] (ui-show after: (BUF <ui-group-fields>) )

[method] (ui-hide after: (BUF <ui-group-fields>) )

[method] (ui-destroy before: (BUF <ui-group-fields>) )

[method] (ui-focus primary: (BUF <ui-group-fields>) )

[method] (ui-unfocus primary: (BUF <ui-group-fields>) )

[method] (ui-update primary: (BUF <ui-group-fields>) )

[class] <ui-basic-block-view>

inherits from: <ui-buffer><ui-selectable>

slot initform
ui-zone
focus-controller focus
group-id (error '|make <ui-basic-block-view>| "Missing 'group-id.")
parent-instance-path (error '|make <ui-basic-block-view>| "Missing 'parent-instance-path.")
metastate-accessor (error '|make <ui-basic-block-view>| "Missing 'metastate-accessor.")
field-ids
field-configs
header-frame
content-frame
rownum-frame
rownum-header
rownums
block-frame
block-header
block-content
xscroll
yscroll
item-cache '()
collapsible #f
packing-args '(expand: 0 fill: both)

Abstract base class for <ui-block-view> and <ui-order-view>, implementing shared code for these two classes. You most likely do not need to construct an instance of this class directly. However, consider from this class if you want to implement an alternative representation of the block node members of an MDAL group node.

[method] (initialize-instance after: (BUF <ui-basic-block-view>) )

[method] (ui-show before: (BUF <ui-basic-block-view>) )

[method] (ui-hide after: (BUF <ui-basic-block-view>) )

[method] (ui-destroy before: (BUF <ui-basic-block-view>) )

[method] (ui-what primary: (BUF <ui-basic-block-view>) )

[method] (ui-blockview-parent-instance primary: (BUF <ui-basic-block-view>) )

[method] (ui-blockview-values->string primary: (BUF <ui-basic-block-view>) VALUES)
Convert the list of row VALUES into a string that can be inserted into the blockview's content-grid or header-grid. Each entry in VALUES must correspond to a field column in the blockview's content-grid.

[method] (ui-blockview-mark->position primary: (BUF <ui-basic-block-view>) MARK)
Returns the position of the Tk text widget MARK as a list containing the row in car, and the character position in cadr. Row position is adjusted to 0-based indexing.

[method] (ui-blockview-get-cursor-position primary: (BUF <ui-basic-block-view>) )
Returns the current cursor position as a list containing the row in car, and the character position in cadr. Row position is adjusted to 0-based indexing.

[method] (ui-blockview-get-current-row primary: (BUF <ui-basic-block-view>) )
Returns the current row, ie. the row that the cursor is currently on.

[method] (ui-blockview-get-current-field-id primary: (BUF <ui-basic-block-view>) )
Returns the field ID that the cursor is currently on.

[method] (ui-blockview-get-current-block-id primary: (BUF <ui-basic-block-view>) )
Returns the ID of the parent block node if the field that the cursor is currently on.

[method] (ui-blockview-get-current-field-config primary: (BUF <ui-basic-block-view>) )
Returns the bv-field-configuration for the field that the cursor is currently on.

[method] (ui-blockview-get-current-digit-index primary: (BUF <ui-basic-block-view>) )
Returns the index of the digit of the numeric block field that the cursor is currently on. Indices are 0-based, with the least significant digit assuming index 0.

[method] (ui-blockview-get-current-field-command primary: (BUF <ui-basic-block-view>) )
Returns the MDAL command config for the field that the cursor is currently on.

[method] (ui-blockview-start+end-positions primary: (BUF <ui-basic-block-view>) )
Determine the start and end positions of each item chunk in the blockview's item cache.

[method] (ui-blockview-get-total-length primary: (BUF <ui-basic-block-view>) )
Get the total number of rows of the blockview's contents.

[method] (ui-blockview-get-current-field-instance primary: (BUF <ui-basic-block-view>) )
Return the field instance ID currently under cursor.

[method] (ui-blockview-get-current-field-index primary: (BUF <ui-basic-block-view>) )
Return the index of the the current field node ID in the blockview's list of field IDs. The result can be used to retrieve a field instance value from a chunk in the item cache.

[method] (ui-blockview-get-current-field-value primary: (BUF <ui-basic-block-view>) )
Returns the (un-normalized) value of the field instance currently under cursor.

[method] (ui-blockview-tag-active-zone primary: (BUF <ui-basic-block-view>) )
Apply type tags and the 'active tag to the current active zone of the blockview BUF.

[method] (ui-blockview-update-row-highlights primary: (BUF <ui-basic-block-view>) )
Update the row highlights of the blockview.

[method] (ui-blockview-update-content-grid primary: (BUF <ui-basic-block-view>) )
Perform a full update of the blockview block-content.

[method] (ui-blockview-update-content-rows primary: (BUF <ui-basic-block-view>) NEW-ITEM-LIST)
Update the blockview content grid on a row by row basis. This compares the NEW-ITEM-LIST against the current item cache, and only updates rows that have changed. The list length of NEW-ITEM-LIST and the lengths of each of the subchunks must match the list of items in the current item cache. This operation does not update the blockview's item cache, which should be done manually after calling this procedure.

[method] (ui-blockview-cursor-x-positions primary: (BUF <ui-basic-block-view>) )
Returns a list of character positions that the blockview's cursor may assume.

[method] (ui-blockview-cursor-do primary: (BUF <ui-basic-block-view>) ACTION)
Show or hide the blockview's cursor. ACTION shall be 'add or 'remove.

[method] (ui-blockview-remove-cursor primary: (BUF <ui-basic-block-view>) )
Hide the blockview's cursor.

[method] (ui-blockview-show-cursor primary: (BUF <ui-basic-block-view>) )
Show the blockview's cursor.

[method] (ui-blockview-focus primary: (BUF <ui-basic-block-view>) )
Set the input focus to the blockview BUF. In addition to setting the Tk focus, it also shows the cursor and updates the status bar info text.

[method] (ui-blockview-unfocus primary: (BUF <ui-basic-block-view>) )
Unset focus from the blockview BUF.

[method] (ui-blockview-cut-current-cell primary: (BUF <ui-basic-block-view>) )
Delete the field node instance that corresponds to the current cursor position, and insert an empty node at the end of the block instead.

[method] (ui-blockview-enter-note primary: (BUF <ui-basic-block-view>) KEYSYM)
Perform an edit action at cursor, assuming that the cursor points to a field that represents a note command.

[method] (ui-blockview-enter-trigger primary: (BUF <ui-basic-block-view>) )
Perform an edit action at cursor, assuming that the cursor points to a field that represents a note command.

[method] (ui-blockview-enter-key primary: (BUF <ui-basic-block-view>) KEYSYM)
Perform an edit action at cursor, assuming that the cursor points to a field that represents a key/ukey command.

[method] (ui-blockview-repeat-last-set primary: (BUF <ui-basic-block-view>) )

[method] (ui-blockview-enter-numeric primary: (BUF <ui-basic-block-view>) KEYSYM)
Perform an edit action at cursor, assuming that the cursor points to a field that represents a numeric (int/uint/reference) command.

[method] (ui-blockview-enter-modifier primary: (BUF <ui-basic-block-view>) KEYSYM)
Perform an edit action at cursor, assuming that the cursor points to a field that represents a modifier command.

[method] (ui-blockview-enter-string primary: (BUF <ui-basic-block-view>) KEYSYM)
Perform an edit action at cursor, assuming that the cursor points to a field that represents a string command.

[method] (ui-blockview-dispatch-entry-event primary: (BUF <ui-basic-block-view>) KEYSYM)
Dispatch entry events occuring on the blockview's content grid to the appropriate edit procedures, depending on field command type.

[method] (ui-blockview-tag-selection primary: (BUF <ui-basic-block-view>) )
Update content tags so current selection is highlighted.

[method] (ui-blockview-selected-fields primary: (BUF <ui-basic-block-view>) )
Returns the field node identifiers of the fields that are currently selected.

[method] (ui-select primary: (BUF <ui-basic-block-view>) KEYSYM)
Initialize or continue a selection process (ie, user selecting a section for copying/modifying/etc).

[method] (ui-cancel-selection primary: (BUF <ui-basic-block-view>) )
Abort the current selection process and reset selection state.

[method] (ui-copy primary: (BUF <ui-basic-block-view>) )
Copy data from the current selection to the global clipboard and cancel the selection. If nothing is selected, copy the field value currently under cursor.

[method] (ui-normalized-selection primary: (BUF <ui-basic-block-view>) )
Return the current selection normalized, so that start-row <= end-row and start-field <= end-field.

[method] (ui-randomize primary: (BUF <ui-basic-block-view>) )
Randomize selected fields

[method] (ui-reverse primary: (BUF <ui-basic-block-view>) )
Reverse the current selection.

[method] (ui-invert primary: (BUF <ui-basic-block-view>) )
Invert selected numeric values

[method] (ui-make-scaling-dialog primary: (BUF <ui-basic-block-view>) )

[method] (ui-blockview-bind-events primary: (BUF <ui-basic-block-view>) )
Bind common event handlers for the blockview BUF.

Generic procedure for mapping tags to the field columns of a textgrid. This can be used either on block-header, or on block-content slots.

Add type tags to the given row in TEXTGRID. If TEXTGRID is not given, it defaults to the blockview's block-content slot.

Returns the active blockview zone as a list containing the first and last row in car and cadr, respectively.

Set the cursor to the given coordinates.

Move the blockview's cursor in DIRECTION.

Insert an empty cell into the field column currently under cursor, shifting the following node instances down and dropping the last instance.

Do-what-I-mean adjust normalized edit buffer values (as provided by normalize-edit-parameters so they better match the target fields. If the target field uses a key/ukey MDAL command, then incoming numeric values are converted to the closest matching key. If the target field uses a numeric command, then incoming key values are converted to the numeric equivalents, and incoming numeric values are adjusted so their range does not exceed that of the target command.

Helper for edit.

Low-level interface for edit. See ui-blockview-blockedit for details.

Low-level interface for edit. See ui-blockview-blockedit for details.

WHERE may be 'cursor, a (ROW FIELD-ID) list specifying the first cell that will be affected,'selection, or a list specifying a selected area of the blockview. The list must have the form(ROW1 FIELD1 ROW2 FIELD2)`, where ROWn is a row number and FIELDn is a field node identifier, describing the upper left and lower right corner of the selection.

edit will update the journal (undo/redo), and update the display.

Helper method for ui-blockview-enter-numeric. Constructs a new block field value from the Tk key symbol KEYSYM, assuming that the cursor is currently positioned on the field digit being edited.

Retrieve the contents (values) within the bounds of SELECTION, which must be a list of four elements denoting the top left and bottom right corners of the selection. Coordinates are given as row, field-id pairs, so SELECTION must have the format (ROW1 FIELD-ID1 ROW2 FIELD-ID2). Order does not matter when specifing the points. When SELECTION is not given, it defaults to the current user selection. If there is no active selection, the value of the field currently under cursor is returned.

Swap the current selection with the clipboard contents

Transpose selected notes.

Interpolate selected block field values.

[class] <ui-block-view>

inherits from: <ui-basic-block-view>

slot initform
ui-zone (gensym 'block-view)
block-ids

A class representing the display of an MDAL group node's blocks, minus the order block. Pattern display is implemented using this class.

(make <ui-order-view>
     'group-id ID
     'parent-instance-path PATH
     'metastate-accessor ACCESSOR)

where ID is the MDAL node identifier of the parent group node, PATH is an MDAL node path string pointing to the parent group node instance, and ACCESSOR is a metastate accessor procedure as described in the <ui-module-view> documentation below.

[method] (initialize-instance after: (BUF <ui-block-view>) )

[method] (ui-init-content-header primary: (BUF <ui-block-view>) )
Set up the column and block header display.

[method] (ui-blockview-cursor-row->order-pos primary: (BUF <ui-block-view>) ROW)
Returns the order position that the vertical cursor position ROW belongs to.

[method] (ui-blockview-get-current-order-pos primary: (BUF <ui-block-view>) )
Returns the corresponding group order position for the chunk currently under cursor.

[method] (ui-blockview-update-current-command-info primary: (BUF <ui-block-view>) )
Update the command information in the status bar, based on the field that the cursor currently points to.

[method] (ui-blockview-get-item-list primary: (BUF <ui-block-view>) )
Get the up-to-date list of items to display. The list is nested. The first nesting level corresponds to an order position. The second nesting level corresponds to a row of fields. For order nodes, there is only one element at the first nesting level.

[method] (ui-blockview-get-current-chunk primary: (BUF <ui-block-view>) )
Returns the chunk from the item cache that the cursor is currently on.

[method] (ui-blockview-get-current-block-instance-path primary: (BUF <ui-block-view>) )
Return the MDAL node path string of the field currently under cursor.

[method] (ui-blockview-perform-edit primary: (BUF <ui-block-view>) ACTION)
The low level interface to blockview editing. ACTION shall be an edit action specifier as described in the ui-metastate documentation.

[method] (ui-blockview-insert-row primary: (BUF <ui-block-view>) )

[method] (ui-blockview-cut-row primary: (BUF <ui-block-view>) )

[method] (ui-blockview-update-row-numbers primary: (BUF <ui-block-view>) )
Update the blockview row numbers according to the current item cache.

[method] (ui-blockview-set-cursor-from-mouse primary: (BUF <ui-block-view>) )
Set the blockview's cursor to the grid position currently closest to the mouse pointer.

[method] (ui-blockview-move-cursor primary: (BUF <ui-block-view>) DIRECTION)

[method] (ui-update primary: (BUF <ui-block-view>) )
Update the blockview display. The procedure attempts to be "smart" about updating, ie. it tries to not perform unnecessary updates. This makes the procedure fast enough to be used after any change to the blockview's content, rather than manually updating the part of the content that has changed.

[method] (ui-show before: (BUF <ui-block-view>) )

[method] (ui-where primary: (BUF <ui-block-view>) )

Return the block instance ID currently under cursor.

Low-level interface for edit. You most likely do not want to call this directly. CONTENTS must be a list of lists, where each sublist represents a block field node, and the contents of the sublist form the values that shall be set. START and END must be a row,field-id pair specifying the first and last affected cell, respectively.

This updates the journal and the display.

deprecated, use (edit BUF 'cursor VALUE) instead Set the field node instance that corresponds to the current cursor position to NEW-VALUE, and update the display and the undo/redo stacks accordingly.

[class] <ui-order-view>

inherits from: <ui-basic-block-view>

slot initform
ui-zone (gensym 'order-view)

A class representing the display of the order block of an MDAL group node instance.

(make <ui-order-view>
     'group-id ID
     'parent-instance-path PATH
     'metastate-accessor ACCESSOR)

where ID is the MDAL node identifier of the parent group node, PATH is an MDAL node path string pointing to the parent group node instance, and ACCESSOR is a metastate accessor procedure as described in the <ui-module-view> documentation below.

[method] (initialize-instance after: (BUF <ui-order-view>) )

[method] (ui-init-content-header primary: (BUF <ui-order-view>) )
Set up the column and block header display.

[method] (ui-blockview-get-current-order-pos primary: (BUF <ui-order-view>) )
Returns the corresponding group order position for the chunk currently under cursor. Alias for ui-blockview-get-current-row.

[method] (ui-blockview-update-current-command-info primary: (BUF <ui-order-view>) )
Update the command information in the status bar, based on the field that the cursor currently points to.

[method] (ui-blockview-get-item-list primary: (BUF <ui-order-view>) )
Get the up-to-date list of items to display. The list is nested. The first nesting level corresponds to an order position. The second nesting level corresponds to a row of fields. For order nodes, there is only one element at the first nesting level.

[method] (ui-blockview-get-current-chunk primary: (BUF <ui-order-view>) )
Returns the chunk from the item cache that the cursor is currently on.

[method] (ui-blockview-update-row-numbers primary: (BUF <ui-order-view>) )
Update the blockview row numbers according to the current item cache.

[method] (ui-blockview-set-cursor-from-mouse primary: (BUF <ui-order-view>) )
Set the blockview's cursor to the grid position currently closest to the mouse pointer.

[method] (ui-blockview-move-cursor primary: (BUF <ui-order-view>) DIRECTION)

[method] (ui-blockview-get-current-block-instance-path primary: (BUF <ui-order-view>) )
Return the MDAL node path string of the field currently under cursor.

[method] (ui-blockview-perform-edit primary: (BUF <ui-order-view>) ACTION)
The low level interface to blockview editing. ACTION shall be an edit action specifier as described in the ui-metastate documentation.

[method] (ui-blockview-cut-row primary: (BUF <ui-order-view>) )
Cut (remove) the row currently under cursor.

[method] (ui-update primary: (BUF <ui-order-view>) )
Update the blockview display. The procedure attempts to be "smart" about updating, ie. it tries to not perform unnecessary updates. This makes the procedure fast enough to be used after any change to the blockview's content, rather than manually updating the part of the content that has changed.

[method] (ui-show before: (BUF <ui-order-view>) )

[method] (ui-where primary: (BUF <ui-order-view>) )

deprecated Set the field node instance that corresponds to the current cursor position to NEW-VALUE, and update the display and the undo/redo stacks accordingly.

Insert a new row at the current cursor position. If ROW is omitted, the current row is cloned, or an empty row is created if the cursor is on row 0. If ROW is given, it must be a list of row values, which may not contain empty nodes.

Low-level interface for edit. You most likely do not want to call this directly. CONTENTS must be a list of lists, where each sublist represents a block field node, and the contents of the sublist form the values that shall be set. START and END must be a row,field-id pair specifying the first and last affected cell, respectively.

This updates the journal and the display.

[class] <ui-blocks>

inherits from: <ui-multibuffer>

slot initform
orient 'horizontal
group-id (error '|make <ui-blocks>| "Missing 'group-id.")
parent-instance-path (error '|make <ui-blocks>| "Missing 'parent-instance-path.")
metastate-accessor (error '|make <ui-blocks>| "Missing 'metastate-accessor.")

A widget class suitable for displaying an MDAL group node's block members. It is a wrapper around a and the associated . Create instances with

(make <ui-group-blocks>
     'group-id ID
     'parent-instance-path PATH
     'metastate-accessor ACCESSOR)

where ID is the MDAL node identifier of the parent group node, PATH is an MDAL node path string pointing to the parent group node instance, and ACCESSOR is a metastate accessor procedure as described in the <ui-module-view> documentation below.

[method] (initialize-instance after: (BUF <ui-blocks>) )

[class] <ui-subgroups>

inherits from: <ui-buffer>

slot initform
packing-args '(expand: 1 fill: both)
group-id (error '|make <ui-subgroups>| "Missing 'group-id.")
parent-instance-path (error '|make <ui-subgroups>| "Missing 'parent-instance-path.")
tabs
subgroups
metastate-accessor (error '|make <ui-subgroup>| "Missing 'metastate-accessor.")

A widget class suitable for displaying an MDAL group node's subgroups.

(make <ui-subgroups>
     'group-id ID
     'parent-instance-path PATH
     'metastate-accessor ACCESSOR)

where ID is the MDAL node identifier of the parent group node, PATH is an MDAL node path string pointing to the parent group node instance, and ACCESSOR is a metastate accessor procedure as described in the <ui-module-view> documentation below.

[method] (initialize-instance after: (BUF <ui-subgroups>) )

[method] (ui-show before: (BUF <ui-subgroups>) )

[method] (ui-destroy before: (BUF <ui-subgroups>) )

[class] <ui-group>

inherits from: <ui-multibuffer>

slot initform
group-id (error '|make <ui-group>| "Missing 'group-id.")
parent-instance-path (error '|make <ui-group>| "Missing 'parent-instance-path.")
current-instance 0
metastate-accessor (error '|make <ui-group>| "Missing 'metastate-accessor.")

A widget class suitable for displaying an MDAL group node.

(make <ui-subgroups>
     'group-id ID
     'parent-instance-path PATH
     'metastate-accessor ACCESSOR)

where ID is the MDAL node identifier of the group node, PATH is an MDAL node path string pointing to the parent group node instance, and ACCESSOR is a metastate accessor procedure as described in the <ui-module-view> documentation below.

[method] (initialize-instance after: (BUF <ui-group>) )

[method] (ui-ref-by-zone-id primary: (BUF <ui-group>) ZONE-ID)

[class] <ui-module-view>

inherits from: <ui-multibuffer>

slot initform
mmod #f
metastate-accessor #f
filename #f
modified #f
journal (make-app-journal)
emulator #f

The top-level abstraction for MMOD displays. An manages the module state (including emulation), and contains the the display of the GLOBAL node.

You can instantiate a with either of the forms

(make <ui-module-view> 'mmod MMOD ['filename FILE])
(make <ui-module-view> 'filename FILE)

where MMOD is a MMOD structure as defined in md-types, and FILE is the fully qualified path to an .mmod FILE. When using the second form, the constructor will automatically construct the appropriate MMOD from the given .mmod FILE.

To interact with the module state, use the ui-metastate method. Note that ui-metastate can be called on any of the module-view's child elements as well, and doing so will act on the module state of the parent <ui-module-view>. See documentation for ui-metastate below.

[method] (make-module-view-settings-bar primary: (BUF <ui-module-view>) )
Helper for <ui-module-view> constructor.

[method] (module-view-push-undo primary: (BUF <ui-module-view>) ACTION)

[method] (module-view-pop-undo primary: (BUF <ui-module-view>) )

[method] (module-view-push-redo primary: (BUF <ui-module-view>) ACTION)

[method] (module-view-pop-redo primary: (BUF <ui-module-view>) )

[method] (module-view-clear-redo primary: (BUF <ui-module-view>) )

[method] (module-view-undo primary: (BUF <ui-module-view>) )

[method] (module-view-redo primary: (BUF <ui-module-view>) )

[method] (make-metastate-accessor primary: (BUF <ui-module-view>) )
Construct a module view metastate accessor procedure. Helper for <ui-module-view> constructor.

[method] (initialize-instance after: (BUF <ui-module-view>) )

[method] (ui-module-view-current-zone primary: (BUF <ui-module-view>) )

[method] (ui-ref-by-zone-id primary: (BUF <ui-module-view>) ZONE-ID)

[method] (ui-show before: (BUF <ui-module-view>) )

[method] (ui-destroy before: (BUF <ui-module-view>) )

Helper for <ui-module-view> constructor.

Interact with the module-view module state. This method can be called on the module-view itself, or any of its child elements.

Given an <ui-module-view> MV, use as follows:

(ui-metastate MV 'mmod)

Returns the associated MDAL module structure.

(ui-metastate MV 'mdef)

Returns the associated MDAL engine definition.

(ui-metastate MV 'emulator ['play-row])

Returns the associated emulator. If the additional 'play-row tag is specified, plays the row of the block that the user is currently editing, if applicable. In this case, returns nothing.

(ui-metastate MV 'modified [NEW-VAL])

Returns the "modified" flag, ie. whether the associated module has changed since the last file save. When NEW-VAL is given and a boolean, sets the "modified" flag.

(ui-metastate MV 'filename [NEW-VAL])

Get the associated filename, or #f if the filename is not set. When NEW-VAL is given, sets the associated filename to it.

(ui-metastate MV 'apply-edit ACTION)

This command is used internally to apply the edit ACTION to the associated associated MDAL module. An edit action is a list that takes the form

(ACTION PARENT-INSTANCE-PATH NODE-ID INSTANCES)

where ACTION is one of the symbols set, insert, remove, block-row-insert, or block-row-remove. PARENT-INSTANCE-PATH is a fully qualified MDAL node path string denoting the parent node instance of the node that you want to edit (ie. a path starting at the global inode, see md-types/MMOD for details), NODE-ID is the ID of the node you want to edit, and INSTANCES is an alist where the keys are node instance ID numbers and the values are the values that you want to set. For block-row-insert/remove, INSTANCES must be an alist where the keys are block instance ids, and the values are in turn alists where the key is a row number (field instance), and the value is a list of field values as required by the block node.

Values for remove/block-row-remove actions are ignored, but you must still provide the argument so Bintracker can deduce the inverse of the action (which gets pushed to the journal).

As the respective names suggest, a set action sets one or more instances of the node NODE-ID at PARENT-INSTANCE-PATH to (a) new value(s), an insert action inserts one or more new instances into the node, and a remove action removes one or more instances from the node. Likewise, a block-row-insert inserts a new row into a given block node instance, and block-row-remove removes a row. It is an error to apply the latter to actions to any non-block node.

Alternatively, an edit action may take the form

(compound ACTIONS))

where ACTIONS is a list of edit actions. In this case, the edit actions are applied in the order provided. A compound action thus bundles one or more edit actions together.

When you use the 'apply-edit command in user code, it is your responsibility to ensure that the metastate's undo stack is updated accordingly by pushing the inverse of ACTION to it. Use the make-reverse-action procedure to derive the inverse from a given edit action.

(ui-metastate MV 'push-undo ACTION)

Push an edit action to the undo stack. ACTION shall be the inverse of an edit your applying (see above).

(ui-metastate MD 'undo)

Undo the most recent edit, if any.

(ui-metastate MD 'redo)

Redo the most recently undone edit.

(ui-metastate MD 'set-info STR)

Set the active command info in the modeline to STR.

Auxiliary module UI accessor procedures

[procedure] (current WHAT)

This accessor can be used to retrieve various components of the module interface the user is currently interacting with. This is inevitably a brittle solution, so be careful when using these.

WHAT must be one of the following:

  • module-view: The current <ui-module-view> instance.
  • blockview: The current <ui-blockview> instance.
  • order-view: The current <ui-order-view> instance.
  • group-fields: The current <ui-group-fields> instance.
  • mmod: The current MDAL module.
  • mdef: The current MDAL engine definition.
  • emulator: The current emulator object.
  • buffer: The current focussed buffer.

Utility procedures

[procedure] (do-current WHAT . ARGS)

[procedure] (shift-current DIRECTION BY)

[procedure] (transpose-current OFFSET)

[procedure] (transpose-note-up)

[procedure] (transpose-note-down)

[procedure] (transpose-octave-up)

[procedure] (transpose-octave-down)

[procedure] (raise-current)

[procedure] (raise-by-unit-current)

[procedure] (lower-current)

[procedure] (lower-by-unit-current)

[procedure] (randomize-current)

[procedure] (invert-current)

[procedure] (reverse-current)

[procedure] (interpolate-linear)

[procedure] (interpolate-cosine)

[procedure] (scale-current)

Screen Reader/Text-to-Speech API

[procedure] (say . ARGS)

An interface to the screen reader/text-to-speech tool. Use as follows:

(say STRING)

Say the string STRING (without sanitization).

(say 'sanitize STRING)

Say a sanitized version of STRING.

(say S-EXP)

Say a stringified, sanitized version of the symbolic expression S-EXP.

(say 'what)

Report the value currently under cursor.

(say 'where)

Report the location of the cursor. The results depend on the widget class type.

[procedure] (what)

Report the value currently under cursor through the screen reader, if any.

[procedure] (where)

Report the current cursor location on screen through the screen reader, if any.