2 paper-column.cc -- implement Paper_column
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2009 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 "rhythmic-head.hh"
22 #include "separation-item.hh"
23 #include "skyline-pair.hh"
24 #include "spaceable-grob.hh"
26 #include "string-convert.hh"
28 #include "text-interface.hh"
32 Paper_column::clone () const
34 return new Paper_column (*this);
38 Paper_column::do_break_processing ()
40 Item::do_break_processing ();
44 Paper_column::get_rank (Grob
const *me
)
46 return dynamic_cast<Paper_column
const *> (me
)->rank_
;
50 Paper_column::get_system () const
56 Paper_column::set_system (System
*s
)
62 Paper_column::get_column () const
64 return (Paper_column
*) (this);
67 Paper_column::Paper_column (SCM l
)
74 Paper_column::Paper_column (Paper_column
const &src
)
82 Paper_column::compare (Grob
* const &a
,
85 return sign (dynamic_cast<Paper_column
*> (a
)->rank_
86 - dynamic_cast<Paper_column
*> (b
)->rank_
);
90 Paper_column::less_than (Grob
*const &a
,
93 Paper_column
*pa
= dynamic_cast<Paper_column
*> (a
);
94 Paper_column
*pb
= dynamic_cast<Paper_column
*> (b
);
96 return pa
->rank_
< pb
->rank_
;
100 Paper_column::when_mom (Grob
*me
)
102 SCM m
= me
->get_property ("when");
103 if (Moment
*when
= unsmob_moment (m
))
109 Paper_column::is_musical (Grob
*me
)
111 SCM m
= me
->get_property ("shortest-starter-duration");
113 if (unsmob_moment (m
))
114 s
= *unsmob_moment (m
);
115 return s
!= Moment (0);
119 Paper_column::is_used (Grob
*me
)
121 extract_grob_set (me
, "elements", elts
);
125 extract_grob_set (me
, "bounded-by-me", bbm
);
129 if (Paper_column::is_breakable (me
))
132 if (to_boolean (me
->get_property ("used")))
138 Paper_column::is_breakable (Grob
*me
)
140 return scm_is_symbol (me
->get_property ("line-break-permission"));
144 Paper_column::minimum_distance (Grob
*left
, Grob
*right
)
146 Drul_array
<Grob
*> cols (left
, right
);
147 Drul_array
<Skyline
> skys
= Drul_array
<Skyline
> (Skyline (RIGHT
), Skyline (LEFT
));
152 Skyline_pair
*sp
= Skyline_pair::unsmob (cols
[d
]->get_property ("horizontal-skylines"));
156 while (flip (&d
) != LEFT
);
158 skys
[RIGHT
].merge (Separation_item::conditional_skyline (right
, left
));
160 return max (0.0, skys
[LEFT
].distance (skys
[RIGHT
]));
164 Paper_column::break_align_width (Grob
*me
)
166 Grob
*p
= me
->get_parent (X_AXIS
);
170 me
->programming_error ("tried to get break-align-width of a non-musical column");
171 return Interval (0, 0) + me
->relative_coordinate (p
, X_AXIS
);
174 Grob
*align
= Pointer_group_interface::find_grob (me
, ly_symbol2scm ("elements"),
175 Break_alignment_interface::has_interface
);
177 return Interval (0, 0) + me
->relative_coordinate (p
, X_AXIS
);
179 return align
->extent (p
, X_AXIS
);
183 Print a vertical line and the rank number, to aid debugging.
185 MAKE_SCHEME_CALLBACK (Paper_column
, print
, 1);
187 Paper_column::print (SCM p
)
189 Paper_column
*me
= dynamic_cast<Paper_column
*> (unsmob_grob (p
));
191 string r
= to_string (Paper_column::get_rank (me
));
193 Moment
*mom
= unsmob_moment (me
->get_property ("when"));
194 string when
= mom
? mom
->to_string () : "?/?";
196 Font_metric
*musfont
= Font_interface::get_default_font (me
);
197 SCM properties
= Font_interface::text_font_alist_chain (me
);
199 SCM scm_mol
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
202 SCM when_mol
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
204 ly_string2scm (when
));
205 Stencil t
= *unsmob_stencil (scm_mol
);
206 t
.add_at_edge (Y_AXIS
, DOWN
, *unsmob_stencil (when_mol
), 0.1);
207 t
.align_to (X_AXIS
, CENTER
);
208 t
.align_to (Y_AXIS
, DOWN
);
210 Stencil l
= Lookup::filled_box (Box (Interval (-0.01, 0.01),
213 SCM small_letters
= scm_cons (scm_acons (ly_symbol2scm ("font-size"),
214 scm_from_int (-6), SCM_EOL
),
218 for (SCM s
= me
->get_object ("ideal-distances");
219 scm_is_pair (s
); s
= scm_cdr (s
))
221 Spring
*sp
= unsmob_spring (scm_caar (s
));
222 if (!unsmob_grob (scm_cdar (s
))
223 || !unsmob_grob (scm_cdar (s
))->get_system ())
229 pts
.push_back (Offset (0, y
));
231 Offset
p2 (sp
->distance (), y
);
234 Stencil id_stencil
= Lookup::points_to_line_stencil (0.1, pts
);
235 Stencil
head (musfont
->find_by_name ("arrowheads.open.01"));
237 SCM distance_stc
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
239 ly_string2scm (String_convert::form_string ("%5.2lf", sp
->distance ())));
241 id_stencil
.add_stencil (unsmob_stencil (distance_stc
)->translated (Offset (sp
->distance ()/3, y
+1)));
242 id_stencil
.add_stencil (head
.translated (p2
));
243 id_stencil
= id_stencil
.in_color (0,0,1);
244 l
.add_stencil (id_stencil
);
247 for (SCM s
= me
->get_object ("minimum-distances");
248 scm_is_pair (s
); s
= scm_cdr (s
))
250 Real dist
= scm_to_double (scm_cdar (s
));
251 Grob
*other
= unsmob_grob (scm_caar (s
));
252 if (!other
|| other
->get_system () != me
->get_system ())
257 Real y
= -j
* 1.0 -3.5;
259 pts
.push_back (Offset (0, y
));
264 Stencil id_stencil
= Lookup::points_to_line_stencil (0.1, pts
);
265 Stencil
head (musfont
->find_by_name ("arrowheads.open.0M1"));
266 head
.translate_axis (y
, Y_AXIS
);
267 id_stencil
.add_stencil (head
);
269 SCM distance_stc
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
271 ly_string2scm (String_convert::form_string ("%5.2lf",
274 id_stencil
.add_stencil (unsmob_stencil (distance_stc
)->translated (Offset (dist
/3, y
-1)));
277 id_stencil
= id_stencil
.in_color (1,0,0);
278 l
.add_stencil (id_stencil
);
281 return t
.smobbed_copy ();
285 This is all too hairy. We use bounded-by-me to make sure that some
286 columns are kept "alive". Unfortunately, when spanners are suicided,
287 this falls apart again, because suicided spanners are still in
290 THIS IS BROKEN KLUDGE. WE SHOULD INVENT SOMETHING BETTER.
292 MAKE_SCHEME_CALLBACK (Paper_column
, before_line_breaking
, 1);
294 Paper_column::before_line_breaking (SCM grob
)
296 Grob
*me
= unsmob_grob (grob
);
298 SCM bbm
= me
->get_object ("bounded-by-me");
299 Grob_array
*ga
= unsmob_grob_array (bbm
);
301 return SCM_UNSPECIFIED
;
303 vector
<Grob
*> &array (ga
->array_reference ());
305 for (vsize i
= array
.size (); i
--;)
309 if (!g
|| !g
->is_live ())
310 /* UGH . potentially quadratic. */
311 array
.erase (array
.begin () + i
);
314 return SCM_UNSPECIFIED
;
317 /* FIXME: This is a hack that we use to identify columns that used to
318 contain note-heads but whose note-heads were moved by one of the ligature
319 engravers. Once the ligature engravers are fixed to behave nicely, this
320 function can be removed.
323 Paper_column::is_extraneous_column_from_ligature (Grob
*me
)
325 if (!is_musical (me
))
328 // If all the note-heads that I think are my children actually belong
329 // to another column, then I am extraneous.
330 extract_grob_set (me
, "elements", elts
);
331 bool has_notehead
= false;
332 for (vsize i
= 0; i
< elts
.size (); i
++)
334 if (Rhythmic_head::has_interface (elts
[i
]))
337 if (dynamic_cast<Item
*> (elts
[i
])->get_column () == me
)
345 ADD_INTERFACE (Paper_column
,
346 "@code{Paper_column} objects form the top-most X@tie{}parents"
347 " for items. There are two types of columns: musical columns,"
348 " where are attached to, and non-musical columns, where"
349 " bar-lines, clefs, etc., are attached to. The spacing engine"
350 " determines the X@tie{}positions of these objects.\n"
352 "They are numbered, the first (leftmost) is column@tie{}0."
353 " Numbering happens before line breaking, and columns are not"
354 " renumbered after line breaking. Since many columns go"
355 " unused, you should only use the rank field to get ordering"
356 " information. Two adjacent columns may have non-adjacent"
362 "full-measure-extra-space "
365 "line-break-system-details "
366 "line-break-penalty "
367 "line-break-permission "
368 "page-break-penalty "
369 "page-break-permission "
371 "page-turn-permission "
373 "shortest-playing-duration "
374 "shortest-starter-duration "