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