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