Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / ligature-engraver.cc
blobbe4917f0c735ec5da9078c875af32a0317ce35ea
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2002--2011 Juergen Reuter <reuter@ipd.uka.de>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "ligature-engraver.hh"
22 #include "context.hh"
23 #include "international.hh"
24 #include "note-head.hh"
25 #include "rest.hh"
26 #include "spanner.hh"
27 #include "stream-event.hh"
28 #include "translator.icc"
31 * This abstract class provides the general framework for ligatures of
32 * any kind. It cares for handling start/stop ligatures events and
33 * collecting all noteheads inbetween, but delegates creation of a
34 * ligature spanner for each start/stop pair and typesetting of the
35 * ligature spanner to a concrete subclass.
37 * A concrete ligature engraver must subclass this class and provide
38 * functions create_ligature_spanner () and typeset_ligature
39 * (Spanner *, vector<Grob_info>). Subclasses of this class basically
40 * fall into two categories.
42 * The first category consists of engravers that engrave ligatures in
43 * a way that really deserves the name ligature. That is, they
44 * produce a single connected graphical object of fixed width,
45 * consisting of noteheads and other primitives. Space may be
46 * inserted only after each ligature, if necessary, but in no case
47 * between the primitives of the ligature. Accidentals have to be put
48 * to the left of the ligature, and not to the left of individual
49 * noteheads. Class Coherent_ligature_engraver is the common
50 * superclass for all of these engravers.
52 * The second category is for engravers that are relaxed in the sense
53 * that they do not require to produce a single connected graphical
54 * object. For example, in contemporary editions, ligatures are often
55 * marked, but otherwise use contemporary notation and spacing. In
56 * this category, there is currently only a single class,
57 * Ligature_bracket_engraver, which marks each ligature with a
58 * horizontal sqare bracket, but otherwise leaves the appearance
59 * untouched.
63 * TODO: lyrics/melisma/syllables: there should be at most one
64 * syllable of lyrics per ligature (i.e. for the lyrics context, a
65 * ligature should count as a single note, regardless of how many
66 * heads the ligature consists of).
68 * TODO: currently, you have to add/remove the proper
69 * Ligature_engraver (Ligature_bracket_engraver,
70 * Mensural_ligature_engraver) to the proper translator
71 * (e.g. VoiceContext) to choose between various representations.
72 * Since adding/removing an engraver to a translator is a global
73 * action in the layout block, you cannot mix various representations
74 * _within_ the same score. Hence, for selecting a representation,
75 * one would rather like to have a property that can be set e.g. for
76 * several staves individually. However, it seems that this approach
77 * would require to have a single, complicated Ligature_engraver that
78 * consists of all the code... This needs further thoughts.
80 Ligature_engraver::Ligature_engraver ()
82 ligature_ = 0;
83 finished_ligature_ = 0;
84 events_drul_[LEFT] = events_drul_[RIGHT] = 0;
85 prev_start_event_ = 0;
86 last_bound_ = 0;
87 brew_ligature_primitive_proc = SCM_EOL;
90 void
91 Ligature_engraver::listen_ligature (Stream_event *ev)
93 Direction d = to_dir (ev->get_property ("span-direction"));
94 ASSIGN_EVENT_ONCE (events_drul_[d], ev);
97 void
98 Ligature_engraver::process_music ()
100 if (events_drul_[STOP])
102 if (!ligature_)
104 events_drul_[STOP]->origin ()->warning (_ ("cannot find start of ligature"));
105 return;
108 if (!last_bound_)
109 events_drul_[STOP]->origin ()->warning (_ ("no right bound"));
110 else
111 ligature_->set_bound (RIGHT, last_bound_);
113 prev_start_event_ = 0;
114 finished_primitives_ = primitives_;
115 finished_ligature_ = ligature_;
116 primitives_.clear ();
117 ligature_ = 0;
119 last_bound_ = unsmob_grob (get_property ("currentMusicalColumn"));
121 if (ligature_)
123 // TODO: maybe forbid breaks only if not transcribing
124 context ()->get_score_context ()->set_property ("forbidBreak", SCM_BOOL_T);
127 if (events_drul_[START])
129 if (ligature_)
131 events_drul_[START]->origin ()->warning (_ ("already have a ligature"));
132 return;
135 prev_start_event_ = events_drul_[START];
136 ligature_ = create_ligature_spanner ();
138 Grob *bound = unsmob_grob (get_property ("currentMusicalColumn"));
139 if (!bound)
140 events_drul_[START]->origin ()->warning (_ ("no left bound"));
141 else
142 ligature_->set_bound (LEFT, bound);
144 ligature_start_mom_ = now_mom ();
146 // TODO: dump cause into make_item/spanner.
147 // announce_grob (ligature_, events_drul_[START]->self_scm ());
151 void
152 Ligature_engraver::stop_translation_timestep ()
154 if (finished_ligature_)
156 if (!finished_primitives_.size ())
158 finished_ligature_->programming_error (
159 "Ligature_engraver::stop_translation_timestep ():"
160 " junking empty ligature");
162 else
164 typeset_ligature (finished_ligature_, finished_primitives_);
165 finished_primitives_.clear ();
167 finished_ligature_ = 0;
170 events_drul_[START] = 0;
171 events_drul_[STOP] = 0;
174 void
175 Ligature_engraver::finalize ()
177 if (finished_ligature_)
179 typeset_ligature (finished_ligature_, finished_primitives_);
180 finished_primitives_.clear ();
181 finished_ligature_ = 0;
183 if (ligature_)
185 prev_start_event_->origin ()->warning (_ ("unterminated ligature"));
186 ligature_->suicide ();
190 Spanner *
191 Ligature_engraver::current_ligature ()
193 return ligature_;
196 void
197 Ligature_engraver::acknowledge_note_head (Grob_info info)
199 if (ligature_)
201 primitives_.push_back (info);
202 if (info.grob () && brew_ligature_primitive_proc != SCM_EOL)
204 info.grob ()->set_property ("stencil", brew_ligature_primitive_proc);
209 void
210 Ligature_engraver::acknowledge_rest (Grob_info info)
212 if (ligature_)
214 info.event_cause ()->origin ()->warning (_ ("ignoring rest: ligature may not contain rest"));
215 prev_start_event_->origin ()->warning (_ ("ligature was started here"));
216 // TODO: maybe better should stop ligature here rather than
217 // ignoring the rest?
221 // no ADD_ACKNOWLEDGER / ADD_ACKNOWLEDGER / ADD_TRANSLATOR macro calls
222 // since this class is abstract