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"
12 #include "paper-score.hh"
14 #include "axis-group-interface.hh"
15 #include "spaceable-grob.hh"
16 #include "text-interface.hh"
18 #include "font-interface.hh"
19 #include "output-def.hh"
20 #include "pointer-group-interface.hh"
21 #include "grob-array.hh"
25 #include "separation-item.hh"
26 #include "string-convert.hh"
29 Paper_column::clone () const
31 return new Paper_column (*this);
35 Paper_column::do_break_processing ()
37 Item::do_break_processing ();
41 Paper_column::get_rank (Grob const *me)
43 return dynamic_cast<Paper_column const *> (me)->rank_;
47 Paper_column::get_system () const
53 Paper_column::set_system (System *s)
59 Paper_column::get_column () const
61 return (Paper_column *) (this);
64 Paper_column::Paper_column (SCM l)
71 Paper_column::Paper_column (Paper_column const &src)
79 Paper_column::compare (Grob * const &a,
82 return sign (dynamic_cast<Paper_column*> (a)->rank_
83 - dynamic_cast<Paper_column*> (b)->rank_);
87 Paper_column::less_than (Grob *const &a,
90 Paper_column *pa = dynamic_cast<Paper_column*> (a);
91 Paper_column *pb = dynamic_cast<Paper_column*> (b);
93 return pa->rank_ < pb->rank_;
97 Paper_column::when_mom (Grob *me)
99 SCM m = me->get_property ("when");
100 if (Moment *when = unsmob_moment (m))
106 Paper_column::is_musical (Grob *me)
108 SCM m = me->get_property ("shortest-starter-duration");
110 if (unsmob_moment (m))
111 s = *unsmob_moment (m);
112 return s != Moment (0);
116 Paper_column::is_used (Grob *me)
118 extract_grob_set (me, "elements", elts);
122 extract_grob_set (me, "bounded-by-me", bbm);
126 if (Paper_column::is_breakable (me))
129 if (to_boolean (me->get_property ("used")))
135 Paper_column::is_breakable (Grob *me)
137 return scm_is_symbol (me->get_property ("line-break-permission"));
141 Paper_column::minimum_distance (Grob *left, Grob *right)
143 Drul_array<Grob*> cols (left, right);
144 Drul_array<Skyline> skys = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
149 skys[d].set_minimum_height (0.0);
150 extract_grob_set (cols[d], "elements", elts);
152 for (vsize i = 0; i < elts.size (); i++)
153 if (Separation_item::has_interface (elts[i]))
155 Skyline_pair *sp = Skyline_pair::unsmob (elts[i]->get_property ("horizontal-skylines"));
157 skys[d].merge ((*sp)[-d]);
160 while (flip (&d) != LEFT);
162 return max (0.0, skys[LEFT].distance (skys[RIGHT]));
166 Print a vertical line and the rank number, to aid debugging.
168 MAKE_SCHEME_CALLBACK (Paper_column, print, 1);
170 Paper_column::print (SCM p)
172 Paper_column *me = dynamic_cast<Paper_column*> (unsmob_grob (p));
174 string r = to_string (Paper_column::get_rank (me));
176 Moment *mom = unsmob_moment (me->get_property ("when"));
177 string when = mom ? mom->to_string () : "?/?";
179 Font_metric *musfont = Font_interface::get_default_font (me);
180 SCM properties = Font_interface::text_font_alist_chain (me);
182 SCM scm_mol = Text_interface::interpret_markup (me->layout ()->self_scm (),
185 SCM when_mol = Text_interface::interpret_markup (me->layout ()->self_scm (),
187 ly_string2scm (when));
188 Stencil t = *unsmob_stencil (scm_mol);
189 t.add_at_edge (Y_AXIS, DOWN, *unsmob_stencil (when_mol), 0.1);
190 t.align_to (X_AXIS, CENTER);
191 t.align_to (Y_AXIS, DOWN);
193 Stencil l = Lookup::filled_box (Box (Interval (-0.01, 0.01),
196 SCM small_letters = scm_cons (scm_acons (ly_symbol2scm ("font-size"),
197 scm_from_int (-6), SCM_EOL),
201 for (SCM s = me->get_object ("ideal-distances");
202 scm_is_pair (s); s = scm_cdr (s))
204 Spring *sp = unsmob_spring (scm_caar (s));
205 if (!unsmob_grob (scm_cdar (s))
206 || !unsmob_grob (scm_cdar (s))->get_system ())
212 pts.push_back (Offset (0, y));
214 Offset p2 (sp->distance (), y);
217 Stencil id_stencil = Lookup::points_to_line_stencil (0.1, pts);
218 Stencil head (musfont->find_by_name ("arrowheads.open.01"));
220 SCM distance_stc = Text_interface::interpret_markup (me->layout ()->self_scm (),
222 ly_string2scm (String_convert::form_string ("%5.2lf", sp->distance ())));
224 id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (sp->distance ()/3, y+1)));
225 id_stencil.add_stencil (head.translated (p2));
226 id_stencil = id_stencil.in_color (0,0,1);
227 l.add_stencil (id_stencil);
230 for (SCM s = me->get_object ("minimum-distances");
231 scm_is_pair (s); s = scm_cdr (s))
233 Real dist = scm_to_double (scm_cdar (s));
234 Grob *other = unsmob_grob (scm_caar (s));
235 if (!other || other->get_system () != me->get_system ())
240 Real y = -j * 1.0 -3.5;
242 pts.push_back (Offset (0, y));
247 Stencil id_stencil = Lookup::points_to_line_stencil (0.1, pts);
248 Stencil head (musfont->find_by_name ("arrowheads.open.0M1"));
249 head.translate_axis (y, Y_AXIS);
250 id_stencil.add_stencil (head);
252 SCM distance_stc = Text_interface::interpret_markup (me->layout ()->self_scm (),
254 ly_string2scm (String_convert::form_string ("%5.2lf",
257 id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (dist/3, y-1)));
260 id_stencil = id_stencil.in_color (1,0,0);
261 l.add_stencil (id_stencil);
264 return t.smobbed_copy ();
268 This is all too hairy. We use bounded-by-me to make sure that some
269 columns are kept "alive". Unfortunately, when spanners are suicided,
270 this falls apart again, because suicided spanners are still in
273 THIS IS BROKEN KLUDGE. WE SHOULD INVENT SOMETHING BETTER.
275 MAKE_SCHEME_CALLBACK (Paper_column, before_line_breaking, 1);
277 Paper_column::before_line_breaking (SCM grob)
279 Grob *me = unsmob_grob (grob);
281 SCM bbm = me->get_object ("bounded-by-me");
282 Grob_array *ga = unsmob_grob_array (bbm);
284 return SCM_UNSPECIFIED;
286 vector<Grob*> &array (ga->array_reference ());
288 for (vsize i = array.size (); i--;)
292 if (!g || !g->is_live ())
293 /* UGH . potentially quadratic. */
294 array.erase (array.begin () + i);
297 return SCM_UNSPECIFIED;
301 ADD_INTERFACE (Paper_column,
302 "@code{Paper_column} objects form the top-most X-parents for items."
303 " The are two types of columns: musical columns, where are attached to, and "
304 " non-musical columns, where bar-lines, clefs etc. are attached to. "
305 " The spacing engine determines the X-positions of these objects."
309 " numbered, the first (leftmost) is column 0. Numbering happens before\n"
310 " line-breaking, and columns are not renumbered after line breaking.\n"
311 " Since many columns go unused, you should only use the rank field to\n"
312 " get ordering information. Two adjacent columns may have\n"
313 " non-adjacent numbers.\n",
321 "line-break-system-details "
322 "line-break-penalty "
323 "line-break-permission "
324 "page-break-penalty "
325 "page-break-permission "
327 "page-turn-permission "
329 "shortest-playing-duration "
330 "shortest-starter-duration "