From 4b7d95665a24a10d6b893df83152d4bc9a7fb055 Mon Sep 17 00:00:00 2001 From: Neil Puttock Date: Sun, 9 Aug 2009 23:25:15 +0100 Subject: [PATCH] New instrument name positioning in scheme. * split ly:system-start-text::print into three scheme callbacks in output-lib.scm (X-/Y-offset calculations and print function) * compensate for system start delimiter extents so all instrument names in a system are aligned correctly based on self-alignment-X * use 'when from left-bound instead of get_break_index () to determine which text to print; this fixes incorrect indentation and text for shortInstrumentName overrides (Issue #452) * remove acknowledger for system-start-text from system-start-delimiter-engraver.cc * remove system-start-text.cc * add system-start-text-interface to define-grob-interfaces.scm * add library functions used by new callbacks to lily-library.scm and output-lib.scm * update snippets broken by changes * add news entry and convert rule --- Documentation/changes.tely | 39 +++- Documentation/snippets/incipit.ly | 69 +++--- Documentation/snippets/new/incipit.ly | 273 ++++++++++++++++++++++++ input/regression/incipit.ly | 28 +-- lily/system-start-delimiter-engraver.cc | 75 +++---- lily/system-start-text.cc | 121 ----------- python/convertrules.py | 12 +- scm/define-grob-interfaces.scm | 7 +- scm/define-grobs.scm | 5 +- scm/lily-library.scm | 48 +++-- scm/output-lib.scm | 190 ++++++++++++----- 11 files changed, 572 insertions(+), 295 deletions(-) create mode 100644 Documentation/snippets/new/incipit.ly delete mode 100644 lily/system-start-text.cc diff --git a/Documentation/changes.tely b/Documentation/changes.tely index 3d1b6f51fb..98c22f58dc 100644 --- a/Documentation/changes.tely +++ b/Documentation/changes.tely @@ -62,6 +62,43 @@ which scares away people. @end ignore +@item +Instrument names and vocal names now take into account the extent of +system start delimiters in other staves for their positioning, +resulting in improved default alignment for left-, center- and +right-aligned names. +@lilypond[quote,indent=18\mm] +<< + \new StaffGroup << + \new GrandStaff << + \new Staff { + \set Staff.instrumentName = #"Piccolo" + c''1 + } + \new Staff { + \set Staff.instrumentName = #"Flute" + c''1 + } + >> + \new Staff { + \set Staff.instrumentName = #"Bassoon" + \clef tenor + c'1 + } + >> + \new PianoStaff << + \set PianoStaff.instrumentName = #"Piano" + \context Staff = "up" { + c'1 + } + \context Staff = "down" { + \clef bass + c1 + } + >> +>> +@end lilypond + @item Braces in markup can now be selected by point size using the markup commands @code{\left-brace} and @code{\right-brace}. @@ -95,7 +132,7 @@ c4( d e f) @end lilypond @item -An eyeglasses markup was added, incidating strongly to look at the +An eyeglasses markup was added, indicating strongly to look at the conductor for instructions: @lilypond[quote,relative=2] \mark \markup { \eyeglasses } diff --git a/Documentation/snippets/incipit.ly b/Documentation/snippets/incipit.ly index 46710df5a1..3501ce2334 100644 --- a/Documentation/snippets/incipit.ly +++ b/Documentation/snippets/incipit.ly @@ -1,11 +1,10 @@ -%% Do not edit this file; it is automatically -%% generated from LSR http://lsr.dsi.unimi.it -%% This file is in the public domain. +% Do not edit this file; it is automatically +% generated from Documentation/snippets/new +% This file is in the public domain. +%% Note: this file works from version 2.13.4 \version "2.13.4" \header { - lsrtags = "staff-notation, ancient-notation" - %% Translation of GIT committish: b2d4318d6c53df8469dfa4da09b27c15a374d0ca texidoces = " Los «incipit» se pueden escribir utilizando el grob del nombre del @@ -14,48 +13,52 @@ nombre del instrumento y del incipit." doctitlees = "Incipit" + lsrtags = "staff-notation, ancient-notation" texidoc = " Incipits can be added using the instrument name grob, but keeping separate the instrument name definition and the incipit definition. - " doctitle = "Incipit" } % begin verbatim + incipit = #(define-music-function (parser location incipit-music) (ly:music?) #{ \once \override Staff.InstrumentName #'self-alignment-X = #RIGHT \once \override Staff.InstrumentName #'self-alignment-Y = #UP - \once \override Staff.InstrumentName #'Y-offset = #4 + \once \override Staff.InstrumentName #'Y-offset = + #(lambda (grob) + (+ 4 (system-start-text::calc-y-offset grob))) \once \override Staff.InstrumentName #'padding = #0.3 \once \override Staff.InstrumentName #'stencil = - #(lambda (grob) - (let* ((instrument-name (ly:grob-property grob 'long-text)) - (layout (ly:output-def-clone (ly:grob-layout grob))) - (music (make-music 'SequentialMusic - 'elements (list (make-music 'ContextSpeccedMusic - 'context-type 'MensuralStaff - 'element (make-music 'PropertySet - 'symbol 'instrumentName - 'value instrument-name)) - $incipit-music))) - (score (ly:make-score music)) - (mm (ly:output-def-lookup layout 'mm)) - (indent (ly:output-def-lookup layout 'indent)) - (width (ly:output-def-lookup layout 'incipit-width)) - (incipit-width (if (number? width) - (* width mm) - (* indent 0.5)))) - (ly:output-def-set-variable! layout 'indent (- indent incipit-width)) - (ly:output-def-set-variable! layout 'line-width indent) - (ly:output-def-set-variable! layout 'ragged-right #f) - (ly:output-def-set-variable! layout 'ragged-last #f) - (ly:output-def-set-variable! layout 'system-count 1) - (ly:score-add-output-def! score layout) - (ly:grob-set-property! grob 'long-text - (markup #:score score)) - (ly:system-start-text::print grob))) + #(lambda (grob) + (let* ((instrument-name (ly:grob-property grob 'long-text)) + (layout (ly:output-def-clone (ly:grob-layout grob))) + (music (make-sequential-music + (list (context-spec-music + (make-property-set + 'instrumentName instrument-name) + 'MensuralStaff) + $incipit-music))) + (score (ly:make-score music)) + (mm (ly:output-def-lookup layout 'mm)) + (indent (ly:output-def-lookup layout 'indent)) + (width (ly:output-def-lookup layout 'incipit-width)) + (incipit-width (if (number? width) + (* width mm) + (* indent 0.5)))) + + (ly:output-def-set-variable! layout 'indent (- indent + incipit-width)) + (ly:output-def-set-variable! layout 'line-width indent) + (ly:output-def-set-variable! layout 'ragged-right #f) + (ly:output-def-set-variable! layout 'ragged-last #f) + (ly:output-def-set-variable! layout 'system-count 1) + (ly:score-add-output-def! score layout) + (ly:grob-set-property! grob 'long-text + (markup #:score score)) + (system-start-text::print grob))) #}) %%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Documentation/snippets/new/incipit.ly b/Documentation/snippets/new/incipit.ly new file mode 100644 index 0000000000..4b18983390 --- /dev/null +++ b/Documentation/snippets/new/incipit.ly @@ -0,0 +1,273 @@ +\version "2.13.4" + +\header { + lsrtags = "staff-notation, ancient-notation" + texidoc = " +Incipits can be added using the instrument name grob, but keeping +separate the instrument name definition and the incipit definition. +" + doctitle = "Incipit" +} + +incipit = +#(define-music-function (parser location incipit-music) (ly:music?) + #{ + \once \override Staff.InstrumentName #'self-alignment-X = #RIGHT + \once \override Staff.InstrumentName #'self-alignment-Y = #UP + \once \override Staff.InstrumentName #'Y-offset = + #(lambda (grob) + (+ 4 (system-start-text::calc-y-offset grob))) + \once \override Staff.InstrumentName #'padding = #0.3 + \once \override Staff.InstrumentName #'stencil = + #(lambda (grob) + (let* ((instrument-name (ly:grob-property grob 'long-text)) + (layout (ly:output-def-clone (ly:grob-layout grob))) + (music (make-sequential-music + (list (context-spec-music + (make-property-set + 'instrumentName instrument-name) + 'MensuralStaff) + $incipit-music))) + (score (ly:make-score music)) + (mm (ly:output-def-lookup layout 'mm)) + (indent (ly:output-def-lookup layout 'indent)) + (width (ly:output-def-lookup layout 'incipit-width)) + (incipit-width (if (number? width) + (* width mm) + (* indent 0.5)))) + + (ly:output-def-set-variable! layout 'indent (- indent + incipit-width)) + (ly:output-def-set-variable! layout 'line-width indent) + (ly:output-def-set-variable! layout 'ragged-right #f) + (ly:output-def-set-variable! layout 'ragged-last #f) + (ly:output-def-set-variable! layout 'system-count 1) + (ly:score-add-output-def! score layout) + (ly:grob-set-property! grob 'long-text + (markup #:score score)) + (system-start-text::print grob))) + #}) + +%%%%%%%%%%%%%%%%%%%%%%%%% + +global = { + \set Score.skipBars = ##t + \key g \major + \time 4/4 + + % the actual music + \skip 1*8 + + % let finis bar go through all staves + \override Staff.BarLine #'transparent = ##f + + % finis bar + \bar "|." +} + +discantusIncipit = << + \new MensuralVoice = "discantusIncipit" << + \repeat unfold 9 { s1 \noBreak } + { + \clef "neomensural-c1" + \key f \major + \time 2/2 + c''1. + } + >> + \new Lyrics \lyricsto discantusIncipit { IV- } +>> + +discantusNotes = { + \transpose c' c'' { + \clef "treble" + d'2. d'4 | + b e' d'2 | + c'4 e'4.( d'8 c' b | + a4) b a2 | + b4.( c'8 d'4) c'4 | + \once \override NoteHead #'transparent = ##t + c'1 | + b\breve | + } +} + +discantusLyrics = \lyricmode { + Ju -- bi -- | + la -- te De -- | + o, om -- + nis ter -- | + ra, __ om- | + "..." | + -us. | +} + +altusIncipit = << + \new MensuralVoice = "altusIncipit" << + \repeat unfold 9 { s1 \noBreak } + { + \clef "neomensural-c3" + \key f \major + \time 2/2 + r1 f'1. + } + >> + \new Lyrics \lyricsto altusIncipit { IV- } +>> + +altusNotes = { + \transpose c' c'' { + \clef "treble" + % two measures + r2 g2. e4 fis g | + a2 g4 e | + fis g4.( fis16 e fis4) | + g1 | + \once \override NoteHead #'transparent = ##t + g1 | + g\breve | + } +} + +altusLyrics = \lyricmode { + % two measures + Ju -- bi -- la -- te | + De -- o, om -- | + nis ter -- ra, | + "..." | + -us. | +} + +tenorIncipit = << + \new MensuralVoice = "tenorIncipit" << + \repeat unfold 9 { s1 \noBreak } + { + \clef "neomensural-c4" + \key f \major + \time 2/2 + r\longa + r\breve + r1 c'1. + } + >> + \new Lyrics \lyricsto tenorIncipit { IV- } +>> + +tenorNotes = { + \transpose c' c' { + \once \override Staff.VerticalAxisGroup #'minimum-Y-extent = #'(-6 . 3) + \clef "treble_8" + R1 | + R1 | + R1 | + % two measures + r2 d'2. d'4 b e' | + \once \override NoteHead #'transparent = ##t + e'1 | + d'\breve | + } +} + +tenorLyrics = \lyricmode { + % two measures + Ju -- bi -- la -- te | + "..." | + -us. +} + +bassusIncipit = << + \new MensuralVoice = "bassusIncipit" << + \repeat unfold 9 { s1 \noBreak } + { + \clef "bass" + \key f \major + \time 2/2 + %% incipit + r\maxima + f1. + } + >> + \new Lyrics \lyricsto bassusIncipit { IV- } +>> + +bassusNotes = { + \transpose c' c' { + \clef "bass" + R1 | + R1 | + R1 | + R1 | + g2. e4 | + \once \override NoteHead #'transparent = ##t + e1 | + g\breve | + } +} + +bassusLyrics = \lyricmode { + Ju -- bi- | + "..." | + -us. +} + +\score { + << + \new StaffGroup = choirStaff << + \new Voice = "discantusNotes" << + \global + \set Staff.instrumentName = #"Discantus" + \incipit \discantusIncipit + \discantusNotes + >> + \new Lyrics = "discantusLyrics" \lyricsto discantusNotes { \discantusLyrics } + \new Voice = "altusNotes" << + \global + \set Staff.instrumentName = #"Altus" + \incipit \altusIncipit + \altusNotes + >> + \new Lyrics = "altusLyrics" \lyricsto altusNotes { \altusLyrics } + \new Voice = "tenorNotes" << + \global + \set Staff.instrumentName = #"Tenor" + \incipit \tenorIncipit + \tenorNotes + >> + \new Lyrics = "tenorLyrics" \lyricsto tenorNotes { \tenorLyrics } + \new Voice = "bassusNotes" << + \global + \set Staff.instrumentName = #"Bassus" + \incipit \bassusIncipit + \bassusNotes + >> + \new Lyrics = "bassusLyrics" \lyricsto bassusNotes { \bassusLyrics } + >> + >> + \layout { + \context { + \Score + %% no bar lines in staves or lyrics + \override BarLine #'transparent = ##t + } + %% the next two instructions keep the lyrics between the bar lines + \context { + \Lyrics + \consists "Bar_engraver" + \consists "Separating_line_group_engraver" + } + \context { + \Voice + %% no slurs + \override Slur #'transparent = ##t + %% Comment in the below "\remove" command to allow line + %% breaking also at those bar lines where a note overlaps + %% into the next measure. The command is commented out in this + %% short example score, but especially for large scores, you + %% will typically yield better line breaking and thus improve + %% overall spacing if you comment in the following command. + %%\remove "Forbid_line_break_engraver" + } + indent = 6\cm + incipit-width = 4\cm + } +} diff --git a/input/regression/incipit.ly b/input/regression/incipit.ly index 31d9e6f252..3dee8198a4 100644 --- a/input/regression/incipit.ly +++ b/input/regression/incipit.ly @@ -1,24 +1,27 @@ -\header { - - texidoc = "Incipit can be printed using an InstrumentName grob." +\version "2.13.4" +\header { + texidoc = "Incipits can be printed using an @code{InstrumentName} +grob." } -\version "2.12.0" - -%% to avoid warnings: +%% to prevent warnings/programming errors: #(set-object-property! 'music 'backend-type? ly:music?) #(set-object-property! 'music 'backend-doc "Incipit music") +#(ly:add-interface 'incipit-interface "An incipit." '(music)) +#(let* ((instrument-def (assoc 'InstrumentName all-grob-descriptions)) + (meta-def (assoc 'meta (cdr instrument-def))) + (interfaces-def (assoc 'interfaces (cdr meta-def))) + (interfaces (cdr interfaces-def))) + (set-cdr! interfaces-def (cons 'incipit-interface interfaces))) \score { \new Staff { %% All this would be shortcuted by an appropriate music function: \override Staff.InstrumentName #'music = ##{ \clef "petrucci-c1" c'4 d' e' f' #} \override Staff.InstrumentName #'self-alignment-X = #RIGHT - \override Staff.InstrumentName #'self-alignment-Y = #UP - \override Staff.InstrumentName #'Y-offset = #4 \override Staff.InstrumentName #'padding = #0 - \override Staff.InstrumentName #'stencil = + \override Staff.InstrumentName #'stencil = #(lambda (grob) (let* ((instrument-name (ly:grob-property grob 'long-text)) (layout (ly:output-def-clone (ly:grob-layout grob))) @@ -42,15 +45,14 @@ (ly:score-add-output-def! score layout) (set! (ly:grob-property grob 'long-text) (markup #:score score)) - (ly:system-start-text::print grob))) + (system-start-text::print grob))) %% the instrument name definition is separated: - \set Staff.instrumentName = \markup Instrument + \set Staff.instrumentName = #"Instrument" c'4 d' e' f' g'1 } \layout { - ragged-right = ##t indent = 5\cm - incipit-width = 3 \cm + incipit-width = 3\cm } } \ No newline at end of file diff --git a/lily/system-start-delimiter-engraver.cc b/lily/system-start-delimiter-engraver.cc index ea4fcf38a8..7d86470510 100644 --- a/lily/system-start-delimiter-engraver.cc +++ b/lily/system-start-delimiter-engraver.cc @@ -5,28 +5,26 @@ source file of the GNU LilyPond music typesetter (c) 2005--2009 Han-Wen Nienhuys - */ #include "engraver.hh" - -#include "side-position-interface.hh" -#include "system-start-delimiter.hh" -#include "staff-symbol.hh" -#include "pointer-group-interface.hh" -#include "paper-column.hh" #include "output-def.hh" +#include "paper-column.hh" +#include "pointer-group-interface.hh" +#include "side-position-interface.hh" #include "spanner.hh" +#include "staff-symbol.hh" +#include "system-start-delimiter.hh" struct Bracket_nesting_node { public: - virtual ~Bracket_nesting_node (){} + virtual ~Bracket_nesting_node () {} virtual bool add_staff (Grob *) { return false; } - virtual void add_support (Grob *) { } - virtual void set_bound (Direction, Grob *){} - virtual void set_nesting_support (Grob*) {} - virtual void create_grobs (Engraver*, SCM) {} + virtual void add_support (Grob *) {} + virtual void set_bound (Direction, Grob *) {} + virtual void set_nesting_support (Grob *) {} + virtual void create_grobs (Engraver *, SCM) {} }; struct Bracket_nesting_group : public Bracket_nesting_node @@ -35,12 +33,12 @@ struct Bracket_nesting_group : public Bracket_nesting_node vector children_; SCM symbol_; - void from_list (SCM ); + void from_list (SCM); virtual void add_support (Grob *grob); virtual bool add_staff (Grob *grob); - virtual void set_nesting_support (Grob*); + virtual void set_nesting_support (Grob *); virtual void set_bound (Direction, Grob *grob); - virtual void create_grobs (Engraver*, SCM); + virtual void create_grobs (Engraver *, SCM); ~Bracket_nesting_group (); Bracket_nesting_group (); }; @@ -76,12 +74,11 @@ void Bracket_nesting_group::create_grobs (Engraver *engraver, SCM default_type) { SCM type = scm_is_symbol (symbol_) ? symbol_ : default_type; - delimiter_ = engraver->make_spanner (ly_symbol2string (type).c_str (), SCM_EOL); + delimiter_ = engraver->make_spanner (ly_symbol2string (type).c_str (), + SCM_EOL); for (vsize i = 0 ; i < children_.size (); i++) - { - children_[i]->create_grobs (engraver, default_type); - } + children_[i]->create_grobs (engraver, default_type); } void @@ -89,9 +86,7 @@ Bracket_nesting_group::add_support (Grob *g) { Side_position_interface::add_support (g, delimiter_); for (vsize i = 0 ; i < children_.size (); i++) - { - children_[i]->add_support (g); - } + children_[i]->add_support (g); } Bracket_nesting_group::~Bracket_nesting_group () @@ -104,9 +99,7 @@ Bracket_nesting_group::set_bound (Direction d, Grob *g) { delimiter_->set_bound (d, g); for (vsize i = 0 ; i < children_.size (); i++) - { - children_[i]->set_bound (d, g); - } + children_[i]->set_bound (d, g); } void @@ -114,11 +107,9 @@ Bracket_nesting_group::set_nesting_support (Grob *parent) { if (parent) Side_position_interface::add_support (delimiter_, parent); - + for (vsize i = 0 ; i < children_.size (); i++) - { - children_[i]->set_nesting_support (delimiter_); - } + children_[i]->set_nesting_support (delimiter_); } @@ -137,13 +128,10 @@ Bracket_nesting_group::from_list (SCM x) else if (entry == ly_symbol2scm ("SystemStartBrace") || entry == ly_symbol2scm ("SystemStartBracket") || entry == ly_symbol2scm ("SystemStartBar") - || entry == ly_symbol2scm ("SystemStartSquare") - ) + || entry == ly_symbol2scm ("SystemStartSquare")) symbol_ = entry; else - { - children_.push_back (new Bracket_nesting_staff (0)); - } + children_.push_back (new Bracket_nesting_staff (0)); } } @@ -154,11 +142,11 @@ Bracket_nesting_group::add_staff (Grob *grob) { if (children_[i]->add_staff (grob)) { - Pointer_group_interface::add_grob (delimiter_, ly_symbol2scm ("elements"), grob); + Pointer_group_interface::add_grob (delimiter_, + ly_symbol2scm ("elements"), grob); return true; } } - return false; } @@ -174,9 +162,8 @@ public: protected: Bracket_nesting_group *nesting_; - + DECLARE_ACKNOWLEDGER (system_start_delimiter); - DECLARE_ACKNOWLEDGER (system_start_text); DECLARE_ACKNOWLEDGER (staff_symbol); void process_music (); @@ -199,7 +186,8 @@ System_start_delimiter_engraver::process_music () nesting_->from_list (hierarchy); nesting_->create_grobs (this, delimiter_name); - nesting_->set_bound (LEFT, unsmob_grob (get_property ("currentCommandColumn"))); + nesting_->set_bound (LEFT, + unsmob_grob (get_property ("currentCommandColumn"))); } } @@ -229,14 +217,6 @@ System_start_delimiter_engraver::acknowledge_staff_symbol (Grob_info inf) } } - - -void -System_start_delimiter_engraver::acknowledge_system_start_text (Grob_info inf) -{ - nesting_->add_support (inf.grob ()); -} - void System_start_delimiter_engraver::acknowledge_system_start_delimiter (Grob_info inf) { @@ -247,7 +227,6 @@ System_start_delimiter_engraver::acknowledge_system_start_delimiter (Grob_info i ADD_ACKNOWLEDGER (System_start_delimiter_engraver, staff_symbol); ADD_ACKNOWLEDGER (System_start_delimiter_engraver, system_start_delimiter); -ADD_ACKNOWLEDGER (System_start_delimiter_engraver, system_start_text); ADD_TRANSLATOR (System_start_delimiter_engraver, /* doc */ diff --git a/lily/system-start-text.cc b/lily/system-start-text.cc deleted file mode 100644 index 33b0f68f40..0000000000 --- a/lily/system-start-text.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* - system-start-text.cc -- implement System_start_text - - source file of the GNU LilyPond music typesetter - - (c) 2006--2009 Han-Wen Nienhuys - -*/ - -#include "text-interface.hh" -#include "pointer-group-interface.hh" -#include "output-def.hh" -#include "font-interface.hh" -#include "spanner.hh" -#include "stencil.hh" -#include "item.hh" - -class System_start_text -{ -public: - static Stencil get_stencil (Grob *); - DECLARE_GROB_INTERFACE (); - - DECLARE_SCHEME_CALLBACK (print, (SCM)); -}; - -Stencil -System_start_text::get_stencil (Grob *me_grob) -{ - Spanner *me = dynamic_cast (me_grob); - SCM t = me->get_property ("text"); - if (me->get_break_index () == 0) - t = me->get_property ("long-text"); - - - SCM chain = Font_interface::text_font_alist_chain (me); - - SCM scm_stencil = Text_interface::is_markup (t) - ? Text_interface::interpret_markup (me->layout ()->self_scm (), chain, t) - : SCM_EOL; - - - if (Stencil *p = unsmob_stencil (scm_stencil)) - { - SCM align_y = me_grob->get_property ("self-alignment-Y"); - if (scm_is_number (align_y)) - p->align_to (Y_AXIS, robust_scm2double (align_y, 0.0)); - - /* Horizontal alignment according to the self-alignment-X property - * and indent value. */ - Output_def *layout = me_grob->layout (); - Real indent; - if (me->get_break_index () == 0) - indent = robust_scm2double (layout->c_variable ("indent"), 0); - else - indent = robust_scm2double (layout->c_variable ("short-indent"), 0); - Real align_x = robust_scm2double (me->get_property ("self-alignment-X"), 0); - Interval p_extent_x = p->extent (X_AXIS); - Interval padding (0.0, max (0.0, indent - p_extent_x.length ())); - Real right_padding = padding.length () - padding.linear_combination (align_x); - Box box (Interval (p_extent_x[LEFT], p_extent_x[RIGHT] + right_padding), - p->extent (Y_AXIS)); - Stencil *aligned_p = new Stencil (box, p->expr ()); - return *aligned_p; - } - return Stencil (); -} - - -MAKE_SCHEME_CALLBACK (System_start_text, print, 1); -SCM -System_start_text::print (SCM smob) -{ - Spanner *me = unsmob_spanner (smob); - - if (!me->get_bound (LEFT)->break_status_dir ()) - { - me->suicide (); - return SCM_EOL; - } - - extract_grob_set (me, "elements", all_elts); - vector elts; - for (vsize i = 0; i < all_elts.size (); i++) - if (all_elts[i]->is_live ()) - elts.push_back (all_elts[i]); - - if (!elts.size ()) - { - me->suicide (); - return SCM_EOL; - } - - Grob *common = common_refpoint_of_array (elts, me, Y_AXIS); - - Interval ext; - for (vsize i = elts.size (); i--;) - { - Spanner *sp = dynamic_cast (elts[i]); - - if (sp - && sp->get_bound (LEFT) == me->get_bound (LEFT)) - ext.add_point (sp->relative_coordinate (common, Y_AXIS)); - } - - Stencil m = get_stencil (me); - if (!ext.is_empty ()) - m.translate_axis (ext.center (), Y_AXIS); - return m.smobbed_copy (); -} - - -ADD_INTERFACE (System_start_text, - "Text in front of the system.", - - /* properties */ - "text " - "long-text " - "self-alignment-Y " - "self-alignment-X " - ); diff --git a/python/convertrules.py b/python/convertrules.py index 187dfdd09b..8f9c9d00d4 100644 --- a/python/convertrules.py +++ b/python/convertrules.py @@ -10,7 +10,7 @@ _ = lilylib._ NOT_SMART = _ ("Not smart enough to convert %s") -UPDATE_MANUALLY = _ ("Please refer to the manual for details, and update manually.") +UPDATE_MANUALLY = _ ("Please refer to the manual for details, and update manually.") FROM_TO = _ ( "%s has been replaced by %s") @@ -2911,7 +2911,8 @@ def conv(str): _ ("Autobeaming rules have changed. override-auto-beam-setting and\n\ revert-auto-beam-setting have been eliminated. \\overrideBeamSettings has been\n\ added. BeatGrouping has been eliminated.\n\ -Different settings for vertical layout.")) +Different settings for vertical layout.\n\ +ly:system-start-text::print -> system-start-text::print")) def conv(str): if re.search("override-auto-beam-setting", str): stderr_write ("\n") @@ -2923,9 +2924,9 @@ def conv(str): stderr_write (NOT_SMART % _("override-auto-beam-setting.\n\ Autobeam settings are now reverted with \\revertBeamSettings.\n")) stderr_write (UPDATE_MANUALLY) - str = re.sub(r"\\set\s+#\'beatGrouping", r"\\setBeatGrouping", str) - if re.search(r"(\w+\.beatGrouping)", str): - stderr_write (NOT_SMART % _(".beatGrouping. \n\ + str = re.sub(r"\\set\s+beatGrouping", r"\\setBeatGrouping", str) + if re.search(r"\w+\s*.\s*beatGrouping", str): + stderr_write (NOT_SMART % _("beatGrouping. \n\ beatGrouping with a specified context must now be accomplished with\n\ \\overrideBeamSettings.\n")) stderr_write (UPDATE_MANUALLY) @@ -2934,6 +2935,7 @@ def conv(str): stderr_write(NOT_SMART % _("alignment-offsets has been changed to alignment-distances: \ you must now specify the distances between staves rather than the offset of staves.\n")) stderr_write(UPDATE_MANUALLY) + str = re.sub ('ly:system-start-text::print', 'system-start-text::print', str) return str # Guidelines to write rules (please keep this at the end of this file) diff --git a/scm/define-grob-interfaces.scm b/scm/define-grob-interfaces.scm index 0bed1adc65..f06b0d4a90 100644 --- a/scm/define-grob-interfaces.scm +++ b/scm/define-grob-interfaces.scm @@ -167,11 +167,10 @@ interesting enough to maintain a hara-kiri staff." "A right hand finger instruction." '(digit-names)) -;;; todo: this is not typesetting info. Move to interpretation. (ly:add-interface - 'tablature-interface - "An interface for any notes set in a tablature staff." - '()) + 'system-start-text-interface + "Text in front of the system." + '(long-text self-alignment-X self-alignment-Y text)) (ly:add-interface 'trill-spanner-interface diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index a20dc54cb0..9a43c08933 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -864,8 +864,9 @@ (padding . 0.3) (self-alignment-X . ,CENTER) (self-alignment-Y . ,CENTER) - (stencil . ,ly:system-start-text::print) - (X-offset . ,ly:side-position-interface::x-aligned-side) + (stencil . ,system-start-text::print) + (X-offset . ,system-start-text::calc-x-offset) + (Y-offset . ,system-start-text::calc-y-offset) (meta . ((class . Spanner) (interfaces . (font-interface self-alignment-interface diff --git a/scm/lily-library.scm b/scm/lily-library.scm index adb2bdfdc8..e7f1d295d8 100644 --- a/scm/lily-library.scm +++ b/scm/lily-library.scm @@ -2,7 +2,7 @@ ;;;; lily-library.scm -- utilities ;;;; ;;;; source file of the GNU LilyPond music typesetter -;;;; +;;;; ;;;; (c) 1998--2009 Jan Nieuwenhuizen ;;;; Han-Wen Nienhuys @@ -47,11 +47,15 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; moments -(define-public ZERO-MOMENT (ly:make-moment 0 1)) +(define-public ZERO-MOMENT (ly:make-moment 0 1)) (define-public (moment-min a b) (if (ly:moment output hooks. - + (define-public (collect-bookpart-for-book parser book-part) "Toplevel book-part handler" (define (add-bookpart book-part) @@ -123,7 +127,7 @@ (define-public (scorify-music music parser) "Preprocess MUSIC." - + (for-each (lambda (func) (set! music (func music parser))) toplevel-music-functions) @@ -239,7 +243,7 @@ found." (hash-fold (lambda (k v acc) (acons k v acc)) '() t)) -;; todo: code dup with C++. +;; todo: code dup with C++. (define-safe-public (alist->hash-table lst) "Convert alist to table" (let ((m (make-hash-table (length lst)))) @@ -263,14 +267,14 @@ found." (define (split-list lst n) "Split LST in N equal sized parts" - + (define (helper todo acc-vector k) (if (null? todo) acc-vector (begin (if (< k 0) (set! k (+ n k))) - + (vector-set! acc-vector k (cons (car todo) (vector-ref acc-vector k))) (helper (cdr todo) acc-vector (1- k))))) @@ -296,7 +300,7 @@ found." (reverse (helper lst '() 1))) - + (define-public (list-join lst intermediate) "put INTERMEDIATE between all elts of LST." @@ -314,7 +318,7 @@ found." (define (flatten-list lst) - "Unnest LST" + "Unnest LST" (if (null? lst) '() (if (pair? (car lst)) @@ -328,7 +332,7 @@ found." (define-public (uniq-list lst) "Uniq LST, assuming that it is sorted. Uses equal? for comparisons." - (reverse! + (reverse! (fold (lambda (x acc) (if (null? acc) (list x) @@ -363,7 +367,7 @@ found." (define-public (offset-add a b) (cons (+ (car a) (car b)) - (+ (cdr a) (cdr b)))) + (+ (cdr a) (cdr b)))) (define-public (offset-flip-y o) (cons (car o) (- (cdr o)))) @@ -392,6 +396,8 @@ found." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; intervals +(define-public empty-interval '(+inf.0 . -inf.0)) + (define-public (interval-length x) "Length of the number-pair X, when an interval" (max 0 (- (cdr x) (car x)))) @@ -408,7 +414,7 @@ found." (define-public (interval-index interval dir) "Interpolate INTERVAL between between left (DIR=-1) and right (DIR=+1)" - + (* (+ (interval-start interval) (interval-end interval) (* dir (- (interval-end interval) (interval-start interval)))) 0.5)) @@ -447,6 +453,10 @@ found." (inf? (cdr i)) (> (car i) (cdr i))))) +(define-public (add-point interval p) + (cons (min (interval-start interval) p) + (max (interval-end interval) p))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; string @@ -455,10 +465,10 @@ found." (equal? suffix (substring s (max 0 (- (string-length s) (string-length suffix))) (string-length s)))) - + (define-public (string-startswith s prefix) (equal? prefix (substring s 0 (min (string-length s) (string-length prefix))))) - + (define-public (string-encode-integer i) (cond ((= i 0) "o") @@ -522,7 +532,7 @@ possibly turned off." (fold-right conc #f lst)) (define-public (string-regexp-substitute a b str) - (regexp-substitute/global #f a str 'pre b 'post)) + (regexp-substitute/global #f a str 'pre b 'post)) (define (regexp-split str regex) (define matches '()) @@ -577,8 +587,8 @@ applied to function @var{getter}.") (stringstring (car lst)) (symbol->string (car r)))) ;; -;; don't confuse users with # syntax. -;; +;; don't confuse users with # syntax. +;; (define-public (scm->string val) (if (and (procedure? val) (symbol? (procedure-name val))) @@ -633,7 +643,7 @@ applied to function @var{getter}.") (define-public (version-not-seen-message input-file-name) (ly:message - "~a:0: ~a ~a" + "~a:0: ~a ~a" input-file-name (_ "warning:") (format #f @@ -642,7 +652,7 @@ applied to function @var{getter}.") (define-public (old-relative-not-used-message input-file-name) (ly:message - "~a:0: ~a ~a" + "~a:0: ~a ~a" input-file-name (_ "warning:") (_ "old relative compatibility not used"))) diff --git a/scm/output-lib.scm b/scm/output-lib.scm index db1181f740..c174a295c3 100644 --- a/scm/output-lib.scm +++ b/scm/output-lib.scm @@ -1,7 +1,7 @@ ;;;; output-lib.scm -- implement Scheme output helper functions ;;;; ;;;; source file of the GNU LilyPond music typesetter -;;;; +;;;; ;;;; (c) 1998--2009 Jan Nieuwenhuizen ;;;; Han-Wen Nienhuys @@ -13,16 +13,19 @@ (define-public (grob::has-interface grob iface) (memq iface (ly:grob-interfaces grob))) +(define-public (grob::is-live? grob) + (pair? (ly:grob-basic-properties grob))) + (define-public (make-stencil-boxer thickness padding callback) "Return function that adds a box around the grob passed as argument." (lambda (grob) - + (box-stencil (callback grob) thickness padding))) (define-public (make-stencil-circler thickness padding callback) "Return function that adds a circle around the grob passed as argument." - + (lambda (grob) (circle-stencil (callback grob) thickness padding))) (define-public (print-circled-text-callback grob) @@ -33,7 +36,7 @@ (define-public (event-cause grob) (let* ((cause (ly:grob-property grob 'cause))) - + (cond ((ly:stream-event? cause) cause) ((ly:grob? cause) (event-cause cause)) @@ -56,14 +59,14 @@ (eq? 'harmonic-event (ly:event-property ev 'class))) (ly:event-property event 'articulations))))) - + (make-whiteout-markup (make-vcenter-markup (format "~a" (- (ly:pitch-semitones pitch) (list-ref tuning - ;; remove 1 because list index starts at 0 and guitar string at 1. + ;; remove 1 because list index starts at 0 and guitar string at 1. (- string 1)))))) )) @@ -73,14 +76,14 @@ ;; the "first fret" on the fifth string is really the sixth fret ;; on the banjo neck. ;; We solve this by defining a new fret-number-tablature function: -(define-public (fret-number-tablature-format-banjo string +(define-public (fret-number-tablature-format-banjo string context event) (let* ((tuning (ly:context-property context 'stringTunings)) (pitch (ly:event-property event 'pitch)) ) (make-whiteout-markup - (make-vcenter-markup + (make-vcenter-markup (let ((fret (- (ly:pitch-semitones pitch) (list-ref tuning (- string 1))))) (number->string (cond ((and (> fret 0) (= string 5)) @@ -98,7 +101,7 @@ (ly:event-property (event-cause grob) 'duration))) (define-public (note-head::calc-duration-log grob) - (min 2 + (min 2 (ly:duration-log (ly:event-property (event-cause grob) 'duration)))) @@ -126,12 +129,12 @@ -;; silly, use alist? +;; silly, use alist? (define-public (note-head::calc-glyph-name grob) (let* ((style (ly:grob-property grob 'style)) (log (min 2 (ly:grob-property grob 'duration-log)))) - + (case style ;; "default" style is directly handled in note-head.cc as a ;; special case (HW says, mainly for performance reasons). @@ -142,7 +145,7 @@ ((harmonic-black) "2harmonic") ((harmonic-mixed) (if (<= log 1) "0harmonic" "2harmonic")) - ((baroque) + ((baroque) ;; Oops, I actually would not call this "baroque", but, for ;; backwards compatibility to 1.4, this is supposed to take ;; brevis, longa and maxima from the neo-mensural font and all @@ -214,19 +217,19 @@ centered, X==1 is at the right, X == -1 is at the left." ;; Bar lines. ;; -;; How should a bar line behave at a break? +;; How should a bar line behave at a break? (define bar-glyph-alist '((":|:" . (":|" . "|:")) (":|.|:" . (":|" . "|:")) (":|.:" . (":|" . "|:")) ("||:" . ("||" . "|:")) - ("dashed" . ("dashed" . '())) + ("dashed" . ("dashed" . '())) ("|" . ("|" . ())) ("||:" . ("||" . "|:")) ("|s" . (() . "|")) ("|:" . ("|" . "|:")) ("|." . ("|." . ())) - + ;; hmm... should we end with a bar line here? (".|" . ("|" . ".|")) (":|" . (":|" . ())) @@ -239,7 +242,7 @@ centered, X==1 is at the right, X == -1 is at the left." ("'" . ("'" . ())) ("empty" . (() . ())) ("brace" . (() . "brace")) - ("bracket" . (() . "bracket")) + ("bracket" . (() . "bracket")) )) (define-public (bar-line::calc-glyph-name grob) @@ -280,28 +283,28 @@ centered, X==1 is at the right, X == -1 is at the left." (let* ((ev (event-cause grob))) - (format "~a:~a" + (format "~a:~a" (ly:event-property ev 'denominator) (ly:event-property ev 'numerator)))) -; a formatter function, which is simply a wrapper around an existing +; a formatter function, which is simply a wrapper around an existing ; tuplet formatter function. It takes the value returned by the given -; function and appends a note of given length. +; function and appends a note of given length. (define-public ((tuplet-number::append-note-wrapper function note) grob) (let* ((txt (if function (function grob) #f))) - (if txt + (if txt (markup txt #:fontsize -5 #:note note UP) (markup #:fontsize -5 #:note note UP)))) -; Print a tuplet denominator with a different number than the one derived from +; Print a tuplet denominator with a different number than the one derived from ; the actual tuplet fraction (define-public ((tuplet-number::non-default-tuplet-denominator-text denominator) grob) -(number->string (if denominator - denominator +(number->string (if denominator + denominator (ly:event-property (event-cause grob) 'denominator)))) -; Print a tuplet fraction with different numbers than the ones derived from +; Print a tuplet fraction with different numbers than the ones derived from ; the actual tuplet fraction (define-public ((tuplet-number::non-default-tuplet-fraction-text denominator numerator) grob) (let* ((ev (event-cause grob)) @@ -309,7 +312,7 @@ centered, X==1 is at the right, X == -1 is at the left." (num (if numerator numerator (ly:event-property ev 'numerator)))) (format "~a:~a" den num))) -; Print a tuplet fraction with note durations appended to the numerator and the +; Print a tuplet fraction with note durations appended to the numerator and the ; denominator (define-public ((tuplet-number::fraction-with-notes denominatornote numeratornote) grob) (let* ((ev (event-cause grob)) @@ -317,17 +320,17 @@ centered, X==1 is at the right, X == -1 is at the left." (numerator (ly:event-property ev 'numerator))) ((tuplet-number::non-default-fraction-with-notes denominator denominatornote numerator numeratornote) grob))) -; Print a tuplet fraction with note durations appended to the numerator and the +; Print a tuplet fraction with note durations appended to the numerator and the ; denominator (define-public ((tuplet-number::non-default-fraction-with-notes denominator denominatornote numerator numeratornote) grob) (let* ((ev (event-cause grob)) (den (if denominator denominator (ly:event-property ev 'denominator))) (num (if numerator numerator (ly:event-property ev 'numerator)))) - (make-concat-markup (list - (make-simple-markup (format "~a" den)) + (make-concat-markup (list + (make-simple-markup (format "~a" den)) (markup #:fontsize -5 #:note denominatornote UP) (make-simple-markup " : ") - (make-simple-markup (format "~a" num)) + (make-simple-markup (format "~a" num)) (markup #:fontsize -5 #:note numeratornote UP))))) @@ -361,10 +364,10 @@ centered, X==1 is at the right, X == -1 is at the left." (define-public (key-signature-interface::alteration-position step alter c0-position) ;; TODO: memoize - this is mostly constant. - + ;; fes, ges, as and bes typeset in lower octave (define FLAT_TOP_PITCH 2) - + ;; ais and bis typeset in lower octave (define SHARP_TOP_PITCH 4) @@ -374,19 +377,19 @@ centered, X==1 is at the right, X == -1 is at the left." ((from-bottom-pos (modulo (+ 4 49 c0-position) 7)) (p step) (c0 (- from-bottom-pos 4))) - + (if (or (and (< alter 0) (or (> p FLAT_TOP_PITCH) (> (+ p c0) 4)) (> (+ p c0) 1)) (and (> alter 0) (or (> p SHARP_TOP_PITCH) (> (+ p c0) 5)) (> (+ p c0) 2)) ) - ;; Typeset below c_position + ;; Typeset below c_position (set! p (- p 7))) ;; Provide for the four cases in which there's a glitch ;; it's a hack, but probably not worth ;; the effort of finding a nicer solution. - ;; --dl. + ;; --dl. (cond ((and (= c0 2) (= p 3) (> alter 0)) (set! p (- p 7))) @@ -419,7 +422,7 @@ centered, X==1 is at the right, X == -1 is at the left." (1 . "accidentals.doublesharp") (-1 . "accidentals.flatflat") - + (3/4 . "accidentals.sharp.slashslash.stemstemstem") (1/4 . "accidentals.sharp.slashslash.stem") (-1/4 . "accidentals.mirroredflat") @@ -442,7 +445,7 @@ centered, X==1 is at the right, X == -1 is at the left." (-8/9 . "accidentals.flat.slashslash") (-1 . "accidentals.flatflat") )) - + (define-public alteration-hufnagel-glyph-name-alist '((-1/2 . "accidentals.hufnagelM1") (0 . "accidentals.vaticana0") @@ -508,7 +511,7 @@ centered, X==1 is at the right, X == -1 is at the left." (lp (car stencils)) (rp (cadr stencils)) (padding (ly:grob-property grob 'padding 0.1))) - + (ly:stencil-add (ly:stencil-translate-axis lp (- (car x-ext) padding) X) (ly:stencil-translate-axis rp (+ (cdr x-ext) padding) X)) @@ -537,7 +540,7 @@ centered, X==1 is at the right, X == -1 is at the left." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; +;; (define-public (chain-grob-member-functions grob value . funcs) (for-each @@ -553,14 +556,14 @@ centered, X==1 is at the right, X == -1 is at the left." (define-public (bend::print spanner) (define (close a b) (< (abs (- a b)) 0.01)) - + (let* ((delta-y (* 0.5 (ly:grob-property spanner 'delta-position))) (left-span (ly:spanner-bound spanner LEFT)) (dots (if (and (grob::has-interface left-span 'note-head-interface) (ly:grob? (ly:grob-object left-span 'dot))) (ly:grob-object left-span 'dot) #f)) - + (right-span (ly:spanner-bound spanner RIGHT)) (thickness (* (ly:grob-property spanner 'thickness) (ly:output-def-lookup (ly:grob-layout spanner) @@ -588,12 +591,12 @@ centered, X==1 is at the right, X == -1 is at the left." (+ left-x minimum-length))) (self-x (ly:grob-relative-coordinate spanner common X)) (dx (- right-x left-x)) - (exp (list 'path thickness + (exp (list 'path thickness `(quote (rmoveto ,(- left-x self-x) 0 - rcurveto + rcurveto ,(/ dx 3) 0 ,dx ,(* 0.66 delta-y) @@ -619,7 +622,7 @@ centered, X==1 is at the right, X == -1 is at the left." (ly:grob-array-ref cols (1+ idx)) 'when) (ly:grob-property (ly:grob-array-ref cols idx) 'when)))) - + (moment-min (lambda (x y) (cond ((and x y) @@ -628,7 +631,7 @@ centered, X==1 is at the right, X == -1 is at the left." y)) (x x) (y y))))) - + (fold moment-min #f (map get-difference (iota (1- (ly:grob-array-length cols))))))) @@ -641,7 +644,7 @@ centered, X==1 is at the right, X == -1 is at the left." (let* ((event (event-cause grob)) (digit (ly:event-property event 'digit))) - + (if (> digit 5) (ly:input-message (ly:event-property event 'origin) "Warning: Fingering notation for finger number ~a" digit)) @@ -652,7 +655,7 @@ centered, X==1 is at the right, X == -1 is at the left." (define-public (string-number::calc-text grob) (let* ((digit (ly:event-property (event-cause grob) 'string-number))) - + (number->string digit 10) )) @@ -679,11 +682,11 @@ centered, X==1 is at the right, X == -1 is at the left." (define-public (lyric-text::print grob) "Allow interpretation of tildes as lyric tieing marks." - + (let* ((text (ly:grob-property grob 'text))) - (grob-interpret-markup grob + (grob-interpret-markup grob (if (string? text) (make-tied-lyric-markup text) text)))) @@ -695,7 +698,7 @@ centered, X==1 is at the right, X == -1 is at the left." ;; fret boards (define-public (fret-board::calc-stencil grob) - (grob-interpret-markup + (grob-interpret-markup grob (make-fret-diagram-verbose-markup (ly:grob-property grob 'dot-placement-list)))) @@ -723,3 +726,92 @@ centered, X==1 is at the right, X == -1 is at the left." note-head-location))) 0.0)) 0.0)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; instrument names + +(define-public (system-start-text::print grob) + (let* ((left-bound (ly:spanner-bound grob LEFT)) + (left-mom (ly:grob-property left-bound 'when)) + (name (if (moment<=? left-mom ZERO-MOMENT) + (ly:grob-property grob 'long-text) + (ly:grob-property grob 'text)))) + + (if (and (markup? name) + (!= (ly:item-break-dir left-bound) CENTER)) + + (grob-interpret-markup grob name) + (ly:grob-suicide! grob)))) + +(define-public (system-start-text::calc-x-offset grob) + (let* ((left-bound (ly:spanner-bound grob LEFT)) + (left-mom (ly:grob-property left-bound 'when)) + (layout (ly:grob-layout grob)) + (indent (ly:output-def-lookup layout + (if (moment<=? left-mom ZERO-MOMENT) + 'indent + 'short-indent) + 0.0)) + (system (ly:grob-system grob)) + (my-extent (ly:grob-extent grob system X)) + (elements (ly:grob-object system 'elements)) + (common (ly:grob-common-refpoint-of-array system elements X)) + (total-ext empty-interval) + (align-x (ly:grob-property grob 'self-alignment-X 0)) + (padding (min 0 (- (interval-length my-extent) indent))) + (right-padding (- padding + (/ (* padding (1+ align-x)) 2)))) + + (let loop ((l (ly:grob-array-length elements))) + (if (> l 0) + (let ((elt (ly:grob-array-ref elements (1- l)))) + + (if (grob::has-interface elt 'system-start-delimiter-interface) + (let ((dims (ly:grob-extent elt common X))) + (if (interval-sane? dims) + (set! total-ext (interval-union total-ext dims))))) + (loop (1- l))))) + + (+ + (ly:side-position-interface::x-aligned-side grob) + right-padding + (- (interval-length total-ext))))) + +(define-public (system-start-text::calc-y-offset grob) + + (define (live-elements-list me) + (let* ((elements (ly:grob-object me 'elements)) + (elts-length (ly:grob-array-length elements)) + (live-elements '())) + (let get-live ((len elts-length)) + (if (> len 0) + (let ((elt (ly:grob-array-ref elements (1- len)))) + + (if (grob::is-live? elt) + (set! live-elements (cons elt live-elements))) + (get-live (1- len))))) + live-elements)) + + (let* ((left-bound (ly:spanner-bound grob LEFT)) + (live-elts (live-elements-list grob)) + (system (ly:grob-system grob)) + (extent empty-interval)) + + (if (and (pair? live-elts) + (interval-sane? (ly:grob-extent grob system Y))) + (let get-extent ((lst live-elts)) + (if (pair? lst) + (let ((axis-group (car lst))) + + (if (and (ly:spanner? axis-group) + (equal? (ly:spanner-bound axis-group LEFT) + left-bound)) + (set! extent (add-point + extent + (ly:grob-relative-coordinate axis-group system Y)))) + + (get-extent (cdr lst)))))) + + (+ + (ly:self-alignment-interface::y-aligned-on-self grob) + (interval-center extent)))) -- 2.39.5