Hi,

I'm creating a TextSpanner to indicate a gradual transition between 
instrumental techniques. In order that the left and right texts don't collide, 
my before-line-breaking callback sets the minimum-length property of the 
spanner to the sum of the width of the two markups.

This all works well, until the spanner is broken. Then, the first part retains 
this minimum-length, making it unnecessarily long. The problem is that once the 
spanner has been broken, it is too late to reset minimum-length.

Ideally there could be a property `minimum-length-before-break` to match 
`minimum-length-after-break` to address this? Or am I simply approaching this 
problem from the wrong angle?

See attachments for code and examples.

Thanks for any input,

Mark

\version "2.23.10"

#(define (get-markup-width grob text)
  (let* ((layout (ly:grob-layout grob))
         (props (ly:grob-alist-chain
                 grob
                 (ly:output-def-lookup layout 'text-font-defaults))))
    (interval-length
     (ly:stencil-extent
      (interpret-markup layout props (markup text))
      X))))

#(define (text-spanner-minimum-length grob padding)
  (let* ((details (ly:grob-property grob 'bound-details))
         (lprops (assoc-get 'left details '()))
         (ltext (assoc-get 'text lprops '()))
         (lwidth (get-markup-width grob ltext))
         (rprops (assoc-get 'right details '()))
         (rtext (assoc-get 'text rprops '()))
         (rwidth (get-markup-width grob rtext))
         (minlength (+ lwidth rwidth padding)))
    ;; (pretty-print (list lwidth rwidth minlength))
    (ly:grob-set-property! grob 'minimum-length minlength)
    ;; TODO ideally we could set a property `minimum-length-before-break'
    (ly:grob-set-property! grob 'minimum-length-after-break rwidth)))

transitionSpanner =
#(define-music-function
   (padding from to)
   ((number? 2) markup? markup?)
   (_i "Set up a TextSpanner to indicate transition from one technique to 
another.
        Spanner is forced to a @code{minimum-length} of the combined widths of
        the markups @var{from} and @var{to} plus the extra value of 
@var{padding}.
        @var{to} markup is right-aligned.")
   ;; TODO recalculate minimum-length when broken, otherwise individual parts 
are stretched unnecessarily
   ;; PROBLEM: springs-and-rods has already run by the time the spanner is 
broken
   #{
     \override TextSpanner.style = #'dashed-line
     \override TextSpanner.dash-fraction = 0.35
     \override TextSpanner.dash-period = 1.2
     \override TextSpanner.bound-details.left.text = \markup \concat { #from 
\hspace #0.5 }
     \override TextSpanner.bound-details.right.text = \markup \halign #RIGHT 
\concat { \hspace #0.5 #to }
     \override TextSpanner.bound-details.left-broken.text = ##f
     \override TextSpanner.bound-details.right-broken.text = ##f
     \override TextSpanner.bound-details.left.padding = #0
     \override TextSpanner.bound-details.right.padding = #0
     \override TextSpanner.bound-details.right.attach-dir = #RIGHT
     \override TextSpanner.bound-details.left.stencil-offset = #'(0 . -0.5)
     \override TextSpanner.bound-details.right.stencil-offset = #'(0 . -0.5)
     \override TextSpanner.bound-details.right.arrow = ##t
     \override TextSpanner.before-line-breaking = #(lambda (grob) 
(text-spanner-minimum-length grob padding))
     \override TextSpanner.springs-and-rods = #ly:spanner::set-spacing-rods
   #})

% { %% EXAMPLES AND TESTS
{
  c'1
  \once \transitionSpanner "sul pont" "sul tasto"
  \once \override TextSpanner.before-line-breaking = ##f
  c'4\startTextSpan^\markup \with-color #red \box \column { "without 
adjustment" "BAD" }
  bes'4
  bes'4
  f''4\stopTextSpan
  \repeat unfold 16 c'16
  \once \transitionSpanner "sul pont" "sul tasto"
  c'4\startTextSpan^\markup \with-color #blue \box \column { "with adjustment" 
"GOOD" }
  bes'4
  bes'4
  f''4\stopTextSpan
  c'1
  c'1
  \repeat unfold 16 c'16
  c'4 4
  \once \transitionSpanner "sul pont" "sul tasto"
  c'4\startTextSpan^\markup \with-color #red \box \column { "but too long" 
"when broken" "BAD" }
  bes'4
  \break
  bes'4
  f''4\stopTextSpan
  c'2
  \repeat unfold 16 c'16
  c'4 4
  \once \transitionSpanner "sul pont" "sul tasto"
  \once \override TextSpanner.before-line-breaking = ##f
  c'4\startTextSpan^\markup \with-color #blue \box \column { "without" 
"adjustment" "GOOD" }
  bes'4
  \break
  bes'4
  f''4\stopTextSpan
  c'2
  \repeat unfold 24 c'16
  2
}
%}

Attachment: transitionSpanner.pdf
Description: Adobe PDF document



--
Mark Knoop

Reply via email to