]> git.donarmstrong.com Git - lilypond.git/commitdiff
Improves horizontal spacing of vertical axis groups that span bars traverse.
authorMike Solomon <mike@apollinemike.com>
Sat, 1 Oct 2011 14:40:28 +0000 (16:40 +0200)
committerMike Solomon <mike@apollinemike.com>
Sat, 1 Oct 2011 14:40:28 +0000 (16:40 +0200)
Fixes issue 1846.

This patch introduces the idea of a pure-from-neighbor-interface.
The interface provides support for grobs whose pure height is difficult
to estimate (any grob that crosses staffs likely suffers from this)
by allowing for the creation of spacing "stubs" in the crossed
vertical axis groups.  These stubs take their pure heights from their
neighbors.  So long as one knows that a grob fully crosses a vertical
axis group and the grob should take up the full vertical space of this
axis group for its rank, using approximations of pure height's from the
grob's neighbors ensures that it will be as tall as the rest of the
axis group without triggering a vertical alignment.

13 files changed:
input/regression/span-bar-allow-span-bar.ly [new file with mode: 0644]
lily/grob.cc
lily/include/grob.hh
lily/include/pure-from-neighbor-interface.hh [new file with mode: 0644]
lily/pure-from-neighbor-engraver.cc [new file with mode: 0644]
lily/pure-from-neighbor-interface.cc [new file with mode: 0644]
lily/span-bar-engraver.cc
lily/span-bar-stub-engraver.cc [new file with mode: 0644]
lily/span-bar.cc
ly/engraver-init.ly
scm/define-grob-properties.scm
scm/define-grobs.scm
scm/output-lib.scm

diff --git a/input/regression/span-bar-allow-span-bar.ly b/input/regression/span-bar-allow-span-bar.ly
new file mode 100644 (file)
index 0000000..5bb765d
--- /dev/null
@@ -0,0 +1,59 @@
+
+\version "2.15.10"
+
+\header {
+  texidoc = "The @code{SpanBarStub} grob takes care of horizontal spacing
+for @code{SpanBar} grobs.  When the @code{SpanBar} is disallowed, objects
+in contexts that the span bar would have otherwise crossed align as if the
+span bar were not there.
+"
+}
+
+<<
+  \new Staff {
+    \repeat unfold 64 { c''8 }
+  }
+  \new GrandStaff <<
+    \new Staff
+      \new Voice = "upper"
+        \relative c'' {
+          c2 c c c
+          \once \override Staff . BarLine #'allow-span-bar = ##f
+          c2 c c c
+          c2 c c c
+          \once \override Staff . BarLine #'allow-span-bar = ##f
+          c2 c c c
+        }
+    \new Lyrics \lyricsto "upper" \lyricmode {
+      long-syllable a b c long-syllable a b c
+      long-syllable a b c long-syllable a b c
+    }
+
+    \new Staff
+      \new Voice = "middle"
+        \relative c'' {
+          c2 c c c
+          c2 c c c
+          c2 c c c
+          \once \override Staff . BarLine #'allow-span-bar = ##f
+          c2 c c c
+        }
+    \new Lyrics \lyricsto "middle" \lyricmode {
+      syllable a b c syllable a b c
+      syllable a b c syllable a b c
+    }
+
+    \new Staff
+      \new Voice = "lower"
+        \relative c'' {
+          c2 c c c
+          c2 c c c
+          c2 c c c
+          c2 c c c
+        }
+    \new Lyrics \lyricsto "lower" \lyricmode {
+      word a b c word a b c
+      word a b c word a b c
+    }
+  >>
+>>
index 36aadb4e938b549df05260d98cf7dc13030e6455..fa8e1f684307453ec9d90b1d4998c9747b2e212a 100644 (file)
@@ -572,6 +572,82 @@ Grob::fixup_refpoint ()
     }
 }
 
