]> git.donarmstrong.com Git - lilypond.git/blob - lily/item.cc
fdf9b00ce9d36c1498076dc221e6ab01f992be61
[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
253                "Grobs can be distinguished in their role in the horizontal spacing.\n"
254                "Many grobs define constraints on the spacing by their sizes. For\n"
255                "example, note heads, clefs, stems, and all other symbols with a fixed\n"
256                "shape.  These grobs form a subtype called @code{Item}.\n"
257                "\n"
258                "\n"
259                "Some items need special treatment for line breaking. For example, a\n"
260                "clef is normally only printed at the start of a line (i.e. after a\n"
261                "line break).  To model this, `breakable' items (clef, key signature,\n"
262                "bar lines, etc.) are copied twice. Then we have three versions of each\n"
263                "breakable item: one version if there is no line break, one version\n"
264                "that is printed before the line break (at the end of a system), one\n"
265                "version that is printed after the line break.\n"
266                "\n"
267                "Whether these versions are visible and take up space, is determined by\n"
268                "the outcome of the @code{break-visibility}. This grob property is a\n"
269                "function taking a direction (-1, 0 or 1) as argument. It returns a\n"
270                "cons of booleans, signifying whether this grob should be transparent\n"
271                "and have no extent.\n"
272                "\n"
273                "The following variables for break-visibility are predefined:\n"
274                "@example\n"
275                "           grob will show:   before  no     after\n"
276                "                             break   break  break\n"
277                "  all-invisible              no      no     no\n"
278                "  begin-of-line-visible      no      no     yes\n"
279                "  end-of-line-visible        yes     no     no\n"
280                "  all-visible                yes     yes    yes\n"
281                "  begin-of-line-invisible    yes     yes    no\n"
282                "  end-of-line-invisible      no      yes    yes\n"
283                "  center-invisible           yes      no    yes\n"
284                "@end example\n",
285
286                /* properties */
287                "break-visibility "
288                "extra-spacing-width "
289                "infinite-spacing-height "
290                "non-musical")