>From 53e80c9c17cfa2b11deb15ccfef4587b82c06d52 Mon Sep 17 00:00:00 2001 From: Knut Petersen Date: Thu, 15 Dec 2016 12:52:06 +0100 Subject: [PATCH] Automated lyric extenders Automatically add lyric extenders whenever they are appropriate. Add new property no-extender to forbid all extenders unless overridden by the 2nd new boolean property force-extender. Enabled by default. Signed-off-by: Knut Petersen --- lily/lyric-extender.cc | 44 +++++++++++++++++++++------------------ scm/define-context-properties.scm | 2 ++ scm/define-grob-properties.scm | 6 ++++++ scm/define-grobs.scm | 2 ++ scm/music-functions.scm | 12 ++++++++--- 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/lily/lyric-extender.cc b/lily/lyric-extender.cc index 8afe2c5569..f7d49ac916 100644 --- a/lily/lyric-extender.cc +++ b/lily/lyric-extender.cc @@ -45,51 +45,53 @@ Lyric_extender::print (SCM smob) common = common->common_refpoint (me->get_system (), X_AXIS); Real sl = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness")); + bool at_start_of_line = !left_edge->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface")); + bool at_end_of_line = me->get_bound (RIGHT)->break_status_dir (); + bool force_extender = to_boolean (me->get_property ("force-extender")); + bool no_extender = to_boolean (me->get_property ("no-extender")); + + if (!force_extender && no_extender) + return SCM_EOL; extract_grob_set (me, "heads", heads); - if (!heads.size ()) + if (!heads.size () || (!force_extender && !at_start_of_line && !at_end_of_line && heads.size () < 2)) return SCM_EOL; common = common_refpoint_of_array (heads, common, X_AXIS); Real left_point = 0.0; - if (left_edge->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))) + if (!at_start_of_line) left_point = left_edge->extent (common, X_AXIS)[RIGHT]; - else if (heads.size ()) - left_point = heads[0]->extent (common, X_AXIS)[LEFT]; else - left_point = left_edge->extent (common, X_AXIS)[RIGHT]; + left_point = heads[0]->extent (common, X_AXIS)[LEFT]; if (isinf (left_point)) return SCM_EOL; - /* It seems that short extenders are even lengthened to go past the - note head, but haven't found a pattern in it yet. --hwn 1/1/04 */ - SCM minlen = me->get_property ("minimum-length"); - Real right_point - = left_point + (robust_scm2double (minlen, 0)); - - right_point = min (right_point, me->get_system ()->get_bound (RIGHT)->relative_coordinate (common, X_AXIS)); - - if (heads.size ()) - right_point = max (right_point, heads.back ()->extent (common, X_AXIS)[RIGHT]); - Real h = sl * robust_scm2double (me->get_property ("thickness"), 0); Drul_array paddings (robust_scm2double (me->get_property ("left-padding"), h), robust_scm2double (me->get_property ("right-padding"), h)); + Real minlen = robust_scm2double (me->get_property ("minimum-length"), 0); + + Real right_point = heads.back ()->extent (common, X_AXIS)[RIGHT]; + + if (force_extender) + right_point = max (heads.back ()->extent (common, X_AXIS)[RIGHT], left_point + minlen); + if (right_text) right_point = min (right_point, (robust_relative_extent (right_text, common, X_AXIS)[LEFT] - paddings[RIGHT])); - /* run to end of line. */ - if (me->get_bound (RIGHT)->break_status_dir ()) + if (at_end_of_line) right_point = max (right_point, (robust_relative_extent (me->get_bound (RIGHT), common, X_AXIS)[LEFT] - paddings[RIGHT])); - left_point += paddings[LEFT]; + if (!at_start_of_line) + left_point += paddings[LEFT]; + Real w = right_point - left_point; - if (w < 1.5 * h) + if (w < minlen && !at_start_of_line && !at_end_of_line && !force_extender) return SCM_EOL; Stencil mol (Lookup::round_filled_box (Box (Interval (0, w), @@ -111,4 +113,6 @@ ADD_INTERFACE (Lyric_extender, "next " "right-padding " "thickness " + "force-extender " + "no-extender " ); diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index 75f1807e61..7a4024c167 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -331,6 +331,7 @@ staff switches by a thin line.") (fontSize ,number? "The relative size of all grobs in a context.") (forbidBreak ,boolean? "If set to @code{#t}, prevent a line break at this point.") + (force-extender ,boolean? "Whether to force lyric extenders.") (forceClef ,boolean? "Show clef symbol, even if it has not changed. Only active for the first clef after the property is set, not for the full staff.") @@ -483,6 +484,7 @@ for a minor chord") (noChordSymbol ,markup? "Markup to be displayed for rests in a ChordNames context.") + (no-extender ,boolean? "Whether to inhibit lyric extenders.") (noteToFretFunction ,procedure? "Convert list of notes and list of defined strings to full list of strings and fret numbers. Parameters: The context, a list of note events, a list of diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index c234792dd2..0e8cc5d576 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -330,6 +330,10 @@ allowed.") (footnote ,boolean? "Should this be a footnote or in-note?") (footnote-music ,ly:music? "Music creating a footnote.") (footnote-text ,markup? "A footnote for the grob.") + (force-extender ,boolean? "Force a lyric extender to be generated +if none would be generated otherwise and/or force it to be at least as +wide as indicated by property @code{minimum-width} unless it would +collide with the next syllable. Overrides property @code{no-extender}.") (force-hshift ,number? "This specifies a manual shift for notes in collisions. The unit is the note head width of the first voice note. This is used by @rinternals{note-collision-interface}.") @@ -663,6 +667,8 @@ syllable following an extender).") (no-alignment ,boolean? "If set, don't place this grob in a @code{VerticalAlignment}; rather, place it using its own @code{Y-offset} callback.") + (no-extender ,boolean? "Inhibits generation of lyric extenders. +Can be overridden by property @code{force-extender}.") (no-ledgers ,boolean? "If set, don't draw ledger lines on this object.") (no-stem-extend ,boolean? "If set, notes with ledger lines do not diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index e36ea12bf2..d4ad46e644 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -1361,7 +1361,9 @@ (LyricExtender . ( + (force-extender . #f) (minimum-length . 1.5) + (no-extender . #f) (stencil . ,ly:lyric-extender::print) (thickness . 0.8) ; line-thickness (Y-extent . (0 . 0)) diff --git a/scm/music-functions.scm b/scm/music-functions.scm index b1dc2f9c61..8cb9cf7ac5 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -728,10 +728,16 @@ making it possible to @code{\\revert} to any previous value afterwards." 'articulation-type name properties)) +(define (add-extender! event) + (ly:music-set-property! event 'articulations + (append (ly:music-property event 'articulations) + (list (make-music (quote ExtenderEvent))))) + event) + (define-public (make-lyric-event string duration) - (make-music 'LyricEvent - 'duration duration - 'text string)) + (if (and (string? string)(string=? " " string)) + (make-music 'LyricEvent 'duration duration 'text string) + (add-extender! (make-music 'LyricEvent 'duration duration 'text string)))) (define-safe-public (make-span-event type span-dir) (make-music type -- 2.11.0