Adding properties and types#
This appendix describes methods to define new context and grob properties as well as new music and grob types.
The reader should be warned that these are not proper interfaces at the moment. They may stop working in future versions when more extensibility is added.
This is adapted from the famous regression test scheme-text-spanner.ly by David Nalesnik.
For context types, there is proper extensibility as detailed at Defining new context types.
New properties#
Defining a property comes down to defining a predicate used to check values
given to this property by the user. This is done through setting object
properties on the property name symbol. The relevant properties are
translation-type?
, for context properties, and backend-type?
, for grob
properties.
#(set-object-property! 'myAwesomeContextProperty 'translation-type? number?)
#(set-object-property! 'my-awesome-grob-property 'backend-type? boolean?)
Music properties are not type-checked, thus no definition is required.
New event class#
The existing function define-event-class
takes a class name and a parent class
name. If no particular event class stands out for the parent, music-event
is
often a fair choice.
#(define-event-class 'highlight-event 'span-event)
New music type#
Use the following function:
#(define (define-event! type properties)
(set-object-property! type
'music-description
(cdr (assq 'description properties)))
(set! properties (assoc-set! properties 'name type))
(set! properties (assq-remove! properties 'description))
(hashq-set! music-name-to-property-table type properties)
(set! music-descriptions
(sort (cons (cons type properties)
music-descriptions)
alist<?)))
The type argument is the name of the new music type as a symbol, and
properties is an associative list of properties and defaults. The most
important properties are description
and types
. The description is
mandatory. The types are optional music classes this event type is made to
belong to.
Here is how one might define an event used for drawing highlight boxes:
#(define-event!
'HighlightEvent
'((description . "Used to signal where colored highlights start and stop.")
(types . (post-event highlight-event event))))
New grob type#
Use this function:
#(define (define-grob! grob-name grob-entry)
(set! all-grob-descriptions
(cons ((@@ (lily) completize-grob-entry)
(cons grob-name grob-entry))
all-grob-descriptions)))
Defining the new grob type is done in two steps. First, call define-grob!
with
the name of the new grob type and an alist of default properties. The alist must
contain a meta
entry with the class (Item
, Spanner
or Paper_column
, see
Grob flavors and line breaks
) and a list of interfaces. The interfaces
corresponding to the class (just the item-interface
in this case) are added
automatically.
#(define-grob!
'JustText
`((stencil . ,ly:text-interface::print)
(X-extent . ,empty-interval)
(Y-extent . ,empty-interval)
(meta . ((class . Item)
(interfaces . (text-interface))))))
After this call, the list of grob descriptions must be reset.
\layout {
\context {
\Global
\grobdescriptions #all-grob-descriptions
}
}
Grob interfaces should not need any particular definition.