6.4.3 Definición de una instrucción de marcado nueva
Las instrucciones de marcado nuevas se pueden definir con el macro de
Scheme define-markup-command
.
(define-markup-command (nombre-de-la-instruccion layout props arg1 arg2 ...) (arg1-type? arg2-type? ...) ..command body..) |
Los argumentos son
- argi
i-ésimo argumento de la instrucción
- argi-type?
predicado de tipo para el argumento i-ésimo
- layout
la definición de ‘presentación’
- props
lista de listas asociativas, que contiene todas las propiedades activas.
Como ejemplo sencillo, mostramos cómo añadir una instrucción
\smallcaps
, que selecciona una tipografía de versalitas.
Normalmente podríamos seleccionar la tipografía de versalitas,
\markup { \override #'(font-shape . caps) Texto-en-versalitas }
Esto selecciona la tipografía de versalitas mediante el
establecimiento de la propiedad font-shape
a #'caps
para
la interpretación de Texto-en-versalitas
.
Para poner lo anterior disponible como la instrucción
\smallcaps
, tenemos que definir una función utilizando
define-markup-command
. La instrucción ha de tomar un argumento
del tipo markup
. Por tanto, el inicio de la definición ha de
ser
(define-markup-command (smallcaps layout props argument) (markup?)
Lo que aparece a continuación es el contenido de la instrucción:
debemos interpretar el argument
como un marcado, es decir:
(interpret-markup layout … argument)
Esta interpretación tiene que añadir '(font-shape . caps)
a las
propiedades activas, por lo que sustituimos lo siguiente por los
… en el ejemplo anterior:
(cons (list '(font-shape . caps) ) props)
La variable props
es una lista de a-listas, y se lo anteponemos
haciendo la operación cons de una lista con el ajuste adicional.
Supongamos que estamos tipografiando un recitativo de una ópera y nos
gustaría definir una instrucción que presente los nombres de los
personajes de una forma personalizada. Queremos que los nombres se
impriman con versalitas y se desplacen un poco a la izquierda y hacia
arriba. Definimos una instrucción \character
que toma en
cuenta la traslación necesaria y utiliza la instrucción
\smallcaps
recién definida:
#(define-markup-command (character layout props nombre) (string?) "Imprimir el nombre del personaje en versalitas, desplazado a la izquierda y hacia arriba. Sintaxis: \\character #\"nombre\"" (interpret-markup layout props (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps nombre)))
Esta es una complicación que requiere una explicación: los textos por
encima y por debajo del pentagrama se mueven verticalmente de forma
que estén a una cierta distancia (la propiedad padding
) del
pentagrama y de las notas. Para asegurar que este mecanismo no anula
el efecto de nuestro #:translate
, añadimos una cadena vacía
(#:hspace 0
) antes del texto trasladado. Ahora el
#:hspace 0
se pone encima de las notas, y el nombre
se
mueve en relación a dicha cadena vacía. El efecto neto es que el
texto se mueve hacia la izquierda y hacia arriba.
El resultado final es como sigue:
{ c''^\markup \character #"Cleopatra" e'^\markup \character #"Giulio Cesare" }
Hemos usado la forma de fuente tipográfica caps
, pero
supongamos que nuestra fuente no tiene la variante de versalitas. En
ese caso tenemos que hacer una falsa fuente de mayúsculas pequeñas
haciendo que la cadena en mayúsculas tenga la primera legra un poco
mayor:
#(define-markup-command (smallcaps layout props str) (string?) "Print the string argument in small caps." (interpret-markup layout props (make-line-markup (map (lambda (s) (if (= (string-length s) 0) s (markup #:large (string-upcase (substring s 0 1)) #:translate (cons -0.6 0) #:tiny (string-upcase (substring s 1))))) (string-split str #\Space)))))
La instrucción smallcaps
primero divide su argumento de cadena
en unidades o palabras separadas por espacios ((string-split str
#\Space)
); para cada unidad o palabra, se construye un marcado con la
primera letra agrandada y en mayúscula (#:large (string-upcase
(substring s 0 1))
), y un segundo marcado construido con las letras
siguientes reducidas de tamaño y en mayúsculas (#:tiny
(string-upcase (substring s 1))
). Como LilyPond introduce un espacio
entre los marcados de una misma línea, el segundo marcado se traslada
a la izquierda (#:translate (cons -0.6 0) ...
). Después, los
marcados construidos para cada palabra se ponen en una línea mediante
(make-line-markup ...)
. Finalmente, el marcado resultante se
pasa a la función interpret-markup
, con los argumentos
layout
y props
.
Nota: ahora existe una instrucción interna \smallCaps
que se
puede usar para poner texto en versalitas. Consulte Text markup commands, para ver más detalles.
Advertencias y problemas conocidos
Actualmente las combinaciones de argumentos que hay disponibles
(después de los argumentos estándar layout y props) para
una instrucción de marcado definida con define-markup-command
se limitan a la siguiente lista:
- (ningún argumento)
- list
- markup
- markup markup
- scm
- scm markup
- scm scm
- scm scm markup
- scm scm markup markup
- scm markup markup
- scm scm scm
En la tabla de arriba, scm representa los tipos de datos nativos de Scheme como ‘number’ (número) o ‘string’ (cadena).
Como ejemplo, no es posible usar una instrucción de marcado
fulanito
con cuatro argumentos definida como
#(define-markup-command (fulanito layout props num1 str1 num2 str2) (number? string? number? string?) ...)
Si la aplicamos como, digamos,
\markup \fulanito #1 #"mengano" #2 #"zutano"
lilypond
protesta diciendo que no puede analizar
fulanito
debido a su firma de Scheme desconocida.
Otros idiomas: English.