]> git.donarmstrong.com Git - lilypond.git/commitdiff
Make \footnote work via \tweak
authorDavid Kastrup <dak@gnu.org>
Wed, 16 May 2012 14:47:41 +0000 (16:47 +0200)
committerDavid Kastrup <dak@gnu.org>
Mon, 21 May 2012 04:34:37 +0000 (06:34 +0200)
lily/footnote-engraver.cc
lily/grob.cc
ly/music-functions-init.ly
python/convertrules.py
scm/define-grob-properties.scm

index 4a2070a6cd5f94da9f379a174e5902f11a4cd532..78d2f0e6d3b8edaa761dbf243522d2691d432ecf 100644 (file)
@@ -19,7 +19,9 @@
 
 #include "engraver.hh"
 
+#include "music.hh"
 #include "stream-event.hh"
+#include "international.hh"
 #include "item.hh"
 #include "pointer-group-interface.hh"
 #include "spanner.hh"
@@ -39,6 +41,7 @@ class Footnote_engraver : public Engraver
 
   void stop_translation_timestep ();
   void finalize ();
+  virtual void derived_mark () const;
 
   void footnotify (Grob *, Stream_event *);
 };
@@ -59,7 +62,14 @@ Footnote_engraver::stop_translation_timestep ()
 void
 Footnote_engraver::finalize ()
 {
-  annotated_spanners_.resize (0);
+  annotated_spanners_.clear ();
+}
+
+void
+Footnote_engraver::derived_mark () const
+{
+  for (vsize i = 0; i < events_.size (); ++i)
+    scm_gc_mark (events_[i]->self_scm ());
 }
 
 Footnote_engraver::Footnote_engraver ()
@@ -91,6 +101,26 @@ Footnote_engraver::footnotify (Grob *g, Stream_event *event)
 void
 Footnote_engraver::acknowledge_grob (Grob_info info)
 {
+  Music *mus = unsmob_music (info.grob ()->get_property ("footnote-music"));
+
+  if (mus)
+    {
+      if (!mus->is_mus_type ("footnote-event")) {
+       mus->origin ()->programming_error (_ ("Must be footnote-event."));
+       return;
+      }
+      Stream_event *ev = mus->to_event (context ());
+      footnotify (info.grob (), ev);
+      ev->unprotect ();
+      return;
+    }
+
+  // The following performance hog should eventually be removed:
+  // instead of adding a -\footnote ... \default articulation at the
+  // end of a note, you can perfectly well use \footnote ... before
+  // the note.  This is just for the sake of automatic convert-ly
+  // rules.
+
   Stream_event *cause = info.event_cause ();
 
   SCM arts = cause ? cause->get_property ("articulations") : SCM_EOL;
@@ -101,6 +131,10 @@ Footnote_engraver::acknowledge_grob (Grob_info info)
         footnotify (info.grob (), e);
     }
 
+  // In contrast, the following code is only called when actual
+  // footnote events have been listened to.  It should not affect
+  // performance.
+
   for (vsize i = 0; i < events_.size (); i++)
     {
       if (info.grob ()->name () == ly_symbol2string (events_[i]->get_property ("symbol")))
index ed96f1d13a9b1386a4c64912c2d823684b397097..cc39c979f0e9cf146b40975b01f82ed9441d08bc 100644 (file)
@@ -799,6 +799,7 @@ ADD_INTERFACE (Grob,
                "extra-X-extent "
                "extra-Y-extent "
                "extra-offset "
+               "footnote-music "
                "forced-spacing "
                "interfaces "
                "layer "
index f9f6ef7b35370446a51e1759594f62d878b1a491..21f6c51fd7a511bf0db3529dbea5ed19edd4d840 100644 (file)
@@ -342,23 +342,46 @@ featherDurations=
      argument))
 
 footnote =
