]> git.donarmstrong.com Git - lilypond.git/blob - lily/item.cc
restore regression tests for time-signature styles; issue 4176
[lilypond.git] / lily / item.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
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.
10
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.
15
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/>.
18 */
19
20 #include "item.hh"
21
22 #include "axis-group-interface.hh"
23 #include "paper-score.hh"
24 #include "warn.hh"
25 #include "paper-column.hh"
26 #include "lily-guile.hh"
27 #include "system.hh"
28 #include "pointer-group-interface.hh"
29
30 #include "moment.hh"
31
32 Grob *
33 Item::clone () const
34 {
35   return new Item (*this);
36 }
37
38 Item::Item (SCM s)
39   : Grob (s)
40 {
41   broken_to_drul_[LEFT] = broken_to_drul_[RIGHT] = 0;
42   cached_pure_height_valid_ = false;
43 }
44
45 /**
46    Item copy ctor.  Copy nothing: everything should be an elt property
47    or a special purpose pointer (such as broken_to_drul_[]) */
48 Item::Item (Item const &s)
49   : Grob (s)
50 {
51   broken_to_drul_[LEFT] = broken_to_drul_[RIGHT] = 0;
52   cached_pure_height_valid_ = false;
53 }
54
55 bool
56 Item::is_non_musical (Grob *me)
57 {
58   Item *i = dynamic_cast<Item *> (me->get_parent (X_AXIS));
59   return i ? Item::is_non_musical (i) : to_boolean (me->get_property ("non-musical"));
60 }
61
62 Paper_column *
63 Item::get_column () const
64 {
65   Item *parent = dynamic_cast<Item *> (get_parent (X_AXIS));
66   return parent ? parent->get_column () : 0;
67 }
68
69 System *
70 Item::get_system () const
71 {
72   Grob *g = get_parent (X_AXIS);
73   return g ? g->get_system () : 0;
74 }
75
76 void
77 Item::copy_breakable_items ()
78 {
79   Drul_array<Item *> new_copies;
80   for (LEFT_and_RIGHT (d))
81     {
82       Grob *dolly = clone ();
83       Item *item = dynamic_cast<Item *> (dolly);
84       get_root_system (this)->typeset_grob (item);
85       new_copies[d] = item;
86     }
87
88   broken_to_drul_ = new_copies;
89 }
90
91 bool
92 Item::is_broken () const
93 {
94   return broken_to_drul_[LEFT] || broken_to_drul_[RIGHT];
95 }
96
97 /*
98   Generate items for begin and end-of line.
99 */
100 void
101 Item::discretionary_processing ()
102 {
103   if (is_broken () || original ())
104     return;
105
106   if (Item::is_non_musical (this))
107     copy_breakable_items ();
108 }
109
110 Grob *
111 Item::find_broken_piece (System *l) const
112 {
113   if (get_system () == l)
114     return (Item *) (this);
115
116   for (LEFT_and_RIGHT (d))
117     {
118       Grob *s = broken_to_drul_[d];
119       if (s && s->get_system () == l)
120         return s;
121     }
122
123   return 0;
124 }
125
126 Item *
127 Item::find_prebroken_piece (Direction d) const
128 {
129   Item *me = (Item *) (this);
130   if (!d)
131     return me;
132   return dynamic_cast<Item *> (broken_to_drul_[d]);
133 }
134
135 Direction
136 Item::break_status_dir () const
137 {
138   if (original ())
139     {
140       Item *i = dynamic_cast<Item *> (original ());
141
142       return (i->broken_to_drul_[LEFT] == this) ? LEFT : RIGHT;
143     }
144   else
145     return CENTER;
146 }
147
148 void
149 Item::handle_prebroken_dependencies ()
150 {
151   Grob::handle_prebroken_dependencies ();
152
153   /*
154     Can't do this earlier, because try_visibility_lambda () might set
155     the elt property transparent, which would then be copied.
156   */
157   if (!Item::break_visible (this))
158     suicide ();
159 }
160
161 bool
162 Item::break_visible (Grob *g)
163 {
164   Item *it = dynamic_cast<Item *> (g);
165   SCM vis = g->get_property ("break-visibility");
166   if (scm_is_vector (vis))
167     return to_boolean (scm_c_vector_ref (vis, it->break_status_dir () + 1));
168   return true;
169 }
170
171 bool
172 Item::pure_is_visible (int start, int end) const
173 {
174   SCM vis = get_property ("break-visibility");
175   if (scm_is_vector (vis))
176     {
177       int pos = 1;
178       int pc_rank = Paper_column::get_rank (get_column ());
179       if (pc_rank == start)
180         pos = 2;
181       else if (pc_rank == end)
182         pos = 0;
183       return to_boolean (scm_vector_ref (vis, scm_from_int (pos)));
184     }
185   return true;
186 }
187
188 Interval_t<int>
189 Item::spanned_rank_interval () const
190 {
191   int c = get_column ()->get_rank ();
192   return Interval_t<int> (c, c);
193 }
194
195 Interval_t<Moment>
196 spanned_time_interval (Item *l, Item *r)
197 {
198   Drul_array<Item *> bounds (l, r);
199   Interval_t<Moment> iv;
200
201   for (LEFT_and_RIGHT (d))
202     {
203       if (bounds[d] && bounds[d]->get_column ())
204         iv[d] = robust_scm2moment (bounds[d]->get_column ()->get_property ("when"),
205                                    iv[d]);
206     }
207
208   for (LEFT_and_RIGHT (d))
209     {
210       if (!bounds[d] || !bounds[d]->get_column ())
211         iv[d] = iv[-d];
212     }
213
214   return iv;
215 }
216
217 void
218 Item::derived_mark () const
219 {
220   if (broken_to_drul_[LEFT])
221     scm_gc_mark (broken_to_drul_[LEFT]->self_scm ());
222   if (broken_to_drul_[RIGHT])
223     scm_gc_mark (broken_to_drul_[RIGHT]->self_scm ());
224 }
225
226 Interval
227 Item::pure_height (Grob *g, int start, int end)
228 {
229   if (cached_pure_height_valid_)
230     return cached_pure_height_ + pure_relative_y_coordinate (g, start, end);
231   /* Note: cached_pure_height_ does not notice if start changes, implicitly
232      assuming that Items' pure_heights do not depend on 'start' or 'end'.
233   */
234
235   cache_pure_height (Grob::pure_height (this, start, end));
236   return cached_pure_height_ + pure_relative_y_coordinate (g, start, end);
237 }
238
239 void
240 Item::cache_pure_height (Interval height)
241 {
242   cached_pure_height_ = height;
243   cached_pure_height_valid_ = true;
244 }
245
246 ADD_INTERFACE (Item,
247                "Grobs can be distinguished in their role in the horizontal"
248                " spacing.  Many grobs define constraints on the spacing by"
249                " their sizes, for example, note heads, clefs, stems, and all"
250                " other symbols with a fixed shape.  These grobs form a"
251                " subtype called @code{Item}.\n"
252                "\n"
253                "Some items need special treatment for line breaking.  For"
254                " example, a clef is normally only printed at the start of a"
255                " line (i.e., after a line break).   To model this,"
256                " @q{breakable} items (clef, key signature, bar lines, etc.)"
257                " are copied twice.  Then we have three versions of each"
258                " breakable item: one version if there is no line break, one"
259                " version that is printed before the line break (at the end of"
260                " a system), and one version that is printed after the line"
261                " break.\n"
262                "\n"
263                "Whether these versions are visible and take up space is"
264                " determined by the outcome of the @code{break-visibility}"
265                " grob property, which is a function taking a direction"
266                " (@w{@code{-1}}, @code{0} or@tie{}@code{1}) as an argument.  It"
267                " returns a cons of booleans, signifying whether this grob"
268                " should be transparent and have no extent.\n"
269                "\n"
270                "The following variables for @code{break-visibility} are"
271                " predefined:\n"
272                "@example\n"
273                "           grob will show:   before  no     after\n"
274                "                             break   break  break\n"
275                "  all-invisible              no      no     no\n"
276                "  begin-of-line-visible      no      no     yes\n"
277                "  end-of-line-visible        yes     no     no\n"
278                "  all-visible                yes     yes    yes\n"
279                "  begin-of-line-invisible    yes     yes    no\n"
280                "  end-of-line-invisible      no      yes    yes\n"
281                "  center-invisible           yes      no    yes\n"
282                "@end example",
283
284                /* properties */
285                "break-visibility "
286                "extra-spacing-height "
287                "extra-spacing-width "
288                "non-musical "
289               );