X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fgrace-engraver.cc;h=59550ba8326c17c9c2bd5bb74360020ccd40573f;hb=97a0169312a260933246ab224e4f8b0969871dd5;hp=352fc840fd57325acd08aed5f3a72e367ebae1b5;hpb=728e41a1741382885396935663e35f9dceaf1d49;p=lilypond.git diff --git a/lily/grace-engraver.cc b/lily/grace-engraver.cc index 352fc840fd..59550ba832 100644 --- a/lily/grace-engraver.cc +++ b/lily/grace-engraver.cc @@ -1,102 +1,179 @@ -/* - grace-engraver.cc -- implement Grace_engraver - - source file of the GNU LilyPond music typesetter - - (c) 2004 Han-Wen Nienhuys - +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2004--2015 Han-Wen Nienhuys + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . */ #include "engraver.hh" #include "context.hh" +#include "dispatcher.hh" +#include "listener.hh" #include "warn.hh" +#include "grob-properties.hh" +#include "stream-event.hh" +#include "translator.icc" class Grace_engraver : public Engraver { + Moment last_moment_; + SCM grace_settings_; + void consider_change_grace_settings (); protected: + virtual void derived_mark () const; + virtual void process_music (); virtual void start_translation_timestep (); - virtual void derived_mark (); - + virtual void finalize (); + TRANSLATOR_DECLARATIONS (Grace_engraver); - Moment last_moment_; - SCM grace_settings_; -public: + void grace_change (SCM); }; - -Grace_engraver::Grace_engraver() +Grace_engraver::Grace_engraver (Context *c) + : Engraver (c) { grace_settings_ = SCM_EOL; + last_moment_ = Moment (Rational (-1, 1)); } +// The iterator should usually come before process_music void -Grace_engraver::derived_mark () +Grace_engraver::grace_change (SCM) { - scm_gc_mark (grace_settings_); + consider_change_grace_settings (); } +// if we are in grace time already on initialization, it is unlikely +// that we'll receive a GraceChange event from the grace iterator yet, +// so we want to start into grace mode anyway. The downside is that +// this will get us confused when given something like +// +// \new Voice { \oneVoice \grace { c''8 8 } g'1 } +// +// where \grace executes its actions already before \oneVoice, causing +// different stem directions. + void Grace_engraver::start_translation_timestep () +{ + // Only on startup + if (last_moment_ == Rational (-1)) + consider_change_grace_settings (); +} + +// If the grace iterator has moved off to some other context, we might +// not get to see the ChangeContext event. In that case, we still +// want to change into or out of grace mode settings as appropriate + +void +Grace_engraver::process_music () +{ + // We may have lost connection to the iterator in which case we + // still need to call consider_change_grace_settings in particular + // in order to get out of grace mode again + if (last_moment_ != now_mom ()) + consider_change_grace_settings (); +} + +void +Grace_engraver::consider_change_grace_settings () { Moment now = now_mom (); - if (last_moment_.grace_part_ && !now.grace_part_) + + if (!now.grace_part_) { for (SCM s = grace_settings_; scm_is_pair (s); s = scm_cdr (s)) - { - SCM context = scm_caar (s); - SCM entry = scm_cdar (s); - SCM grob = scm_cadr (entry); - SCM sym = scm_caddr (entry); - - execute_pushpop_property (unsmob_context (context), - grob, sym, SCM_UNDEFINED); - } + { + SCM elt = scm_car (s); + SCM context = scm_car (elt); + SCM grob = scm_cadr (elt); + SCM cell = scm_cddr (elt); + Grob_property_info (unsmob (context), grob).matched_pop (cell); + } grace_settings_ = SCM_EOL; } - else if (!last_moment_.grace_part_ && now.grace_part_) + else if (!last_moment_.grace_part_) { SCM settings = get_property ("graceSettings"); grace_settings_ = SCM_EOL; for (SCM s = settings; scm_is_pair (s); s = scm_cdr (s)) - { - SCM entry = scm_car (s); - SCM context_name = scm_car (entry); - SCM grob = scm_cadr (entry); - SCM sym = scm_caddr (entry); - SCM val = scm_cadddr (entry); - - Context *c = context (); - while (c - && c->context_name_symbol () != context_name) - { - c = c->get_parent_context (); - } - - if (c) - { - execute_pushpop_property (c, - grob, sym, val); - grace_settings_ - = scm_cons (scm_cons (c->self_scm(), entry), grace_settings_); - } - else - { - programming_error ("Cannot find context"); - scm_display (context_name, scm_current_error_port()); - } - } - } + { + SCM entry = scm_car (s); + SCM context_name = scm_car (entry); + SCM grob = scm_cadr (entry); + SCM sym = scm_caddr (entry); + SCM val = scm_cadr (scm_cddr (entry)); + + if (!scm_is_pair (sym)) + sym = scm_list_1 (sym); + Context *c = find_context_above (context (), context_name); + if (c) + { + SCM cell = Grob_property_info (c, grob).push (sym, val); + grace_settings_ + = scm_cons (scm_cons2 (c->self_scm (), grob, cell), grace_settings_); + } + else + programming_error ("cannot find context from graceSettings: " + + ly_symbol2string (context_name)); + } + } + if (last_moment_ == Rational (-1)) + { + Dispatcher *d = context ()->event_source (); + d->add_listener (GET_LISTENER (Grace_engraver, grace_change), ly_symbol2scm ("GraceChange")); + } last_moment_ = now; } +void +Grace_engraver::finalize () +{ + if (last_moment_ != Rational (-1)) + { + Dispatcher *d = context ()->event_source (); + d->remove_listener (GET_LISTENER (Grace_engraver, grace_change), ly_symbol2scm ("GraceChange")); + } +} + +void +Grace_engraver::derived_mark () const +{ + scm_gc_mark (grace_settings_); + Engraver::derived_mark (); +} + +void +Grace_engraver::boot () +{ + +} + +ADD_TRANSLATOR (Grace_engraver, + /* doc */ + "Set font size and other properties for grace notes.", + + /* create */ + "", + + /* read */ + "graceSettings ", -ENTER_DESCRIPTION (Grace_engraver, - /* descr */ "Set font size and other properties for grace notes.", - /* creats*/ "", - /* accepts */ "", - /* acks */ "", - /* reads */ "graceSettings", - /* write */ ""); + /* write */ + "" + );