Am 14.09.2015 um 14:34 schrieb BB:
Tried to compile with version 2.19.25

.../tmp/frescobaldi-6V3LoT/tmpI8U_qS/text-spanner-centered-text.ly:152:20 <0>: In expression (ly:line-interface::line grob (caar exts) ...):
/tmp/frescobaldi-6V3LoT/tmpI8U_qS/text-spanner-centered-text.ly:152:20 
<1>: Unbound variable: ly:line-interface::line
Please reread David’s post: that’s functionality available only in 
v2.19.27, but there is a workaround. Though: why not get Lily 2.19.27?
Yours, Simon


On 14.09.2015 14:22, David Nalesnik wrote:
\version "2.19.27"

%% Adapted from 'justify-line-helper' in scm/define-markup-commands.scm.
#(define (distribute-text-spanner-stencils grob args extent padding)
    "Return a stencil which spreads @var{args} along an extent
@var{extent}, with spaces filled by a line."
    (let* ((orig-stencils
            (map (lambda (a) (grob-interpret-markup grob a)) args))
           (stencils
            (map (lambda (stc)
                   (if (ly:stencil-empty? stc X)
                       (ly:make-stencil (ly:stencil-expr stc)
                         '(0 . 0) (ly:stencil-extent stc Y))
                       stc))
              orig-stencils))
           (line-contents
            (if (= (length stencils) 1)
                (list point-stencil (car stencils) point-stencil)
                stencils))
           (text-extents
            (map (lambda (stc) (ly:stencil-extent stc X))
              line-contents))
           (te1 text-extents)
           ;; How much shift is necessary to align left edge of first
           ;; stencil with extent?  Apply this shift to all stencils.
           (text-extents
            (map (lambda (stc)
                   (coord-translate
                    stc
                    (- (car extent) (caar text-extents))))
              text-extents))
           ;; how much does the last stencil need to be translated for
           ;; its right edge to touch the end of the spanner?
           (last-shift (- (cdr extent) (cdr (last text-extents))))
           (word-count (length line-contents))
           ;; Make a list of stencils and their extents, scaling the
           ;; extents across extent. The right edge of the last stencil
           ;; is now aligned with the right edge of the spanner.  The
           ;; first stencil will be moved 0.0, the last stencil the
           ;; amount given by last-shift.
           (stencils-shifted-extents-list
            (let loop ((contents line-contents) (exts text-extents)
                        (idx 0) (result '()))
              (if (null? contents)
                  result
                  (loop
                   (cdr contents) (cdr exts) (1+ idx)
                   (append result
                     (list
                      (cons (car contents)
                        (coord-translate
                         (car exts)
                         (* idx
                           (/ last-shift (1- word-count)))))))))))
           ; Remove non-marker spacers from list of extents.  This is done
           ; so that a single line is drawn to cover the total gap rather
           ; than several. (A single line is needed since successive dashed
           ; lines will not connect properly.) TODO: seems broken!
           (stencils-extents-list-no-spacers
            (let loop ((orig stencils-shifted-extents-list) (idx 0) (result 
'()))
              (cond
               ((= idx (length stencils-shifted-extents-list)) result)
               ; Ignore first and last stencils, which--if point stencil--
               ; will be markers.
               ((or (= idx 0)
                    (= idx (1- (length stencils-shifted-extents-list))))
                (loop (cdr orig) (1+ idx)
                  (append result (list (car orig)))))
               ; Remove spacers.  Better way to identify them than comparing
               ; left and right extents?
               ((= (cadar orig) (cddar orig))
                (loop (cdr orig) (1+ idx) result))
               ; Keep any visible stencil.
               (else (loop (cdr orig) (1+ idx)
                       (append result (list (car orig))))))))
(padding (ly:grob-property grob 'padding 0.0))
           (padded-stencils-extents-list
            (let loop ((orig stencils-extents-list-no-spacers) (idx 0) (result 
'()))
              (cond
               ((= idx (length stencils-extents-list-no-spacers)) result)
               ;; don't widen line markers
               ((= (cadar orig) (cddar orig))
                (loop (cdr orig) (1+ idx)
                  (append result (list (car orig)))))
               ;; right padding only if object starts line
               ((= idx 0)
                (loop (cdr orig) (1+ idx)
                  (append
                   result
                   (list (cons (caar orig)
                           (coord-translate (cdar orig) (cons 0 padding)))))))
               ;; left padding only if object ends a line
               ((= idx (1- (length stencils-extents-list-no-spacers)))
                (loop (cdr orig) (1+ idx)
                  (append
                   result
                   (list (cons (caar orig)
                           (coord-translate (cdar orig) (cons (- padding) 
0.0)))))))
               ;; otherwise right- and left-padding
               (else
                (loop (cdr orig) (1+ idx)
                  (append
                   result
                   (list (cons (caar orig)
                           (interval-widen (cdar orig) padding)))))))))
           ;; Spaces between the text stencils will be filled with lines.
           (spaces
            (if (> (length padded-stencils-extents-list) 1)
                (let loop ((orig padded-stencils-extents-list)
                           (result '()))
                  (if (null? (cdr orig))
                      result
                      (loop
                       (cdr orig)
                       (append
                        result
                        (list (cons (cdr (cdr (first orig)))
                                (car (cdr (second orig)))))))))
                '()))
           (spaces (remove interval-empty? spaces)))
; Create a stencil using the modified list of extents.
      (if (null? (remove ly:stencil-empty? orig-stencils))
          empty-stencil
          (begin
           (set! line-contents
                 (let loop ((contents stencils-extents-list-no-spacers)
                            (stil empty-stencil))
                   (if (null? contents)
                       stil
                       (loop
                        (cdr contents)
                        (ly:stencil-add stil
                          (ly:stencil-translate-axis
                           (caar contents)
                           (- (car (cdr (car contents)))
                             (car (ly:stencil-extent (car (car contents)) X)))
                           X))))))))
      ; add lines to stencil
      (set! line-contents
            (let loop ((exts spaces) (result line-contents))
              (if (null? exts)
                  result
                  (loop
                   (cdr exts)
                   (ly:stencil-add
                    result
                    ;(make-line-stencil 0.1
                    ;; For versions < 2.19.27, replace line below with
                    ;; commented line.  No dashed lines!
                    (ly:line-interface::line grob
                      (caar exts) 0.0
                      (cdar exts) 0.0))))))
line-contents))
#(define (normalize-text-list lines text-lst)
    ;; Make sure every sibling has text.
    (let ((text-count (length text-lst)))
      (if (< text-count lines)
          (let* ((delta (- lines text-count))
                 (blanks (make-list delta #{ \markup \null #}))
                 (head (list-head text-lst (- lines 2)))
                 (tail (append blanks (list (last text-lst)))))
            (append head tail))
          text-lst)))


#(define (get-line-arrangement grob siblings text-lst)
    ;; We need to work stencil extents into this.  If a spanner
    ;; ends at the beginning of a measure after a line break (or
    ;; starts at the end of a line), multiple texts will clump.
    (let ((sib-len (length siblings)))
      (if (= sib-len 0)
          ;; only one line...
          text-lst
          (let* (;; Ensure that all lines have text.  If there isn't
                  ;; enough text, blanks are inserted for lines
                  ;; immediately before last such that the last line
                  ;; has text.)
                  (text-lst (normalize-text-list sib-len text-lst))
                  (text-lines (make-vector sib-len 0))
                  ;; fill vector with number of texts per line
                  ;; 3 lines, 7 texts: 3, 2, 2
                  ;; Later, we will redistribute texts from
                  ;; first and last lines (as a start) for
                  ;; a better arrangement.
                  (text-counts
                   (let loop ((txts text-lst) (idx 0) (lines text-lines))
                     (cond
                      ((null? txts) lines)
                      (else
                       (vector-set! lines idx
                         (1+ (vector-ref lines idx)))
                       (loop (cdr txts)
                         (if (= idx (1- sib-len)) 0 (1+ idx))
                         lines)))))
                  ;; read texts into vector
                  (texts-by-line
                   (let loop ((idx 0) (texts text-lst) (tcs text-counts))
                     (if (= idx sib-len)
                         tcs
                         (let ((num (vector-ref tcs idx)))
                           (vector-set! tcs idx
                             (list-head texts num))
                           (loop (1+ idx)
                             (list-tail texts num)
                             tcs)))))
                  ;; Add null-markup at the beginning of lines 2...n.
                  ;; Add null-markup at the end of lines 1...(n-1). Purpose
                  ;; is as anchors for lines which begin and end systems in
                  ;; broken spanners.
                  (lines-with-markers
                   (let loop ((idx 0))
                     (if (= idx (vector-length texts-by-line))
                         texts-by-line
                         (begin
                          (if (> idx 0)
                              (vector-set! texts-by-line idx
                                (cons #{ \markup \null #}
                                  (vector-ref texts-by-line idx))))
                          (if (< idx (1- (vector-length texts-by-line)))
                              (vector-set! texts-by-line idx
                                (append (vector-ref texts-by-line idx)
                                  (list #{ \markup \null #}))))
                          (loop (1+ idx)))))))

            ;; which text does our sibling take?
            (vector-ref
             text-lines
             (list-index (lambda (x) (eq? x grob)) siblings))))))


%% Based on addTextSpannerText, by Thomas Morley.  See
%%http://www.mail-archive.com/lilypond-user%40gnu.org/msg81685.html
addTextSpannerText =
#(define-music-function (text-lst) (list?)
    (if (< (length text-lst) 2)
        (begin
         (ly:warning "At least two texts required for `addTextSpannerText'.")
         (make-music 'Music))
#{
          % The following overrides of 'bound-details are needed to give the
          % correct length to the default spanner we replace.
          \once \override TextSpanner.bound-details.left.text = #(car text-lst)
          \once \override TextSpanner.bound-details.left-broken.text = ##f
          \once \override TextSpanner.bound-details.right.text = #(last 
text-lst)
          \once \override TextSpanner.bound-details.right-broken.text = ##f
\once \override TextSpanner.stencil =
          #(lambda (grob)
             (let* ((stil (ly:line-spanner::print grob))
                    ;; have we been split?
                    (orig (ly:grob-original grob))
                    ;; if yes, get the split pieces (our siblings)
                    (siblings (if (ly:grob? orig)
                                  (ly:spanner-broken-into orig)
                                  '()))
                    (stil-ext-X (ly:stencil-extent stil X))
                    (line-width (interval-length stil-ext-X))
                    (padding (ly:grob-property grob 'padding 0.0))
                    (text-line (get-line-arrangement grob siblings text-lst)))
(distribute-text-spanner-stencils
                grob text-line stil-ext-X padding)))
        #}))

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\markup \bold "Default (no inner text possible)"

\relative c'' {
   \override TextSpanner.bound-details.left.text = #"ral"
   \override TextSpanner.bound-details.left-broken.text = ##f
   \override TextSpanner.bound-details.right.text = #"do"
   \override TextSpanner.bound-details.right-broken.text = ##f
   c,1\startTextSpan
   d'1\stopTextSpan
}

\markup \bold "All on one line"

\relative c' {
   \addTextSpannerText #(list "ral" "len" "tan" "do")
   c1\startTextSpan
   d'1\stopTextSpan
}

\markup \bold "Broken"
% Spacer needed so terminal texts don't clump.  Texts are
% allocated line1, line2, line1, line2, line1... So
% we have three texts on first line, two on the last--including
% the spacer.
\relative c' {
   \override TextSpanner.padding = 1
   \addTextSpannerText #(list "ral" "len" "tan" "" "do")
   c1\startTextSpan
   \break
   d'1\stopTextSpan
}


\markup \bold "More lines than text"

\relative c' {
   \addTextSpannerText #(list "one" "two" "three")
   c1~\startTextSpan
   \break
   c1~
   \break
   c1~
   \break
   c1\stopTextSpan
}

\markup \bold "Markups.  Changes of alignment, padding, line-style."

\relative c'' {
   \addTextSpannerText #(list
                         #{ \markup \right-align "ral" #}
                         "len"
                         #{ \markup \translate #'(-10 . 0) "tan" #}
                         #{ \markup \center-align "do" #} )
   c,1\startTextSpan
   \break
   d'2 d\stopTextSpan
}

\relative c'' {
   \override TextSpanner.style = #'zigzag
   \override TextSpanner.padding = 0.5
   \addTextSpannerText #(list
                         #{ \markup \draw-circle #1 #0.2 ##f #}
                         #{ \markup \with-color #grey \draw-circle #1 #0.2 ##t 
#}
                         #{ \markup \draw-circle #1 #0.2 ##t #}
                         #{ \markup \with-color #grey \draw-circle #1 #0.2 ##t 
#}
                         #{ \markup \draw-circle #1 #0.2 ##f #} )
   c1\startTextSpan
   %\break
   d'2 d\stopTextSpan
}

\layout {
   ragged-right = ##f
   indent = 0
}


_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user
_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to