>From ce43c71a46035b75ad5020796c8dcc4d021371af Mon Sep 17 00:00:00 2001 From: Ian Hulin
Date: Tue, 29 Nov 2011 17:46:50 +0000 Subject: [PATCH] T2026: Use new (scm markup-facility-defs) scheme module for markup commands. This affects the following files. New file scm/markup-utility-defs.scm ly/music-functions-init.ly Add #(use-modules (scm markup-facility-defs)) statement. ly/titling-init.ly Add #(use-modules (scm markup-facility-defs)) statement. scm/lily.scm Add (use-modules (scm markup-facility-defs)) statement. Group I18n declarations together at the beginning. Add some comments. Add better --loglevel=DEBUG statement when running with Guile V2. scm/markup.scm Gutted. scm/markup-macros.scm (will be deleted) scm/define-markup-commands.scm Add (use-modules (scm markup-facility-defs)) statement. scm/define-woodwind-diagrams.scm Add (use-modules (scm markup-facility-defs)) statement. scm/display-woodwind-diagrams.scm Add (use-modules (scm markup-facility-defs)) statement. scm/font.scm Add (use-modules (oops goops)) statement. scm/fret-diagrams.scm Add (use-modules (scm markup-facility-defs)) statement. scm/harp-pedals.scm Add (use-modules (scm markup-facility-defs)) statement. scm/tablature.scm Add (use-modules (scm markup-facility-defs)) statement. --- ly/music-functions-init.ly | 2 + ly/titling-init.ly | 1 + scm/define-markup-commands.scm | 4612 +++++++++++++++++++------------------ scm/define-woodwind-diagrams.scm | 24 +- scm/display-woodwind-diagrams.scm | 1 + scm/font.scm | 2 +- scm/fret-diagrams.scm | 2 +- scm/harp-pedals.scm | 2 +- scm/lily.scm | 50 +- scm/markup-facility-defs.scm | 646 ++++++ scm/markup.scm | 257 ++- scm/page.scm | 1 + scm/tablature.scm | 2 +- 13 files changed, 3158 insertions(+), 2444 deletions(-) create mode 100644 scm/markup-facility-defs.scm diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly index 8b5cddf..88d6ee4 100644 --- a/ly/music-functions-init.ly +++ b/ly/music-functions-init.ly @@ -28,6 +28,8 @@ %% need SRFI-1 for filter; optargs for lambda* #(use-modules (srfi srfi-1) (ice-9 optargs)) +%% need (scm markup-facility-defs)for markup? +#(use-modules (scm markup-facility-defs)) %% TODO: using define-music-function in a .scm causes crash. diff --git a/ly/titling-init.ly b/ly/titling-init.ly index f6daacd..8a883b2 100644 --- a/ly/titling-init.ly +++ b/ly/titling-init.ly @@ -1,5 +1,6 @@ \version "2.15.20" +(use-modules (scm markup-facility-defs)) slashSeparator = \markup { \center-align \vcenter \combine diff --git a/scm/define-markup-commands.scm b/scm/define-markup-commands.scm index 4b2aff5..9466074 100644 --- a/scm/define-markup-commands.scm +++ b/scm/define-markup-commands.scm @@ -106,6 +106,8 @@ ;;; with description, syntax and example. (use-modules (ice-9 regex)) +(use-modules (scm markup-facility-defs)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; utility functions @@ -113,2351 +115,1917 @@ (define-public empty-stencil (ly:make-stencil '() '(1 . -1) '(1 . -1))) (define-public point-stencil (ly:make-stencil "" '(0 . 0) '(0 . 0))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; geometric shapes +;; basic formatting. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define-markup-command (draw-line layout props dest) - (number-pair?) - #:category graphic - #:properties ((thickness 1)) +(define-markup-command (simple layout props str) + (string?) + #:category font " address@hidden drawing lines within text address@hidden simple text strings -A simple line. address@hidden,quote] -\\markup { - \\draw-line #'(4 . 4) - \\override #'(thickness . 5) - \\draw-line #'(-3 . 0) -} address@hidden lilypond" - (let ((th (* (ly:output-def-lookup layout 'line-thickness) - thickness)) - (x (car dest)) - (y (cdr dest))) - (make-line-stencil th 0 0 x y))) +A simple text string; @code{\\markup @{ foo @}} is equivalent with address@hidden @{ \\simple #\"foo\" @}}. -(define-markup-command (draw-hline layout props) - () - #:category graphic - #:properties ((draw-line-markup) - (line-width) - (span-factor 1)) - " address@hidden drawing a line across a page +Note: for creating standard text markup or defining new markup commands, +the use of @code{\\simple} is unnecessary. -Draws a line across a page, where the property @code{span-factor} -controls what fraction of the page is taken up. @lilypond[verbatim,quote] \\markup { - \\column { - \\draw-hline - \\override #'(span-factor . 1/3) - \\draw-hline - } + \\simple #\"simple\" + \\simple #\"text\" + \\simple #\"strings\" } @end lilypond" - (interpret-markup layout - props - (markup #:draw-line (cons (* line-width - span-factor) - 0)))) - -(define-markup-command (draw-circle layout props radius thickness filled) - (number? number? boolean?) - #:category graphic - " address@hidden drawing circles within text - -A circle of radius @var{radius} and thickness @var{thickness}, -optionally filled. + (interpret-markup layout props str)) +(define-markup-command (line layout props args) + (markup-list?) + #:category align + #:properties ((word-space) + (text-direction RIGHT)) + "Put @var{args} in a horizontal line. The property @code{word-space} +determines the space between markups in @var{args}. @lilypond[verbatim,quote] \\markup { - \\draw-circle #2 #0.5 ##f - \\hspace #2 - \\draw-circle #2 #0 ##t + \\line { + one two three + } } @end lilypond" - (make-circle-stencil radius thickness filled)) - -(define-markup-command (triangle layout props filled) - (boolean?) - #:category graphic - #:properties ((thickness 0.1) - (font-size 0) - (baseline-skip 2)) - " address@hidden drawing triangles within text - -A triangle, either filled or empty. + (let ((stencils (interpret-markup-list layout props args))) + (if (= text-direction LEFT) + (set! stencils (reverse stencils))) + (stack-stencil-line + word-space + (remove ly:stencil-empty? stencils)))) +(define-markup-command (fill-line layout props args) + (markup-list?) + #:category align + #:properties ((text-direction RIGHT) + (word-space 0.6) + (line-width #f)) + "Put @var{markups} in a horizontal line of width @var{line-width}. +The markups are spaced or flushed to fill the entire line. +If there are no arguments, return an empty stencil. @lilypond[verbatim,quote] \\markup { - \\triangle ##t - \\hspace #2 - \\triangle ##f + \\column { + \\fill-line { + Words evenly spaced across the page + } + \\null + \\fill-line { + \\line { Text markups } + \\line { + \\italic { evenly spaced } + } + \\line { across the page } + } + } } @end lilypond" - (let ((ex (* (magstep font-size) 0.8 baseline-skip))) - (ly:make-stencil - `(polygon '(0.0 0.0 - ,ex 0.0 - ,(* 0.5 ex) - ,(* 0.86 ex)) - ,thickness - ,filled) - (cons 0 ex) - (cons 0 (* .86 ex))))) + (let* ((orig-stencils (interpret-markup-list layout props args)) + (stencils + (map (lambda (stc) + (if (ly:stencil-empty? stc) + point-stencil + stc)) orig-stencils)) + (text-widths + (map (lambda (stc) + (if (ly:stencil-empty? stc) + 0.0 + (interval-length (ly:stencil-extent stc X)))) + stencils)) + (text-width (apply + text-widths)) + (word-count (length stencils)) + (line-width (or line-width (ly:output-def-lookup layout 'line-width))) + (fill-space + (cond + ((= word-count 1) + (list + (/ (- line-width text-width) 2) + (/ (- line-width text-width) 2))) + ((= word-count 2) + (list + (- line-width text-width))) + (else + (get-fill-space word-count line-width word-space text-widths)))) -(define-markup-command (circle layout props arg) - (markup?) - #:category graphic - #:properties ((thickness 1) - (font-size 0) - (circle-padding 0.2)) - " address@hidden circling text + (line-contents (if (= word-count 1) + (list + point-stencil + (car stencils) + point-stencil) + stencils))) -Draw a circle around @var{arg}. Use @code{thickness}, address@hidden and @code{font-size} properties to determine line -thickness and padding around the markup. + (if (null? (remove ly:stencil-empty? orig-stencils)) + empty-stencil + (begin + (if (= text-direction LEFT) + (set! line-contents (reverse line-contents))) + (set! line-contents + (stack-stencils-padding-list + X RIGHT fill-space line-contents)) + (if (> word-count 1) + ;; shift s.t. stencils align on the left edge, even if + ;; first stencil had negative X-extent (e.g. center-column) + ;; (if word-count = 1, X-extents are already normalized in + ;; the definition of line-contents) + (set! line-contents + (ly:stencil-translate-axis + line-contents + (- (car (ly:stencil-extent (car stencils) X))) + X))) + line-contents)))) address@hidden,quote] -\\markup { - \\circle { - Hi - } -} address@hidden lilypond" - (let ((th (* (ly:output-def-lookup layout 'line-thickness) - thickness)) - (pad (* (magstep font-size) circle-padding)) - (m (interpret-markup layout props arg))) - (circle-stencil m th pad))) -(define-markup-command (with-url layout props url arg) - (string? markup?) - #:category graphic +(define-markup-command (concat layout props args) + (markup-list?) + #:category align " address@hidden inserting URL links into text address@hidden concatenating text address@hidden ligatures in text -Add a link to URL @var{url} around @var{arg}. This only works in -the PDF backend. +Concatenate @var{args} in a horizontal line, without spaces in between. +Strings and simple markups are concatenated on the input level, allowing +ligatures. For example, @code{\\concat @{ \"f\" \\simple #\"i\" @}} is +equivalent to @code{\"fi\"}. @lilypond[verbatim,quote] \\markup { - \\with-url #\"http://lilypond.org/web/\" { - LilyPond ... \\italic { - music notation for everyone - } + \\concat { + one + two + three } } @end lilypond" - (let* ((stil (interpret-markup layout props arg)) - (xextent (ly:stencil-extent stil X)) - (yextent (ly:stencil-extent stil Y)) - (old-expr (ly:stencil-expr stil)) - (url-expr (list 'url-link url `(quote ,xextent) `(quote ,yextent)))) - - (ly:stencil-add (ly:make-stencil url-expr xextent yextent) stil))) + (define (concat-string-args arg-list) + (fold-right (lambda (arg result-list) + (let ((result (if (pair? result-list) + (car result-list) + '()))) + (if (and (pair? arg) (eqv? (car arg) simple-markup)) + (set! arg (cadr arg))) + (if (and (string? result) (string? arg)) + (cons (string-append arg result) (cdr result-list)) + (cons arg result-list)))) + '() + arg-list)) -(define-markup-command (page-link layout props page-number arg) - (number? markup?) - #:category other - " address@hidden referencing page numbers in text + (interpret-markup layout + (prepend-alist-chain 'word-space 0 props) + (make-line-markup (if (markup-command-list? args) + args + (concat-string-args args))))) -Add a link to the page @var{page-number} around @var{arg}. This only works -in the PDF backend. +(define (wordwrap-stencils stencils + justify base-space line-width text-dir) + "Perform simple wordwrap, return stencil of each line." + (define space (if justify + ;; justify only stretches lines. + (* 0.7 base-space) + base-space)) + (define (take-list width space stencils + accumulator accumulated-width) + "Return (head-list . tail) pair, with head-list fitting into width" + (if (null? stencils) + (cons accumulator stencils) + (let* ((first (car stencils)) + (first-wid (cdr (ly:stencil-extent (car stencils) X))) + (newwid (+ space first-wid accumulated-width))) + (if (or (null? accumulator) + (< newwid width)) + (take-list width space + (cdr stencils) + (cons first accumulator) + newwid) + (cons accumulator stencils))))) + (let loop ((lines '()) + (todo stencils)) + (let* ((line-break (take-list line-width space todo + '() 0.0)) + (line-stencils (car line-break)) + (space-left (- line-width + (apply + (map (lambda (x) (cdr (ly:stencil-extent x X))) + line-stencils)))) + (line-word-space (cond ((not justify) space) + ;; don't stretch last line of paragraph. + ;; hmmm . bug - will overstretch the last line in some case. + ((null? (cdr line-break)) + base-space) + ((null? line-stencils) 0.0) + ((null? (cdr line-stencils)) 0.0) + (else (/ space-left (1- (length line-stencils)))))) + (line (stack-stencil-line line-word-space + (if (= text-dir RIGHT) + (reverse line-stencils) + line-stencils)))) + (if (pair? (cdr line-break)) + (loop (cons line lines) + (cdr line-break)) + (begin + (if (= text-dir LEFT) + (set! line + (ly:stencil-translate-axis + line + (- line-width (interval-end (ly:stencil-extent line X))) + X))) + (reverse (cons line lines))))))) + +(define-markup-list-command (wordwrap-internal layout props justify args) + (boolean? markup-list?) + #:properties ((line-width #f) + (word-space) + (text-direction RIGHT)) + "Internal markup list command used to define @code{\\justify} and @code{\\wordwrap}." + (wordwrap-stencils (remove ly:stencil-empty? + (interpret-markup-list layout props args)) + justify + word-space + (or line-width + (ly:output-def-lookup layout 'line-width)) + text-direction)) + +(define-markup-command (justify layout props args) + (markup-list?) + #:category align + #:properties ((baseline-skip) + wordwrap-internal-markup-list) + " address@hidden justifying text + +Like @code{\\wordwrap}, but with lines stretched to justify the margins. +Use @code{\\override #'(line-width . @var{X})} to set the line width; address@hidden@tie{}is the number of staff spaces. @lilypond[verbatim,quote] \\markup { - \\page-link #2 { \\italic { This links to page 2... } } + \\justify { + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed + do eiusmod tempor incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. + } } @end lilypond" - (let* ((stil (interpret-markup layout props arg)) - (xextent (ly:stencil-extent stil X)) - (yextent (ly:stencil-extent stil Y)) - (old-expr (ly:stencil-expr stil)) - (link-expr (list 'page-link page-number `(quote ,xextent) `(quote ,yextent)))) - - (ly:stencil-add (ly:make-stencil link-expr xextent yextent) stil))) - -(define-markup-command (with-link layout props label arg) - (symbol? markup?) - #:category other - " address@hidden referencing page labels in text + (stack-lines DOWN 0.0 baseline-skip + (wordwrap-internal-markup-list layout props #t args))) -Add a link to the page holding label @var{label} around @var{arg}. This -only works in the PDF backend. +(define-markup-command (wordwrap layout props args) + (markup-list?) + #:category align + #:properties ((baseline-skip) + wordwrap-internal-markup-list) + "Simple wordwrap. Use @code{\\override #'(line-width . @var{X})} to set +the line width, where @var{X} is the number of staff spaces. @lilypond[verbatim,quote] \\markup { - \\with-link #'label { - \\italic { This links to the page containing the label... } + \\wordwrap { + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed + do eiusmod tempor incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. } } @end lilypond" - (let* ((arg-stencil (interpret-markup layout props arg)) - (x-ext (ly:stencil-extent arg-stencil X)) - (y-ext (ly:stencil-extent arg-stencil Y))) - (ly:make-stencil - `(delay-stencil-evaluation - ,(delay (ly:stencil-expr - (let* ((table (ly:output-def-lookup layout 'label-page-table)) - (page-number (if (list? table) - (assoc-get label table) - #f)) - (link-expr (list 'page-link page-number - `(quote ,x-ext) `(quote ,y-ext)))) - (ly:stencil-add (ly:make-stencil link-expr x-ext y-ext) -arg-stencil))))) - x-ext - y-ext))) + (stack-lines DOWN 0.0 baseline-skip + (wordwrap-internal-markup-list layout props #f args))) +(define-markup-list-command (wordwrap-string-internal layout props justify arg) + (boolean? string?) + #:properties ((line-width) + (word-space) + (text-direction RIGHT)) + "Internal markup list command used to define @code{\\justify-string} and address@hidden" + (let* ((para-strings (regexp-split + (string-regexp-substitute + "\r" "\n" + (string-regexp-substitute "\r\n" "\n" arg)) + "\n[ \t\n]*\n[ \t\n]*")) + (list-para-words (map (lambda (str) + (regexp-split str "[ \t\n]+")) + para-strings)) + (para-lines (map (lambda (words) + (let* ((stencils + (remove ly:stencil-empty? + (map (lambda (x) + (interpret-markup layout props x)) + words)))) + (wordwrap-stencils stencils + justify word-space + line-width text-direction))) + list-para-words))) + (apply append para-lines))) -(define-markup-command (beam layout props width slope thickness) - (number? number? number?) - #:category graphic - " address@hidden drawing beams within text +(define-markup-command (wordwrap-string layout props arg) + (string?) + #:category align + #:properties ((baseline-skip) + wordwrap-string-internal-markup-list) + "Wordwrap a string. Paragraphs may be separated with double newlines. -Create a beam with the specified parameters. @lilypond[verbatim,quote] \\markup { - \\beam #5 #1 #2 -} address@hidden lilypond" - (let* ((y (* slope width)) - (yext (cons (min 0 y) (max 0 y))) - (half (/ thickness 2))) + \\override #'(line-width . 40) + \\wordwrap-string #\"Lorem ipsum dolor sit amet, consectetur + adipisicing elit, sed do eiusmod tempor incididunt ut labore + et dolore magna aliqua. - (ly:make-stencil - `(polygon ',(list - 0 (/ thickness -2) - width (+ (* width slope) (/ thickness -2)) - width (+ (* width slope) (/ thickness 2)) - 0 (/ thickness 2)) - ,(ly:output-def-lookup layout 'blot-diameter) - #t) - (cons 0 width) - (cons (+ (- half) (car yext)) - (+ half (cdr yext)))))) -(define-markup-command (underline layout props arg) - (markup?) - #:category font - #:properties ((thickness 1) (offset 2)) - " address@hidden underlining text + Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. -Underline @var{arg}. Looks at @code{thickness} to determine line -thickness, and @code{offset} to determine line y-offset. address@hidden,quote] -\\markup \\fill-line { - \\underline \"underlined\" - \\override #'(offset . 5) - \\override #'(thickness . 1) - \\underline \"underlined\" - \\override #'(offset . 1) - \\override #'(thickness . 5) - \\underline \"underlined\" + Excepteur sint occaecat cupidatat non proident, sunt in culpa + qui officia deserunt mollit anim id est laborum\" } @end lilypond" - (let* ((thick (ly:output-def-lookup layout 'line-thickness)) - (underline-thick (* thickness thick)) - (markup (interpret-markup layout props arg)) - (x1 (car (ly:stencil-extent markup X))) - (x2 (cdr (ly:stencil-extent markup X))) - (y (* thick (- offset))) - (line (make-line-stencil underline-thick x1 y x2 y))) - (ly:stencil-add markup line))) - -(define-markup-command (box layout props arg) - (markup?) - #:category font - #:properties ((thickness 1) - (font-size 0) - (box-padding 0.2)) - " address@hidden enclosing text within a box + (stack-lines DOWN 0.0 baseline-skip + (wordwrap-string-internal-markup-list layout props #f arg))) -Draw a box round @var{arg}. Looks at @code{thickness}, address@hidden and @code{font-size} properties to determine line -thickness and padding around the markup. +(define-markup-command (justify-string layout props arg) + (string?) + #:category align + #:properties ((baseline-skip) + wordwrap-string-internal-markup-list) + "Justify a string. Paragraphs may be separated with double newlines @lilypond[verbatim,quote] \\markup { - \\override #'(box-padding . 0.5) - \\box - \\line { V. S. } -} address@hidden lilypond" - (let* ((th (* (ly:output-def-lookup layout 'line-thickness) - thickness)) - (pad (* (magstep font-size) box-padding)) - (m (interpret-markup layout props arg))) - (box-stencil m th pad))) - -(define-markup-command (filled-box layout props xext yext blot) - (number-pair? number-pair? number?) - #:category graphic - " address@hidden drawing solid boxes within text address@hidden drawing boxes with rounded corners + \\override #'(line-width . 40) + \\justify-string #\"Lorem ipsum dolor sit amet, consectetur + adipisicing elit, sed do eiusmod tempor incididunt ut labore + et dolore magna aliqua. -Draw a box with rounded corners of dimensions @var{xext} and address@hidden For example, address@hidden -\\filled-box #'(-.3 . 1.8) #'(-.3 . 1.8) #0 address@hidden verbatim -creates a box extending horizontally from -0.3 to 1.8 and -vertically from -0.3 up to 1.8, with corners formed from a -circle of address@hidden (i.e., sharp corners). + + Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. + + + Excepteur sint occaecat cupidatat non proident, sunt in culpa + qui officia deserunt mollit anim id est laborum\" +} address@hidden lilypond" + (stack-lines DOWN 0.0 baseline-skip + (wordwrap-string-internal-markup-list layout props #t arg))) + +(define-markup-command (wordwrap-field layout props symbol) + (symbol?) + #:category align + "Wordwrap the data which has been assigned to @var{symbol}. @lilypond[verbatim,quote] +\\header { + title = \"My title\" + myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing + elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud + exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat.\" +} + +\\paper { + bookTitleMarkup = \\markup { + \\column { + \\fill-line { \\fromproperty #'header:title } + \\null + \\wordwrap-field #'header:myText + } + } +} + \\markup { - \\filled-box #'(0 . 4) #'(0 . 4) #0 - \\filled-box #'(0 . 2) #'(-4 . 2) #0.4 - \\filled-box #'(1 . 8) #'(0 . 7) #0.2 - \\with-color #white - \\filled-box #'(-4.5 . -2.5) #'(3.5 . 5.5) #0.7 + \\null } @end lilypond" - (ly:round-filled-box - xext yext blot)) + (let* ((m (chain-assoc-get symbol props))) + (if (string? m) + (wordwrap-string-markup layout props m) + empty-stencil))) -(define-markup-command (rounded-box layout props arg) - (markup?) - #:category graphic - #:properties ((thickness 1) - (corner-radius 1) - (font-size 0) - (box-padding 0.5)) - "@cindex enclosing text in a box with rounded corners - @cindex drawing boxes with rounded corners around text -Draw a box with rounded corners around @var{arg}. Looks at @code{thickness}, address@hidden and @code{font-size} properties to determine line -thickness and padding around the markup; the @code{corner-radius} property -makes it possible to define another shape for the corners (default is 1). +(define-markup-command (justify-field layout props symbol) + (symbol?) + #:category align + "Justify the data which has been assigned to @var{symbol}. address@hidden,verbatim,relative=2] -c4^\\markup { - \\rounded-box { - Overtura address@hidden,quote] +\\header { + title = \"My title\" + myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing + elit, sed do eiusmod tempor incididunt ut labore et dolore magna + aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat.\" +} + +\\paper { + bookTitleMarkup = \\markup { + \\column { + \\fill-line { \\fromproperty #'header:title } + \\null + \\justify-field #'header:myText + } } } -c,8. c16 c4 r + +\\markup { + \\null +} @end lilypond" - (let ((th (* (ly:output-def-lookup layout 'line-thickness) - thickness)) - (pad (* (magstep font-size) box-padding)) - (m (interpret-markup layout props arg))) - (ly:stencil-add (rounded-box-stencil m th pad corner-radius) - m))) + (let* ((m (chain-assoc-get symbol props))) + (if (string? m) + (justify-string-markup layout props m) + empty-stencil))) -(define-markup-command (rotate layout props ang arg) - (number? markup?) +(define-markup-command (combine layout props arg1 arg2) + (markup? markup?) #:category align " address@hidden rotating text address@hidden merging text -Rotate object with @var{ang} degrees around its center. +Print two markups on top of each other. + +Note: @code{\\combine} cannot take a list of markups enclosed in +curly braces as an argument; the follow example will not compile: + address@hidden +\\combine @{ a list @} address@hidden example @lilypond[verbatim,quote] \\markup { - default - \\hspace #2 - \\rotate #45 - \\line { - rotated 45° - } + \\fontsize #5 + \\override #'(thickness . 2) + \\combine + \\draw-line #'(0 . 4) + \\arrow-head #Y #DOWN ##f } @end lilypond" - (let* ((stil (interpret-markup layout props arg))) - (ly:stencil-rotate stil ang 0 0))) + (let* ((s1 (interpret-markup layout props arg1)) + (s2 (interpret-markup layout props arg2))) + (ly:stencil-add s1 s2))) -(define-markup-command (whiteout layout props arg) - (markup?) - #:category other +;; +;; TODO: should extract baseline-skip from each argument somehow.. +;; +(define-markup-command (column layout props args) + (markup-list?) + #:category align + #:properties ((baseline-skip)) " address@hidden adding a white background to text address@hidden stacking text in a column -Provide a white background for @var{arg}. +Stack the markups in @var{args} vertically. The property address@hidden determines the space between markups +in @var{args}. @lilypond[verbatim,quote] \\markup { - \\combine - \\filled-box #'(-1 . 10) #'(-3 . 4) #1 - \\whiteout whiteout + \\column { + one + two + three + } } @end lilypond" - (stencil-whiteout (interpret-markup layout props arg))) + (let ((arg-stencils (interpret-markup-list layout props args))) + (stack-lines -1 0.0 baseline-skip + (remove ly:stencil-empty? arg-stencils)))) -(define-markup-command (pad-markup layout props amount arg) - (number? markup?) +(define-markup-command (dir-column layout props args) + (markup-list?) #:category align + #:properties ((direction) + (baseline-skip)) " address@hidden padding text address@hidden putting space around text address@hidden changing direction of text columns -Add space around a markup object. +Make a column of @var{args}, going up or down, depending on the +setting of the @code{direction} layout property. @lilypond[verbatim,quote] \\markup { - \\box { - default + \\override #`(direction . ,UP) { + \\dir-column { + going up + } } - \\hspace #2 - \\box { - \\pad-markup #1 { - padded + \\hspace #1 + \\dir-column { + going down + } + \\hspace #1 + \\override #'(direction . 1) { + \\dir-column { + going up } } } @end lilypond" - (let* - ((stil (interpret-markup layout props arg)) - (xext (ly:stencil-extent stil X)) - (yext (ly:stencil-extent stil Y))) - - (ly:make-stencil - (ly:stencil-expr stil) - (interval-widen xext amount) - (interval-widen yext amount)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; space -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (stack-lines (if (number? direction) direction -1) + 0.0 + baseline-skip + (interpret-markup-list layout props args))) -(define-markup-command (strut layout props) - () - #:category other - " address@hidden creating vertical spaces in text +(define (general-column align-dir baseline mols) + "Stack @var{mols} vertically, aligned to @var{align-dir} horizontally." -Create a box of the same height as the space in the current font." - (let ((m (ly:text-interface::interpret-markup layout props " "))) - (ly:make-stencil (ly:stencil-expr m) - '(0 . 0) - (ly:stencil-extent m X) - ))) + (let* ((aligned-mols (map (lambda (x) (ly:stencil-aligned-to x X align-dir)) mols)) + (stacked-stencil (stack-lines -1 0.0 baseline aligned-mols)) + (stacked-extent (ly:stencil-extent stacked-stencil X))) + (ly:stencil-translate-axis stacked-stencil (- (car stacked-extent)) X ))) -;; todo: fix negative space -(define-markup-command (hspace layout props amount) - (number?) +(define-markup-command (center-column layout props args) + (markup-list?) #:category align - #:properties ((word-space)) + #:properties ((baseline-skip)) " address@hidden creating horizontal spaces in text address@hidden centering a column of text -Create an invisible object taking up horizontal space @var{amount}. +Put @code{args} in a centered column. @lilypond[verbatim,quote] \\markup { - one - \\hspace #2 - two - \\hspace #8 - three -} + \\center-column { + one + two + three + } +} @end lilypond" - (let ((corrected-space (- amount word-space))) - (if (> corrected-space 0) - (ly:make-stencil "" (cons 0 corrected-space) '(0 . 0)) - (ly:make-stencil "" (cons corrected-space corrected-space) '(0 . 0))))) + (general-column CENTER baseline-skip (interpret-markup-list layout props args))) -;; todo: fix negative space -(define-markup-command (vspace layout props amount) - (number?) - #:category align +(define-markup-command (left-column layout props args) + (markup-list?) + #:category align + #:properties ((baseline-skip)) " address@hidden creating vertical spaces in text address@hidden text columns, left-aligned -Create an invisible object taking up vertical space -of @var{amount} multiplied by 3. +Put @code{args} in a left-aligned column. @lilypond[verbatim,quote] \\markup { - \\center-column { + \\left-column { one - \\vspace #2 two - \\vspace #5 three } } @end lilypond" - (let ((amount (* amount 3.0))) - (if (> amount 0) - (ly:make-stencil "" (cons 0 0) (cons 0 amount)) - (ly:make-stencil "" (cons 0 0) (cons amount amount))))) + (general-column LEFT baseline-skip (interpret-markup-list layout props args))) +(define-markup-command (right-column layout props args) + (markup-list?) + #:category align + #:properties ((baseline-skip)) + " address@hidden text columns, right-aligned -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; importing graphics. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +Put @code{args} in a right-aligned column. -(define-markup-command (stencil layout props stil) - (ly:stencil?) - #:category other address@hidden,quote] +\\markup { + \\right-column { + one + two + three + } +} address@hidden lilypond" + (general-column RIGHT baseline-skip (interpret-markup-list layout props args))) + +(define-markup-command (vcenter layout props arg) + (markup?) + #:category align " address@hidden importing stencils into text address@hidden vertically centering text -Use a stencil as markup. +Align @code{arg} to its address@hidden @lilypond[verbatim,quote] \\markup { - \\stencil #(make-circle-stencil 2 0 #t) + one + \\vcenter + two + three } @end lilypond" - stil) - -(define bbox-regexp - (make-regexp "%%BoundingBox:[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)")) + (let* ((mol (interpret-markup layout props arg))) + (ly:stencil-aligned-to mol Y CENTER))) -(define (get-postscript-bbox string) - "Extract the bbox from STRING, or return #f if not present." - (let* - ((match (regexp-exec bbox-regexp string))) +(define-markup-command (center-align layout props arg) + (markup?) + #:category align + " address@hidden horizontally centering text - (if match - (map (lambda (x) - (string->number (match:substring match x))) - (cdr (iota 5))) +Align @code{arg} to its address@hidden - #f))) address@hidden,quote] +\\markup { + \\column { + one + \\center-align + two + three + } +} address@hidden lilypond" + (let* ((mol (interpret-markup layout props arg))) + (ly:stencil-aligned-to mol X CENTER))) -(define-markup-command (epsfile layout props axis size file-name) - (number? number? string?) - #:category graphic +(define-markup-command (right-align layout props arg) + (markup?) + #:category align " address@hidden inlining an Encapsulated PostScript image address@hidden right aligning text -Inline an EPS image. The image is scaled along @var{axis} to address@hidden +Align @var{arg} on its right edge. @lilypond[verbatim,quote] \\markup { - \\general-align #Y #DOWN { - \\epsfile #X #20 #\"context-example.eps\" - \\epsfile #Y #20 #\"context-example.eps\" + \\column { + one + \\right-align + two + three } } @end lilypond" - (if (ly:get-option 'safe) - (interpret-markup layout props "not allowed in safe") - (eps-file->stencil axis size file-name) - )) + (let* ((m (interpret-markup layout props arg))) + (ly:stencil-aligned-to m X RIGHT))) -(define-markup-command (postscript layout props str) - (string?) - #:category graphic +(define-markup-command (left-align layout props arg) + (markup?) + #:category align " address@hidden inserting PostScript directly into text -This inserts @var{str} directly into the output as a PostScript -command string. - address@hidden,quote] -ringsps = #\" - 0.15 setlinewidth - 0.9 0.6 moveto - 0.4 0.6 0.5 0 361 arc - stroke - 1.0 0.6 0.5 0 361 arc - stroke - \" address@hidden left aligning text -rings = \\markup { - \\with-dimensions #'(-0.2 . 1.6) #'(0 . 1.2) - \\postscript #ringsps -} +Align @var{arg} on its left edge. -\\relative c'' { - c2^\\rings - a2_\\rings address@hidden,quote] +\\markup { + \\column { + one + \\left-align + two + three + } } @end lilypond" - ;; FIXME - (ly:make-stencil - (list 'embedded-ps - (format #f " -gsave currentpoint translate -0.1 setlinewidth - ~a -grestore -" - str)) - '(0 . 0) '(0 . 0))) + (let* ((m (interpret-markup layout props arg))) + (ly:stencil-aligned-to m X LEFT))) -(define-markup-command (path layout props thickness commands) (number? list?) - #:category graphic - #:properties ((line-cap-style 'round) - (line-join-style 'round) - (filled #f)) +(define-markup-command (general-align layout props axis dir arg) + (integer? number? markup?) + #:category align " address@hidden paths, drawing address@hidden drawing paths -Draws a path with line thickness @var{thickness} according to the -directions given in @var{commands}. @var{commands} is a list of -lists where the @code{car} of each sublist is a drawing command and -the @code{cdr} comprises the associated arguments for each command. - -Line-cap styles and line-join styles may be customized by -overriding the @code{line-cap-style} and @code{line-join-style} -properties, respectively. Available line-cap styles are address@hidden'butt}, @code{'round}, and @code{'square}. Available -line-join styles are @code{'miter}, @code{'round}, and address@hidden'bevel}. - -The property @code{filled} specifies whether or not the path is -filled with color. address@hidden controlling general text alignment -There are seven commands available to use in the list address@hidden: @code{moveto}, @code{rmoveto}, @code{lineto}, address@hidden, @code{curveto}, @code{rcurveto}, and address@hidden Note that the commands that begin with @emph{r} -are the relative variants of the other three commands. +Align @var{arg} in @var{axis} direction to the @var{dir} side. -The commands @code{moveto}, @code{rmoveto}, @code{lineto}, and address@hidden take 2 arguments; they are the X and Y coordinates -for the destination point. address@hidden,quote] +\\markup { + \\column { + one + \\general-align #X #LEFT + two + three + \\null + one + \\general-align #X #CENTER + two + three + \\null + \\line { + one + \\general-align #Y #UP + two + three + } + \\null + \\line { + one + \\general-align #Y #3.2 + two + three + } + } +} address@hidden lilypond" + (let* ((m (interpret-markup layout props arg))) + (ly:stencil-aligned-to m axis dir))) -The commands @code{curveto} and @code{rcurveto} create cubic -Bézier curves, and take 6 arguments; the first two are the X and Y -coordinates for the first control point, the second two are the X -and Y coordinates for the second control point, and the last two -are the X and Y coordinates for the destination point. +(define-markup-command (halign layout props dir arg) + (number? markup?) + #:category align + " address@hidden setting horizontal text alignment -The @code{closepath} command takes zero arguments and closes the -current subpath in the active path. - -Note that a sequence of commands @emph{must} begin with a address@hidden or @code{rmoveto} to work with the SVG output. +Set horizontal alignment. If @var{dir} is @address@hidden, then it is +left-aligned, while @code{+1} is right. Values in between interpolate +alignment accordingly. @lilypond[verbatim,quote] -samplePath = - #'((moveto 0 0) - (lineto -1 1) - (lineto 1 1) - (lineto 1 -1) - (curveto -5 -5 -5 5 -1 0) - (closepath)) - \\markup { - \\path #0.25 #samplePath + \\column { + one + \\halign #LEFT + two + three + \\null + one + \\halign #CENTER + two + three + \\null + one + \\halign #RIGHT + two + three + \\null + one + \\halign #-5 + two + three + } } @end lilypond" - (let* ((half-thickness (/ thickness 2)) - (current-point '(0 . 0)) - (set-point (lambda (lst) (set! current-point lst))) - (relative? (lambda (x) - (string-prefix? "r" (symbol->string (car x))))) - ;; For calculating extents, we want to modify the command - ;; list so that all coordinates are absolute. - (new-commands (map (lambda (x) - (cond - ;; for rmoveto, rlineto - ((and (relative? x) (eq? 3 (length x))) - (let ((cp (cons - (+ (car current-point) - (second x)) - (+ (cdr current-point) - (third x))))) - (set-point cp) - (list (car cp) - (cdr cp)))) - ;; for rcurveto - ((and (relative? x) (eq? 7 (length x))) - (let* ((old-cp current-point) - (cp (cons - (+ (car old-cp) - (sixth x)) - (+ (cdr old-cp) - (seventh x))))) - (set-point cp) - (list (+ (car old-cp) (second x)) - (+ (cdr old-cp) (third x)) - (+ (car old-cp) (fourth x)) - (+ (cdr old-cp) (fifth x)) - (car cp) - (cdr cp)))) - ;; for moveto, lineto - ((eq? 3 (length x)) - (set-point (cons (second x) - (third x))) - (drop x 1)) - ;; for curveto - ((eq? 7 (length x)) - (set-point (cons (sixth x) - (seventh x))) - (drop x 1)) - ;; keep closepath for filtering; - ;; see `without-closepath'. - (else x))) - commands)) - ;; path-min-max does not accept 0-arg lists, - ;; and since closepath does not affect extents, filter - ;; out those commands here. - (without-closepath (filter (lambda (x) - (not (equal? 'closepath (car x)))) - new-commands)) - (extents (path-min-max - ;; set the origin to the first moveto - (list (list-ref (car without-closepath) 0) - (list-ref (car without-closepath) 1)) - without-closepath)) - (X-extent (cons (list-ref extents 0) (list-ref extents 1))) - (Y-extent (cons (list-ref extents 2) (list-ref extents 3))) - (command-list (fold-right append '() commands))) - - ;; account for line thickness - (set! X-extent (interval-widen X-extent half-thickness)) - (set! Y-extent (interval-widen Y-extent half-thickness)) - - (ly:make-stencil - `(path ,thickness `(,@',command-list) - ',line-cap-style ',line-join-style ,filled) - X-extent - Y-extent))) + (let* ((m (interpret-markup layout props arg))) + (ly:stencil-aligned-to m X dir))) -(define-markup-command (score layout props score) - (ly:score?) - #:category music - #:properties ((baseline-skip)) +(define-markup-command (with-dimensions layout props x y arg) + (number-pair? number-pair? markup?) + #:category other " address@hidden inserting music into text address@hidden setting extent of text objects -Inline an image of music. +Set the dimensions of @var{arg} to @var{x} address@hidden@var{y}." + (let* ((m (interpret-markup layout props arg))) + (ly:make-stencil (ly:stencil-expr m) x y))) + +(define-markup-command (pad-around layout props amount arg) + (number? markup?) + #:category align + "Add padding @var{amount} all around @var{arg}. @lilypond[verbatim,quote] \\markup { - \\score { - \\new PianoStaff << - \\new Staff \\relative c' { - \\key f \\major - \\time 3/4 - \\mark \\markup { Allegro } - f2\\p( a4) - c2( a4) - bes2( g'4) - f8( e) e4 r - } - \\new Staff \\relative c { - \\clef bass - \\key f \\major - \\time 3/4 - f8( a c a c a - f c' es c es c) - f,( bes d bes d bes) - f( g bes g bes g) - } - >> - \\layout { - indent = 0.0\\cm - \\context { - \\Score - \\override RehearsalMark - #'break-align-symbols = #'(time-signature key-signature) - \\override RehearsalMark - #'self-alignment-X = #LEFT - } - \\context { - \\Staff - \\override TimeSignature - #'break-align-anchor-alignment = #LEFT - } + \\box { + default + } + \\hspace #2 + \\box { + \\pad-around #0.5 { + padded } } } @end lilypond" - (let ((output (ly:score-embedded-format score layout))) - - (if (ly:music-output? output) - (stack-stencils Y DOWN baseline-skip - (map paper-system-stencil - (vector->list - (ly:paper-score-paper-systems output)))) - (begin - (ly:warning (_"no systems found in \\score markup, does it have a \\layout block?")) - empty-stencil)))) + (let* ((m (interpret-markup layout props arg)) + (x (ly:stencil-extent m X)) + (y (ly:stencil-extent m Y))) + (ly:make-stencil (ly:stencil-expr m) + (interval-widen x amount) + (interval-widen y amount)))) -(define-markup-command (null layout props) - () - #:category other +(define-markup-command (pad-x layout props amount arg) + (number? markup?) + #:category align " address@hidden creating empty text objects address@hidden padding text horizontally -An empty markup with extents of a single point. +Add padding @var{amount} around @var{arg} in the address@hidden @lilypond[verbatim,quote] \\markup { - \\null + \\box { + default + } + \\hspace #4 + \\box { + \\pad-x #2 { + padded + } + } } @end lilypond" - point-stencil) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; basic formatting. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define-markup-command (simple layout props str) - (string?) - #:category font - " address@hidden simple text strings + (let* ((m (interpret-markup layout props arg)) + (x (ly:stencil-extent m X)) + (y (ly:stencil-extent m Y))) + (ly:make-stencil (ly:stencil-expr m) + (interval-widen x amount) + y))) -A simple text string; @code{\\markup @{ foo @}} is equivalent with address@hidden @{ \\simple #\"foo\" @}}. +(define-markup-command (put-adjacent layout props axis dir arg1 arg2) + (integer? ly:dir? markup? markup?) + #:category align + "Put @var{arg2} next to @var{arg1}, without moving @var{arg1}." + (let ((m1 (interpret-markup layout props arg1)) + (m2 (interpret-markup layout props arg2))) + (ly:stencil-combine-at-edge m1 axis dir m2 0.0))) -Note: for creating standard text markup or defining new markup commands, -the use of @code{\\simple} is unnecessary. +(define-markup-command (transparent layout props arg) + (markup?) + #:category other + "Make @var{arg} transparent. @lilypond[verbatim,quote] \\markup { - \\simple #\"simple\" - \\simple #\"text\" - \\simple #\"strings\" + \\transparent { + invisible text + } } @end lilypond" - (interpret-markup layout props str)) + (let* ((m (interpret-markup layout props arg)) + (x (ly:stencil-extent m X)) + (y (ly:stencil-extent m Y))) + (ly:make-stencil "" x y))) -(define-markup-command (tied-lyric layout props str) - (string?) - #:category music - #:properties ((word-space)) - " address@hidden simple text strings with tie characters - -Like simple-markup, but use tie characters for @q{~} tilde symbols. +(define-markup-command (pad-to-box layout props x-ext y-ext arg) + (number-pair? number-pair? markup?) + #:category align + "Make @var{arg} take at least @var{x-ext}, @var{y-ext} space. @lilypond[verbatim,quote] -\\markup \\column { - \\tied-lyric #\"Siam navi~all'onde~algenti Lasciate~in abbandono\" - \\tied-lyric #\"Impetuosi venti I nostri~affetti sono\" - \\tied-lyric #\"Ogni diletto~e scoglio Tutta la vita~e~un mar.\" +\\markup { + \\box { + default + } + \\hspace #4 + \\box { + \\pad-to-box #'(0 . 10) #'(0 . 3) { + padded + } + } } @end lilypond" - (define (replace-ties tie str) - (if (string-contains str "~") - (let* - ((half-space (/ word-space 2)) - (parts (string-split str #\~)) - (tie-str (markup #:hspace half-space - #:musicglyph tie - #:hspace half-space)) - (joined (list-join parts tie-str))) - (make-concat-markup joined)) - str)) - - (define short-tie-regexp (make-regexp "~[^.]~")) - (define (match-short str) (regexp-exec short-tie-regexp str)) - - (define (replace-short str mkp) - (let ((match (match-short str))) - (if (not match) - (make-concat-markup (list - mkp - (replace-ties "ties.lyric.default" str))) - (let ((new-str (match:suffix match)) - (new-mkp (make-concat-markup (list - mkp - (replace-ties "ties.lyric.default" - (match:prefix match)) - (replace-ties "ties.lyric.short" - (match:substring match)))))) - (replace-short new-str new-mkp))))) - - (interpret-markup layout - props - (replace-short str (markup)))) - -(define-public empty-markup - (make-simple-markup "")) + (let* ((m (interpret-markup layout props arg)) + (x (ly:stencil-extent m X)) + (y (ly:stencil-extent m Y))) + (ly:make-stencil (ly:stencil-expr m) + (interval-union x-ext x) + (interval-union y-ext y)))) -;; helper for justifying lines. -(define (get-fill-space word-count line-width word-space text-widths) - "Calculate the necessary paddings between each two adjacent texts. - The lengths of all texts are stored in @var{text-widths}. - The normal formula for the padding between texts a and b is: - padding = line-width/(word-count - 1) - (length(a) + length(b))/2 - The first and last padding have to be calculated specially using the - whole length of the first or last text. - All paddings are checked to be at least word-space, to ensure that - no texts collide. - Return a list of paddings." - (cond - ((null? text-widths) '()) +(define-markup-command (hcenter-in layout props length arg) + (number? markup?) + #:category align + "Center @var{arg} horizontally within a box of extending address@hidden/2 to the left and right. - ;; special case first padding - ((= (length text-widths) word-count) - (cons - (- (- (/ line-width (1- word-count)) (car text-widths)) - (/ (car (cdr text-widths)) 2)) - (get-fill-space word-count line-width word-space (cdr text-widths)))) - ;; special case last padding - ((= (length text-widths) 2) - (list (- (/ line-width (1- word-count)) - (+ (/ (car text-widths) 2) (car (cdr text-widths)))) 0)) - (else - (let ((default-padding - (- (/ line-width (1- word-count)) - (/ (+ (car text-widths) (car (cdr text-widths))) 2)))) - (cons - (if (> word-space default-padding) - word-space - default-padding) - (get-fill-space word-count line-width word-space (cdr text-widths))))))) address@hidden,verbatim] +\\new StaffGroup << + \\new Staff { + \\set Staff.instrumentName = \\markup { + \\hcenter-in #12 + Oboe + } + c''1 + } + \\new Staff { + \\set Staff.instrumentName = \\markup { + \\hcenter-in #12 + Bassoon + } + \\clef tenor + c'1 + } +>> address@hidden lilypond" + (interpret-markup layout props + (make-pad-to-box-markup + (cons (/ length -2) (/ length 2)) + '(0 . 0) + (make-center-align-markup arg)))) -(define-markup-command (fill-line layout props args) - (markup-list?) +(define-markup-command (rotate layout props ang arg) + (number? markup?) #:category align - #:properties ((text-direction RIGHT) - (word-space 0.6) - (line-width #f)) - "Put @var{markups} in a horizontal line of width @var{line-width}. -The markups are spaced or flushed to fill the entire line. -If there are no arguments, return an empty stencil. + " address@hidden rotating text + +Rotate object with @var{ang} degrees around its center. @lilypond[verbatim,quote] \\markup { - \\column { - \\fill-line { - Words evenly spaced across the page - } - \\null - \\fill-line { - \\line { Text markups } - \\line { - \\italic { evenly spaced } - } - \\line { across the page } - } + default + \\hspace #2 + \\rotate #45 + \\line { + rotated 45° } } @end lilypond" - (let* ((orig-stencils (interpret-markup-list layout props args)) - (stencils - (map (lambda (stc) - (if (ly:stencil-empty? stc) - point-stencil - stc)) orig-stencils)) - (text-widths - (map (lambda (stc) - (if (ly:stencil-empty? stc) - 0.0 - (interval-length (ly:stencil-extent stc X)))) - stencils)) - (text-width (apply + text-widths)) - (word-count (length stencils)) - (line-width (or line-width (ly:output-def-lookup layout 'line-width))) - (fill-space - (cond - ((= word-count 1) - (list - (/ (- line-width text-width) 2) - (/ (- line-width text-width) 2))) - ((= word-count 2) - (list - (- line-width text-width))) - (else - (get-fill-space word-count line-width word-space text-widths)))) - - (line-contents (if (= word-count 1) - (list - point-stencil - (car stencils) - point-stencil) - stencils))) + (let* ((stil (interpret-markup layout props arg))) + (ly:stencil-rotate stil ang 0 0))) - (if (null? (remove ly:stencil-empty? orig-stencils)) - empty-stencil - (begin - (if (= text-direction LEFT) - (set! line-contents (reverse line-contents))) - (set! line-contents - (stack-stencils-padding-list - X RIGHT fill-space line-contents)) - (if (> word-count 1) - ;; shift s.t. stencils align on the left edge, even if - ;; first stencil had negative X-extent (e.g. center-column) - ;; (if word-count = 1, X-extents are already normalized in - ;; the definition of line-contents) - (set! line-contents - (ly:stencil-translate-axis - line-contents - (- (car (ly:stencil-extent (car stencils) X))) - X))) - line-contents)))) +(define-markup-command (whiteout layout props arg) + (markup?) + #:category other + " address@hidden adding a white background to text -(define-markup-command (line layout props args) - (markup-list?) - #:category align - #:properties ((word-space) - (text-direction RIGHT)) - "Put @var{args} in a horizontal line. The property @code{word-space} -determines the space between markups in @var{args}. +Provide a white background for @var{arg}. @lilypond[verbatim,quote] \\markup { - \\line { - one two three - } + \\combine + \\filled-box #'(-1 . 10) #'(-3 . 4) #1 + \\whiteout whiteout } @end lilypond" - (let ((stencils (interpret-markup-list layout props args))) - (if (= text-direction LEFT) - (set! stencils (reverse stencils))) - (stack-stencil-line - word-space - (remove ly:stencil-empty? stencils)))) + (stencil-whiteout (interpret-markup layout props arg))) -(define-markup-command (concat layout props args) - (markup-list?) +(define-markup-command (pad-markup layout props amount arg) + (number? markup?) #:category align " address@hidden concatenating text address@hidden ligatures in text address@hidden padding text address@hidden putting space around text -Concatenate @var{args} in a horizontal line, without spaces in between. -Strings and simple markups are concatenated on the input level, allowing -ligatures. For example, @code{\\concat @{ \"f\" \\simple #\"i\" @}} is -equivalent to @code{\"fi\"}. +Add space around a markup object. @lilypond[verbatim,quote] \\markup { - \\concat { - one - two - three + \\box { + default + } + \\hspace #2 + \\box { + \\pad-markup #1 { + padded + } } } @end lilypond" - (define (concat-string-args arg-list) - (fold-right (lambda (arg result-list) - (let ((result (if (pair? result-list) - (car result-list) - '()))) - (if (and (pair? arg) (eqv? (car arg) simple-markup)) - (set! arg (cadr arg))) - (if (and (string? result) (string? arg)) - (cons (string-append arg result) (cdr result-list)) - (cons arg result-list)))) - '() - arg-list)) + (let* + ((stil (interpret-markup layout props arg)) + (xext (ly:stencil-extent stil X)) + (yext (ly:stencil-extent stil Y))) - (interpret-markup layout - (prepend-alist-chain 'word-space 0 props) - (make-line-markup (if (markup-command-list? args) - args - (concat-string-args args))))) + (ly:make-stencil + (ly:stencil-expr stil) + (interval-widen xext amount) + (interval-widen yext amount)))) -(define (wordwrap-stencils stencils - justify base-space line-width text-dir) - "Perform simple wordwrap, return stencil of each line." - (define space (if justify - ;; justify only stretches lines. - (* 0.7 base-space) - base-space)) - (define (take-list width space stencils - accumulator accumulated-width) - "Return (head-list . tail) pair, with head-list fitting into width" - (if (null? stencils) - (cons accumulator stencils) - (let* ((first (car stencils)) - (first-wid (cdr (ly:stencil-extent (car stencils) X))) - (newwid (+ space first-wid accumulated-width))) - (if (or (null? accumulator) - (< newwid width)) - (take-list width space - (cdr stencils) - (cons first accumulator) - newwid) - (cons accumulator stencils))))) - (let loop ((lines '()) - (todo stencils)) - (let* ((line-break (take-list line-width space todo - '() 0.0)) - (line-stencils (car line-break)) - (space-left (- line-width - (apply + (map (lambda (x) (cdr (ly:stencil-extent x X))) - line-stencils)))) - (line-word-space (cond ((not justify) space) - ;; don't stretch last line of paragraph. - ;; hmmm . bug - will overstretch the last line in some case. - ((null? (cdr line-break)) - base-space) - ((null? line-stencils) 0.0) - ((null? (cdr line-stencils)) 0.0) - (else (/ space-left (1- (length line-stencils)))))) - (line (stack-stencil-line line-word-space - (if (= text-dir RIGHT) - (reverse line-stencils) - line-stencils)))) - (if (pair? (cdr line-break)) - (loop (cons line lines) - (cdr line-break)) - (begin - (if (= text-dir LEFT) - (set! line - (ly:stencil-translate-axis - line - (- line-width (interval-end (ly:stencil-extent line X))) - X))) - (reverse (cons line lines))))))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; space +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define-markup-list-command (wordwrap-internal layout props justify args) - (boolean? markup-list?) - #:properties ((line-width #f) - (word-space) - (text-direction RIGHT)) - "Internal markup list command used to define @code{\\justify} and @code{\\wordwrap}." - (wordwrap-stencils (remove ly:stencil-empty? - (interpret-markup-list layout props args)) - justify - word-space - (or line-width - (ly:output-def-lookup layout 'line-width)) - text-direction)) +(define-markup-command (strut layout props) + () + #:category other + " address@hidden creating vertical spaces in text -(define-markup-command (justify layout props args) - (markup-list?) +Create a box of the same height as the space in the current font." + (let ((m (ly:text-interface::interpret-markup layout props " "))) + (ly:make-stencil (ly:stencil-expr m) + '(0 . 0) + (ly:stencil-extent m X) + ))) + +;; todo: fix negative space +(define-markup-command (hspace layout props amount) + (number?) #:category align - #:properties ((baseline-skip) - wordwrap-internal-markup-list) + #:properties ((word-space)) " address@hidden justifying text address@hidden creating horizontal spaces in text -Like @code{\\wordwrap}, but with lines stretched to justify the margins. -Use @code{\\override #'(line-width . @var{X})} to set the line width; address@hidden@tie{}is the number of staff spaces. +Create an invisible object taking up horizontal space @var{amount}. @lilypond[verbatim,quote] \\markup { - \\justify { - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna aliqua. - Ut enim ad minim veniam, quis nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat. - } + one + \\hspace #2 + two + \\hspace #8 + three } @end lilypond" - (stack-lines DOWN 0.0 baseline-skip - (wordwrap-internal-markup-list layout props #t args))) + (let ((corrected-space (- amount word-space))) + (if (> corrected-space 0) + (ly:make-stencil "" (cons 0 corrected-space) '(0 . 0)) + (ly:make-stencil "" (cons corrected-space corrected-space) '(0 . 0))))) -(define-markup-command (wordwrap layout props args) - (markup-list?) - #:category align - #:properties ((baseline-skip) - wordwrap-internal-markup-list) - "Simple wordwrap. Use @code{\\override #'(line-width . @var{X})} to set -the line width, where @var{X} is the number of staff spaces. +;; todo: fix negative space +(define-markup-command (vspace layout props amount) + (number?) + #:category align + " address@hidden creating vertical spaces in text + +Create an invisible object taking up vertical space +of @var{amount} multiplied by 3. @lilypond[verbatim,quote] \\markup { - \\wordwrap { - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna aliqua. - Ut enim ad minim veniam, quis nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat. + \\center-column { + one + \\vspace #2 + two + \\vspace #5 + three } } @end lilypond" - (stack-lines DOWN 0.0 baseline-skip - (wordwrap-internal-markup-list layout props #f args))) + (let ((amount (* amount 3.0))) + (if (> amount 0) + (ly:make-stencil "" (cons 0 0) (cons 0 amount)) + (ly:make-stencil "" (cons 0 0) (cons amount amount))))) -(define-markup-list-command (wordwrap-string-internal layout props justify arg) - (boolean? string?) - #:properties ((line-width) - (word-space) - (text-direction RIGHT)) - "Internal markup list command used to define @code{\\justify-string} and address@hidden" - (let* ((para-strings (regexp-split - (string-regexp-substitute - "\r" "\n" - (string-regexp-substitute "\r\n" "\n" arg)) - "\n[ \t\n]*\n[ \t\n]*")) - (list-para-words (map (lambda (str) - (regexp-split str "[ \t\n]+")) - para-strings)) - (para-lines (map (lambda (words) - (let* ((stencils - (remove ly:stencil-empty? - (map (lambda (x) - (interpret-markup layout props x)) - words)))) - (wordwrap-stencils stencils - justify word-space - line-width text-direction))) - list-para-words))) - (apply append para-lines))) -(define-markup-command (wordwrap-string layout props arg) - (string?) - #:category align - #:properties ((baseline-skip) - wordwrap-string-internal-markup-list) - "Wordwrap a string. Paragraphs may be separated with double newlines. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; importing graphics. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-markup-command (stencil layout props stil) + (ly:stencil?) + #:category other + " address@hidden importing stencils into text + +Use a stencil as markup. @lilypond[verbatim,quote] \\markup { - \\override #'(line-width . 40) - \\wordwrap-string #\"Lorem ipsum dolor sit amet, consectetur - adipisicing elit, sed do eiusmod tempor incididunt ut labore - et dolore magna aliqua. + \\stencil #(make-circle-stencil 2 0 #t) +} address@hidden lilypond" + stil) +(define bbox-regexp + (make-regexp "%%BoundingBox:[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)")) - Ut enim ad minim veniam, quis nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat. +(define (get-postscript-bbox string) + "Extract the bbox from STRING, or return #f if not present." + (let* + ((match (regexp-exec bbox-regexp string))) + (if match + (map (lambda (x) + (string->number (match:substring match x))) + (cdr (iota 5))) - Excepteur sint occaecat cupidatat non proident, sunt in culpa - qui officia deserunt mollit anim id est laborum\" -} address@hidden lilypond" - (stack-lines DOWN 0.0 baseline-skip - (wordwrap-string-internal-markup-list layout props #f arg))) + #f))) -(define-markup-command (justify-string layout props arg) - (string?) - #:category align - #:properties ((baseline-skip) - wordwrap-string-internal-markup-list) - "Justify a string. Paragraphs may be separated with double newlines +(define-markup-command (epsfile layout props axis size file-name) + (number? number? string?) + #:category graphic + " address@hidden inlining an Encapsulated PostScript image + +Inline an EPS image. The image is scaled along @var{axis} to address@hidden @lilypond[verbatim,quote] \\markup { - \\override #'(line-width . 40) - \\justify-string #\"Lorem ipsum dolor sit amet, consectetur - adipisicing elit, sed do eiusmod tempor incididunt ut labore - et dolore magna aliqua. - - - Ut enim ad minim veniam, quis nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat. - - - Excepteur sint occaecat cupidatat non proident, sunt in culpa - qui officia deserunt mollit anim id est laborum\" + \\general-align #Y #DOWN { + \\epsfile #X #20 #\"context-example.eps\" + \\epsfile #Y #20 #\"context-example.eps\" + } } @end lilypond" - (stack-lines DOWN 0.0 baseline-skip - (wordwrap-string-internal-markup-list layout props #t arg))) + (if (ly:get-option 'safe) + (interpret-markup layout props "not allowed in safe") + (eps-file->stencil axis size file-name) + )) -(define-markup-command (wordwrap-field layout props symbol) - (symbol?) - #:category align - "Wordwrap the data which has been assigned to @var{symbol}. +(define-markup-command (postscript layout props str) + (string?) + #:category graphic + " address@hidden inserting PostScript directly into text +This inserts @var{str} directly into the output as a PostScript +command string. @lilypond[verbatim,quote] -\\header { - title = \"My title\" - myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing - elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud - exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat.\" -} +ringsps = #\" + 0.15 setlinewidth + 0.9 0.6 moveto + 0.4 0.6 0.5 0 361 arc + stroke + 1.0 0.6 0.5 0 361 arc + stroke + \" -\\paper { - bookTitleMarkup = \\markup { - \\column { - \\fill-line { \\fromproperty #'header:title } - \\null - \\wordwrap-field #'header:myText - } - } +rings = \\markup { + \\with-dimensions #'(-0.2 . 1.6) #'(0 . 1.2) + \\postscript #ringsps } -\\markup { - \\null +\\relative c'' { + c2^\\rings + a2_\\rings } @end lilypond" - (let* ((m (chain-assoc-get symbol props))) - (if (string? m) - (wordwrap-string-markup layout props m) - empty-stencil))) + ;; FIXME + (ly:make-stencil + (list 'embedded-ps + (format #f " +gsave currentpoint translate +0.1 setlinewidth + ~a +grestore +" + str)) + '(0 . 0) '(0 . 0))) -(define-markup-command (justify-field layout props symbol) - (symbol?) - #:category align - "Justify the data which has been assigned to @var{symbol}. +(define-markup-command (path layout props thickness commands) (number? list?) + #:category graphic + #:properties ((line-cap-style 'round) + (line-join-style 'round) + (filled #f)) + " address@hidden paths, drawing address@hidden drawing paths +Draws a path with line thickness @var{thickness} according to the +directions given in @var{commands}. @var{commands} is a list of +lists where the @code{car} of each sublist is a drawing command and +the @code{cdr} comprises the associated arguments for each command. address@hidden,quote] -\\header { - title = \"My title\" - myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing - elit, sed do eiusmod tempor incididunt ut labore et dolore magna - aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat.\" -} +Line-cap styles and line-join styles may be customized by +overriding the @code{line-cap-style} and @code{line-join-style} +properties, respectively. Available line-cap styles are address@hidden'butt}, @code{'round}, and @code{'square}. Available +line-join styles are @code{'miter}, @code{'round}, and address@hidden'bevel}. -\\paper { - bookTitleMarkup = \\markup { - \\column { - \\fill-line { \\fromproperty #'header:title } - \\null - \\justify-field #'header:myText - } - } -} +The property @code{filled} specifies whether or not the path is +filled with color. -\\markup { - \\null -} address@hidden lilypond" - (let* ((m (chain-assoc-get symbol props))) - (if (string? m) - (justify-string-markup layout props m) - empty-stencil))) +There are seven commands available to use in the list address@hidden: @code{moveto}, @code{rmoveto}, @code{lineto}, address@hidden, @code{curveto}, @code{rcurveto}, and address@hidden Note that the commands that begin with @emph{r} +are the relative variants of the other three commands. -(define-markup-command (combine layout props arg1 arg2) - (markup? markup?) - #:category align - " address@hidden merging text +The commands @code{moveto}, @code{rmoveto}, @code{lineto}, and address@hidden take 2 arguments; they are the X and Y coordinates +for the destination point. -Print two markups on top of each other. +The commands @code{curveto} and @code{rcurveto} create cubic +Bézier curves, and take 6 arguments; the first two are the X and Y +coordinates for the first control point, the second two are the X +and Y coordinates for the second control point, and the last two +are the X and Y coordinates for the destination point. -Note: @code{\\combine} cannot take a list of markups enclosed in -curly braces as an argument; the follow example will not compile: +The @code{closepath} command takes zero arguments and closes the +current subpath in the active path. address@hidden -\\combine @{ a list @} address@hidden example +Note that a sequence of commands @emph{must} begin with a address@hidden or @code{rmoveto} to work with the SVG output. @lilypond[verbatim,quote] +samplePath = + #'((moveto 0 0) + (lineto -1 1) + (lineto 1 1) + (lineto 1 -1) + (curveto -5 -5 -5 5 -1 0) + (closepath)) + \\markup { - \\fontsize #5 - \\override #'(thickness . 2) - \\combine - \\draw-line #'(0 . 4) - \\arrow-head #Y #DOWN ##f + \\path #0.25 #samplePath } @end lilypond" - (let* ((s1 (interpret-markup layout props arg1)) - (s2 (interpret-markup layout props arg2))) - (ly:stencil-add s1 s2))) + (let* ((half-thickness (/ thickness 2)) + (current-point '(0 . 0)) + (set-point (lambda (lst) (set! current-point lst))) + (relative? (lambda (x) + (string-prefix? "r" (symbol->string (car x))))) + ;; For calculating extents, we want to modify the command + ;; list so that all coordinates are absolute. + (new-commands (map (lambda (x) + (cond + ;; for rmoveto, rlineto + ((and (relative? x) (eq? 3 (length x))) + (let ((cp (cons + (+ (car current-point) + (second x)) + (+ (cdr current-point) + (third x))))) + (set-point cp) + (list (car cp) + (cdr cp)))) + ;; for rcurveto + ((and (relative? x) (eq? 7 (length x))) + (let* ((old-cp current-point) + (cp (cons + (+ (car old-cp) + (sixth x)) + (+ (cdr old-cp) + (seventh x))))) + (set-point cp) + (list (+ (car old-cp) (second x)) + (+ (cdr old-cp) (third x)) + (+ (car old-cp) (fourth x)) + (+ (cdr old-cp) (fifth x)) + (car cp) + (cdr cp)))) + ;; for moveto, lineto + ((eq? 3 (length x)) + (set-point (cons (second x) + (third x))) + (drop x 1)) + ;; for curveto + ((eq? 7 (length x)) + (set-point (cons (sixth x) + (seventh x))) + (drop x 1)) + ;; keep closepath for filtering; + ;; see `without-closepath'. + (else x))) + commands)) + ;; path-min-max does not accept 0-arg lists, + ;; and since closepath does not affect extents, filter + ;; out those commands here. + (without-closepath (filter (lambda (x) + (not (equal? 'closepath (car x)))) + new-commands)) + (extents (path-min-max + ;; set the origin to the first moveto + (list (list-ref (car without-closepath) 0) + (list-ref (car without-closepath) 1)) + without-closepath)) + (X-extent (cons (list-ref extents 0) (list-ref extents 1))) + (Y-extent (cons (list-ref extents 2) (list-ref extents 3))) + (command-list (fold-right append '() commands))) -;; -;; TODO: should extract baseline-skip from each argument somehow.. -;; -(define-markup-command (column layout props args) - (markup-list?) - #:category align + ;; account for line thickness + (set! X-extent (interval-widen X-extent half-thickness)) + (set! Y-extent (interval-widen Y-extent half-thickness)) + + (ly:make-stencil + `(path ,thickness `(,@',command-list) + ',line-cap-style ',line-join-style ,filled) + X-extent + Y-extent))) + +(define-markup-command (score layout props score) + (ly:score?) + #:category music #:properties ((baseline-skip)) " address@hidden stacking text in a column address@hidden inserting music into text -Stack the markups in @var{args} vertically. The property address@hidden determines the space between markups -in @var{args}. - address@hidden,quote] -\\markup { - \\column { - one - two - three - } -} address@hidden lilypond" - (let ((arg-stencils (interpret-markup-list layout props args))) - (stack-lines -1 0.0 baseline-skip - (remove ly:stencil-empty? arg-stencils)))) - -(define-markup-command (dir-column layout props args) - (markup-list?) - #:category align - #:properties ((direction) - (baseline-skip)) - " address@hidden changing direction of text columns - -Make a column of @var{args}, going up or down, depending on the -setting of the @code{direction} layout property. +Inline an image of music. @lilypond[verbatim,quote] \\markup { - \\override #`(direction . ,UP) { - \\dir-column { - going up - } - } - \\hspace #1 - \\dir-column { - going down - } - \\hspace #1 - \\override #'(direction . 1) { - \\dir-column { - going up + \\score { + \\new PianoStaff << + \\new Staff \\relative c' { + \\key f \\major + \\time 3/4 + \\mark \\markup { Allegro } + f2\\p( a4) + c2( a4) + bes2( g'4) + f8( e) e4 r + } + \\new Staff \\relative c { + \\clef bass + \\key f \\major + \\time 3/4 + f8( a c a c a + f c' es c es c) + f,( bes d bes d bes) + f( g bes g bes g) + } + >> + \\layout { + indent = 0.0\\cm + \\context { + \\Score + \\override RehearsalMark + #'break-align-symbols = #'(time-signature key-signature) + \\override RehearsalMark + #'self-alignment-X = #LEFT + } + \\context { + \\Staff + \\override TimeSignature + #'break-align-anchor-alignment = #LEFT + } } } } @end lilypond" - (stack-lines (if (number? direction) direction -1) - 0.0 - baseline-skip - (interpret-markup-list layout props args))) - -(define (general-column align-dir baseline mols) - "Stack @var{mols} vertically, aligned to @var{align-dir} horizontally." + (let ((output (ly:score-embedded-format score layout))) - (let* ((aligned-mols (map (lambda (x) (ly:stencil-aligned-to x X align-dir)) mols)) - (stacked-stencil (stack-lines -1 0.0 baseline aligned-mols)) - (stacked-extent (ly:stencil-extent stacked-stencil X))) - (ly:stencil-translate-axis stacked-stencil (- (car stacked-extent)) X ))) + (if (ly:music-output? output) + (stack-stencils Y DOWN baseline-skip + (map paper-system-stencil + (vector->list + (ly:paper-score-paper-systems output)))) + (begin + (ly:warning (_"no systems found in \\score markup, does it have a \\layout block?")) + empty-stencil)))) -(define-markup-command (center-column layout props args) - (markup-list?) - #:category align - #:properties ((baseline-skip)) +(define-markup-command (null layout props) + () + #:category other " address@hidden centering a column of text address@hidden creating empty text objects -Put @code{args} in a centered column. +An empty markup with extents of a single point. @lilypond[verbatim,quote] \\markup { - \\center-column { - one - two - three - } + \\null } @end lilypond" - (general-column CENTER baseline-skip (interpret-markup-list layout props args))) - -(define-markup-command (left-column layout props args) - (markup-list?) - #:category align - #:properties ((baseline-skip)) - " address@hidden text columns, left-aligned + point-stencil) -Put @code{args} in a left-aligned column. address@hidden,quote] -\\markup { - \\left-column { - one - two - three - } -} address@hidden lilypond" - (general-column LEFT baseline-skip (interpret-markup-list layout props args))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; property +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define-markup-command (right-column layout props args) - (markup-list?) - #:category align - #:properties ((baseline-skip)) - " address@hidden text columns, right-aligned +(define-markup-command (property-recursive layout props symbol) + (symbol?) + #:category other + "Print out a warning when a header field markup contains some recursive +markup definition." + (ly:warning "Recursive definition of property ~a detected!" symbol) + empty-stencil) -Put @code{args} in a right-aligned column. +(define-markup-command (fromproperty layout props symbol) + (symbol?) + #:category other + "Read the @var{symbol} from property settings, and produce a stencil +from the markup contained within. If @var{symbol} is not defined, it +returns an empty markup. @lilypond[verbatim,quote] -\\markup { - \\right-column { - one - two - three +\\header { + myTitle = \"myTitle\" + title = \\markup { + from + \\italic + \\fromproperty #'header:myTitle } } address@hidden lilypond" - (general-column RIGHT baseline-skip (interpret-markup-list layout props args))) - -(define-markup-command (vcenter layout props arg) - (markup?) - #:category align - " address@hidden vertically centering text - -Align @code{arg} to its address@hidden - address@hidden,quote] \\markup { - one - \\vcenter - two - three + \\null } @end lilypond" - (let* ((mol (interpret-markup layout props arg))) - (ly:stencil-aligned-to mol Y CENTER))) + (let ((m (chain-assoc-get symbol props))) + (if (markup? m) + ;; prevent infinite loops by clearing the interpreted property: + (interpret-markup layout (cons (list (cons symbol `(,property-recursive-markup ,symbol))) props) m) + empty-stencil))) -(define-markup-command (center-align layout props arg) - (markup?) - #:category align - " address@hidden horizontally centering text +(define-markup-command (on-the-fly layout props procedure arg) + (procedure? markup?) + #:category other + "Apply the @var{procedure} markup command to @var{arg}. address@hidden should take a single argument." + (let ((anonymous-with-signature (lambda (layout props arg) (procedure layout props arg)))) + (set-object-property! anonymous-with-signature + 'markup-signature + (list markup?)) + (interpret-markup layout props (list anonymous-with-signature arg)))) -Align @code{arg} to its address@hidden +(define-markup-command (footnote layout props mkup note) + (markup? markup?) + #:category other + "Have footnote @var{note} act as an annotation to the markup @var{mkup}. @lilypond[verbatim,quote] \\markup { - \\column { - one - \\center-align - two - three - } + \\auto-footnote a b + \\override #'(padding . 0.2) + \\auto-footnote c d } address@hidden lilypond" - (let* ((mol (interpret-markup layout props arg))) - (ly:stencil-aligned-to mol X CENTER))) - -(define-markup-command (right-align layout props arg) - (markup?) - #:category align - " address@hidden right aligning text address@hidden lilypond +The footnote will not be annotated automatically." + (ly:stencil-combine-at-edge + (interpret-markup layout props mkup) + X + RIGHT + (ly:make-stencil + `(footnote (gensym "footnote") #f ,(interpret-markup layout props note)) + '(0 . 0) + '(0 . 0)) + 0.0)) -Align @var{arg} on its right edge. +(define-markup-command (auto-footnote layout props mkup note) + (markup? markup?) + #:category other + #:properties ((raise 0.5) + (padding 0.0)) + "Have footnote @var{note} act as an annotation to the markup @var{mkup}. @lilypond[verbatim,quote] \\markup { - \\column { - one - \\right-align - two - three - } + \\auto-footnote a b + \\override #'(padding . 0.2) + \\auto-footnote c d } address@hidden lilypond" - (let* ((m (interpret-markup layout props arg))) - (ly:stencil-aligned-to m X RIGHT))) address@hidden lilypond +The footnote will be annotated automatically." + (let* ((markup-stencil (interpret-markup layout props mkup)) + (auto-numbering (ly:output-def-lookup layout + 'footnote-auto-numbering)) + (footnote-hash (gensym "footnote")) + (stencil-seed 0) + (gauge-stencil (if auto-numbering + (interpret-markup + layout + props + ((ly:output-def-lookup + layout + 'footnote-numbering-function) + stencil-seed)) + empty-stencil)) + (x-ext (if auto-numbering + (ly:stencil-extent gauge-stencil X) + '(0 . 0))) + (y-ext (if auto-numbering + (ly:stencil-extent gauge-stencil Y) + '(0 . 0))) + (footnote-number + (if auto-numbering + `(delay-stencil-evaluation + ,(delay + (ly:stencil-expr + (let* ((table + (ly:output-def-lookup layout + 'number-footnote-table)) + (footnote-stencil (if (list? table) + (assoc-get footnote-hash + table) + empty-stencil)) + (footnote-stencil (if (ly:stencil? footnote-stencil) + footnote-stencil + (begin + (ly:programming-error +"Cannot find correct footnote for a markup object.") + empty-stencil))) + (gap (- (interval-length x-ext) + (interval-length + (ly:stencil-extent footnote-stencil X)))) + (y-trans (- (+ (cdr y-ext) + raise) + (cdr (ly:stencil-extent footnote-stencil + Y))))) + (ly:stencil-translate footnote-stencil + (cons gap y-trans)))))) + '())) + (main-stencil (ly:stencil-combine-at-edge + markup-stencil + X + RIGHT + (ly:make-stencil footnote-number x-ext y-ext) + padding))) + (ly:stencil-add + main-stencil + (ly:make-stencil + `(footnote ,footnote-hash #t ,(interpret-markup layout props note)) + '(0 . 0) + '(0 . 0))))) -(define-markup-command (left-align layout props arg) - (markup?) - #:category align +(define-markup-command (override layout props new-prop arg) + (pair? markup?) + #:category other " address@hidden left aligning text address@hidden overriding properties within text markup -Align @var{arg} on its left edge. +Add the argument @var{new-prop} to the property list. Properties +may be any property supported by @rinternals{font-interface}, address@hidden and address@hidden @lilypond[verbatim,quote] \\markup { - \\column { - one - \\left-align - two - three + \\line { + \\column { + default + baseline-skip + } + \\hspace #2 + \\override #'(baseline-skip . 4) { + \\column { + increased + baseline-skip + } + } } } @end lilypond" - (let* ((m (interpret-markup layout props arg))) - (ly:stencil-aligned-to m X LEFT))) + (interpret-markup layout (cons (list new-prop) props) arg)) -(define-markup-command (general-align layout props axis dir arg) - (integer? number? markup?) - #:category align - " address@hidden controlling general text alignment +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; files +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Align @var{arg} in @var{axis} direction to the @var{dir} side. +(define-markup-command (verbatim-file layout props name) + (string?) + #:category other + "Read the contents of file @var{name}, and include it verbatim. @lilypond[verbatim,quote] \\markup { - \\column { - one - \\general-align #X #LEFT - two - three - \\null - one - \\general-align #X #CENTER - two - three - \\null - \\line { - one - \\general-align #Y #UP - two - three - } - \\null - \\line { - one - \\general-align #Y #3.2 - two - three - } - } + \\verbatim-file #\"simple.ly\" } @end lilypond" - (let* ((m (interpret-markup layout props arg))) - (ly:stencil-aligned-to m axis dir))) + (interpret-markup layout props + (if (ly:get-option 'safe) + "verbatim-file disabled in safe mode" + (let* ((str (ly:gulp-file name)) + (lines (string-split str #\nl))) + (make-typewriter-markup + (make-column-markup lines)))))) -(define-markup-command (halign layout props dir arg) - (number? markup?) - #:category align - " address@hidden setting horizontal text alignment +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; fonts. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Set horizontal alignment. If @var{dir} is @address@hidden, then it is -left-aligned, while @code{+1} is right. Values in between interpolate -alignment accordingly. + +(define-markup-command (smaller layout props arg) + (markup?) + #:category font + "Decrease the font size relative to the current setting. @lilypond[verbatim,quote] \\markup { - \\column { - one - \\halign #LEFT - two - three - \\null - one - \\halign #CENTER - two - three - \\null - one - \\halign #RIGHT - two - three - \\null - one - \\halign #-5 - two - three + \\fontsize #3.5 { + some large text + \\hspace #2 + \\smaller { + a bit smaller + } + \\hspace #2 + more large text } } @end lilypond" - (let* ((m (interpret-markup layout props arg))) - (ly:stencil-aligned-to m X dir))) - -(define-markup-command (with-dimensions layout props x y arg) - (number-pair? number-pair? markup?) - #:category other - " address@hidden setting extent of text objects - -Set the dimensions of @var{arg} to @var{x} address@hidden@var{y}." - (let* ((m (interpret-markup layout props arg))) - (ly:make-stencil (ly:stencil-expr m) x y))) + (interpret-markup layout props + `(,fontsize-markup -1 ,arg))) -(define-markup-command (pad-around layout props amount arg) - (number? markup?) - #:category align - "Add padding @var{amount} all around @var{arg}. +(define-markup-command (larger layout props arg) + (markup?) + #:category font + "Increase the font size relative to the current setting. @lilypond[verbatim,quote] \\markup { - \\box { - default - } + default \\hspace #2 - \\box { - \\pad-around #0.5 { - padded - } - } + \\larger + larger } @end lilypond" - (let* ((m (interpret-markup layout props arg)) - (x (ly:stencil-extent m X)) - (y (ly:stencil-extent m Y))) - (ly:make-stencil (ly:stencil-expr m) - (interval-widen x amount) - (interval-widen y amount)))) - -(define-markup-command (pad-x layout props amount arg) - (number? markup?) - #:category align - " address@hidden padding text horizontally + (interpret-markup layout props + `(,fontsize-markup 1 ,arg))) -Add padding @var{amount} around @var{arg} in the address@hidden +(define-markup-command (finger layout props arg) + (markup?) + #:category font + "Set @var{arg} as small numbers. @lilypond[verbatim,quote] \\markup { - \\box { - default - } - \\hspace #4 - \\box { - \\pad-x #2 { - padded - } + \\finger { + 1 2 3 4 5 } } @end lilypond" - (let* ((m (interpret-markup layout props arg)) - (x (ly:stencil-extent m X)) - (y (ly:stencil-extent m Y))) - (ly:make-stencil (ly:stencil-expr m) - (interval-widen x amount) - y))) - -(define-markup-command (put-adjacent layout props axis dir arg1 arg2) - (integer? ly:dir? markup? markup?) - #:category align - "Put @var{arg2} next to @var{arg1}, without moving @var{arg1}." - (let ((m1 (interpret-markup layout props arg1)) - (m2 (interpret-markup layout props arg2))) - (ly:stencil-combine-at-edge m1 axis dir m2 0.0))) + (interpret-markup layout + (cons '((font-size . -5) (font-encoding . fetaText)) props) + arg)) -(define-markup-command (transparent layout props arg) - (markup?) - #:category other - "Make @var{arg} transparent. +(define-markup-command (abs-fontsize layout props size arg) + (number? markup?) + #:category font + "Use @var{size} as the absolute font size to display @var{arg}. +Adjusts @code{baseline-skip} and @code{word-space} accordingly. @lilypond[verbatim,quote] \\markup { - \\transparent { - invisible text - } + default text font size + \\hspace #2 + \\abs-fontsize #16 { text font size 16 } + \\hspace #2 + \\abs-fontsize #12 { text font size 12 } } @end lilypond" - (let* ((m (interpret-markup layout props arg)) - (x (ly:stencil-extent m X)) - (y (ly:stencil-extent m Y))) - (ly:make-stencil "" x y))) + (let* ((ref-size (ly:output-def-lookup layout 'text-font-size 12)) + (text-props (list (ly:output-def-lookup layout 'text-font-defaults))) + (ref-word-space (chain-assoc-get 'word-space text-props 0.6)) + (ref-baseline (chain-assoc-get 'baseline-skip text-props 3)) + (magnification (/ size ref-size))) + (interpret-markup + layout + (cons + `((baseline-skip . ,(* magnification ref-baseline)) + (word-space . ,(* magnification ref-word-space)) + (font-size . ,(magnification->font-size magnification))) + props) + arg))) -(define-markup-command (pad-to-box layout props x-ext y-ext arg) - (number-pair? number-pair? markup?) - #:category align - "Make @var{arg} take at least @var{x-ext}, @var{y-ext} space. +(define-markup-command (fontsize layout props increment arg) + (number? markup?) + #:category font + #:properties ((font-size 0) + (word-space 1) + (baseline-skip 2)) + "Add @var{increment} to the font-size. Adjusts @code{baseline-skip} +accordingly. @lilypond[verbatim,quote] \\markup { - \\box { - default - } - \\hspace #4 - \\box { - \\pad-to-box #'(0 . 10) #'(0 . 3) { - padded - } - } + default + \\hspace #2 + \\fontsize #-1.5 + smaller } @end lilypond" - (let* ((m (interpret-markup layout props arg)) - (x (ly:stencil-extent m X)) - (y (ly:stencil-extent m Y))) - (ly:make-stencil (ly:stencil-expr m) - (interval-union x-ext x) - (interval-union y-ext y)))) + (interpret-markup + layout + (cons + `((baseline-skip . ,(* baseline-skip (magstep increment))) + (word-space . ,(* word-space (magstep increment))) + (font-size . ,(+ font-size increment))) + props) + arg)) -(define-markup-command (hcenter-in layout props length arg) +(define-markup-command (magnify layout props sz arg) (number? markup?) - #:category align - "Center @var{arg} horizontally within a box of extending address@hidden/2 to the left and right. + #:category font + " address@hidden magnifying text address@hidden,verbatim] -\\new StaffGroup << - \\new Staff { - \\set Staff.instrumentName = \\markup { - \\hcenter-in #12 - Oboe - } - c''1 - } - \\new Staff { - \\set Staff.instrumentName = \\markup { - \\hcenter-in #12 - Bassoon - } - \\clef tenor - c'1 +Set the font magnification for its argument. In the following +example, the address@hidden is 10% larger: + address@hidden +A \\magnify #1.1 @{ A @} A address@hidden example + +Note: Magnification only works if a font name is explicitly selected. +Use @code{\\fontsize} otherwise. + address@hidden,quote] +\\markup { + default + \\hspace #2 + \\magnify #1.5 { + 50% larger } ->> +} @end lilypond" - (interpret-markup layout props - (make-pad-to-box-markup - (cons (/ length -2) (/ length 2)) - '(0 . 0) - (make-center-align-markup arg)))) + (interpret-markup + layout + (prepend-alist-chain 'font-size (magnification->font-size sz) props) + arg)) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; property -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(define-markup-command (bold layout props arg) + (markup?) + #:category font + "Switch to bold font-series. -(define-markup-command (property-recursive layout props symbol) - (symbol?) - #:category other - "Print out a warning when a header field markup contains some recursive -markup definition." - (ly:warning "Recursive definition of property ~a detected!" symbol) - empty-stencil) address@hidden,quote] +\\markup { + default + \\hspace #2 + \\bold + bold +} address@hidden lilypond" + (interpret-markup layout (prepend-alist-chain 'font-series 'bold props) arg)) -(define-markup-command (fromproperty layout props symbol) - (symbol?) - #:category other - "Read the @var{symbol} from property settings, and produce a stencil -from the markup contained within. If @var{symbol} is not defined, it -returns an empty markup. +(define-markup-command (sans layout props arg) + (markup?) + #:category font + "Switch to the sans serif font family. @lilypond[verbatim,quote] -\\header { - myTitle = \"myTitle\" - title = \\markup { - from - \\italic - \\fromproperty #'header:myTitle +\\markup { + default + \\hspace #2 + \\sans { + sans serif } } address@hidden lilypond" + (interpret-markup layout (prepend-alist-chain 'font-family 'sans props) arg)) + +(define-markup-command (number layout props arg) + (markup?) + #:category font + "Set font family to @code{number}, which yields the font used for +time signatures and fingerings. This font contains numbers and +some punctuation; it has no letters. + address@hidden,quote] \\markup { - \\null + \\number { + 0 1 2 3 4 5 6 7 8 9 . , + } } @end lilypond" - (let ((m (chain-assoc-get symbol props))) - (if (markup? m) - ;; prevent infinite loops by clearing the interpreted property: - (interpret-markup layout (cons (list (cons symbol `(,property-recursive-markup ,symbol))) props) m) - empty-stencil))) - -(define-markup-command (on-the-fly layout props procedure arg) - (procedure? markup?) - #:category other - "Apply the @var{procedure} markup command to @var{arg}. address@hidden should take a single argument." - (let ((anonymous-with-signature (lambda (layout props arg) (procedure layout props arg)))) - (set-object-property! anonymous-with-signature - 'markup-signature - (list markup?)) - (interpret-markup layout props (list anonymous-with-signature arg)))) + (interpret-markup layout (prepend-alist-chain 'font-encoding 'fetaText props) arg)) -(define-markup-command (footnote layout props mkup note) - (markup? markup?) - #:category other - "Have footnote @var{note} act as an annotation to the markup @var{mkup}. +(define-markup-command (roman layout props arg) + (markup?) + #:category font + "Set font family to @code{roman}. @lilypond[verbatim,quote] \\markup { - \\auto-footnote a b - \\override #'(padding . 0.2) - \\auto-footnote c d + \\sans \\bold { + sans serif, bold + \\hspace #2 + \\roman { + text in roman font family + } + \\hspace #2 + return to sans + } } address@hidden lilypond -The footnote will not be annotated automatically." - (ly:stencil-combine-at-edge - (interpret-markup layout props mkup) - X - RIGHT - (ly:make-stencil - `(footnote (gensym "footnote") #f ,(interpret-markup layout props note)) - '(0 . 0) - '(0 . 0)) - 0.0)) address@hidden lilypond" + (interpret-markup layout (prepend-alist-chain 'font-family 'roman props) arg)) -(define-markup-command (auto-footnote layout props mkup note) - (markup? markup?) - #:category other - #:properties ((raise 0.5) - (padding 0.0)) - "Have footnote @var{note} act as an annotation to the markup @var{mkup}. +(define-markup-command (huge layout props arg) + (markup?) + #:category font + "Set font size to +2. @lilypond[verbatim,quote] \\markup { - \\auto-footnote a b - \\override #'(padding . 0.2) - \\auto-footnote c d -} address@hidden lilypond -The footnote will be annotated automatically." - (let* ((markup-stencil (interpret-markup layout props mkup)) - (auto-numbering (ly:output-def-lookup layout - 'footnote-auto-numbering)) - (footnote-hash (gensym "footnote")) - (stencil-seed 0) - (gauge-stencil (if auto-numbering - (interpret-markup - layout - props - ((ly:output-def-lookup - layout - 'footnote-numbering-function) - stencil-seed)) - empty-stencil)) - (x-ext (if auto-numbering - (ly:stencil-extent gauge-stencil X) - '(0 . 0))) - (y-ext (if auto-numbering - (ly:stencil-extent gauge-stencil Y) - '(0 . 0))) - (footnote-number - (if auto-numbering - `(delay-stencil-evaluation - ,(delay - (ly:stencil-expr - (let* ((table - (ly:output-def-lookup layout - 'number-footnote-table)) - (footnote-stencil (if (list? table) - (assoc-get footnote-hash - table) - empty-stencil)) - (footnote-stencil (if (ly:stencil? footnote-stencil) - footnote-stencil - (begin - (ly:programming-error -"Cannot find correct footnote for a markup object.") - empty-stencil))) - (gap (- (interval-length x-ext) - (interval-length - (ly:stencil-extent footnote-stencil X)))) - (y-trans (- (+ (cdr y-ext) - raise) - (cdr (ly:stencil-extent footnote-stencil - Y))))) - (ly:stencil-translate footnote-stencil - (cons gap y-trans)))))) - '())) - (main-stencil (ly:stencil-combine-at-edge - markup-stencil - X - RIGHT - (ly:make-stencil footnote-number x-ext y-ext) - padding))) - (ly:stencil-add - main-stencil - (ly:make-stencil - `(footnote ,footnote-hash #t ,(interpret-markup layout props note)) - '(0 . 0) - '(0 . 0))))) - -(define-markup-command (override layout props new-prop arg) - (pair? markup?) - #:category other - " address@hidden overriding properties within text markup - -Add the argument @var{new-prop} to the property list. Properties -may be any property supported by @rinternals{font-interface}, address@hidden and address@hidden - address@hidden,quote] -\\markup { - \\line { - \\column { - default - baseline-skip - } - \\hspace #2 - \\override #'(baseline-skip . 4) { - \\column { - increased - baseline-skip - } - } - } + default + \\hspace #2 + \\huge + huge } @end lilypond" - (interpret-markup layout (cons (list new-prop) props) arg)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; files -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (interpret-markup layout (prepend-alist-chain 'font-size 2 props) arg)) -(define-markup-command (verbatim-file layout props name) - (string?) - #:category other - "Read the contents of file @var{name}, and include it verbatim. +(define-markup-command (large layout props arg) + (markup?) + #:category font + "Set font size to +1. @lilypond[verbatim,quote] \\markup { - \\verbatim-file #\"simple.ly\" + default + \\hspace #2 + \\large + large } @end lilypond" - (interpret-markup layout props - (if (ly:get-option 'safe) - "verbatim-file disabled in safe mode" - (let* ((str (ly:gulp-file name)) - (lines (string-split str #\nl))) - (make-typewriter-markup - (make-column-markup lines)))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; fonts. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - + (interpret-markup layout (prepend-alist-chain 'font-size 1 props) arg)) -(define-markup-command (smaller layout props arg) +(define-markup-command (normalsize layout props arg) (markup?) #:category font - "Decrease the font size relative to the current setting. + "Set font size to default. @lilypond[verbatim,quote] \\markup { - \\fontsize #3.5 { - some large text + \\teeny { + this is very small \\hspace #2 - \\smaller { - a bit smaller + \\normalsize { + normal size } \\hspace #2 - more large text + teeny again } } @end lilypond" - (interpret-markup layout props - `(,fontsize-markup -1 ,arg))) + (interpret-markup layout (prepend-alist-chain 'font-size 0 props) arg)) -(define-markup-command (larger layout props arg) +(define-markup-command (small layout props arg) (markup?) #:category font - "Increase the font size relative to the current setting. + "Set font size to -1. @lilypond[verbatim,quote] \\markup { default \\hspace #2 - \\larger - larger + \\small + small } @end lilypond" - (interpret-markup layout props - `(,fontsize-markup 1 ,arg))) + (interpret-markup layout (prepend-alist-chain 'font-size -1 props) arg)) -(define-markup-command (finger layout props arg) +(define-markup-command (tiny layout props arg) (markup?) #:category font - "Set @var{arg} as small numbers. - address@hidden,quote] -\\markup { - \\finger { - 1 2 3 4 5 - } -} address@hidden lilypond" - (interpret-markup layout - (cons '((font-size . -5) (font-encoding . fetaText)) props) - arg)) - -(define-markup-command (abs-fontsize layout props size arg) - (number? markup?) - #:category font - "Use @var{size} as the absolute font size to display @var{arg}. -Adjusts @code{baseline-skip} and @code{word-space} accordingly. + "Set font size to -2. @lilypond[verbatim,quote] \\markup { - default text font size - \\hspace #2 - \\abs-fontsize #16 { text font size 16 } + default \\hspace #2 - \\abs-fontsize #12 { text font size 12 } + \\tiny + tiny } @end lilypond" - (let* ((ref-size (ly:output-def-lookup layout 'text-font-size 12)) - (text-props (list (ly:output-def-lookup layout 'text-font-defaults))) - (ref-word-space (chain-assoc-get 'word-space text-props 0.6)) - (ref-baseline (chain-assoc-get 'baseline-skip text-props 3)) - (magnification (/ size ref-size))) - (interpret-markup - layout - (cons - `((baseline-skip . ,(* magnification ref-baseline)) - (word-space . ,(* magnification ref-word-space)) - (font-size . ,(magnification->font-size magnification))) - props) - arg))) + (interpret-markup layout (prepend-alist-chain 'font-size -2 props) arg)) -(define-markup-command (fontsize layout props increment arg) - (number? markup?) +(define-markup-command (teeny layout props arg) + (markup?) #:category font - #:properties ((font-size 0) - (word-space 1) - (baseline-skip 2)) - "Add @var{increment} to the font-size. Adjusts @code{baseline-skip} -accordingly. + "Set font size to -3. @lilypond[verbatim,quote] \\markup { default \\hspace #2 - \\fontsize #-1.5 - smaller + \\teeny + teeny } @end lilypond" - (interpret-markup - layout - (cons - `((baseline-skip . ,(* baseline-skip (magstep increment))) - (word-space . ,(* word-space (magstep increment))) - (font-size . ,(+ font-size increment))) - props) - arg)) + (interpret-markup layout (prepend-alist-chain 'font-size -3 props) arg)) -(define-markup-command (magnify layout props sz arg) - (number? markup?) +(define-markup-command (fontCaps layout props arg) + (markup?) #:category font - " address@hidden magnifying text + "Set @code{font-shape} to @code{caps} -Set the font magnification for its argument. In the following -example, the address@hidden is 10% larger: +Note: @code{\\fontCaps} requires the installation and selection of +fonts which support the @code{caps} font shape." + (interpret-markup layout (prepend-alist-chain 'font-shape 'caps props) arg)) address@hidden -A \\magnify #1.1 @{ A @} A address@hidden example +;; Poor man's caps -Note: Magnification only works if a font name is explicitly selected. -Use @code{\\fontsize} otherwise. +;;(define-markup-command (smallCaps layout props arg) +;; (markup?) +;; #:category font +;; "Emit @var{arg} as small caps. +;; +;;Note: @code{\\smallCaps} does not support accented characters. +;; +;;@lilypond[verbatim,quote] +;;\\markup { +;; default +;; \\hspace #2 +;; \\smallCaps { +;; Text in small caps +;; } +;;} +;;@end lilypond" +;; (define (char-list->markup chars lower) +;; (let ((final-string (string-upcase (reverse-list->string chars)))) +;; (if lower +;; (markup #:fontsize -2 final-string) +;; final-string))) +;; (define (make-small-caps rest-chars currents current-is-lower prev-result) +;; (if (null? rest-chars) +;; (make-concat-markup +;; (reverse! (cons (char-list->markup currents current-is-lower) +;; prev-result))) +;; (let* ((ch (car rest-chars)) +;; (is-lower (char-lower-case? ch))) +;; (if (or (and current-is-lower is-lower) +;; (and (not current-is-lower) (not is-lower))) +;; (make-small-caps (cdr rest-chars) +;; (cons ch currents) +;; is-lower +;; prev-result) +;; (make-small-caps (cdr rest-chars) +;; (list ch) +;; is-lower +;; (if (null? currents) +;; prev-result +;; (cons (char-list->markup +;; currents current-is-lower) +;; prev-result))))))) +;; (interpret-markup layout props +;; (if (string? arg) +;; (make-small-caps (string->list arg) (list) #f (list)) +;; arg))) + +(define-markup-command (caps layout props arg) + (markup?) + #:category font + "Copy of the @code{\\smallCaps} command. @lilypond[verbatim,quote] \\markup { default \\hspace #2 - \\magnify #1.5 { - 50% larger + \\caps { + Text in small caps } } @end lilypond" - (interpret-markup - layout - (prepend-alist-chain 'font-size (magnification->font-size sz) props) - arg)) + (interpret-markup layout props (make-smallCaps-markup arg))) -(define-markup-command (bold layout props arg) - (markup?) - #:category font - "Switch to bold font-series. - address@hidden,quote] -\\markup { - default - \\hspace #2 - \\bold - bold -} address@hidden lilypond" - (interpret-markup layout (prepend-alist-chain 'font-series 'bold props) arg)) - -(define-markup-command (sans layout props arg) - (markup?) - #:category font - "Switch to the sans serif font family. - address@hidden,quote] -\\markup { - default - \\hspace #2 - \\sans { - sans serif - } -} address@hidden lilypond" - (interpret-markup layout (prepend-alist-chain 'font-family 'sans props) arg)) - -(define-markup-command (number layout props arg) - (markup?) - #:category font - "Set font family to @code{number}, which yields the font used for -time signatures and fingerings. This font contains numbers and -some punctuation; it has no letters. - address@hidden,quote] -\\markup { - \\number { - 0 1 2 3 4 5 6 7 8 9 . , - } -} address@hidden lilypond" - (interpret-markup layout (prepend-alist-chain 'font-encoding 'fetaText props) arg)) - -(define-markup-command (roman layout props arg) - (markup?) - #:category font - "Set font family to @code{roman}. - address@hidden,quote] -\\markup { - \\sans \\bold { - sans serif, bold - \\hspace #2 - \\roman { - text in roman font family - } - \\hspace #2 - return to sans - } -} address@hidden lilypond" - (interpret-markup layout (prepend-alist-chain 'font-family 'roman props) arg)) - -(define-markup-command (huge layout props arg) - (markup?) - #:category font - "Set font size to +2. - address@hidden,quote] -\\markup { - default - \\hspace #2 - \\huge - huge -} address@hidden lilypond" - (interpret-markup layout (prepend-alist-chain 'font-size 2 props) arg)) - -(define-markup-command (large layout props arg) - (markup?) - #:category font - "Set font size to +1. - address@hidden,quote] -\\markup { - default - \\hspace #2 - \\large - large -} address@hidden lilypond" - (interpret-markup layout (prepend-alist-chain 'font-size 1 props) arg)) - -(define-markup-command (normalsize layout props arg) - (markup?) - #:category font - "Set font size to default. - address@hidden,quote] -\\markup { - \\teeny { - this is very small - \\hspace #2 - \\normalsize { - normal size - } - \\hspace #2 - teeny again - } -} address@hidden lilypond" - (interpret-markup layout (prepend-alist-chain 'font-size 0 props) arg)) - -(define-markup-command (small layout props arg) - (markup?) - #:category font - "Set font size to -1. - address@hidden,quote] -\\markup { - default - \\hspace #2 - \\small - small -} address@hidden lilypond" - (interpret-markup layout (prepend-alist-chain 'font-size -1 props) arg)) - -(define-markup-command (tiny layout props arg) - (markup?) - #:category font - "Set font size to -2. - address@hidden,quote] -\\markup { - default - \\hspace #2 - \\tiny - tiny -} address@hidden lilypond" - (interpret-markup layout (prepend-alist-chain 'font-size -2 props) arg)) - -(define-markup-command (teeny layout props arg) - (markup?) - #:category font - "Set font size to -3. - address@hidden,quote] -\\markup { - default - \\hspace #2 - \\teeny - teeny -} address@hidden lilypond" - (interpret-markup layout (prepend-alist-chain 'font-size -3 props) arg)) - -(define-markup-command (fontCaps layout props arg) - (markup?) - #:category font - "Set @code{font-shape} to @code{caps} - -Note: @code{\\fontCaps} requires the installation and selection of -fonts which support the @code{caps} font shape." - (interpret-markup layout (prepend-alist-chain 'font-shape 'caps props) arg)) - -;; Poor man's caps -(define-markup-command (smallCaps layout props arg) - (markup?) - #:category font - "Emit @var{arg} as small caps. - -Note: @code{\\smallCaps} does not support accented characters. - address@hidden,quote] -\\markup { - default - \\hspace #2 - \\smallCaps { - Text in small caps - } -} address@hidden lilypond" - (define (char-list->markup chars lower) - (let ((final-string (string-upcase (reverse-list->string chars)))) - (if lower - (markup #:fontsize -2 final-string) - final-string))) - (define (make-small-caps rest-chars currents current-is-lower prev-result) - (if (null? rest-chars) - (make-concat-markup - (reverse! (cons (char-list->markup currents current-is-lower) - prev-result))) - (let* ((ch (car rest-chars)) - (is-lower (char-lower-case? ch))) - (if (or (and current-is-lower is-lower) - (and (not current-is-lower) (not is-lower))) - (make-small-caps (cdr rest-chars) - (cons ch currents) - is-lower - prev-result) - (make-small-caps (cdr rest-chars) - (list ch) - is-lower - (if (null? currents) - prev-result - (cons (char-list->markup - currents current-is-lower) - prev-result))))))) - (interpret-markup layout props - (if (string? arg) - (make-small-caps (string->list arg) (list) #f (list)) - arg))) - -(define-markup-command (caps layout props arg) - (markup?) - #:category font - "Copy of the @code{\\smallCaps} command. - address@hidden,quote] -\\markup { - default - \\hspace #2 - \\caps { - Text in small caps - } -} address@hidden lilypond" - (interpret-markup layout props (make-smallCaps-markup arg))) - -(define-markup-command (dynamic layout props arg) +(define-markup-command (dynamic layout props arg) (markup?) #:category font "Use the dynamic font. This font only contains @b{s}, @b{f}, @b{m}, @@ -2624,7 +2192,7 @@ the possible glyphs. (ly:warning (_ "Cannot find glyph ~a") glyph-name)) glyph)) - +;(start-repl) (define-markup-command (doublesharp layout props) () #:category music @@ -2758,39 +2326,127 @@ Draw @var{arg} in color specified by @var{color}. (ly:stencil-extent stil X) (ly:stencil-extent stil Y)))) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; glyphs -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define-markup-command (arrow-head layout props axis dir filled) - (integer? ly:dir? boolean?) - #:category graphic - "Produce an arrow head in specified direction and axis. -Use the filled head if @var{filled} is specified. +(define-markup-command (tied-lyric layout props str) + (string?) + #:category music + #:properties ((word-space)) + " address@hidden simple text strings with tie characters + +Like simple-markup, but use tie characters for @q{~} tilde symbols. + @lilypond[verbatim,quote] -\\markup { - \\fontsize #5 { - \\general-align #Y #DOWN { - \\arrow-head #Y #UP ##t - \\arrow-head #Y #DOWN ##f - \\hspace #2 - \\arrow-head #X #RIGHT ##f - \\arrow-head #X #LEFT ##f - } - } +\\markup \\column { + \\tied-lyric #\"Siam navi~all'onde~algenti Lasciate~in abbandono\" + \\tied-lyric #\"Impetuosi venti I nostri~affetti sono\" + \\tied-lyric #\"Ogni diletto~e scoglio Tutta la vita~e~un mar.\" } @end lilypond" - (let* - ((name (format #f "arrowheads.~a.~a~a" - (if filled - "close" - "open") - axis - dir))) - (ly:font-get-glyph - (ly:paper-get-font layout (cons '((font-encoding . fetaMusic)) - props)) - name))) + (define (replace-ties tie str) + (if (string-contains str "~") + (let* + ((half-space (/ word-space 2)) + (parts (string-split str #\~)) + (tie-str (markup #:hspace half-space + #:musicglyph tie + #:hspace half-space)) + (joined (list-join parts tie-str))) + (make-concat-markup joined)) + str)) + + (define short-tie-regexp (make-regexp "~[^.]~")) + (define (match-short str) (regexp-exec short-tie-regexp str)) + + (define (replace-short str mkp) + (let ((match (match-short str))) + (if (not match) + (make-concat-markup (list + mkp + (replace-ties "ties.lyric.default" str))) + (let ((new-str (match:suffix match)) + (new-mkp (make-concat-markup (list + mkp + (replace-ties "ties.lyric.default" + (match:prefix match)) + (replace-ties "ties.lyric.short" + (match:substring match)))))) + (replace-short new-str new-mkp))))) + + (interpret-markup layout + props + (replace-short str (markup)))) + +(define-public empty-markup + (make-simple-markup "")) + +;; helper for justifying lines. +(define (get-fill-space word-count line-width word-space text-widths) + "Calculate the necessary paddings between each two adjacent texts. + The lengths of all texts are stored in @var{text-widths}. + The normal formula for the padding between texts a and b is: + padding = line-width/(word-count - 1) - (length(a) + length(b))/2 + The first and last padding have to be calculated specially using the + whole length of the first or last text. + All paddings are checked to be at least word-space, to ensure that + no texts collide. + Return a list of paddings." + (cond + ((null? text-widths) '()) + + ;; special case first padding + ((= (length text-widths) word-count) + (cons + (- (- (/ line-width (1- word-count)) (car text-widths)) + (/ (car (cdr text-widths)) 2)) + (get-fill-space word-count line-width word-space (cdr text-widths)))) + ;; special case last padding + ((= (length text-widths) 2) + (list (- (/ line-width (1- word-count)) + (+ (/ (car text-widths) 2) (car (cdr text-widths)))) 0)) + (else + (let ((default-padding + (- (/ line-width (1- word-count)) + (/ (+ (car text-widths) (car (cdr text-widths))) 2)))) + (cons + (if (> word-space default-padding) + word-space + default-padding) + (get-fill-space word-count line-width word-space (cdr text-widths))))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; glyphs +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-markup-command (arrow-head layout props axis dir filled) + (integer? ly:dir? boolean?) + #:category graphic + "Produce an arrow head in specified direction and axis. +Use the filled head if @var{filled} is specified. address@hidden,quote] +\\markup { + \\fontsize #5 { + \\general-align #Y #DOWN { + \\arrow-head #Y #UP ##t + \\arrow-head #Y #DOWN ##f + \\hspace #2 + \\arrow-head #X #RIGHT ##f + \\arrow-head #X #LEFT ##f + } + } +} address@hidden lilypond" + (let* + ((name (format #f "arrowheads.~a.~a~a" + (if filled + "close" + "open") + axis + dir))) + (ly:font-get-glyph + (ly:paper-get-font layout (cons '((font-encoding . fetaMusic)) + props)) + name))) (define-markup-command (lookup layout props glyph-name) (string?) @@ -3215,507 +2871,867 @@ the @var{duration} for the note head type and augmentation dots. For example, @code{\\note #\"4.\" #-0.75} creates a dotted quarter note, with a shortened down stem. address@hidden,quote] -\\markup { - \\override #'(style . cross) { - \\note #\"4..\" #UP - } - \\hspace #2 - \\note #\"breve\" #0 -} address@hidden lilypond" - (let ((parsed (parse-simple-duration duration))) - (note-by-number-markup layout props (car parsed) (cadr parsed) dir))) address@hidden,quote] +\\markup { + \\override #'(style . cross) { + \\note #\"4..\" #UP + } + \\hspace #2 + \\note #\"breve\" #0 +} address@hidden lilypond" + (let ((parsed (parse-simple-duration duration))) + (note-by-number-markup layout props (car parsed) (cadr parsed) dir))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; translating. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-markup-command (lower layout props amount arg) + (number? markup?) + #:category align + " address@hidden lowering text + +Lower @var{arg} by the distance @var{amount}. +A negative @var{amount} indicates raising; see also @code{\\raise}. + address@hidden,quote] +\\markup { + one + \\lower #3 + two + three +} address@hidden lilypond" + (ly:stencil-translate-axis (interpret-markup layout props arg) + (- amount) Y)) + +(define-markup-command (translate-scaled layout props offset arg) + (number-pair? markup?) + #:category align + #:properties ((font-size 0)) + " address@hidden translating text address@hidden scaling text + +Translate @var{arg} by @var{offset}, scaling the offset by the address@hidden + address@hidden,quote] +\\markup { + \\fontsize #5 { + * \\translate #'(2 . 3) translate + \\hspace #2 + * \\translate-scaled #'(2 . 3) translate-scaled + } +} address@hidden lilypond" + (let* ((factor (magstep font-size)) + (scaled (cons (* factor (car offset)) + (* factor (cdr offset))))) + (ly:stencil-translate (interpret-markup layout props arg) + scaled))) + +(define-markup-command (raise layout props amount arg) + (number? markup?) + #:category align + " address@hidden raising text + +Raise @var{arg} by the distance @var{amount}. +A negative @var{amount} indicates lowering, see also @code{\\lower}. + +The argument to @code{\\raise} is the vertical displacement amount, +measured in (global) staff spaces. @code{\\raise} and @code{\\super} +raise objects in relation to their surrounding markups. + +If the text object itself is positioned above or below the staff, then address@hidden cannot be used to move it, since the mechanism that +positions it next to the staff cancels any shift made with address@hidden For vertical positioning, use the @code{padding} +and/or @code{extra-offset} properties. + address@hidden,quote] +\\markup { + C + \\small + \\bold + \\raise #1.0 + 9/7+ +} address@hidden lilypond" + (ly:stencil-translate-axis (interpret-markup layout props arg) amount Y)) + +(define-markup-command (fraction layout props arg1 arg2) + (markup? markup?) + #:category other + #:properties ((font-size 0)) + " address@hidden creating text fractions + +Make a fraction of two markups. address@hidden,quote] +\\markup { + Ï â + \\fraction 355 113 +} address@hidden lilypond" + (let* ((m1 (interpret-markup layout props arg1)) + (m2 (interpret-markup layout props arg2)) + (factor (magstep font-size)) + (boxdimen (cons (* factor -0.05) (* factor 0.05))) + (padding (* factor 0.2)) + (baseline (* factor 0.6)) + (offset (* factor 0.75))) + (set! m1 (ly:stencil-aligned-to m1 X CENTER)) + (set! m2 (ly:stencil-aligned-to m2 X CENTER)) + (let* ((x1 (ly:stencil-extent m1 X)) + (x2 (ly:stencil-extent m2 X)) + (line (ly:round-filled-box (interval-union x1 x2) boxdimen 0.0)) + ;; should stack mols separately, to maintain LINE on baseline + (stack (stack-lines DOWN padding baseline (list m1 line m2)))) + (set! stack + (ly:stencil-aligned-to stack Y CENTER)) + (set! stack + (ly:stencil-aligned-to stack X LEFT)) + ;; should have EX dimension + ;; empirical anyway + (ly:stencil-translate-axis stack offset Y)))) + +(define-markup-command (normal-size-super layout props arg) + (markup?) + #:category font + #:properties ((baseline-skip)) + " address@hidden setting superscript in standard font size + +Set @var{arg} in superscript with a normal font size. + address@hidden,quote] +\\markup { + default + \\normal-size-super { + superscript in standard size + } +} address@hidden lilypond" + (ly:stencil-translate-axis + (interpret-markup layout props arg) + (* 0.5 baseline-skip) Y)) + +(define-markup-command (super layout props arg) + (markup?) + #:category font + #:properties ((font-size 0) + (baseline-skip)) + " address@hidden superscript text + +Set @var{arg} in superscript. + address@hidden,quote] +\\markup { + E = + \\concat { + mc + \\super + 2 + } +} address@hidden lilypond" + (ly:stencil-translate-axis + (interpret-markup + layout + (cons `((font-size . ,(- font-size 3))) props) + arg) + (* 0.5 baseline-skip) + Y)) + +(define-markup-command (translate layout props offset arg) + (number-pair? markup?) + #:category align + " address@hidden translating text + +Translate @var{arg} relative to its surroundings. @var{offset} +is a pair of numbers representing the displacement in the X and Y axis. + address@hidden,quote] +\\markup { + * + \\translate #'(2 . 3) + \\line { translated two spaces right, three up } +} address@hidden lilypond" + (ly:stencil-translate (interpret-markup layout props arg) + offset)) + +(define-markup-command (sub layout props arg) + (markup?) + #:category font + #:properties ((font-size 0) + (baseline-skip)) + " address@hidden subscript text + +Set @var{arg} in subscript. + address@hidden,quote] +\\markup { + \\concat { + H + \\sub { + 2 + } + O + } +} address@hidden lilypond" + (ly:stencil-translate-axis + (interpret-markup + layout + (cons `((font-size . ,(- font-size 3))) props) + arg) + (* -0.5 baseline-skip) + Y)) + +(define-markup-command (normal-size-sub layout props arg) + (markup?) + #:category font + #:properties ((baseline-skip)) + " address@hidden setting subscript in standard font size + +Set @var{arg} in subscript with a normal font size. + address@hidden,quote] +\\markup { + default + \\normal-size-sub { + subscript in standard size + } +} address@hidden lilypond" + (ly:stencil-translate-axis + (interpret-markup layout props arg) + (* -0.5 baseline-skip) + Y)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; brackets. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-markup-command (hbracket layout props arg) + (markup?) + #:category graphic + " address@hidden placing horizontal brackets around text + +Draw horizontal brackets around @var{arg}. + address@hidden,quote] +\\markup { + \\hbracket { + \\line { + one two three + } + } +} address@hidden lilypond" + (let ((th 0.1) ;; todo: take from GROB. + (m (interpret-markup layout props arg))) + (bracketify-stencil m X th (* 2.5 th) th))) + +(define-markup-command (bracket layout props arg) + (markup?) + #:category graphic + " address@hidden placing vertical brackets around text + +Draw vertical brackets around @var{arg}. + address@hidden,quote] +\\markup { + \\bracket { + \\note #\"2.\" #UP + } +} address@hidden lilypond" + (let ((th 0.1) ;; todo: take from GROB. + (m (interpret-markup layout props arg))) + (bracketify-stencil m Y th (* 2.5 th) th))) + +(define-markup-command (parenthesize layout props arg) + (markup?) + #:category graphic + #:properties ((angularity 0) + (padding) + (size 1) + (thickness 1) + (width 0.25)) + " address@hidden placing parentheses around text + +Draw parentheses around @var{arg}. This is useful for parenthesizing +a column containing several lines of text. + address@hidden,quote] +\\markup { + \\line { + \\parenthesize { + \\column { + foo + bar + } + } + \\override #'(angularity . 2) { + \\parenthesize { + \\column { + bah + baz + } + } + } + } +} address@hidden lilypond" + (let* ((markup (interpret-markup layout props arg)) + (scaled-width (* size width)) + (scaled-thickness + (* (chain-assoc-get 'line-thickness props 0.1) + thickness)) + (half-thickness + (min (* size 0.5 scaled-thickness) + (* (/ 4 3.0) scaled-width))) + (padding (chain-assoc-get 'padding props half-thickness))) + (parenthesize-stencil + markup half-thickness scaled-width angularity padding))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; translating. +;; Delayed markup evaluation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define-markup-command (lower layout props amount arg) - (number? markup?) - #:category align +(define-markup-command (page-ref layout props label gauge default) + (symbol? markup? markup?) + #:category other " address@hidden lowering text address@hidden referencing page numbers in text -Lower @var{arg} by the distance @var{amount}. -A negative @var{amount} indicates raising; see also @code{\\raise}. +Reference to a page number. @var{label} is the label set on the referenced +page (using the @code{\\label} command), @var{gauge} a markup used to estimate +the maximum width of the page number, and @var{default} the value to display +when @var{label} is not found." + (let* ((gauge-stencil (interpret-markup layout props gauge)) + (x-ext (ly:stencil-extent gauge-stencil X)) + (y-ext (ly:stencil-extent gauge-stencil Y))) + (ly:make-stencil + `(delay-stencil-evaluation + ,(delay (ly:stencil-expr + (let* ((table (ly:output-def-lookup layout 'label-page-table)) + (page-number (if (list? table) + (assoc-get label table) + #f)) + (page-markup (if page-number (format #f "~a" page-number) default)) + (page-stencil (interpret-markup layout props page-markup)) + (gap (- (interval-length x-ext) + (interval-length (ly:stencil-extent page-stencil X))))) + (interpret-markup layout props + (markup #:concat (#:hspace gap page-markup))))))) + x-ext + y-ext))) address@hidden,quote] -\\markup { - one - \\lower #3 - two - three -} address@hidden lilypond" - (ly:stencil-translate-axis (interpret-markup layout props arg) - (- amount) Y)) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; scaling +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define-markup-command (translate-scaled layout props offset arg) +(define-markup-command (scale layout props factor-pair arg) (number-pair? markup?) - #:category align - #:properties ((font-size 0)) + #:category graphic " address@hidden translating text address@hidden scaling text address@hidden scaling markup address@hidden mirroring markup -Translate @var{arg} by @var{offset}, scaling the offset by the address@hidden +Scale @var{arg}. @var{factor-pair} is a pair of numbers +representing the scaling-factor in the X and Y axes. +Negative values may be used to produce mirror images. @lilypond[verbatim,quote] \\markup { - \\fontsize #5 { - * \\translate #'(2 . 3) translate - \\hspace #2 - * \\translate-scaled #'(2 . 3) translate-scaled + \\line { + \\scale #'(2 . 1) + stretched + \\scale #'(1 . -1) + mirrored } } @end lilypond" - (let* ((factor (magstep font-size)) - (scaled (cons (* factor (car offset)) - (* factor (cdr offset))))) - (ly:stencil-translate (interpret-markup layout props arg) - scaled))) - -(define-markup-command (raise layout props amount arg) - (number? markup?) - #:category align - " address@hidden raising text - -Raise @var{arg} by the distance @var{amount}. -A negative @var{amount} indicates lowering, see also @code{\\lower}. + (let ((stil (interpret-markup layout props arg)) + (sx (car factor-pair)) + (sy (cdr factor-pair))) + (ly:stencil-scale stil sx sy))) -The argument to @code{\\raise} is the vertical displacement amount, -measured in (global) staff spaces. @code{\\raise} and @code{\\super} -raise objects in relation to their surrounding markups. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Repeating +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -If the text object itself is positioned above or below the staff, then address@hidden cannot be used to move it, since the mechanism that -positions it next to the staff cancels any shift made with address@hidden For vertical positioning, use the @code{padding} -and/or @code{extra-offset} properties. +(define-markup-command (pattern layout props count axis space pattern) + (integer? integer? number? markup?) + #:category other + " +Prints @var{count} times a @var{pattern} markup. +Patterns are spaced apart by @var{space}. +Patterns are distributed on @var{axis}. address@hidden,quote] -\\markup { - C - \\small - \\bold - \\raise #1.0 - 9/7+ address@hidden, quote] +\\markup \\column { + \"Horizontally repeated :\" + \\pattern #7 #X #2 \\flat + \\null + \"Vertically repeated :\" + \\pattern #3 #Y #0.5 \\flat } @end lilypond" - (ly:stencil-translate-axis (interpret-markup layout props arg) amount Y)) + (let ((pattern-width (interval-length + (ly:stencil-extent (interpret-markup layout props pattern) X))) + (new-props (prepend-alist-chain 'word-space 0 (prepend-alist-chain 'baseline-skip 0 props)))) + (let loop ((i (1- count)) (patterns (markup))) + (if (zero? i) + (interpret-markup + layout + new-props + (if (= axis X) + (markup patterns pattern) + (markup #:column (patterns pattern)))) + (loop (1- i) + (if (= axis X) + (markup patterns pattern #:hspace space) + (markup #:column (patterns pattern #:vspace space)))))))) -(define-markup-command (fraction layout props arg1 arg2) - (markup? markup?) - #:category other - #:properties ((font-size 0)) +(define-markup-command (fill-with-pattern layout props space dir pattern left right) + (number? ly:dir? markup? markup? markup?) + #:category align + #:properties ((word-space) + (line-width)) " address@hidden creating text fractions +Put @var{left} and @var{right} in a horizontal line of width @code{line-width} +with a line of markups @var{pattern} in between. +Patterns are spaced apart by @var{space}. +Patterns are aligned to the @var{dir} markup. -Make a fraction of two markups. address@hidden,quote] -\\markup { - Ï â - \\fraction 355 113 address@hidden, quote] +\\markup \\column { + \"right-aligned :\" + \\fill-with-pattern #1 #RIGHT . first right + \\fill-with-pattern #1 #RIGHT . second right + \\null + \"center-aligned :\" + \\fill-with-pattern #1.5 #CENTER - left right + \\null + \"left-aligned :\" + \\override #'(line-width . 50) + \\fill-with-pattern #2 #LEFT : left first + \\override #'(line-width . 50) + \\fill-with-pattern #2 #LEFT : left second } @end lilypond" - (let* ((m1 (interpret-markup layout props arg1)) - (m2 (interpret-markup layout props arg2)) - (factor (magstep font-size)) - (boxdimen (cons (* factor -0.05) (* factor 0.05))) - (padding (* factor 0.2)) - (baseline (* factor 0.6)) - (offset (* factor 0.75))) - (set! m1 (ly:stencil-aligned-to m1 X CENTER)) - (set! m2 (ly:stencil-aligned-to m2 X CENTER)) - (let* ((x1 (ly:stencil-extent m1 X)) - (x2 (ly:stencil-extent m2 X)) - (line (ly:round-filled-box (interval-union x1 x2) boxdimen 0.0)) - ;; should stack mols separately, to maintain LINE on baseline - (stack (stack-lines DOWN padding baseline (list m1 line m2)))) - (set! stack - (ly:stencil-aligned-to stack Y CENTER)) - (set! stack - (ly:stencil-aligned-to stack X LEFT)) - ;; should have EX dimension - ;; empirical anyway - (ly:stencil-translate-axis stack offset Y)))) + (let* ((pattern-x-extent (ly:stencil-extent (interpret-markup layout props pattern) X)) + (pattern-width (interval-length pattern-x-extent)) + (left-width (interval-length (ly:stencil-extent (interpret-markup layout props left) X))) + (right-width (interval-length (ly:stencil-extent (interpret-markup layout props right) X))) + (middle-width (max 0 (- line-width (+ (+ left-width right-width) (* word-space 2))))) + (period (+ space pattern-width)) + (count (truncate (/ (- middle-width pattern-width) period))) + (x-offset (+ (* (- (- middle-width (* count period)) pattern-width) (/ (1+ dir) 2)) (abs (car pattern-x-extent))))) + (interpret-markup layout props + (markup left + #:with-dimensions (cons 0 middle-width) '(0 . 0) + #:translate (cons x-offset 0) + #:pattern (1+ count) X space pattern + right)))) -(define-markup-command (normal-size-super layout props arg) - (markup?) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Replacements +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-markup-command (replace layout props replacements arg) + (list? markup?) #:category font - #:properties ((baseline-skip)) " address@hidden setting superscript in standard font size - -Set @var{arg} in superscript with a normal font size. +Used to automatically replace a string by another in the markup @var{arg}. +Each pair of the alist @var{replacements} specifies what should be replaced. +The @code{key} is the string to be replaced by the @code{value} string. address@hidden,quote] -\\markup { - default - \\normal-size-super { - superscript in standard size - } -} address@hidden, quote] +\\markup \\replace #'((\"thx\" . \"Thanks!\")) thx @end lilypond" - (ly:stencil-translate-axis - (interpret-markup layout props arg) - (* 0.5 baseline-skip) Y)) + (interpret-markup + layout + (internal-add-text-replacements + props + replacements) + (markup arg))) -(define-markup-command (super layout props arg) - (markup?) - #:category font - #:properties ((font-size 0) - (baseline-skip)) - " address@hidden superscript text +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; geometric shapes +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Set @var{arg} in superscript. +(define-markup-command (draw-line layout props dest) + (number-pair?) + #:category graphic + #:properties ((thickness 1)) + " address@hidden drawing lines within text +A simple line. @lilypond[verbatim,quote] \\markup { - E = - \\concat { - mc - \\super - 2 - } + \\draw-line #'(4 . 4) + \\override #'(thickness . 5) + \\draw-line #'(-3 . 0) } @end lilypond" - (ly:stencil-translate-axis - (interpret-markup - layout - (cons `((font-size . ,(- font-size 3))) props) - arg) - (* 0.5 baseline-skip) - Y)) + (let ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (x (car dest)) + (y (cdr dest))) + (make-line-stencil th 0 0 x y))) -(define-markup-command (translate layout props offset arg) - (number-pair? markup?) - #:category align +(define-markup-command (draw-hline layout props) + () + #:category graphic + #:properties ((draw-line-markup) + (line-width) + (span-factor 1)) " address@hidden translating text - -Translate @var{arg} relative to its surroundings. @var{offset} -is a pair of numbers representing the displacement in the X and Y axis. address@hidden drawing a line across a page +Draws a line across a page, where the property @code{span-factor} +controls what fraction of the page is taken up. @lilypond[verbatim,quote] \\markup { - * - \\translate #'(2 . 3) - \\line { translated two spaces right, three up } + \\column { + \\draw-hline + \\override #'(span-factor . 1/3) + \\draw-hline + } } @end lilypond" - (ly:stencil-translate (interpret-markup layout props arg) - offset)) + (interpret-markup layout + props + (markup #:draw-line (cons (* line-width + span-factor) + 0)))) -(define-markup-command (sub layout props arg) - (markup?) - #:category font - #:properties ((font-size 0) - (baseline-skip)) +(define-markup-command (draw-circle layout props radius thickness filled) + (number? number? boolean?) + #:category graphic " address@hidden subscript text address@hidden drawing circles within text -Set @var{arg} in subscript. +A circle of radius @var{radius} and thickness @var{thickness}, +optionally filled. @lilypond[verbatim,quote] \\markup { - \\concat { - H - \\sub { - 2 - } - O - } + \\draw-circle #2 #0.5 ##f + \\hspace #2 + \\draw-circle #2 #0 ##t } @end lilypond" - (ly:stencil-translate-axis - (interpret-markup - layout - (cons `((font-size . ,(- font-size 3))) props) - arg) - (* -0.5 baseline-skip) - Y)) + (make-circle-stencil radius thickness filled)) -(define-markup-command (normal-size-sub layout props arg) - (markup?) - #:category font - #:properties ((baseline-skip)) +(define-markup-command (triangle layout props filled) + (boolean?) + #:category graphic + #:properties ((thickness 0.1) + (font-size 0) + (baseline-skip 2)) " address@hidden setting subscript in standard font size address@hidden drawing triangles within text -Set @var{arg} in subscript with a normal font size. +A triangle, either filled or empty. @lilypond[verbatim,quote] \\markup { - default - \\normal-size-sub { - subscript in standard size - } + \\triangle ##t + \\hspace #2 + \\triangle ##f } @end lilypond" - (ly:stencil-translate-axis - (interpret-markup layout props arg) - (* -0.5 baseline-skip) - Y)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; brackets. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (let ((ex (* (magstep font-size) 0.8 baseline-skip))) + (ly:make-stencil + `(polygon '(0.0 0.0 + ,ex 0.0 + ,(* 0.5 ex) + ,(* 0.86 ex)) + ,thickness + ,filled) + (cons 0 ex) + (cons 0 (* .86 ex))))) -(define-markup-command (hbracket layout props arg) +(define-markup-command (circle layout props arg) (markup?) #:category graphic + #:properties ((thickness 1) + (font-size 0) + (circle-padding 0.2)) " address@hidden placing horizontal brackets around text address@hidden circling text -Draw horizontal brackets around @var{arg}. +Draw a circle around @var{arg}. Use @code{thickness}, address@hidden and @code{font-size} properties to determine line +thickness and padding around the markup. @lilypond[verbatim,quote] \\markup { - \\hbracket { - \\line { - one two three - } + \\circle { + Hi } } @end lilypond" - (let ((th 0.1) ;; todo: take from GROB. - (m (interpret-markup layout props arg))) - (bracketify-stencil m X th (* 2.5 th) th))) + (let ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (pad (* (magstep font-size) circle-padding)) + (m (interpret-markup layout props arg))) + (circle-stencil m th pad))) -(define-markup-command (bracket layout props arg) - (markup?) +(define-markup-command (with-url layout props url arg) + (string? markup?) #:category graphic " address@hidden placing vertical brackets around text address@hidden inserting URL links into text -Draw vertical brackets around @var{arg}. +Add a link to URL @var{url} around @var{arg}. This only works in +the PDF backend. @lilypond[verbatim,quote] \\markup { - \\bracket { - \\note #\"2.\" #UP + \\with-url #\"http://lilypond.org/web/\" { + LilyPond ... \\italic { + music notation for everyone + } } } @end lilypond" - (let ((th 0.1) ;; todo: take from GROB. - (m (interpret-markup layout props arg))) - (bracketify-stencil m Y th (* 2.5 th) th))) + (let* ((stil (interpret-markup layout props arg)) + (xextent (ly:stencil-extent stil X)) + (yextent (ly:stencil-extent stil Y)) + (old-expr (ly:stencil-expr stil)) + (url-expr (list 'url-link url `(quote ,xextent) `(quote ,yextent)))) -(define-markup-command (parenthesize layout props arg) - (markup?) - #:category graphic - #:properties ((angularity 0) - (padding) - (size 1) - (thickness 1) - (width 0.25)) + (ly:stencil-add (ly:make-stencil url-expr xextent yextent) stil))) + +(define-markup-command (page-link layout props page-number arg) + (number? markup?) + #:category other " address@hidden placing parentheses around text address@hidden referencing page numbers in text -Draw parentheses around @var{arg}. This is useful for parenthesizing -a column containing several lines of text. +Add a link to the page @var{page-number} around @var{arg}. This only works +in the PDF backend. @lilypond[verbatim,quote] \\markup { - \\line { - \\parenthesize { - \\column { - foo - bar - } - } - \\override #'(angularity . 2) { - \\parenthesize { - \\column { - bah - baz - } - } - } - } + \\page-link #2 { \\italic { This links to page 2... } } } @end lilypond" - (let* ((markup (interpret-markup layout props arg)) - (scaled-width (* size width)) - (scaled-thickness - (* (chain-assoc-get 'line-thickness props 0.1) - thickness)) - (half-thickness - (min (* size 0.5 scaled-thickness) - (* (/ 4 3.0) scaled-width))) - (padding (chain-assoc-get 'padding props half-thickness))) - (parenthesize-stencil - markup half-thickness scaled-width angularity padding))) - + (let* ((stil (interpret-markup layout props arg)) + (xextent (ly:stencil-extent stil X)) + (yextent (ly:stencil-extent stil Y)) + (old-expr (ly:stencil-expr stil)) + (link-expr (list 'page-link page-number `(quote ,xextent) `(quote ,yextent)))) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Delayed markup evaluation -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (ly:stencil-add (ly:make-stencil link-expr xextent yextent) stil))) -(define-markup-command (page-ref layout props label gauge default) - (symbol? markup? markup?) +(define-markup-command (with-link layout props label arg) + (symbol? markup?) #:category other " address@hidden referencing page numbers in text address@hidden referencing page labels in text -Reference to a page number. @var{label} is the label set on the referenced -page (using the @code{\\label} command), @var{gauge} a markup used to estimate -the maximum width of the page number, and @var{default} the value to display -when @var{label} is not found." - (let* ((gauge-stencil (interpret-markup layout props gauge)) - (x-ext (ly:stencil-extent gauge-stencil X)) - (y-ext (ly:stencil-extent gauge-stencil Y))) +Add a link to the page holding label @var{label} around @var{arg}. This +only works in the PDF backend. + address@hidden,quote] +\\markup { + \\with-link #'label { + \\italic { This links to the page containing the label... } + } +} address@hidden lilypond" + (let* ((arg-stencil (interpret-markup layout props arg)) + (x-ext (ly:stencil-extent arg-stencil X)) + (y-ext (ly:stencil-extent arg-stencil Y))) (ly:make-stencil `(delay-stencil-evaluation ,(delay (ly:stencil-expr - (let* ((table (ly:output-def-lookup layout 'label-page-table)) - (page-number (if (list? table) - (assoc-get label table) - #f)) - (page-markup (if page-number (format #f "~a" page-number) default)) - (page-stencil (interpret-markup layout props page-markup)) - (gap (- (interval-length x-ext) - (interval-length (ly:stencil-extent page-stencil X))))) - (interpret-markup layout props - (markup #:concat (#:hspace gap page-markup))))))) + (let* ((table (ly:output-def-lookup layout 'label-page-table)) + (page-number (if (list? table) + (assoc-get label table) + #f)) + (link-expr (list 'page-link page-number + `(quote ,x-ext) `(quote ,y-ext)))) + (ly:stencil-add (ly:make-stencil link-expr x-ext y-ext) +arg-stencil))))) x-ext y-ext))) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; scaling -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define-markup-command (scale layout props factor-pair arg) - (number-pair? markup?) +(define-markup-command (beam layout props width slope thickness) + (number? number? number?) #:category graphic " address@hidden scaling markup address@hidden mirroring markup - -Scale @var{arg}. @var{factor-pair} is a pair of numbers -representing the scaling-factor in the X and Y axes. -Negative values may be used to produce mirror images. address@hidden drawing beams within text +Create a beam with the specified parameters. @lilypond[verbatim,quote] \\markup { - \\line { - \\scale #'(2 . 1) - stretched - \\scale #'(1 . -1) - mirrored - } + \\beam #5 #1 #2 } @end lilypond" - (let ((stil (interpret-markup layout props arg)) - (sx (car factor-pair)) - (sy (cdr factor-pair))) - (ly:stencil-scale stil sx sy))) + (let* ((y (* slope width)) + (yext (cons (min 0 y) (max 0 y))) + (half (/ thickness 2))) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Repeating -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (ly:make-stencil + `(polygon ',(list + 0 (/ thickness -2) + width (+ (* width slope) (/ thickness -2)) + width (+ (* width slope) (/ thickness 2)) + 0 (/ thickness 2)) + ,(ly:output-def-lookup layout 'blot-diameter) + #t) + (cons 0 width) + (cons (+ (- half) (car yext)) + (+ half (cdr yext)))))) -(define-markup-command (pattern layout props count axis space pattern) - (integer? integer? number? markup?) - #:category other +(define-markup-command (underline layout props arg) + (markup?) + #:category font + #:properties ((thickness 1) (offset 2)) " -Prints @var{count} times a @var{pattern} markup. -Patterns are spaced apart by @var{space}. -Patterns are distributed on @var{axis}. address@hidden underlining text address@hidden, quote] -\\markup \\column { - \"Horizontally repeated :\" - \\pattern #7 #X #2 \\flat - \\null - \"Vertically repeated :\" - \\pattern #3 #Y #0.5 \\flat +Underline @var{arg}. Looks at @code{thickness} to determine line +thickness, and @code{offset} to determine line y-offset. + address@hidden,quote] +\\markup \\fill-line { + \\underline \"underlined\" + \\override #'(offset . 5) + \\override #'(thickness . 1) + \\underline \"underlined\" + \\override #'(offset . 1) + \\override #'(thickness . 5) + \\underline \"underlined\" } @end lilypond" - (let ((pattern-width (interval-length - (ly:stencil-extent (interpret-markup layout props pattern) X))) - (new-props (prepend-alist-chain 'word-space 0 (prepend-alist-chain 'baseline-skip 0 props)))) - (let loop ((i (1- count)) (patterns (markup))) - (if (zero? i) - (interpret-markup - layout - new-props - (if (= axis X) - (markup patterns pattern) - (markup #:column (patterns pattern)))) - (loop (1- i) - (if (= axis X) - (markup patterns pattern #:hspace space) - (markup #:column (patterns pattern #:vspace space)))))))) + (let* ((thick (ly:output-def-lookup layout 'line-thickness)) + (underline-thick (* thickness thick)) + (markup (interpret-markup layout props arg)) + (x1 (car (ly:stencil-extent markup X))) + (x2 (cdr (ly:stencil-extent markup X))) + (y (* thick (- offset))) + (line (make-line-stencil underline-thick x1 y x2 y))) + (ly:stencil-add markup line))) -(define-markup-command (fill-with-pattern layout props space dir pattern left right) - (number? ly:dir? markup? markup? markup?) - #:category align - #:properties ((word-space) - (line-width)) +(define-markup-command (box layout props arg) + (markup?) + #:category font + #:properties ((thickness 1) + (font-size 0) + (box-padding 0.2)) " -Put @var{left} and @var{right} in a horizontal line of width @code{line-width} -with a line of markups @var{pattern} in between. -Patterns are spaced apart by @var{space}. -Patterns are aligned to the @var{dir} markup. address@hidden enclosing text within a box address@hidden, quote] -\\markup \\column { - \"right-aligned :\" - \\fill-with-pattern #1 #RIGHT . first right - \\fill-with-pattern #1 #RIGHT . second right - \\null - \"center-aligned :\" - \\fill-with-pattern #1.5 #CENTER - left right - \\null - \"left-aligned :\" - \\override #'(line-width . 50) - \\fill-with-pattern #2 #LEFT : left first - \\override #'(line-width . 50) - \\fill-with-pattern #2 #LEFT : left second +Draw a box round @var{arg}. Looks at @code{thickness}, address@hidden and @code{font-size} properties to determine line +thickness and padding around the markup. + address@hidden,quote] +\\markup { + \\override #'(box-padding . 0.5) + \\box + \\line { V. S. } } @end lilypond" - (let* ((pattern-x-extent (ly:stencil-extent (interpret-markup layout props pattern) X)) - (pattern-width (interval-length pattern-x-extent)) - (left-width (interval-length (ly:stencil-extent (interpret-markup layout props left) X))) - (right-width (interval-length (ly:stencil-extent (interpret-markup layout props right) X))) - (middle-width (max 0 (- line-width (+ (+ left-width right-width) (* word-space 2))))) - (period (+ space pattern-width)) - (count (truncate (/ (- middle-width pattern-width) period))) - (x-offset (+ (* (- (- middle-width (* count period)) pattern-width) (/ (1+ dir) 2)) (abs (car pattern-x-extent))))) - (interpret-markup layout props - (markup left - #:with-dimensions (cons 0 middle-width) '(0 . 0) - #:translate (cons x-offset 0) - #:pattern (1+ count) X space pattern - right)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Replacements -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (let* ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (pad (* (magstep font-size) box-padding)) + (m (interpret-markup layout props arg))) + (box-stencil m th pad))) -(define-markup-command (replace layout props replacements arg) - (list? markup?) - #:category font +(define-markup-command (filled-box layout props xext yext blot) + (number-pair? number-pair? number?) + #:category graphic " -Used to automatically replace a string by another in the markup @var{arg}. -Each pair of the alist @var{replacements} specifies what should be replaced. -The @code{key} is the string to be replaced by the @code{value} string. address@hidden drawing solid boxes within text address@hidden drawing boxes with rounded corners address@hidden, quote] -\\markup \\replace #'((\"thx\" . \"Thanks!\")) thx +Draw a box with rounded corners of dimensions @var{xext} and address@hidden For example, address@hidden +\\filled-box #'(-.3 . 1.8) #'(-.3 . 1.8) #0 address@hidden verbatim +creates a box extending horizontally from -0.3 to 1.8 and +vertically from -0.3 up to 1.8, with corners formed from a +circle of address@hidden (i.e., sharp corners). + address@hidden,quote] +\\markup { + \\filled-box #'(0 . 4) #'(0 . 4) #0 + \\filled-box #'(0 . 2) #'(-4 . 2) #0.4 + \\filled-box #'(1 . 8) #'(0 . 7) #0.2 + \\with-color #white + \\filled-box #'(-4.5 . -2.5) #'(3.5 . 5.5) #0.7 +} @end lilypond" - (interpret-markup - layout - (internal-add-text-replacements - props - replacements) - (markup arg))) + (ly:round-filled-box + xext yext blot)) + +(define-markup-command (rounded-box layout props arg) + (markup?) + #:category graphic + #:properties ((thickness 1) + (corner-radius 1) + (font-size 0) + (box-padding 0.5)) + "@cindex enclosing text in a box with rounded corners + @cindex drawing boxes with rounded corners around text +Draw a box with rounded corners around @var{arg}. Looks at @code{thickness}, address@hidden and @code{font-size} properties to determine line +thickness and padding around the markup; the @code{corner-radius} property +makes it possible to define another shape for the corners (default is 1). + address@hidden,verbatim,relative=2] +c4^\\markup { + \\rounded-box { + Overtura + } +} +c,8. c16 c4 r address@hidden lilypond" + (let ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (pad (* (magstep font-size) box-padding)) + (m (interpret-markup layout props arg))) + (ly:stencil-add (rounded-box-stencil m th pad corner-radius) + m))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Woodwind Diagram commands +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Draws a circle around markup if (= trigger 0.5) +(define-markup-command + (conditional-circle-markup layout props trigger in-markup) + (number? markup?) + (interpret-markup layout props + (if (eqv? trigger 0.5) + (markup #:circle (markup in-markup)) + (markup in-markup)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Markup list commands diff --git a/scm/define-woodwind-diagrams.scm b/scm/define-woodwind-diagrams.scm index 29825fd..6a373eb 100644 --- a/scm/define-woodwind-diagrams.scm +++ b/scm/define-woodwind-diagrams.scm @@ -16,7 +16,9 @@ ;;;; ;;;; You should have received a copy of the GNU General Public License ;;;; along with LilyPond. If not, see