+/****************************************************************
+  VERTICAL ORDERING
+****************************************************************/
+
+Grob*
+get_maybe_root_vertical_alignment (Grob *g, Grob *maybe)
+{
+  if (!g)
+    return maybe;
+  if (Align_interface::has_interface (g))
+    return get_maybe_root_vertical_alignment (g->get_parent (Y_AXIS), g);
+  return get_maybe_root_vertical_alignment (g->get_parent (Y_AXIS), maybe);
+
+}
+
+Grob*
+Grob::get_root_vertical_alignment (Grob *g)
+{
+  return get_maybe_root_vertical_alignment (g, 0);
+}
+
+Grob*
+Grob::get_vertical_axis_group (Grob *g)
+{
+  if (!g)
+    return 0;
+  if (Axis_group_interface::has_interface (g)
+      && Align_interface::has_interface (g->get_parent (Y_AXIS)))
+    return g;
+  return get_vertical_axis_group (g->get_parent (Y_AXIS));
+
+}
+
+int
+Grob::get_vertical_axis_group_index (Grob *g)
+{
+  Grob *val = get_root_vertical_alignment (g);
+  if (!val)
+    return -1;
+  Grob *vax = get_vertical_axis_group (g);
+  extract_grob_set (val, "elements", elts);
+  for (vsize i = 0; i < elts.size (); i++)
+    if (elts[i] == vax)
+      return (int) i;
+  g->programming_error ("could not find this grob's vertical axis group in the vertical alignment");
+  return -1;
+}
+
+bool
+Grob::vertical_less (Grob *g1, Grob *g2)
+{
+  Grob *vag = get_root_vertical_alignment (g1);
+  if (!vag)
+    return false;
+  if (!vag)
+    {
+      g1->programming_error ("grob does not belong to a VerticalAlignment?");
+      return false;
+    }
+  Grob *ag1 = get_vertical_axis_group (g1);
+  Grob *ag2 = get_vertical_axis_group (g2);
+
+  extract_grob_set (vag, "elements", elts);
+
+  for (vsize i = 0; i < elts.size (); i++)
+    {
+      if (elts[i] == ag1)
+        return true;
+      if (elts[i] == ag2)
+        return false;
+    }
+
+  g1->programming_error ("could not place this grob in its axis group");
+  return false;
+}
+
 /****************************************************************
   MESSAGES
 ****************************************************************/
index 5ca85402e0468d8cb21aee93488e206f835d2f03..36f912a2894629a4b789366bd359d486ee60a238 100644 (file)
@@ -140,6 +140,12 @@ public:
   Grob *get_parent (Axis a) const;
   void fixup_refpoint ();
 
+  /* vertical ordering */
+  static Grob *get_root_vertical_alignment (Grob *g);
+  static Grob *get_vertical_axis_group (Grob *g);
+  static bool vertical_less (Grob *g1, Grob *g2);
+  static int get_vertical_axis_group_index (Grob *g);
+
   virtual Interval_t<int> spanned_rank_interval () const;
   virtual bool pure_is_visible (int start, int end) const;
   bool check_cross_staff (Grob *common);
