lilypond-user
[Top][All Lists]
Advanced

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

Re: Instrument names and smallest possible bounding box


From: Kieren MacMillan
Subject: Re: Instrument names and smallest possible bounding box
Date: Sun, 17 Jan 2016 09:53:28 -0500

Hi all,

On Jan 17, 2016, at 6:24 AM, Malte Meyn <address@hidden> wrote:

> LilyPond tries to center-align the instrument names. Long names which
> don’t fit into the margin defined by indent (default 1.5cm (?)) are
> right-aligned (“Woodwind” in your example). This “mixing” behaviour
> looks odd, I agree. You can make the indent bigger so all names are
> center-aligned or change the alignment of instrument names globally

You can also use David N’s great custom-align function — see snippet, below.

Hope this helps!
Kieren.

p.s. David N: Is this code ready to present as a patch? I think it’s not only a 
very useful function, it should be Lilypond’s default setting.

%%%%  SNIPPET BEGINS
\version "2.19.35"

#(define (align-to-interval victim target dir)
   "Align interval @var{victim} to interval @var{target} according
to the value of @var{dir}.  If @var{dir} is a number, use it to orient
both intervals.  If @var{dir} is a pair, use the @code{car} for the
victim and the @code{cdr} for the target."
   (let ((v-dir (if (number? dir) dir (car dir)))
         (t-dir (if (number? dir) dir (cdr dir))))
     (coord-translate
      victim
      (- (interval-index target t-dir)
        (interval-index victim v-dir)))))

#(define (within-interval? point interval)
   "Does interval @var{interval} enclose number @var{num}?"
   (and
    (interval-sane? interval)
    (not (< point (car interval)))
    (not (> point (cdr interval)))))

#(define (custom-align grob)
   (let* ((system (ly:grob-system grob))
          (elements (ly:grob-array->list
                     (ly:grob-object system 'elements)))
          (elements (filter grob::is-live? elements))
          (text-grobs
           (filter
            (lambda (e) (grob::has-interface e 'system-start-text-interface))
            elements))

          ;; A delimiter is an initial barline, bracket, brace.
          (delims
           (filter
            (lambda (elt)
              (grob::has-interface elt 'system-start-delimiter-interface))
            elements))
          ;; To determine which delimiters affect our grob, we
          ;; unfortunately have to calculate its Y-position and
          ;; that of the delimiters!
          (text-grobs-delims-list
           (map (lambda (tg)
                  (cons tg
                    (list
                     (remove
                      (lambda (d)
                        (not (within-interval?
                              (ly:grob-property tg 'Y-offset)
                              (ly:grob-extent d system Y))))
                      delims))))
             text-grobs))
          (delim-extent-list
           (lambda (delim-list)
             (map
              (lambda (d) (ly:grob-extent d system X))
              delim-list)))
          ; Return a list of text grobs and their associated delimiter extents
          ; if we have no delimiters (as will happen with a single staff), use
          ; the left extent of the (unoffset) text grob itself as a basis.
          (text-grobs-delim-extents
           (map
            (lambda (tgdl)
              (cons (car tgdl)
                (if (null? (cadr tgdl))
                    (let ((me-ext (ly:grob-extent (car tgdl) system X)))
                      (list (cons (car me-ext) (car me-ext))))
                    (delim-extent-list (cadr tgdl)))))
            text-grobs-delims-list))
          ; combine extents
          (text-grobs-total-delim-extents
           (map (lambda (tgde)
                  (cons (car tgde)
                    (reduce interval-union
                      '()
                      (cdr tgde))))
             text-grobs-delim-extents))
          ; assumption?
          (representative-delim-extent
           (cdar text-grobs-total-delim-extents))

          ; In order to calculate how much to move our name, we first need
          ; to construct a list of target positions for all grobs.
          (bar-line-width 0.1) ; Ugh.
          (target
           (map (lambda (tg)
                  (let ((len (interval-length (ly:grob-extent tg system X))))
                    (cons tg
                      (cons (- (cdr representative-delim-extent)
                              bar-line-width)
                        (+ (- (cdr representative-delim-extent) bar-line-width)
                          len)))))
             text-grobs))
          (target
           (map
            (lambda (re)
              (cons (car re)
                (coord-translate
                 (cdr re)
                 (ly:side-position-interface::x-aligned-side (car re)))))
            target))
          (longest
           (car
            (sort target
              (lambda (x y) (> (interval-length (cdr x))
                               (interval-length (cdr y)))))))
          (target
           (map
            (lambda (x)
              (cons (car x)
                (align-to-interval ;align-interval-on-other
                  (cdr x) (cdr longest)
                  (ly:grob-property (car x) 'self-alignment-X 0))))
            target))

          ; determine overlaps of target positioning with delimiters
          (overlap
           (map
            (lambda (x y)
              (cons (car x)
                (interval-intersection (cdr x) (cdr y))))
            target
            text-grobs-total-delim-extents))
          (overlap
           (filter (lambda (x) (interval-sane? (cdr x)))
                   overlap))

          (largest-overlap
           (if (null? overlap)
               0.0
               (apply max
                 (map (lambda (x) (interval-length (cdr x))) overlap))))

          (right-padding
           (ly:grob-property grob 'padding 0.3))
          (my-extent (ly:grob-extent grob system X))
          ; X offset returned will displace grob's extent to match
          ; the target inc. any overlap with delimiters and padding.
          (X-offset
           (- (car (assoc-get grob target))
             (car my-extent)
             largest-overlap
             right-padding)))

     X-offset))

\layout {
  indent = 1\in
  \context {
    \Score
    \override InstrumentName.X-offset = #custom-align
    \override InstrumentName.padding = #0.5
  }
}

\score {
  <<
    \new Staff \with { instrumentName = "very long name" }
      { R1 \break R1 }
   \new StaffGroup <<
    \new Staff \with { instrumentName = "short" }
      { R1 \break R1 }
    \new StaffGroup <<
      \new Staff \with { instrumentName = "Group A" }
        { R1 \break R1 }
      \new Staff \with { instrumentName = "Group B" }
        { R1 \break R1 }
    >>
   >>
  >>
}
%%%%  SNIPPET ENDS

________________________________

Kieren MacMillan, composer
‣ website: www.kierenmacmillan.info
‣ email: address@hidden




reply via email to

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