]> git.donarmstrong.com Git - lilypond.git/commitdiff
Issue 2245: always align dynamics and lyrics on "main" notehead
authorJanek Warchoł <lemniskata.bernoullego@gmail.com>
Wed, 27 Mar 2013 16:20:03 +0000 (17:20 +0100)
committerJanek Warchoł <lemniskata.bernoullego@gmail.com>
Tue, 8 Jul 2014 07:16:58 +0000 (09:16 +0200)
Until now, LyricTexts and DynamicTexts had their X-parents set to
the first NoteHead in the NoteColumn.  This resulted in inconsistent
alignment - placement of lyrics and dynamics depended on the order
of notes in the input:

% this was aligned differently
{ <f' g'>1\p <g' f'>\p }
\addlyrics { la la }

By using NoteColumns themselves as the X-parents, we make sure that
the input order won't matter.  Since the NoteColumn contains all NoteHeads
(including suspended ones, which usually should be ignored when aligning),
as well as Flags and some other objects, we cannot use its X-extent directly -
instead, we add a function for calculating X-extent of the "main" part of the
NoteColumn, i.e. X-extent of the non-suspended NoteHeads (represented by the
NoteHead furthest away from the stem).

input/regression/input-order-alignment.ly [new file with mode: 0644]
lily/dynamic-engraver.cc
lily/include/note-column.hh
lily/lyric-engraver.cc
lily/note-column.cc
lily/self-alignment-interface.cc
scm/define-grob-properties.scm
scm/define-grobs.scm