diff --git a/lily/include/pure-from-neighbor-interface.hh b/lily/include/pure-from-neighbor-interface.hh
new file mode 100644 (file)
index 0000000..eb46139
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2011 Mike Solomon <mike@apollinemike.com>
+
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PURE_FROM_NEIGHBOR_INTERFACE_HH
+#define PURE_FROM_NEIGHBOR_INTERFACE_HH
+
+#include "lily-proto.hh"
+#include "grob-interface.hh"
+
+class Pure_from_neighbor_interface
+{
+public:
+  DECLARE_SCHEME_CALLBACK (filter_elements, (SCM));
+  DECLARE_GROB_INTERFACE ();
+
+};
+
+#endif
diff --git a/lily/pure-from-neighbor-engraver.cc b/lily/pure-from-neighbor-engraver.cc
new file mode 100644 (file)
index 0000000..14d9473
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2011 Mike Solomon <mike@apollinemike.com>
+
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <map>
+#include <algorithm>
+
+#include "grob.hh"
+#include "item.hh"
+#include "pointer-group-interface.hh"
+#include "pure-from-neighbor-interface.hh"
+#include "engraver.hh"
+
+class Pure_from_neighbor_engraver : public Engraver
+{
+  vector<Grob *> items_then_;
+  vector<Grob *> items_now_;
+  vector<Grob *> pures_then_;
+  vector<Grob *> pures_now_;
+
+public:
+  TRANSLATOR_DECLARATIONS (Pure_from_neighbor_engraver);
+protected:
+  DECLARE_ACKNOWLEDGER (pure_from_neighbor);
+  DECLARE_ACKNOWLEDGER (item);
+  void stop_translation_timestep ();
+};
+
+Pure_from_neighbor_engraver::Pure_from_neighbor_engraver ()
+{
+}
+
+void
+Pure_from_neighbor_engraver::acknowledge_item (Grob_info i)
+{
+  SCM pure_relevant_p = ly_lily_module_constant ("pure-relevant?");
+  if (!Pure_from_neighbor_interface::has_interface (i.grob ())
+      && to_boolean (scm_call_1 (pure_relevant_p, i.item ()->self_scm ())))
+    items_now_.push_back (i.item ());
+}
+
+// note that this can get out of hand if there are lots of vertical axis groups...
+
+void
+Pure_from_neighbor_engraver::acknowledge_pure_from_neighbor (Grob_info i)
+{
+  pures_now_.push_back (i.item ());
+}
+
+void
+Pure_from_neighbor_engraver::stop_translation_timestep ()
+{
+  if (pures_now_.size ())
+    {
+      for (vsize i = 0; i < pures_now_.size (); i++)
+        for (vsize j = 0; j < items_then_.size (); j++)
+          Pointer_group_interface::add_grob (pures_now_[i], ly_symbol2scm ("elements"), items_then_[j]);
+
+      for (vsize i = 0; i < pures_then_.size (); i++)
+        for (vsize j = 0; j < items_now_.size (); j++)
+          Pointer_group_interface::add_grob (pures_then_[i], ly_symbol2scm ("elements"), items_now_[j]);
+
+      items_then_.clear ();
+      items_then_.insert (items_then_.end (), items_now_.begin (), items_now_.end ());
+      items_now_.clear ();
+
+      pures_then_.clear ();
+      pures_then_.insert (pures_then_.end (), pures_now_.begin (), pures_now_.end ());
+      pures_now_.clear ();
+    }
+}
+
+#include "translator.icc"
+
+ADD_ACKNOWLEDGER (Pure_from_neighbor_engraver, item);
+ADD_ACKNOWLEDGER (Pure_from_neighbor_engraver, pure_from_neighbor);
+ADD_TRANSLATOR (Pure_from_neighbor_engraver,
+                /* doc */
+                "Coordinates items that get their pure heights from their neighbors.",
+
+                /* create */
+                "",
+
+                /* read */
+                "",
+
+                /* write */
+                ""
+               );
diff --git a/lily/pure-from-neighbor-interface.cc b/lily/pure-from-neighbor-interface.cc
new file mode 100644 (file)
index 0000000..8d5e724
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2011 Mike Solomon <mike@apollinemike.com>
+
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "grob.hh"
+#include "grob-array.hh"
+#include "pointer-group-interface.hh"
+#include "pure-from-neighbor-interface.hh"
+#include "spanner.hh"
+#include "system.hh"
+
+MAKE_SCHEME_CALLBACK (Pure_from_neighbor_interface, filter_elements, 1);
+SCM
+Pure_from_neighbor_interface::filter_elements (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+  extract_grob_set (me, "elements", elts);
+  vector<Grob *> new_elts;
+  Interval_t<int> srl = me->get_system ()->spanned_rank_interval ();
+  for (vsize i = 0; i < elts.size (); i++)
+    if (srl.contains (elts[i]->spanned_rank_interval ()[LEFT]))
+      new_elts.push_back (elts[i]);
+
+  SCM elements_scm = me->get_object ("elements");
+  if (Grob_array::unsmob (elements_scm))
+    {
+      vector<Grob *> &arr
+        = unsmob_grob_array (elements_scm)->array_reference ();
+      arr = new_elts;
+    }
+
+  return SCM_BOOL_T;
+}
+
+ADD_INTERFACE (Pure_from_neighbor_interface,
+               "A collection of routines to allow for objects' pure"
+               "heights and heights to be calculated based on the"
+               "heights of the objects' neighbors.",
+
+               /* properties */
+               "elements-filtered "
+              );
index 6d145898f382ee63f21e92bdb81797c1e77d6653..4addffcac66b218f8c1efd91feb9e16d0a7252dd 100644 (file)
@@ -33,6 +33,7 @@ dependencies to the spanbars.
 class Span_bar_engraver : public Engraver
 {
   Item *spanbar_;
+  bool make_spanbar_;
   vector<Item *> bars_;
 
 public:
@@ -40,11 +41,13 @@ public:
 protected:
   DECLARE_ACKNOWLEDGER (bar_line);
   void stop_translation_timestep ();
+  void process_acknowledged ();
 };
 
 Span_bar_engraver::Span_bar_engraver ()
 {
   spanbar_ = 0;
+  make_spanbar_ = false;
 }
 
 void
