From: David Nalesnik Date: Sun, 5 Feb 2017 01:13:31 +0000 (-0600) Subject: Issue 5064 Let analysis brackets support text X-Git-Url: https://git.donarmstrong.com/?p=lilypond.git;a=commitdiff_plain;h=dbc2dd143e50e000a39883fc8217b4ec60e08657 Issue 5064 Let analysis brackets support text Ability to add labels to brackets is essential for musical analysis. This patch introduces a new grob, "HorizontalBracketText," a spanner created along with "HorizontalBracket" by Horizontal_bracket_engraver. Repeated text of broken brackets is parenthesized. --- diff --git a/Documentation/changes.tely b/Documentation/changes.tely index 2a64778244..f205d0014c 100644 --- a/Documentation/changes.tely +++ b/Documentation/changes.tely @@ -61,6 +61,24 @@ which scares away people. @end ignore +@item +It is now possible to add text to analysis brackets through the +@code{HorizontalBracketText} object. +@lilypond[quote,verbatim] +\layout { + \context { + \Voice + \consists "Horizontal_bracket_engraver" + } +} + +{ + \once \override HorizontalBracketText.text = "a" + c''\startGroup d''\stopGroup + e''-\tweak text "a'" \startGroup d''\stopGroup +} +@end lilypond + @item The ends of hairpins may now be fine-tuned using the @code{shorten-pair} grob property, which previously only affected text-spanners like diff --git a/Documentation/notation/editorial.itely b/Documentation/notation/editorial.itely index 458fce1ff4..8dc3ac9612 100644 --- a/Documentation/notation/editorial.itely +++ b/Documentation/notation/editorial.itely @@ -879,12 +879,19 @@ Analysis brackets may be nested. } @end lilypond -@seealso -Snippets: -@rlsr{Editorial annotations}. +@snippets +@lilypondfile[verbatim,quote,ragged-right,texidoc,doctitle] +{analysis-brackets-above-the-staff.ly} + +@lilypondfile[verbatim,quote,ragged-right,texidoc,doctitle] +{analysis-brackets-with-labels.ly} + +@seealso Internals Reference: @rinternals{Horizontal_bracket_engraver}, @rinternals{HorizontalBracket}, @rinternals{horizontal-bracket-interface}, +@rinternals{HorizontalBracketText}, +@rinternals{horizontal-bracket-text-interface}, @rinternals{Staff}. diff --git a/Documentation/snippets/new/analysis-brackets-with-labels.ly b/Documentation/snippets/new/analysis-brackets-with-labels.ly new file mode 100644 index 0000000000..30ae349b05 --- /dev/null +++ b/Documentation/snippets/new/analysis-brackets-with-labels.ly @@ -0,0 +1,38 @@ +\version "2.19.55" + +\header { + lsrtags = "editorial-annotations, tweaks-and-overrides" + + texidoc = " +Text may be added to analysis brackets through the @code{text} property +of the @code{HorizontalBracketText} grob. Adding different texts to +brackets beginning at the same time requires the @code{\tweak} command. +Bracket text will be parenthesized after a line break. + +" + doctitle = "Analysis brackets with labels" +} + +\layout { + \context { + \Voice + \consists "Horizontal_bracket_engraver" + \override HorizontalBracket.direction = #UP + } +} + +{ + \once\override HorizontalBracketText.text = "a" + c''\startGroup d''\stopGroup + \once\override HorizontalBracketText.text = "a'" + e''\startGroup d''\stopGroup + c'' + -\tweak text \markup \bold \huge "b" \startGroup + -\tweak text "a" \startGroup + d''\stopGroup + e''-\tweak text "a'" \startGroup + d''\stopGroup\stopGroup + c''-\tweak text foo \startGroup d'' e'' f'' + \break + g'' a'' b'' c'''\stopGroup +} diff --git a/input/regression/horizontal-bracket-broken-texted.ly b/input/regression/horizontal-bracket-broken-texted.ly new file mode 100644 index 0000000000..1f8455261e --- /dev/null +++ b/input/regression/horizontal-bracket-broken-texted.ly @@ -0,0 +1,25 @@ +\version "2.19.55" + +\header { + texidoc = "Text is parenthesized when analysis brackets cross line +breaks. +" +} + +\layout { + \context { + \Voice + \consists "Horizontal_bracket_engraver" + } +} + +{ + c'' + -\tweak text \markup \draw-circle #1 #0.5 ##f \startGroup + -\tweak text "a" \startGroup + d'' e'' f'' + g'' a'' b'' c'''\stopGroup + c'''-\tweak text "a'" \startGroup b'' a'' g'' + \break + f'' e'' d'' c''\stopGroup\stopGroup +} diff --git a/input/regression/horizontal-bracket-texted.ly b/input/regression/horizontal-bracket-texted.ly new file mode 100644 index 0000000000..dc1a673a08 --- /dev/null +++ b/input/regression/horizontal-bracket-texted.ly @@ -0,0 +1,36 @@ +\version "2.19.55" + +\header { + texidoc = "Labels may be added to analysis brackets through the +@code{text} property of the @code{HorizontalBracketText} object. Use of +the @code{\tweak} command is necessary for assigning text uniquely to +brackets beginning at the same moment. Text assignments reflect the +usual nesting order of brackets. +" +} + +\layout { + \context { + \Voice + \consists "Horizontal_bracket_engraver" + \override HorizontalBracket.direction = #UP + } +} + +\relative c'' { + \time 3/4 + \key f \major + c4 + -\tweak text "contrasting period" \startGroup + -\tweak text "a" \startGroup + a8( bes c f) + f4( e d) + c d8( c bes c) + \appoggiatura bes4 a2 g4\stopGroup + \once\override HorizontalBracketText.text = "b" + f'8 \startGroup + r a, r d r + c4( e, f) + g8( bes) a4 g8( f) + f2 \stopGroup \stopGroup r4 +} diff --git a/lily/horizontal-bracket-engraver.cc b/lily/horizontal-bracket-engraver.cc index 6dd34c1785..1f176a3215 100644 --- a/lily/horizontal-bracket-engraver.cc +++ b/lily/horizontal-bracket-engraver.cc @@ -33,6 +33,7 @@ class Horizontal_bracket_engraver : public Engraver public: TRANSLATOR_DECLARATIONS (Horizontal_bracket_engraver); vector bracket_stack_; + vector text_stack_; vector events_; vsize pop_count_; vsize push_count_; @@ -81,6 +82,8 @@ Horizontal_bracket_engraver::acknowledge_note_column (Grob_info gi) ly_symbol2scm ("columns"), gi.grob ()); add_bound_item (bracket_stack_[i], gi.grob ()); + add_bound_item (text_stack_[i], + gi.grob ()); } } @@ -91,10 +94,25 @@ Horizontal_bracket_engraver::process_music () { Spanner *sp = make_spanner ("HorizontalBracket", events_[k]->self_scm ()); + Spanner *hbt = make_spanner ("HorizontalBracketText", events_[k]->self_scm ()); + + sp->set_object ("bracket-text", hbt->self_scm ()); + + Side_position_interface::add_support (hbt, sp); + + hbt->set_parent (sp, X_AXIS); + hbt->set_parent (sp, Y_AXIS); + hbt->set_object ("bracket", sp->self_scm ()); + for (vsize i = 0; i < bracket_stack_.size (); i++) /* sp is the smallest, it should be added to the bigger brackets. */ - Side_position_interface::add_support (bracket_stack_[i], sp); + { + Side_position_interface::add_support (bracket_stack_[i], sp); + Side_position_interface::add_support (bracket_stack_[i], hbt); + } + bracket_stack_.push_back (sp); + text_stack_.push_back (hbt); } } @@ -102,8 +120,12 @@ void Horizontal_bracket_engraver::stop_translation_timestep () { for (vsize i = pop_count_; i--;) - if (bracket_stack_.size ()) - bracket_stack_.pop_back (); + { + if (bracket_stack_.size ()) + bracket_stack_.pop_back (); + if (text_stack_.size ()) + text_stack_.pop_back (); + } pop_count_ = 0; push_count_ = 0; events_.clear (); @@ -122,7 +144,8 @@ ADD_TRANSLATOR (Horizontal_bracket_engraver, " purposes.", /* create */ - "HorizontalBracket ", + "HorizontalBracket " + "HorizontalBracketText ", /* read */ "", diff --git a/lily/horizontal-bracket.cc b/lily/horizontal-bracket.cc index ddeec44d75..cf37516d5c 100644 --- a/lily/horizontal-bracket.cc +++ b/lily/horizontal-bracket.cc @@ -92,11 +92,6 @@ Horizontal_bracket::make_enclosing_bracket (Grob *me, Grob *refpoint, } } -/* - TODO: - - Support texts on the brackets? -*/ MAKE_SCHEME_CALLBACK (Horizontal_bracket, print, 1); SCM Horizontal_bracket::print (SCM smob) @@ -127,6 +122,7 @@ ADD_INTERFACE (Horizontal_bracket, /* properties */ "bracket-flare " + "bracket-text " "columns " "edge-height " "shorten-pair " diff --git a/scm/define-grob-interfaces.scm b/scm/define-grob-interfaces.scm index d5f2311396..ffcfc35511 100644 --- a/scm/define-grob-interfaces.scm +++ b/scm/define-grob-interfaces.scm @@ -149,6 +149,11 @@ or 15 (two octaves), but LilyPond allows any integer here." '(columns common-shortest-duration)) +(ly:add-interface + 'horizontal-bracket-text-interface + "Label for an analysis bracket." + '(bracket columns)) + (ly:add-interface 'inline-accidental-interface "An inlined accidental (i.e. normal accidentals, cautionary diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 34450a9d23..e950d53b3a 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -1250,6 +1250,7 @@ for positioning elements that align with a column.") column as start/@/begin point. Only columns that have grobs or act as bounds are spaced.") (bracket ,ly:grob? "The bracket for a number.") + (bracket-text ,ly:grob? "The text for an analysis bracket.") (c0-position ,integer? "An integer indicating the position of middle@tie{}C.") diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index a04e07018c..45cac04bd3 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -1164,6 +1164,24 @@ side-position-interface spanner-interface)))))) + (HorizontalBracketText + . ( + (direction . ,ly:horizontal-bracket-text::calc-direction) + (font-size . -1) + (padding . 0.5) + (parent-alignment-X . ,CENTER) + (self-alignment-X . ,CENTER) + (side-axis . ,Y) + (stencil . ,ly:horizontal-bracket-text::print) + (X-offset . ,ly:self-alignment-interface::aligned-on-x-parent) + (Y-offset . ,side-position-interface::y-aligned-side) + (meta . ((class . Spanner) + (interfaces . (font-interface + horizontal-bracket-text-interface + outside-staff-interface + self-alignment-interface + side-position-interface + text-interface)))))) (InstrumentName . ( diff --git a/scm/output-lib.scm b/scm/output-lib.scm index 5184fdb337..8df9b56ef2 100644 --- a/scm/output-lib.scm +++ b/scm/output-lib.scm @@ -1548,6 +1548,33 @@ numbered in parentheses." X))) num)) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; HorizontalBracketText + +(define-public (ly:horizontal-bracket-text::print grob) + (let ((text (ly:grob-property grob 'text))) + (if (or (null? text) + (equal? text "") + (equal? text empty-markup)) + (begin + (ly:grob-suicide! grob) + '()) + (let* ((orig (ly:grob-original grob)) + (siblings (ly:spanner-broken-into orig)) + (text + (if (or (null? siblings) + (eq? grob (car siblings))) + text + (if (string? text) + (string-append "(" text ")") + (make-parenthesize-markup text))))) + (grob-interpret-markup grob text))))) + +(define-public (ly:horizontal-bracket-text::calc-direction grob) + (let* ((bracket (ly:grob-object grob 'bracket)) + (bracket-dir (ly:grob-property bracket 'direction DOWN))) + bracket-dir)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; make-engraver helper macro