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)
166 me->programming_error ("tried to get break-align-width of a non-musical column");
167 return Interval (0, 0);
170 Grob *align = Pointer_group_interface::find_grob (me, ly_symbol2scm ("elements"),
171 Break_alignment_interface::has_interface);
173 return Interval (0, 0);
175 return align->extent (me->get_parent (X_AXIS), X_AXIS);
179 Print a vertical line and the rank number, to aid debugging.
181 MAKE_SCHEME_CALLBACK (Paper_column, print, 1);
183 Paper_column::print (SCM p)
185 Paper_column *me = dynamic_cast<Paper_column*> (unsmob_grob (p));
187 string r = to_string (Paper_column::get_rank (me));
189 Moment *mom = unsmob_moment (me->get_property ("when"));
190 string when = mom ? mom->to_string () : "?/?";
192 Font_metric *musfont = Font_interface::get_default_font (me);
193 SCM properties = Font_interface::text_font_alist_chain (me);
195 SCM scm_mol = Text_interface::interpret_markup (me->layout ()->self_scm (),
198 SCM when_mol = Text_interface::interpret_markup (me->layout ()->self_scm (),
200 ly_string2scm (when));
201 Stencil t = *unsmob_stencil (scm_mol);
202 t.add_at_edge (Y_AXIS, DOWN, *unsmob_stencil (when_mol), 0.1);
203 t.align_to (X_AXIS, CENTER);
204 t.align_to (Y_AXIS, DOWN);
206 Stencil l = Lookup::filled_box (Box (Interval (-0.01, 0.01),
209 SCM small_letters = scm_cons (scm_acons (ly_symbol2scm ("font-size"),
210 scm_from_int (-6), SCM_EOL),
214 for (SCM s = me->get_object ("ideal-distances");
215 scm_is_pair (s); s = scm_cdr (s))
217 Spring *sp = unsmob_spring (scm_caar (s));
218 if (!unsmob_grob (scm_cdar (s))
219 || !unsmob_grob (scm_cdar (s))->get_system ())
225 pts.push_back (Offset (0, y));
227 Offset p2 (sp->distance (), y);
230 Stencil id_stencil = Lookup::points_to_line_stencil (0.1, pts);
231 Stencil head (musfont->find_by_name ("arrowheads.open.01"));
233 SCM distance_stc = Text_interface::interpret_markup (me->layout ()->self_scm (),
235 ly_string2scm (String_convert::form_string ("%5.2lf", sp->distance ())));
237 id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (sp->distance ()/3, y+1)));
238 id_stencil.add_stencil (head.translated (p2));
239 id_stencil = id_stencil.in_color (0,0,1);
240 l.add_stencil (id_stencil);
243 for (SCM s = me->get_object ("minimum-distances");
244 scm_is_pair (s); s = scm_cdr (s))
246 Real dist = scm_to_double (scm_cdar (s));
247 Grob *other = unsmob_grob (scm_caar (s));
248 if (!other || other->get_system () != me->get_system ())
253 Real y = -j * 1.0 -3.5;
255 pts.push_back (Offset (0, y));
260 Stencil id_stencil = Lookup::points_to_line_stencil (0.1, pts);
261 Stencil head (musfont->find_by_name ("arrowheads.open.0M1"));
262 head.translate_axis (y, Y_AXIS);
263 id_stencil.add_stencil (head);
265 SCM distance_stc = Text_interface::interpret_markup (me->layout ()->self_scm (),
267 ly_string2scm (String_convert::form_string ("%5.2lf",
270 id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (dist/3, y-1)));
273 id_stencil = id_stencil.in_color (1,0,0);
274 l.add_stencil (id_stencil);
277 return t.smobbed_copy ();
281 This is all too hairy. We use bounded-by-me to make sure that some
282 columns are kept "alive". Unfortunately, when spanners are suicided,
283 this falls apart again, because suicided spanners are still in
286 THIS IS BROKEN KLUDGE. WE SHOULD INVENT SOMETHING BETTER.
288 MAKE_SCHEME_CALLBACK (Paper_column, before_line_breaking, 1);
290 Paper_column::before_line_breaking (SCM grob)
292 Grob *me = unsmob_grob (grob);
294 SCM bbm = me->get_object ("bounded-by-me");
295 Grob_array *ga = unsmob_grob_array (bbm);
297 return SCM_UNSPECIFIED;
299 vector<Grob*> &array (ga->array_reference ());
301 for (vsize i = array.size (); i--;)
305 if (!g || !g->is_live ())
306 /* UGH . potentially quadratic. */
307 array.erase (array.begin () + i);
310 return SCM_UNSPECIFIED;
314 ADD_INTERFACE (Paper_column,
315 "@code{Paper_column} objects form the top-most X-parents for items."
316 " The are two types of columns: musical columns, where are attached to, and "
317 " non-musical columns, where bar-lines, clefs etc. are attached to. "
318 " The spacing engine determines the X-positions of these objects."
322 " numbered, the first (leftmost) is column 0. Numbering happens before\n"
323 " line-breaking, and columns are not renumbered after line breaking.\n"
324 " Since many columns go unused, you should only use the rank field to\n"
325 " get ordering information. Two adjacent columns may have\n"
326 " non-adjacent numbers.\n",
334 "line-break-system-details "
335 "line-break-penalty "
336 "line-break-permission "
337 "page-break-penalty "
338 "page-break-permission "
340 "page-turn-permission "
342 "shortest-playing-duration "
343 "shortest-starter-duration "