2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
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.
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.
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/>.
20 #include "note-column.hh"
22 #include <cmath> // ceil
24 #include "accidental-placement.hh"
25 #include "axis-group-interface.hh"
26 #include "directional-element-interface.hh"
27 #include "international.hh"
29 #include "note-head.hh"
30 #include "output-def.hh"
31 #include "pointer-group-interface.hh"
33 #include "staff-symbol-referencer.hh"
38 TODO: figure out if we can prune this class. This is just an
39 annoying layer between (rest)collision & (note-head + stem)
43 Note_column::has_rests (Grob *me)
45 return unsmob<Grob> (me->get_object ("rest"));
49 Note_column::shift_less (Grob *const &p1, Grob *const &p2)
51 SCM s1 = p1->get_property ("horizontal-shift");
52 SCM s2 = p2->get_property ("horizontal-shift");
54 int h1 = (scm_is_number (s1)) ? scm_to_int (s1) : 0;
55 int h2 = (scm_is_number (s2)) ? scm_to_int (s2) : 0;
60 Note_column::get_stem (Grob *me)
62 SCM s = me->get_object ("stem");
63 return unsmob<Item> (s);
67 Note_column::get_flag (Grob *me)
69 Item *stem = get_stem (me);
72 SCM s = stem->get_object ("flag");
73 return unsmob<Item> (s);
79 Note_column::head_positions_interval (Grob *me)
85 extract_grob_set (me, "note-heads", heads);
86 for (vsize i = 0; i < heads.size (); i++)
90 int j = Staff_symbol_referencer::get_rounded_position (se);
91 iv.unite (Slice (j, j));
97 Note_column::dir (Grob *me)
99 Grob *stem = unsmob<Grob> (me->get_object ("stem"));
100 if (has_interface<Stem> (stem))
101 return get_grob_direction (stem);
104 extract_grob_set (me, "note-heads", heads);
106 return (Direction)sign (head_positions_interval (me).center ());
109 if (has_interface<Note_column> (me))
110 programming_error ("Note_column without heads and stem");
112 programming_error ("dir() given grob without Note_column interface");
117 Note_column::set_stem (Grob *me, Grob *stem)
119 me->set_object ("stem", stem->self_scm ());
120 Axis_group_interface::add_element (me, stem);
124 Note_column::get_rest (Grob *me)
126 return unsmob<Grob> (me->get_object ("rest"));
130 Note_column::add_head (Grob *me, Grob *h)
133 if (has_interface<Rest> (h))
135 extract_grob_set (me, "note-heads", heads);
139 me->set_object ("rest", h->self_scm ());
141 else if (has_interface<Note_head> (h))
143 if (unsmob<Grob> (me->get_object ("rest")))
145 Pointer_group_interface::add_grob (me, ly_symbol2scm ("note-heads"), h);
149 me->warning (_ ("cannot have note heads and rests together on a stem"));
151 Axis_group_interface::add_element (me, h);
155 Note_column::first_head (Grob *me)
157 Grob *st = get_stem (me);
158 return st ? Stem::first_head (st) : 0;
162 Return extent of the noteheads in the "main column",
163 (i.e. excluding any suspended noteheads), or extent
164 of the rest (if there are no heads).
167 Note_column::calc_main_extent (Grob *me)
171 main_head = first_head (me);
174 // no stems => no suspended noteheads.
175 extract_grob_set (me, "note-heads", heads);
177 main_head = heads[0];
179 Grob *main_item = main_head
181 : unsmob<Grob> (me->get_object ("rest"));
184 ? main_item->extent (me, X_AXIS)
189 Return the first AccidentalPlacement grob that we find in a note-head.
192 Note_column::accidentals (Grob *me)
194 extract_grob_set (me, "note-heads", heads);
196 for (vsize i = 0; i < heads.size (); i++)
199 acc = h ? unsmob<Grob> (h->get_object ("accidental-grob")) : 0;
207 if (has_interface<Accidental_placement> (acc->get_parent (X_AXIS)))
208 return acc->get_parent (X_AXIS);
215 Note_column::dot_column (Grob *me)
217 extract_grob_set (me, "note-heads", heads);
218 for (vsize i = 0; i < heads.size (); i++)
220 Grob *dots = unsmob<Grob> (heads[i]->get_object ("dot"));
222 return dots->get_parent (X_AXIS);
228 /* If a note-column contains a cross-staff stem then
229 nc->extent (Y_AXIS, refp) will not consider the extent of the stem.
230 If you want the extent of the stem to be included (and you are safe
231 from any cross-staff issues) then call this function instead. */
233 Note_column::cross_staff_extent (Grob *me, Grob *refp)
235 Interval iv = me->extent (refp, Y_AXIS);
236 if (Grob *s = get_stem (me))
237 iv.unite (s->extent (refp, Y_AXIS));
242 ADD_INTERFACE (Note_column,
243 "Stem and noteheads combined.",