-#(define-music-function (parser location text offset grob-name footnote)
-   ((markup?) number-pair? (symbol? '()) markup?)
-   (_i "Attach @var{text} at @var{offset} with @var{text} referring to
-@var{footnote}.  If @var{text} is given as @code{\\default}, use
-autonumbering instead.  Note that, for this to take effect,
-auto-numbering must be turned on in the paper block.  Otherwise, no
-number will appear.  Footnotes are applied like articulations.  If a
-symbol @var{grob-name} is specified, all grobs of that kind at the
-current time step are affected.")
-   (make-music
-    'FootnoteEvent
-    'X-offset (car offset)
-    'Y-offset (cdr offset)
-    'automatically-numbered (not text)
-    'text (or text (make-null-markup))
-    'footnote-text footnote
-    'symbol grob-name))
+#(define-music-function (parser location mark offset grob-name footnote music)
+   ((markup?) number-pair? (symbol?) markup? (ly:music?))
+   (_i "Make the markup @var{footnote} a footnote on @var{music}.  The
+footnote is marked with a markup @var{mark} moved by @var{offset} with
+respect to the marked music.
+
+If @var{mark} is not given or specified as @var{\\default}, it is
+replaced by an automatically generated sequence number.  If a symbol
+@var{grob-name} is specified, then grobs of that type will be marked
+if they have @var{music} as their ultimate cause; by default all grobs
+having @var{music} as their @emph{direct} cause will be marked,
+similar to the way @code{\\tweak} works.
+
+If @var{music} is given as @code{\\default}, a footnote event
+affecting @emph{all} grobs matching @var{grob-name} at a given time
+step is generated.  This may be required for creating footnotes on
+time signatures, clefs, and other items not cooperating with
+@code{\\tweak}.
+
+Like with @code{\\tweak}, if you use a footnote on a following
+post-event, the @code{\\footnote} command itself needs to be attached
+to the preceding note or rest as a post-event with @code{-}.")
+   (let ((mus (make-music
+              'FootnoteEvent
+              'X-offset (car offset)
+              'Y-offset (cdr offset)
+              'automatically-numbered (not mark)
+              'text (or mark (make-null-markup))
+              'footnote-text footnote
+              'symbol (or grob-name '()))))
+     (if music
+        (begin
+          (set! (ly:music-property music 'tweaks)
+                (acons (if grob-name
+                           (cons grob-name 'footnote-music)
+                           'footnote-music)
+                       mus
+                       (ly:music-property music 'tweaks)))
+          music)
+        mus)))
 
 grace =
 #(def-grace-function startGraceMusic stopGraceMusic
index 5c94c59e1f7a88a42aa4cad91598cff460f37965..2bfbdce1ebf9c55b76e02212bc6f88777b49d281 100644 (file)
@@ -3346,6 +3346,20 @@ def conv (str):
                   sub_tempo, str)
     return str
 
+@rule((2, 15, 39), r"\footnote ... -> \footnote ... \default")
+def conv (str):
+    def not_first (s):
+        def match_fun (m):
+            if m.group (1):
+                return m.group (0)
+            return m.expand (s)
+        return match_fun
+    str = re.sub ("(" + matchmarkup + ")|"
+                  + r"(\\footnote(?:\s*"
+                  + matchmarkup + ")?" + matcharg + "(?:" + matcharg
+                  + ")?\s+" + matchmarkup + ")",
+                  not_first (r"\2 \\default"), str)
+    return str
 
 # Guidelines to write rules (please keep this at the end of this file)
 #
index fba256f4bff7fafb283ba5bb86aedc509fa4c09f..6502dd9d722a4b94d3f5641101e925a86b3d4b17 100644 (file)
@@ -307,6 +307,7 @@ include @code{upright}, @code{italic}, @code{caps}.")
 approximately 12% larger; 6@tie{}steps are exactly a factor@tie{}2
 larger.  Fractional values are 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-hshift ,number? "This specifies a manual shift for notes
 in collisions.  The unit is the note head width of the first voice