From 5801d8b438473ad68ae74f7dc742bbc8eea887fa Mon Sep 17 00:00:00 2001 From: David Kastrup Date: Thu, 11 Oct 2012 12:48:25 +0200 Subject: [PATCH] Change \footnote user interface and behavior to match \hide/\omit etc. This does the following changes to the footnote user interface for footnotes in music rather than in markups: Time-based footnote syntax: \footnote [mark] offset #'Grob text \default -> \footnote [mark] offset text [ Context. ] Grob Like with any override, you now need to specify Context if it is not supposed to be Bottom, like with Staff.TimeSignature. Music-based footnote syntax: \footnote [mark] offset text music -> stays identical \footnote [mark] offset #'Grob text music -> \single\footnote [mark] offset text Grob music Specifying Context.Grob is possible, but Context gets ignored. --- lily/footnote-engraver.cc | 43 ++--------------------------------- ly/engraver-init.ly | 1 - ly/music-functions-init.ly | 46 ++++++++++++++------------------------ python/convertrules.py | 28 +++++++++++++++++++++++ 4 files changed, 47 insertions(+), 71 deletions(-) diff --git a/lily/footnote-engraver.cc b/lily/footnote-engraver.cc index 71cd9dd6ff..39e18cd57c 100644 --- a/lily/footnote-engraver.cc +++ b/lily/footnote-engraver.cc @@ -33,45 +33,22 @@ class Footnote_engraver : public Engraver { TRANSLATOR_DECLARATIONS (Footnote_engraver); - DECLARE_TRANSLATOR_LISTENER (footnote); DECLARE_ACKNOWLEDGER (grob); DECLARE_END_ACKNOWLEDGER (grob); - vector events_; + vector > annotated_spanners_; - void stop_translation_timestep (); void finalize (); - virtual void derived_mark () const; void footnotify (Grob *, SCM); }; -IMPLEMENT_TRANSLATOR_LISTENER (Footnote_engraver, footnote); -void -Footnote_engraver::listen_footnote (Stream_event *ev) -{ - events_.push_back (ev); -} - -void -Footnote_engraver::stop_translation_timestep () -{ - events_.clear (); -} - void Footnote_engraver::finalize () { 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 () { } @@ -115,24 +92,8 @@ Footnote_engraver::acknowledge_grob (Grob_info info) // This grob has exhausted its footnote info.grob ()->set_property ("footnote-music", SCM_EOL); - return; - } - if (!events_.empty ()) - { - string grobname = info.grob ()->name (); - - for (vsize i = 0; i < events_.size (); i++) - { - SCM name = events_[i]->get_property ("symbol"); - if (scm_is_symbol (name) - && grobname == ly_symbol2string (name)) - { - footnotify (info.grob (), events_[i]->self_scm ()); - // Event has exhausted its footnote - events_[i]->set_property ("symbol", SCM_EOL); - } - } + return; } } diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 06060c02e1..b6d2a42615 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -85,7 +85,6 @@ \consists "Figured_bass_position_engraver" \consists "Script_row_engraver" \consists "Cue_clef_engraver" - \consists "Footnote_engraver" localKeySignature = #'() createSpacing = ##t diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly index eb9f1cf7ec..371beab4d7 100644 --- a/ly/music-functions-init.ly +++ b/ly/music-functions-init.ly @@ -368,24 +368,23 @@ featherDurations= argument)) footnote = -#(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 +#(define-music-function (parser location mark offset footnote item) + ((markup?) number-pair? markup? symbol-list-or-music?) + (_i "Make the markup @var{footnote} a footnote on @var{item}. 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}. +replaced by an automatically generated sequence number. If @var{item} +is a symbol list of form @samp{Grob} or @samp{Context.Grob}, then +grobs of that type will be marked at the current time step in the +given context (default @code{Bottom}). + +If @var{item} is music, the music will get a footnote attached to a +grob immediately attached to the event, like @var{\\tweak} does. For +attaching a footnote to an @emph{indirectly} caused grob, write +@code{\\single\\footnote}, use @var{item} to specify the grob, and +follow it with the music to annotate. Like with @code{\\tweak}, if you use a footnote on a following post-event, the @code{\\footnote} command itself needs to be attached @@ -396,21 +395,10 @@ to the preceding note or rest as a post-event with @code{-}.") 'Y-offset (cdr offset) 'automatically-numbered (not mark) 'text (or mark (make-null-markup)) - 'footnote-text footnote - 'symbol (or grob-name '())))) - (cond (music - (set! (ly:music-property music 'tweaks) - (acons (if grob-name - (cons grob-name 'footnote-music) - 'footnote-music) - mus - (ly:music-property music 'tweaks))) - music) - (grob-name mus) - (else - (ly:input-warning location - (_ "\\footnote requires music or grob-name")) - (make-music 'Music))))) + 'footnote-text footnote))) + (if (ly:music? item) + #{ \tweak #'footnote-music #mus #item #} + #{ \once\override $item #'footnote-music = #mus #}))) grace = #(def-grace-function startGraceMusic stopGraceMusic diff --git a/python/convertrules.py b/python/convertrules.py index 861e57ac4f..28dad31843 100644 --- a/python/convertrules.py +++ b/python/convertrules.py @@ -3423,11 +3423,34 @@ def conv(str): str = re.sub (barstring + r'"empty"', '\\1\\2"-"', str) return str +symbol_list = (r"#'(?:" + wordsyntax + r"|\(\s*(?:" + wordsyntax + r"\s+)*" + + wordsyntax + r"\s*\))") + @rule ((2, 17, 6), r"""\accidentalStyle #'Context "style" -> \accidentalStyle Context.style \alterBroken "Context.grob" -> \alterBroken Context.grob \overrideProperty "Context.grob" -> \overrideProperty Context.grob \tweak Grob #'symbol -> \tweak Grob.symbol""") def conv (str): + def patrep (m): + def fn_path_replace (m): + x = string.join (re.findall (wordsyntax, m.group (2)), ".") + if x in ["TimeSignature", "KeySignature", "BarLine", + "Clef", "StaffSymbol", "OttavaBracket", + "LedgerLineSpanner"]: + x = "Staff." + x + return m.group (1) + x + if m.group (1): + return m.group (0) + x = m.group (2) + m.group (4) + + if m.group (3): + x = x + re.sub (r"(\s*)(" + symbol_list + ")", fn_path_replace, + m.group (3)) + + if not m.group (5): + x = r"\single" + x + return x + str = re.sub (r'''(\\accidentalStyle\s+)#?"([-A-Za-z]+)"''', r"\1\2", str) str = re.sub (r'''(\\accidentalStyle\s+)#'([A-Za-z]+)\s+#?"?([-A-Za-z]+)"?''', @@ -3436,6 +3459,11 @@ def conv (str): r"\1\2.\3", str) str = re.sub (r'''(\\tweak\s+)#?"?([A-Za-z]+)"?\s+?#'([-A-Za-z]+)''', r"\1\2.\3", str) + str = re.sub ("(" + matchmarkup + ")|" + + r"(\\footnote(?:\s*" + + matchmarkup + ")?" + matcharg + ")(" + matcharg + + r")?(\s+" + matchmarkup + r")(\s+\\default)?", + patrep, str) return str # Guidelines to write rules (please keep this at the end of this file) -- 2.39.2