2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2011 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 "dot-column.hh"
29 #include "axis-group-interface.hh"
30 #include "directional-element-interface.hh"
31 #include "dot-column.hh"
32 #include "dot-configuration.hh"
33 #include "dot-formatting-problem.hh"
36 #include "note-head.hh"
37 #include "pointer-group-interface.hh"
39 #include "rhythmic-head.hh"
40 #include "side-position-interface.hh"
41 #include "staff-symbol-referencer.hh"
44 MAKE_SCHEME_CALLBACK (Dot_column
, calc_positioning_done
, 1);
46 Dot_column::calc_positioning_done (SCM smob
)
48 Grob
*me
= unsmob_grob (smob
);
51 Trigger note collision resolution first, since that may kill off
54 if (Grob
*collision
= unsmob_grob (me
->get_object ("note-collision")))
55 (void) collision
->get_property ("positioning-done");
57 me
->set_property ("positioning-done", SCM_BOOL_T
);
60 = extract_grob_array (me
, "dots");
62 vector
<Grob
*> main_heads
;
66 for (vsize i
= 0; i
< dots
.size (); i
++)
68 Grob
*n
= dots
[i
]->get_parent (Y_AXIS
);
69 commonx
= n
->common_refpoint (commonx
, X_AXIS
);
71 if (Grob
*stem
= unsmob_grob (n
->get_object("stem")))
73 commonx
= stem
->common_refpoint (commonx
, X_AXIS
);
75 if (Stem::first_head (stem
) == n
)
76 main_heads
.push_back (n
);
83 extract_grob_set(me
, "side-support-elements", support
);
86 for (vsize i
= 0; i
< main_heads
.size (); i
++)
87 base_x
.unite (main_heads
[i
]->extent (commonx
, X_AXIS
));
89 for (vsize i
= 0; i
< support
.size (); i
++)
93 ss
= Staff_symbol_referencer::staff_space (s
);
95 /* can't inspect Y extent of rest.
97 Rest collisions should wait after line breaking.
100 if (Rest::has_interface (s
))
102 base_x
.unite (s
->extent (commonx
, X_AXIS
));
105 else if (Stem::has_interface (s
))
107 Real y1
= Stem::head_positions (s
)[-get_grob_direction (s
)];
108 Real y2
= y1
+ get_grob_direction (s
) * 7;
113 else if (Note_head::has_interface (s
))
114 y
= Interval (-1, 1);
117 programming_error ("unknown grob in dot col support");
122 y
+= Staff_symbol_referencer::get_position (s
);
124 Box
b (s
->extent (commonx
, X_AXIS
), y
);
127 if (Grob
*stem
= unsmob_grob (s
->get_object ("stem")))
131 for (set
<Grob
*>::const_iterator
i (stems
.begin());
132 i
!= stems
.end (); i
++)
135 Stencil flag
= Stem::flag (stem
);
136 if (!flag
.is_empty ())
138 Interval y
= flag
.extent (Y_AXIS
)
140 + Stem::stem_end_position (stem
);
142 Interval x
= stem
->relative_coordinate (commonx
, X_AXIS
)
143 + flag
.extent (X_AXIS
);
145 boxes
.push_back (Box (x
,y
));
149 vector_sort (dots
, position_less
);
150 for (vsize i
= dots
.size (); i
--;)
152 if (!dots
[i
]->is_live ())
153 dots
.erase (dots
.begin () + i
);
155 // Undo any fake translations that were done in add_head.
156 dots
[i
]->translate_axis (-dots
[i
]->relative_coordinate (me
, X_AXIS
), X_AXIS
);
159 Dot_formatting_problem
problem (boxes
, base_x
);
161 Dot_configuration
cfg (problem
);
162 for (vsize i
= 0; i
< dots
.size (); i
++)
167 Grob
*note
= dots
[i
]->get_parent (Y_AXIS
);
170 Grob
*stem
= unsmob_grob (note
->get_object ("stem"));
172 dp
.extremal_head_
= Stem::first_head (stem
) == note
;
174 dp
.x_extent_
= note
->extent (commonx
, X_AXIS
);
177 int p
= Staff_symbol_referencer::get_rounded_position (dp
.dot_
);
179 /* icky, since this should go via a Staff_symbol_referencer
180 offset callback but adding a dot overwrites Y-offset. */
181 p
+= (int) robust_scm2double (dp
.dot_
->get_property ("staff-position"), 0.0);
183 if (dp
.extremal_head_
)
184 dp
.dir_
= to_dir (dp
.dot_
->get_property ("direction"));
186 cfg
.remove_collision (p
);
188 if (Staff_symbol_referencer::on_line (dp
.dot_
, p
))
189 cfg
.remove_collision (p
);
192 problem
.register_configuration (cfg
);
194 for (Dot_configuration::const_iterator
i (cfg
.begin ());
195 i
!= cfg
.end (); i
++)
200 Staff_symbol_referencer::set_position (i
->second
.dot_
, i
->first
);
203 me
->translate_axis (cfg
.x_offset () - me
->relative_coordinate (commonx
, X_AXIS
),
209 Dot_column::add_head (Grob
*me
, Grob
*head
)
211 Grob
*d
= unsmob_grob (head
->get_object ("dot"));
214 Side_position_interface::add_support (me
, head
);
216 Pointer_group_interface::add_grob (me
, ly_symbol2scm ("dots"), d
);
217 d
->set_property ("Y-offset", Grob::x_parent_positioning_proc
);
218 // Dot formatting requests the Y-offset, which for rests may
219 // trigger post-linebreak callbacks. On the other hand, we need the
220 // correct X-offset of the dots for horizontal collision avoidance.
221 // The translation here is undone in calc_positioning_done, where we
222 // do the X-offset properly.
223 if (Rest::has_interface (head
))
224 d
->translate_axis (head
->extent (head
, X_AXIS
).length (), X_AXIS
);
226 d
->set_property ("X-offset", Grob::x_parent_positioning_proc
);
227 Axis_group_interface::add_element (me
, d
);
231 ADD_INTERFACE (Dot_column
,
232 "Group dot objects so they form a column, and position"
233 " dots so they do not clash with staff lines.",