Le 28/11/2021 à 16:10, Werner LEMBERG a écrit :
please have a look at this example
```
{
\set Score.skipBars = ##t
\override TextSpanner.bound-details.left.text = "poco a poco tempo I"
\override TextSpanner.bound-details.right.text = "Tempo I"
R1*4\startTextSpan |
R1\stopTextSpan
}
```
What is the equivalent of `\textLengthOn` for `TextSpanner` grobs so
that the multi-measure rest gets properly stretched horizontally?
Use
\override TextSpanner.minimum-length = 30
\override TextSpanner.springs-and-rods = #ly:spanner::set-spacing-rods
Thanks. Alas, doesn't work correctly for broken spanners:
```
\paper {
line-width = 100\mm
}
{
\set Score.skipBars = ##t
\override TextSpanner.bound-details.left.text = "poco a poco tempo I"
\override TextSpanner.bound-details.left-broken.text = ""
\override TextSpanner.bound-details.right.text = "Tempo I"
\override TextSpanner.bound-details.right-broken.text = ""
\override TextSpanner.minimum-length = 34
\override TextSpanner.springs-and-rods = #ly:spanner::set-spacing-rods
R1*4\startTextSpan | \break
R1*4\stopTextSpan |
R1 |
}
```
I also wonder whether there is a solution (or should be a solution)
that doesn't need manual entering of a minimum length value that can
only be found by trial and error. For example, wouldn't it be
sensible to have the possibility of
```
\override TextSpanner.bound-details
.left.extra-spacing-height = #'(-inf.0 . +inf.0)
\override TextSpanner.bound-details
.right.extra-spacing-height = #'(-inf.0 . +inf.0)
```
in combination with the `extra-spacing-width` property to get
automatically the correct value(s)?
Werner
Here is what I could arrive at this evening:
\version "2.23.6"
\paper {
line-width = 100\mm
}
#(use-modules (ice-9 match)
(srfi srfi-26))
#(define (define-grob! grob-name grob-entry)
(let* ((meta-entry (assoc-get 'meta grob-entry))
(class (assoc-get 'class meta-entry))
(ifaces-entry (assoc-get 'interfaces meta-entry)))
(set-object-property! grob-name 'translation-type?
ly:grob-properties?)
(set-object-property! grob-name 'is-grob? #t)
(set! ifaces-entry (append (case class
((Item) '(item-interface))
((Spanner) '(spanner-interface))
((Paper_column) '((item-interface
paper-column-interface)))
((System) '((system-interface
spanner-interface)))
(else '(unknown-interface)))
ifaces-entry))
(set! ifaces-entry (uniq-list (sort ifaces-entry symbol<?)))
(set! ifaces-entry (cons 'grob-interface ifaces-entry))
(set! meta-entry (assoc-set! meta-entry 'name grob-name))
(set! meta-entry (assoc-set! meta-entry 'interfaces
ifaces-entry))
(set! grob-entry (assoc-set! grob-entry 'meta meta-entry))
(set! all-grob-descriptions
(cons (cons grob-name grob-entry)
all-grob-descriptions))))
#(define (text-spanner-bound-stub::text grob)
(let ((details (ly:grob-property grob 'bound-details)))
(chain-assoc-get 'text details empty-markup)))
#(define (text-spanner-bound-stub::X-offset grob)
(let* ((details (ly:grob-property grob 'bound-details))
(padding (chain-assoc-get details 'padding 0))
(column (ly:grob-parent grob X))
(direction (ly:grob-property grob 'direction))
(text-spanner (ly:grob-parent grob Y))
(parent-bound (ly:spanner-bound text-spanner direction))
(extent (ly:generic-bound-extent parent-bound column))
(attach (chain-assoc-get details 'attach-dir CENTER)))
(- (interval-index extent attach)
(* padding direction))))
#(define-grob! 'TextSpannerBoundStub
`((Y-extent . ,grob::always-Y-extent-from-stencil)
(after-line-breaking . ,ly:grob-suicide!)
(text . ,text-spanner-bound-stub::text)
(stencil . ,ly:text-interface::print)
(font-shape . italic)
(X-offset . ,text-spanner-bound-stub::X-offset)
;; Watch the hack!
;; NB: This relies on an arcane inconsistency that should
;; really be fixed...
(cross-staff . #t)
(meta . ((classes . (Item))
(interfaces . ())))))
#(define (transform-nested-path! path transform alist)
(match path
(() (transform alist))
((key . rest)
(assoc-set! alist key (transform-nested-path! rest transform
(assoc-get key alist))))))
#(transform-nested-path!
'(TextSpanner meta interfaces)
(cute cons 'text-spanner-interface <>)
all-grob-descriptions)
#(define (Text_spanner_stub_engraver context)
(let ((text-spanner #f))
(define (get-details syms)
(let ((bound-details (ly:grob-property text-spanner
'bound-details)))
(map (cute assoc-get <> bound-details '())
syms)))
(define (new-stub engraver)
(let ((stub (ly:engraver-make-grob engraver
'TextSpannerBoundStub '())))
(ly:grob-set-parent! stub Y text-spanner)
stub))
(make-engraver
(acknowledgers
((text-spanner-interface engraver grob source-engraver)
(set! text-spanner grob)
(let ((stub (new-stub engraver)))
(ly:grob-set-parent! stub Y grob)
(ly:grob-set-property! stub 'direction LEFT)
(ly:grob-set-property! stub 'bound-details (get-details
'(left))))))
((process-music engraver)
(if text-spanner
(let ((column (ly:context-property context
'currentCommandColumn))
(stub-left (new-stub engraver))
(stub-right (new-stub engraver)))
(ly:grob-set-property! stub-left 'bound-details
(get-details '(left-broken left)))
(ly:grob-set-property! stub-left 'direction LEFT)
(ly:grob-set-property! stub-left 'break-visibility #(#f
#f #t))
(ly:grob-set-property! stub-left 'non-musical #t)
(ly:grob-set-property! stub-right 'bound-details
(get-details '(right-broken right)))
(ly:grob-set-property! stub-right 'direction RIGHT)
(ly:grob-set-property! stub-right 'break-visibility
#(#t #f #f))
(ly:grob-set-property! stub-right 'non-musical #t))))
(end-acknowledgers
((text-spanner-interface engraver grob source-engraver)
(let ((stub (new-stub engraver)))
(ly:grob-set-property! stub 'bound-details (get-details
'(right)))
(ly:grob-set-property! stub 'direction RIGHT))
(set! text-spanner #f))))))
\layout {
\context {
\Global
\grobdescriptions #all-grob-descriptions
}
\context {
\Voice
\consists #Text_spanner_stub_engraver
}
}
{
\set Score.skipBars = ##t
\override TextSpanner.bound-details.left.padding = -10
\override TextSpanner.color = red
\override TextSpanner.bound-details.left.text = "poco a poco tempo I"
\override TextSpanner.bound-details.left-broken.text = ""
\override TextSpanner.bound-details.right.text = "Tempo I"
\override TextSpanner.bound-details.right-broken.text = ""
R1*4\startTextSpan |
R1*4\stopTextSpan |
R1 |
}
But,
- The spacing is not pretty;
- The code is not pretty.
It is a proof of concept. Even though I'd probably go
for a somewhat different if similar approach if I
were actually trying to integrate this into LilyPond.
Basically, extra-spacing-width etc. work on items, and
not on spanners. If you want a spanner to occupy space
at its bounds, the state of the art is that you have
to create "stub" items.
I won't have the time to work on it more, sorry.
Does David N's text-spanner work solve this problem, I wonder?
Nice, I didn't know about it. It doesn't handle this as
far as I can see, however.
Best,
Jean