lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Text centralized above a TextSpan


From: Simon Albrecht
Subject: Re: Text centralized above a TextSpan
Date: Mon, 14 Sep 2015 14:39:10 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.2.0

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: In _expression_ (ly:line-interface::line grob (caar exts) ...):

/tmp/frescobaldi-6V3LoT/tmpI8U_qS/text-spanner-centered-text.ly:152:20: 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
address@hidden
https://lists.gnu.org/mailman/listinfo/lilypond-user


reply via email to

[Prev in Thread] Current Thread [Next in Thread]