diff --git a/input/regression/input-order-alignment.ly b/input/regression/input-order-alignment.ly
new file mode 100644 (file)
index 0000000..cabb357
--- /dev/null
@@ -0,0 +1,25 @@
+\version "2.19.9"
+
+\header {
+  texidoc = "Alignment of lyrics, dynamics, textscripts and articulations
+attached to chords with suspended notes doesn't depend on input order.
+All these items are aligned on the \"main\" notehead (the one at the
+end of the stem)."
+}
+
+<<
+  \new Staff {
+    <b' c''>2 s
+    <b' c''>\f s
+    <b' c''>^"Text" s
+    <b' c''>-! s
+  }
+  \addlyrics { blah }
+  \new Staff {
+    <c'' b'>2 s
+    <c'' b'>\f s
+    <c'' b'>^"Text" s
+    <c'' b'>-! s
+  }
+  \addlyrics { blah }
+>>
index a91d742ee80306de3221656808baea2d52ff3ed1..fdf682f7733cd993bd3d0331b67cb859276cc817 100644 (file)
@@ -261,11 +261,11 @@ Dynamic_engraver::acknowledge_note_column (Grob_info info)
     {
       extract_grob_set (info.grob (), "note-heads", heads);
       /*
-        Spacing constraints may require dynamics to be aligned on rests,
+        Spacing constraints may require dynamics to be attached to rests,
         so check for a rest if this note column has no note heads.
       */
       Grob *x_parent = (heads.size ()
-                        ? heads[0]
+                        ? info.grob ()
                         : unsmob_grob (info.grob ()->get_object ("rest")));
       if (x_parent)
         script_->set_parent (x_parent, X_AXIS);
index 151d9208adc20b66a4b9957845902edd725c38e4..9fdabd296247388778aa3588783f7d8ea5883bb1 100644 (file)
@@ -36,6 +36,7 @@ public:
   static Grob *accidentals (Grob *me);
   static Slice head_positions_interval (Grob *me);
   static Grob *first_head (Grob *me);
+  static Interval calc_main_heads_extent (Grob *me);
   static Grob *get_rest (Grob *me);
   static void set_stem (Grob *me, Grob *);
   static void add_head (Grob *me, Grob *);
index 3ea4498baf1381ef764749dba93964e6b7a93bb8..1cbaffeb7d5376f7301cbdbcefc2301c28503d23 100644 (file)
@@ -175,7 +175,7 @@ Lyric_engraver::stop_translation_timestep ()
 
           if (head)
             {
-              text_->set_parent (head, X_AXIS);
+              text_->set_parent (head->get_parent(X_AXIS), X_AXIS);
               if (melisma_busy (voice)
                   && !to_boolean (get_property ("ignoreMelismata")))
                 text_->set_property ("self-alignment-X",
index 867542bdbd39fe497b6da103e66572e5840ddf4c..625bed1b2f4cbc27fc507c2be414a2066cae7be9 100644 (file)
@@ -156,6 +156,26 @@ Note_column::first_head (Grob *me)
   return st ? Stem::first_head (st) : 0;
 }
 
+/*
+  Return extent of the noteheads in the "main column",
+  i.e. excluding any suspended noteheads.
+*/
+Interval
+Note_column::calc_main_heads_extent (Grob *me)
+{
+  if (get_stem (me))
+    return first_head (me)->extent (me, X_AXIS);
+  else
+    {
+      // no stems => no suspended noteheads.
+      extract_grob_set (me, "note-heads", heads);
+      if (heads.size())
+        return heads[0]->extent (me, X_AXIS);
+      else
+        return Interval (0, 0);
+    }
+}
+
 /*
   Return the first AccidentalPlacement grob that we find in a note-head.
 */
index d1cb1bf50ca54e92295d13ef468b0e5580585936..664a111642362ba1174d1715ded14a1a134d65db 100644 (file)
@@ -114,7 +114,13 @@ Self_alignment_interface::aligned_on_parent (Grob *me, Axis a)
     he = Paper_column::get_interface_extent
               (him, ly_symbol2scm ("note-column-interface"), a);
   else
-    he = him->extent (him, a);
+    {
+      if (ly_scm2bool(me->internal_get_property (ly_symbol2scm ("X-align-on-main-noteheads")))
+          && Note_column::has_interface (him))
+        he = Note_column::calc_main_heads_extent(him);
+      else
+        he = him->extent (him, a);
+    }
 
   SCM sym = (a == X_AXIS) ? ly_symbol2scm ("self-alignment-X")
             : ly_symbol2scm ("self-alignment-Y");
@@ -169,4 +175,5 @@ ADD_INTERFACE (Self_alignment_interface,
                /* properties */
                "self-alignment-X "
                "self-alignment-Y "
+               "X-align-on-main-noteheads "
               );
index 24e8e3298abeb0d93607832d0d1422b757e83c8d..fbb9d679ac50bd06f5eda056093fe3612bfc7772 100644 (file)
@@ -1023,6 +1023,8 @@ texts.")
 ;;;
 ;;; x
 ;;;
+     (X-align-on-main-noteheads ,boolean? "If true, this grob will
+ignore suspended noteheads when aligning itself on NoteColumn.")
      (X-extent ,number-pair? "Extent (size) in the X@tie{}direction,
 measured in staff-space units, relative to object's reference point.")
      (X-offset ,number? "The horizontal amount that this object is
index ddacbcb7ec1131864197462b77ef59f7dca37b4b..572f80f660da0c5edf008246b24ed1c0aa66dedc 100644 (file)
         (stencil . ,ly:text-interface::print)
         (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
         (Y-extent . ,grob::always-Y-extent-from-stencil)
+        (X-align-on-main-noteheads . #t)
         (X-offset . ,ly:self-alignment-interface::aligned-on-x-parent)
         (Y-offset . ,(scale-by-font-size -0.6)) ; center on an 'm'
         (meta . ((class . Item)
         (word-space . 0.6)
         (skyline-horizontal-padding . 0.1)
         (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+        (X-align-on-main-noteheads . #t)
         (X-offset . ,ly:self-alignment-interface::aligned-on-x-parent)
         (Y-extent . ,grob::always-Y-extent-from-stencil)
         (meta . ((class . Item)