--- /dev/null
+\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 }
+>>
{
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);
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 *);
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",
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.
*/
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");
/* properties */
"self-alignment-X "
"self-alignment-Y "
+ "X-align-on-main-noteheads "
);
;;;
;;; 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
(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)