2 paper-column.cc -- implement Paper_column
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 #include "paper-column.hh"
11 #include "break-align-interface.hh"
13 #include "paper-score.hh"
15 #include "axis-group-interface.hh"
16 #include "spaceable-grob.hh"
17 #include "text-interface.hh"
19 #include "font-interface.hh"
20 #include "output-def.hh"
21 #include "pointer-group-interface.hh"
22 #include "grob-array.hh"
26 #include "separation-item.hh"
27 #include "string-convert.hh"
30 Paper_column::clone () const
32 return new Paper_column (*this);
36 Paper_column::do_break_processing ()
38 Item::do_break_processing ();
42 Paper_column::get_rank (Grob const *me)
44 return dynamic_cast<Paper_column const *> (me)->rank_;
48 Paper_column::get_system () const
54 Paper_column::set_system (System *s)
60 Paper_column::get_column () const
62 return (Paper_column *) (this);
65 Paper_column::Paper_column (SCM l)
72 Paper_column::Paper_column (Paper_column const &src)
80 Paper_column::compare (Grob * const &a,
83 return sign (dynamic_cast<Paper_column*> (a)->rank_
84 - dynamic_cast<Paper_column*> (b)->rank_);
88 Paper_column::less_than (Grob *const &a,
91 Paper_column *pa = dynamic_cast<Paper_column*> (a);
92 Paper_column *pb = dynamic_cast<Paper_column*> (b);
94 return pa->rank_ < pb->rank_;
98 Paper_column::when_mom (Grob *me)
100 SCM m = me->get_property ("when");
101 if (Moment *when = unsmob_moment (m))
107 Paper_column::is_musical (Grob *me)
109 SCM m = me->get_property ("shortest-starter-duration");
111 if (unsmob_moment (m))
112 s = *unsmob_moment (m);
113 return s != Moment (0);
117 Paper_column::is_used (Grob *me)
119 extract_grob_set (me, "elements", elts);
123 extract_grob_set (me, "bounded-by-me", bbm);
127 if (Paper_column::is_breakable (me))
130 if (to_boolean (me->get_property ("used")))
136 Paper_column::is_breakable (Grob *me)
138 return scm_is_symbol (me->get_property ("line-break-permission"));
142 Paper_column::minimum_distance (Grob *left, Grob *right)
144 Drul_array<Grob*> cols (left, right);
145 Drul_array<Skyline> skys = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
150 Skyline_pair *sp = Skyline_pair::unsmob (cols[d]->get_property ("horizontal-skylines"));
154 while (flip (&d) != LEFT);
156 skys[RIGHT].merge (Separation_item::conditional_skyline (right, left));
158 return max (0.0, skys[LEFT].distance (skys[RIGHT]));
162 Paper_column::break_align_width (Grob *me)
164 Grob *p = me->get_parent (X_AXIS);
168 me->programming_error ("tried to get break-align-width of a non-musical column");
169 return Interval (0, 0) + me->relative_coordinate (p, X_AXIS);
172 Grob *align = Pointer_group_interface::find_grob (me, ly_symbol2scm ("elements"),
173 Break_alignment_interface::has_interface);
175 return Interval (0, 0) + me->relative_coordinate (p, X_AXIS);
177 return align->extent (p, X_AXIS);
181 Print a vertical line and the rank number, to aid debugging.
183 MAKE_SCHEME_CALLBACK (Paper_column, print, 1);
185 Paper_column::print (SCM p)
187 Paper_column *me = dynamic_cast<Paper_column*> (unsmob_grob (p));
189 string r = to_string (Paper_column::get_rank (me));
191 Moment *mom = unsmob_moment (me->get_property ("when"));
192 string when = mom ? mom->to_string () : "?/?";
194 Font_metric *musfont = Font_interface::get_default_font (me);
195 SCM properties = Font_interface::text_font_alist_chain (me);
197 SCM scm_mol = Text_interface::interpret_markup (me->layout ()->self_scm (),
200 SCM when_mol = Text_interface::interpret_markup (me->layout ()->self_scm (),
202 ly_string2scm (when));
203 Stencil t = *unsmob_stencil (scm_mol);
204 t.add_at_edge (Y_AXIS, DOWN, *unsmob_stencil (when_mol), 0.1);
205 t.align_to (X_AXIS, CENTER);
206 t.align_to (Y_AXIS, DOWN);
208 Stencil l = Lookup::filled_box (Box (Interval (-0.01, 0.01),
211 SCM small_letters = scm_cons (scm_acons (ly_symbol2scm ("font-size"),
212 scm_from_int (-6), SCM_EOL),
216 for (SCM s = me->get_object ("ideal-distances");
217 scm_is_pair (s); s = scm_cdr (s))
219 Spring *sp = unsmob_spring (scm_caar (s));
220 if (!unsmob_grob (scm_cdar (s))
221 || !unsmob_grob (scm_cdar (s))->get_system ())
227 pts.push_back (Offset (0, y));
229 Offset p2 (sp->distance (), y);
232 Stencil id_stencil = Lookup::points_to_line_stencil (0.1, pts);
233 Stencil head (musfont->find_by_name ("arrowheads.open.01"));
235 SCM distance_stc = Text_interface::interpret_markup (me->layout ()->self_scm (),
237 ly_string2scm (String_convert::form_string ("%5.2lf", sp->distance ())));
239 id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (sp->distance ()/3, y+1)));
240 id_stencil.add_stencil (head.translated (p2));
241 id_stencil = id_stencil.in_color (0,0,1);
242 l.add_stencil (id_stencil);
245 for (SCM s = me->get_object ("minimum-distances");
246 scm_is_pair (s); s = scm_cdr (s))
248 Real dist = scm_to_double (scm_cdar (s));
249 Grob *other = unsmob_grob (scm_caar (s));
250 if (!other || other->get_system () != me->get_system ())
255 Real y = -j * 1.0 -3.5;
257 pts.push_back (Offset (0, y));
262 Stencil id_stencil = Lookup::points_to_line_stencil (0.1, pts);
263 Stencil head (musfont->find_by_name ("arrowheads.open.0M1"));
264 head.translate_axis (y, Y_AXIS);
265 id_stencil.add_stencil (head);
267 SCM distance_stc = Text_interface::interpret_markup (me->layout ()->self_scm (),
269 ly_string2scm (String_convert::form_string ("%5.2lf",
272 id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (dist/3, y-1)));
275 id_stencil = id_stencil.in_color (1,0,0);
276 l.add_stencil (id_stencil);
279 return t.smobbed_copy ();
283 This is all too hairy. We use bounded-by-me to make sure that some
284 columns are kept "alive". Unfortunately, when spanners are suicided,
285 this falls apart again, because suicided spanners are still in
288 THIS IS BROKEN KLUDGE. WE SHOULD INVENT SOMETHING BETTER.
290 MAKE_SCHEME_CALLBACK (Paper_column, before_line_breaking, 1);
292 Paper_column::before_line_breaking (SCM grob)
294 Grob *me = unsmob_grob (grob);
296 SCM bbm = me->get_object ("bounded-by-me");
297 Grob_array *ga = unsmob_grob_array (bbm);
299 return SCM_UNSPECIFIED;
301 vector<Grob*> &array (ga->array_reference ());
303 for (vsize i = array.size (); i--;)
307 if (!g || !g->is_live ())
308 /* UGH . potentially quadratic. */
309 array.erase (array.begin () + i);
312 return SCM_UNSPECIFIED;
316 ADD_INTERFACE (Paper_column,
317 "@code{Paper_column} objects form the top-most X@tie{}parents"
318 " for items. There are two types of columns: musical columns,"
319 " where are attached to, and non-musical columns, where"
320 " bar-lines, clefs, etc., are attached to. The spacing engine"
321 " determines the X@tie{}positions of these objects.\n"
323 "They are numbered, the first (leftmost) is column@tie{}0."
324 " Numbering happens before line breaking, and columns are not"
325 " renumbered after line breaking. Since many columns go"
326 " unused, you should only use the rank field to get ordering"
327 " information. Two adjacent columns may have non-adjacent"
335 "line-break-system-details "
336 "line-break-penalty "
337 "line-break-permission "
338 "page-break-penalty "
339 "page-break-permission "
341 "page-turn-permission "
343 "shortest-playing-duration "
344 "shortest-starter-duration "