]> git.donarmstrong.com Git - lilypond.git/commitdiff
Issue 5064 Let analysis brackets support text
authorDavid Nalesnik <david.nalesnik@gmail.com>
Sun, 5 Feb 2017 01:13:31 +0000 (19:13 -0600)
committerThomas Morley <thomasmorley65@gmail.com>
Mon, 20 Feb 2017 23:42:07 +0000 (23:42 +0000)
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.

Documentation/changes.tely
Documentation/notation/editorial.itely
Documentation/snippets/new/analysis-brackets-with-labels.ly [new file with mode: 0644]
input/regression/horizontal-bracket-broken-texted.ly [new file with mode: 0644]
input/regression/horizontal-bracket-texted.ly [new file with mode: 0644]
lily/horizontal-bracket-engraver.cc
lily/horizontal-bracket.cc
scm/define-grob-interfaces.scm
scm/define-grob-properties.scm
scm/define-grobs.scm
scm/output-lib.scm

index 2a647782442518f0e8eb42656a5a04ca1378193b..f205d0014cb270556d9d6c1bf52de721d4d0e13b 100644 (file)
@@ -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
index 458fce1ff4d97dbd8c6f27c6afb0f14ed297f2df..8dc3ac9612991082a43eac6d014d02f065a893c9 100644 (file)
@@ -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 (file)
index 0000000..30ae349
--- /dev/null
@@ -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 (file)
index 0000000..1f84552
--- /dev/null
@@ -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 (file)
index 0000000..dc1a673
--- /dev/null
@@ -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
+}
index 6dd34c17855f564989dcf79ccedfa9da3a6f018a..1f176a321591a5c18b5446e506ed8182c3266199 100644 (file)
@@ -33,6 +33,7 @@ class Horizontal_bracket_engraver : public Engraver
 public:
   TRANSLATOR_DECLARATIONS (Horizontal_bracket_engraver);
   vector<Spanner *> bracket_stack_;
+  vector<Spanner *> text_stack_;
   vector<Stream_event *> 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 */
                 "",
index ddeec44d750e74b12fd0cef139280846dc62293d..cf37516d5c0c0b697659f10d003ffafd05ec9392 100644 (file)
@@ -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 "
index d5f23113961f88049016d1670f252d535c9fb3ee..ffcfc355113af36777ec91bb8bce72930e5a870b 100644 (file)
@@ -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
index 34450a9d23000eb79d4b1ec71be38abb90540ab3..e950d53b3a712f32d7020a794f3a69a7fb94762c 100644 (file)
@@ -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.")
index a04e07018cc0a3a07c27550927ef8a9052a39af8..45cac04bd3d65b1146beec8acdf89b42bcf8be7c 100644 (file)
                                 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
      . (
index 5184fdb3377fae3444b6d3a6b40a3d7075ab7611..8df9b56ef2489c4bcbd6737c71523016bf405d27 100644 (file)
@@ -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