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 "axis-group-interface.hh"
12 #include "break-align-interface.hh"
13 #include "font-interface.hh"
14 #include "grob-array.hh"
18 #include "output-def.hh"
19 #include "paper-score.hh"
20 #include "pointer-group-interface.hh"
21 #include "separation-item.hh"
22 #include "skyline-pair.hh"
23 #include "spaceable-grob.hh"
25 #include "string-convert.hh"
27 #include "text-interface.hh"
31 Paper_column::clone () const
33 return new Paper_column (*this);
37 Paper_column::do_break_processing ()
39 Item::do_break_processing ();
43 Paper_column::get_rank (Grob
const *me
)
45 return dynamic_cast<Paper_column
const *> (me
)->rank_
;
49 Paper_column::get_system () const
55 Paper_column::set_system (System
*s
)
61 Paper_column::get_column () const
63 return (Paper_column
*) (this);
66 Paper_column::Paper_column (SCM l
)
73 Paper_column::Paper_column (Paper_column
const &src
)
81 Paper_column::compare (Grob
* const &a
,
84 return sign (dynamic_cast<Paper_column
*> (a
)->rank_
85 - dynamic_cast<Paper_column
*> (b
)->rank_
);
89 Paper_column::less_than (Grob
*const &a
,
92 Paper_column
*pa
= dynamic_cast<Paper_column
*> (a
);
93 Paper_column
*pb
= dynamic_cast<Paper_column
*> (b
);
95 return pa
->rank_
< pb
->rank_
;
99 Paper_column::when_mom (Grob
*me
)
101 SCM m
= me
->get_property ("when");
102 if (Moment
*when
= unsmob_moment (m
))
108 Paper_column::is_musical (Grob
*me
)
110 SCM m
= me
->get_property ("shortest-starter-duration");
112 if (unsmob_moment (m
))
113 s
= *unsmob_moment (m
);
114 return s
!= Moment (0);
118 Paper_column::is_used (Grob
*me
)
120 extract_grob_set (me
, "elements", elts
);
124 extract_grob_set (me
, "bounded-by-me", bbm
);
128 if (Paper_column::is_breakable (me
))
131 if (to_boolean (me
->get_property ("used")))
137 Paper_column::is_breakable (Grob
*me
)
139 return scm_is_symbol (me
->get_property ("line-break-permission"));
143 Paper_column::minimum_distance (Grob
*left
, Grob
*right
)
145 Drul_array
<Grob
*> cols (left
, right
);
146 Drul_array
<Skyline
> skys
= Drul_array
<Skyline
> (Skyline (RIGHT
), Skyline (LEFT
));
151 Skyline_pair
*sp
= Skyline_pair::unsmob (cols
[d
]->get_property ("horizontal-skylines"));
155 while (flip (&d
) != LEFT
);
157 skys
[RIGHT
].merge (Separation_item::conditional_skyline (right
, left
));
159 return max (0.0, skys
[LEFT
].distance (skys
[RIGHT
]));
163 Paper_column::break_align_width (Grob
*me
)
165 Grob
*p
= me
->get_parent (X_AXIS
);
169 me
->programming_error ("tried to get break-align-width of a non-musical column");
170 return Interval (0, 0) + me
->relative_coordinate (p
, X_AXIS
);
173 Grob
*align
= Pointer_group_interface::find_grob (me
, ly_symbol2scm ("elements"),
174 Break_alignment_interface::has_interface
);
176 return Interval (0, 0) + me
->relative_coordinate (p
, X_AXIS
);
178 return align
->extent (p
, X_AXIS
);
182 Print a vertical line and the rank number, to aid debugging.
184 MAKE_SCHEME_CALLBACK (Paper_column
, print
, 1);
186 Paper_column::print (SCM p
)
188 Paper_column
*me
= dynamic_cast<Paper_column
*> (unsmob_grob (p
));
190 string r
= to_string (Paper_column::get_rank (me
));
192 Moment
*mom
= unsmob_moment (me
->get_property ("when"));
193 string when
= mom
? mom
->to_string () : "?/?";
195 Font_metric
*musfont
= Font_interface::get_default_font (me
);
196 SCM properties
= Font_interface::text_font_alist_chain (me
);
198 SCM scm_mol
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
201 SCM when_mol
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
203 ly_string2scm (when
));
204 Stencil t
= *unsmob_stencil (scm_mol
);
205 t
.add_at_edge (Y_AXIS
, DOWN
, *unsmob_stencil (when_mol
), 0.1);
206 t
.align_to (X_AXIS
, CENTER
);
207 t
.align_to (Y_AXIS
, DOWN
);
209 Stencil l
= Lookup::filled_box (Box (Interval (-0.01, 0.01),
212 SCM small_letters
= scm_cons (scm_acons (ly_symbol2scm ("font-size"),
213 scm_from_int (-6), SCM_EOL
),
217 for (SCM s
= me
->get_object ("ideal-distances");
218 scm_is_pair (s
); s
= scm_cdr (s
))
220 Spring
*sp
= unsmob_spring (scm_caar (s
));
221 if (!unsmob_grob (scm_cdar (s
))
222 || !unsmob_grob (scm_cdar (s
))->get_system ())
228 pts
.push_back (Offset (0, y
));
230 Offset
p2 (sp
->distance (), y
);
233 Stencil id_stencil
= Lookup::points_to_line_stencil (0.1, pts
);
234 Stencil
head (musfont
->find_by_name ("arrowheads.open.01"));
236 SCM distance_stc
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
238 ly_string2scm (String_convert::form_string ("%5.2lf", sp
->distance ())));
240 id_stencil
.add_stencil (unsmob_stencil (distance_stc
)->translated (Offset (sp
->distance ()/3, y
+1)));
241 id_stencil
.add_stencil (head
.translated (p2
));
242 id_stencil
= id_stencil
.in_color (0,0,1);
243 l
.add_stencil (id_stencil
);
246 for (SCM s
= me
->get_object ("minimum-distances");
247 scm_is_pair (s
); s
= scm_cdr (s
))
249 Real dist
= scm_to_double (scm_cdar (s
));
250 Grob
*other
= unsmob_grob (scm_caar (s
));
251 if (!other
|| other
->get_system () != me
->get_system ())
256 Real y
= -j
* 1.0 -3.5;
258 pts
.push_back (Offset (0, y
));
263 Stencil id_stencil
= Lookup::points_to_line_stencil (0.1, pts
);
264 Stencil
head (musfont
->find_by_name ("arrowheads.open.0M1"));
265 head
.translate_axis (y
, Y_AXIS
);
266 id_stencil
.add_stencil (head
);
268 SCM distance_stc
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
270 ly_string2scm (String_convert::form_string ("%5.2lf",
273 id_stencil
.add_stencil (unsmob_stencil (distance_stc
)->translated (Offset (dist
/3, y
-1)));
276 id_stencil
= id_stencil
.in_color (1,0,0);
277 l
.add_stencil (id_stencil
);
280 return t
.smobbed_copy ();
284 This is all too hairy. We use bounded-by-me to make sure that some
285 columns are kept "alive". Unfortunately, when spanners are suicided,
286 this falls apart again, because suicided spanners are still in
289 THIS IS BROKEN KLUDGE. WE SHOULD INVENT SOMETHING BETTER.
291 MAKE_SCHEME_CALLBACK (Paper_column
, before_line_breaking
, 1);
293 Paper_column::before_line_breaking (SCM grob
)
295 Grob
*me
= unsmob_grob (grob
);
297 SCM bbm
= me
->get_object ("bounded-by-me");
298 Grob_array
*ga
= unsmob_grob_array (bbm
);
300 return SCM_UNSPECIFIED
;
302 vector
<Grob
*> &array (ga
->array_reference ());
304 for (vsize i
= array
.size (); i
--;)
308 if (!g
|| !g
->is_live ())
309 /* UGH . potentially quadratic. */
310 array
.erase (array
.begin () + i
);
313 return SCM_UNSPECIFIED
;
317 ADD_INTERFACE (Paper_column
,
318 "@code{Paper_column} objects form the top-most X@tie{}parents"
319 " for items. There are two types of columns: musical columns,"
320 " where are attached to, and non-musical columns, where"
321 " bar-lines, clefs, etc., are attached to. The spacing engine"
322 " determines the X@tie{}positions of these objects.\n"
324 "They are numbered, the first (leftmost) is column@tie{}0."
325 " Numbering happens before line breaking, and columns are not"
326 " renumbered after line breaking. Since many columns go"
327 " unused, you should only use the rank field to get ordering"
328 " information. Two adjacent columns may have non-adjacent"
336 "line-break-system-details "
337 "line-break-penalty "
338 "line-break-permission "
339 "page-break-penalty "
340 "page-break-permission "
342 "page-turn-permission "
344 "shortest-playing-duration "
345 "shortest-starter-duration "