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