]> git.donarmstrong.com Git - lilypond.git/blob - lily/note-column.cc
146b3b06545c9eecf3c6b1fd691f34b3ddcd22b8
[lilypond.git] / lily / note-column.cc
1 /*
2   note-column.cc -- implement Note_column
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "note-column.hh"
10
11 #include <cmath>                // ceil
12 using namespace std;
13
14 #include "accidental-placement.hh"
15 #include "axis-group-interface.hh"
16 #include "directional-element-interface.hh"
17 #include "international.hh"
18 #include "note-head.hh"
19 #include "output-def.hh"
20 #include "pointer-group-interface.hh"
21 #include "rest.hh"
22 #include "staff-symbol-referencer.hh"
23 #include "stem.hh"
24 #include "warn.hh"
25
26 /*
27   TODO: figure out if we can prune this class. This is just an
28   annoying layer between (rest)collision & (note-head + stem)
29 */
30
31 bool
32 Note_column::has_rests (Grob *me)
33 {
34   return unsmob_grob (me->get_object ("rest"));
35 }
36
37 bool
38 Note_column::shift_less (Grob *const &p1, Grob *const &p2)
39 {
40   SCM s1 = p1->get_property ("horizontal-shift");
41   SCM s2 = p2->get_property ("horizontal-shift");
42
43   int h1 = (scm_is_number (s1)) ? scm_to_int (s1) : 0;
44   int h2 = (scm_is_number (s2)) ? scm_to_int (s2) : 0;
45   return h1 < h2;
46 }
47
48 Item *
49 Note_column::get_stem (Grob *me)
50 {
51   SCM s = me->get_object ("stem");
52   return unsmob_item (s);
53 }
54
55 Slice
56 Note_column::head_positions_interval (Grob *me)
57 {
58   Slice iv;
59
60   iv.set_empty ();
61
62   extract_grob_set (me, "note-heads", heads);
63   for (vsize i = 0; i < heads.size (); i++)
64     {
65       Grob *se = heads[i];
66
67       int j = Staff_symbol_referencer::get_rounded_position (se);
68       iv.unite (Slice (j, j));
69     }
70   return iv;
71 }
72
73 Direction
74 Note_column::dir (Grob *me)
75 {
76   Grob *stem = unsmob_grob (me->get_object ("stem"));
77   if (stem && Stem::has_interface (stem))
78     return get_grob_direction (stem);
79   else
80     {
81       extract_grob_set (me, "note-heads", heads);
82       if (heads.size ())
83         return (Direction)sign (head_positions_interval (me).center ());
84     }
85
86   programming_error ("note column without heads and stem");
87   return CENTER;
88 }
89
90 void
91 Note_column::set_stem (Grob *me, Grob *stem)
92 {
93   me->set_object ("stem", stem->self_scm ());
94   Axis_group_interface::add_element (me, stem);
95 }
96
97 Grob *
98 Note_column::get_rest (Grob *me)
99 {
100   return unsmob_grob (me->get_object ("rest"));
101 }
102
103 void
104 Note_column::add_head (Grob *me, Grob *h)
105 {
106   bool both = false;
107   if (Rest::has_interface (h))
108     {
109       extract_grob_set (me, "note-heads", heads);
110       if (heads.size ())
111         both = true;
112       else
113         me->set_object ("rest", h->self_scm ());
114     }
115   else if (Note_head::has_interface (h))
116     {
117       if (unsmob_grob (me->get_object ("rest")))
118         both = true;
119       Pointer_group_interface::add_grob (me, ly_symbol2scm ("note-heads"), h);
120     }
121
122   if (both)
123     me->warning (_ ("can't have note heads and rests together on a stem"));
124   else
125     Axis_group_interface::add_element (me, h);
126 }
127
128 /**
129    translate the rest symbols vertically by amount DY, but only if
130    they have no staff-position set.
131 */
132 void
133 Note_column::translate_rests (Grob *me, int dy)
134 {
135   Grob *r = unsmob_grob (me->get_object ("rest"));
136   if (r && !scm_is_number (r->get_property ("staff-position")))
137     {
138       r->translate_axis (dy * Staff_symbol_referencer::staff_space (r) / 2.0, Y_AXIS);
139       Grob *p = r->get_parent (Y_AXIS);
140       p->flush_extent_cache (Y_AXIS);
141     }
142 }
143
144 void
145 Note_column::set_dotcol (Grob *me, Grob *d)
146 {
147   Axis_group_interface::add_element (me, d);
148 }
149
150 Grob *
151 Note_column::first_head (Grob *me)
152 {
153   Grob *st = get_stem (me);
154   return st ? Stem::first_head (st) : 0;
155 }
156
157 /*
158   Return the first Accidentals grob that we find in a note-head.
159 */
160 Grob *
161 Note_column::accidentals (Grob *me)
162 {
163   extract_grob_set (me, "note-heads", heads);
164   Grob *acc = 0;
165   for (vsize i = 0; i < heads.size (); i++)
166     {
167       Grob *h = heads[i];
168       acc = h ? unsmob_grob (h->get_object ("accidental-grob")) : 0;
169       if (acc)
170         break;
171     }
172
173   if (!acc)
174     return 0;
175
176   if (Accidental_placement::has_interface (acc->get_parent (X_AXIS)))
177     return acc->get_parent (X_AXIS);
178
179   /* compatibility. */
180   return acc;
181 }
182
183 Grob *
184 Note_column::arpeggio (Grob *me)
185 {
186   return unsmob_grob (me->get_object ("arpeggio"));
187 }
188
189 ADD_INTERFACE (Note_column, "note-column-interface",
190                "Stem and noteheads combined",
191
192                /* properties */
193                "accidentals "
194                "arpeggio "
195                "force-hshift "
196                "horizontal-shift "
197                "note-heads "
198                "rest "
199                "rest-collision "
200                "stem "
201                );