@@ -57,22 +60,32 @@ Span_bar_engraver::acknowledge_bar_line (Grob_info i)
       bars_.push_back (it);
 
       if (bars_.size () >= 2 && !spanbar_)
-        {
-          spanbar_ = make_item ("SpanBar", SCM_EOL);
-
-          spanbar_->set_parent (bars_[0], X_AXIS);
-        }
+        make_spanbar_ = true;
     }
 }
 
 void
-Span_bar_engraver::stop_translation_timestep ()
+Span_bar_engraver::process_acknowledged ()
 {
-  if (spanbar_)
+  if (make_spanbar_)
     {
+      Grob *vag = Grob::get_root_vertical_alignment (bars_[0]);
+      if (vag)
+        vector_sort (bars_, Grob::vertical_less);
+      spanbar_ = make_item ("SpanBar", SCM_EOL);
+
+      spanbar_->set_parent (bars_[0], X_AXIS);
       for (vsize i = 0; i < bars_.size (); i++)
         Span_bar::add_bar (spanbar_, bars_[i]);
+      make_spanbar_ = false;
+    }
+}
 
+void
+Span_bar_engraver::stop_translation_timestep ()
+{
+  if (spanbar_)
+    {
       SCM vissym = ly_symbol2scm ("break-visibility");
       SCM vis = bars_[0]->internal_get_property (vissym);
       if (ly_is_equal (spanbar_->internal_get_property (vissym), vis))
diff --git a/lily/span-bar-stub-engraver.cc b/lily/span-bar-stub-engraver.cc
new file mode 100644 (file)
index 0000000..47b0c1a
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2011 Mike Solomon <mike@apollinemike.com>
+
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <map>
+#include <algorithm>
+
+#include "align-interface.hh"
+#include "bar-line.hh"
+#include "context.hh"
+#include "grob.hh"
+#include "item.hh"
+#include "pointer-group-interface.hh"
+#include "span-bar.hh"
+#include "engraver.hh"
+
+class Span_bar_stub_engraver : public Engraver
+{
+  vector<Grob *> spanbars_;
+  map<Grob *, Context *> axis_groups_;
+
+public:
+  TRANSLATOR_DECLARATIONS (Span_bar_stub_engraver);
+protected:
+  DECLARE_ACKNOWLEDGER (span_bar);
+  DECLARE_ACKNOWLEDGER (hara_kiri_group_spanner);
+  void process_acknowledged ();
+};
+
+Span_bar_stub_engraver::Span_bar_stub_engraver ()
+{
+}
+
+void
+Span_bar_stub_engraver::acknowledge_span_bar (Grob_info i)
+{
+  spanbars_.push_back (i.grob ());
+}
+
+// note that this can get out of hand if there are lots of vertical axis groups...
+
+void
+Span_bar_stub_engraver::acknowledge_hara_kiri_group_spanner (Grob_info i)
+{
+  axis_groups_[i.grob ()] = i.context ();
+}
+
+void
+Span_bar_stub_engraver::process_acknowledged ()
+{
+  if (!spanbars_.size ())
+    return;
+
+  Grob *vertical_alignment = Grob::get_root_vertical_alignment ((*axis_groups_.begin ()).first);
+  if (!vertical_alignment) // we are at the beginning of a score, so no need for stubs
+    return;
+
+  extract_grob_set (vertical_alignment, "elements", elts);
+
+  for (vsize i = 0; i < spanbars_.size (); i++)
+    {
+      extract_grob_set (spanbars_[i], "elements", bars);
+      vector<vsize> bar_axis_indices;
+      for (vsize j = 0; j < bars.size (); j++)
+        {
+          int i = Grob::get_vertical_axis_group_index (bars[j]);
+          if (i >= 0)
+            bar_axis_indices.push_back ((vsize) i);
+        }
+      vector<Context *> affected_contexts;
+      vector<Grob *> y_parents;
+      vector<bool> keep_extent;
+      for (vsize j = 0; j < elts.size (); j++)
+        {
+          if (j > bar_axis_indices[0]
+              && j < bar_axis_indices.back ()
+              && find (bar_axis_indices.begin (), bar_axis_indices.end (), j) == bar_axis_indices.end ())
+            {
+              vsize k = 0;
+              for (; k < bar_axis_indices.size (); k++)
+                if (bar_axis_indices[k] > j)
+                  break;
+
+              k--;
+              keep_extent.push_back (to_boolean (bars[k]->get_property ("allow-span-bar")));
+
+              Context *c = axis_groups_[elts[j]];
+              if (c && c->get_parent_context ())
+                {
+                  y_parents.push_back (elts[j]);
+                  affected_contexts.push_back (c);
+                }
+            }
+        }
+      reverse (affected_contexts); // from bottom to top
+      reverse (y_parents); // from bottom to top
+      reverse (keep_extent); // from bottom to top
+      for (vsize j = 0; j < affected_contexts.size (); j++)
+        {
+          Item *it = new Item (updated_grob_properties (affected_contexts[j], ly_symbol2scm ("SpanBarStub")));
+          it->set_parent (spanbars_[i], X_AXIS);
+          Grob_info gi = make_grob_info (it, spanbars_[i]->self_scm ());
+          gi.rerouting_daddy_context_ = affected_contexts[j];
+          announce_grob (gi);
+          if (!keep_extent[j])
+            it->set_property ("Y-extent", ly_interval2scm (Interval (infinity_f, -infinity_f)));
+        }
+    }
+  spanbars_.clear ();
+}
+
+#include "translator.icc"
+
+ADD_ACKNOWLEDGER (Span_bar_stub_engraver, span_bar);
+ADD_ACKNOWLEDGER (Span_bar_stub_engraver, hara_kiri_group_spanner);
+ADD_TRANSLATOR (Span_bar_stub_engraver,
+                /* doc */
+                "Make stubs for span bars in all contexts that the span bars cross.",
+
+                /* create */
+                "SpanBarStub ",
+
+                /* read */
+                "",
+
+                /* write */
+                ""
+               );
index 4cc9971d5da80fc3550f077a53cdad6014da9182..0a46aa69798e1a0b5a1b80161aa774997f7ea4ee 100644 (file)
@@ -88,8 +88,6 @@ Span_bar::print (SCM smobbed_me)
   if (!model_bar)
     model_bar = me;
 
-  vector_sort (extents, Interval::left_less);
-
   Stencil span_bar;
   for (vsize i = 1; i < extents.size (); i++)
     {
index d719d4a43ff9e2d0a3d8355c812540adc116a7ec..41569cd4aed702c7837e76e341b03768a8afaffb 100644 (file)
@@ -312,6 +312,7 @@ contained staves are connected vertically."
 
   \consists "Instrument_name_engraver"
   \consists "Span_bar_engraver"
+  \consists "Span_bar_stub_engraver"
   \consists "Span_arpeggio_engraver"
   \consists "System_start_delimiter_engraver"
   \consists "Vertical_align_engraver"
@@ -428,6 +429,7 @@ printing of a single line of lyrics."
   \consists "Instrument_name_engraver"
   \consists "Font_size_engraver"
   \consists "Hara_kiri_engraver"
+  \consists "Pure_from_neighbor_engraver"
   searchForVoice = ##f
   %% explicitly set instrument, so it is not inherited from the parent
   instrumentName = #'()
index eea44eed4df130d569d3f38d8bd8a3f1b6e3f9b6..58a085800f6ed7a2597ff61c44077eb839d2d1f9 100644 (file)
@@ -242,6 +242,7 @@ Positive means move the center to the right.")
 the vertical edges: @code{(@var{left-height} . @var{right-height})}.")
      (edge-text ,pair? "A pair specifying the texts to be set at the
 edges: @code{(@var{left-text} . @var{right-text})}.")
+     (elements-filtered ,boolean? "Callback to filter an element list.")
      (round-up-exceptions ,list? "A list of pairs where car is the numerator
 and cdr the denominator of a moment.  Each pair in this list means that
 the multi-measure rests of the corresponding length will be rounded up to
index 5e551acf8f3cdad946c128bf9b4bde6636009c0c..db39b6889c20a562259c7620a671c8d12ed634dc 100644 (file)
        (non-musical . #t)
        (stencil . ,ly:span-bar::print)
        (X-extent . ,ly:span-bar::width)
-       (Y-extent . ,ly:axis-group-interface::height)
+       (Y-extent . #f)
        (meta . ((class . Item)
-                (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
-                                     (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
                 (interfaces . (bar-line-interface
                                font-interface
                                span-bar-interface))))))
 
+    (SpanBarStub
+     . (
+       (elements-filtered . ,ly:pure-from-neighbor-interface::filter-elements)
+        (X-extent . ,grob::x-parent-width)
+       (Y-extent . ,span-bar-stub::height)
+       (meta . ((class . Item)
+                (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
+                                     (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
+                (interfaces . (pure-from-neighbor-interface))))))
+
     (StaffGrouper
      . (
        (staff-staff-spacing . ((basic-distance . 9)
     (,ly:side-position-interface::y-aligned-side . ,ly:side-position-interface::pure-y-aligned-side)
     (,ly:slur::height . ,ly:slur::pure-height)
     (,ly:slur::outside-slur-callback . ,ly:slur::pure-outside-slur-callback)
+    (,span-bar-stub::height . ,ly:axis-group-interface::pure-height)
     (,ly:stem::calc-stem-begin-position . ,ly:stem::pure-calc-stem-begin-position)
     (,ly:stem::calc-stem-end-position . ,ly:stem::pure-calc-stem-end-position)
     (,stem::length . ,stem::pure-length)
index 0fbe9ee3c9ac086e682f3cc64c655d3ce5e00b33..5a15551b340998e43b5df97164680359a5044edd 100644 (file)
@@ -26,6 +26,9 @@
 (define-public (grob::is-live? grob)
   (pair? (ly:grob-basic-properties grob)))
 
+(define-public (grob::x-parent-width grob)
+  (ly:grob-property (ly:grob-parent grob X) 'X-extent))
+
 (define-public (make-stencil-boxer thickness padding callback)
   "Return function that adds a box around the grob passed as argument."
   (lambda (grob)
@@ -345,6 +348,9 @@ and duration-log @var{log}."
           (equal? (ly:item-break-dir g) RIGHT))
       (ly:grob-translate-axis! g 3.5 X)))
 
+(define-public (span-bar-stub::height grob)
+  (ly:grob-property grob 'elements-filtered)
+  (ly:axis-group-interface::height grob))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Tuplets