2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2010 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "paper-column.hh"
22 #include "axis-group-interface.hh"
23 #include "break-align-interface.hh"
24 #include "font-interface.hh"
25 #include "grob-array.hh"
29 #include "output-def.hh"
30 #include "paper-score.hh"
31 #include "pointer-group-interface.hh"
32 #include "rhythmic-head.hh"
33 #include "separation-item.hh"
34 #include "skyline-pair.hh"
35 #include "spaceable-grob.hh"
37 #include "string-convert.hh"
39 #include "text-interface.hh"
43 Paper_column::clone () const
45 return new Paper_column (*this);
49 Paper_column::do_break_processing ()
51 Item::do_break_processing ();
55 Paper_column::get_rank (Grob
const *me
)
57 return dynamic_cast<Paper_column
const *> (me
)->rank_
;
61 Paper_column::set_rank (int rank
)
67 Paper_column::get_system () const
73 Paper_column::set_system (System
*s
)
79 Paper_column::get_column () const
81 return (Paper_column
*) (this);
84 Paper_column::Paper_column (SCM l
)
91 Paper_column::Paper_column (Paper_column
const &src
)
99 Paper_column::compare (Grob
* const &a
,
102 return sign (dynamic_cast<Paper_column
*> (a
)->rank_
103 - dynamic_cast<Paper_column
*> (b
)->rank_
);
107 Paper_column::less_than (Grob
*const &a
,
110 Paper_column
*pa
= dynamic_cast<Paper_column
*> (a
);
111 Paper_column
*pb
= dynamic_cast<Paper_column
*> (b
);
113 return pa
->rank_
< pb
->rank_
;
117 Paper_column::when_mom (Grob
*me
)
119 SCM m
= me
->get_property ("when");
120 if (Moment
*when
= unsmob_moment (m
))
126 Paper_column::is_musical (Grob
*me
)
128 SCM m
= me
->get_property ("shortest-starter-duration");
130 if (unsmob_moment (m
))
131 s
= *unsmob_moment (m
);
132 return s
!= Moment (0);
136 Paper_column::is_used (Grob
*me
)
138 extract_grob_set (me
, "elements", elts
);
142 extract_grob_set (me
, "bounded-by-me", bbm
);
146 if (Paper_column::is_breakable (me
))
149 if (to_boolean (me
->get_property ("used")))
155 Paper_column::is_breakable (Grob
*me
)
157 return scm_is_symbol (me
->get_property ("line-break-permission"));
161 Paper_column::minimum_distance (Grob
*left
, Grob
*right
)
163 Drul_array
<Grob
*> cols (left
, right
);
164 Drul_array
<Skyline
> skys
= Drul_array
<Skyline
> (Skyline (RIGHT
), Skyline (LEFT
));
169 Skyline_pair
*sp
= Skyline_pair::unsmob (cols
[d
]->get_property ("horizontal-skylines"));
173 while (flip (&d
) != LEFT
);
175 skys
[RIGHT
].merge (Separation_item::conditional_skyline (right
, left
));
177 return max (0.0, skys
[LEFT
].distance (skys
[RIGHT
]));
181 Paper_column::break_align_width (Grob
*me
)
183 Grob
*p
= me
->get_parent (X_AXIS
);
187 me
->programming_error ("tried to get break-align-width of a non-musical column");
188 return Interval (0, 0) + me
->relative_coordinate (p
, X_AXIS
);
191 Grob
*align
= Pointer_group_interface::find_grob (me
, ly_symbol2scm ("elements"),
192 Break_alignment_interface::has_interface
);
194 return Interval (0, 0) + me
->relative_coordinate (p
, X_AXIS
);
196 return align
->extent (p
, X_AXIS
);
200 Print a vertical line and the rank number, to aid debugging.
202 MAKE_SCHEME_CALLBACK (Paper_column
, print
, 1);
204 Paper_column::print (SCM p
)
206 Paper_column
*me
= dynamic_cast<Paper_column
*> (unsmob_grob (p
));
208 string r
= to_string (Paper_column::get_rank (me
));
210 Moment
*mom
= unsmob_moment (me
->get_property ("when"));
211 string when
= mom
? mom
->to_string () : "?/?";
213 Font_metric
*musfont
= Font_interface::get_default_font (me
);
214 SCM properties
= Font_interface::text_font_alist_chain (me
);
216 SCM scm_mol
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
219 SCM when_mol
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
221 ly_string2scm (when
));
222 Stencil t
= *unsmob_stencil (scm_mol
);
223 t
.add_at_edge (Y_AXIS
, DOWN
, *unsmob_stencil (when_mol
), 0.1);
224 t
.align_to (X_AXIS
, CENTER
);
225 t
.align_to (Y_AXIS
, DOWN
);
227 Stencil l
= Lookup::filled_box (Box (Interval (-0.01, 0.01),
230 SCM small_letters
= scm_cons (scm_acons (ly_symbol2scm ("font-size"),
231 scm_from_int (-6), SCM_EOL
),
235 for (SCM s
= me
->get_object ("ideal-distances");
236 scm_is_pair (s
); s
= scm_cdr (s
))
238 Spring
*sp
= unsmob_spring (scm_caar (s
));
239 if (!unsmob_grob (scm_cdar (s
))
240 || !unsmob_grob (scm_cdar (s
))->get_system ())
246 pts
.push_back (Offset (0, y
));
248 Offset
p2 (sp
->distance (), y
);
251 Stencil id_stencil
= Lookup::points_to_line_stencil (0.1, pts
);
252 Stencil
head (musfont
->find_by_name ("arrowheads.open.01"));
254 SCM distance_stc
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
256 ly_string2scm (String_convert::form_string ("%5.2lf", sp
->distance ())));
258 id_stencil
.add_stencil (unsmob_stencil (distance_stc
)->translated (Offset (sp
->distance ()/3, y
+1)));
259 id_stencil
.add_stencil (head
.translated (p2
));
260 id_stencil
= id_stencil
.in_color (0,0,1);
261 l
.add_stencil (id_stencil
);
264 for (SCM s
= me
->get_object ("minimum-distances");
265 scm_is_pair (s
); s
= scm_cdr (s
))
267 Real dist
= scm_to_double (scm_cdar (s
));
268 Grob
*other
= unsmob_grob (scm_caar (s
));
269 if (!other
|| other
->get_system () != me
->get_system ())
274 Real y
= -j
* 1.0 -3.5;
276 pts
.push_back (Offset (0, y
));
281 Stencil id_stencil
= Lookup::points_to_line_stencil (0.1, pts
);
282 Stencil
head (musfont
->find_by_name ("arrowheads.open.0M1"));
283 head
.translate_axis (y
, Y_AXIS
);
284 id_stencil
.add_stencil (head
);
286 SCM distance_stc
= Text_interface::interpret_markup (me
->layout ()->self_scm (),
288 ly_string2scm (String_convert::form_string ("%5.2lf",
291 id_stencil
.add_stencil (unsmob_stencil (distance_stc
)->translated (Offset (dist
/3, y
-1)));
294 id_stencil
= id_stencil
.in_color (1,0,0);
295 l
.add_stencil (id_stencil
);
298 return t
.smobbed_copy ();
302 This is all too hairy. We use bounded-by-me to make sure that some
303 columns are kept "alive". Unfortunately, when spanners are suicided,
304 this falls apart again, because suicided spanners are still in
307 THIS IS BROKEN KLUDGE. WE SHOULD INVENT SOMETHING BETTER.
309 MAKE_SCHEME_CALLBACK (Paper_column
, before_line_breaking
, 1);
311 Paper_column::before_line_breaking (SCM grob
)
313 Grob
*me
= unsmob_grob (grob
);
315 SCM bbm
= me
->get_object ("bounded-by-me");
316 Grob_array
*ga
= unsmob_grob_array (bbm
);
318 return SCM_UNSPECIFIED
;
320 vector
<Grob
*> &array (ga
->array_reference ());
322 for (vsize i
= array
.size (); i
--;)
326 if (!g
|| !g
->is_live ())
327 /* UGH . potentially quadratic. */
328 array
.erase (array
.begin () + i
);
331 return SCM_UNSPECIFIED
;
334 /* FIXME: This is a hack that we use to identify columns that used to
335 contain note-heads but whose note-heads were moved by one of the ligature
336 engravers. Once the ligature engravers are fixed to behave nicely, this
337 function can be removed.
340 Paper_column::is_extraneous_column_from_ligature (Grob
*me
)
342 if (!is_musical (me
))
345 // If all the note-heads that I think are my children actually belong
346 // to another column, then I am extraneous.
347 extract_grob_set (me
, "elements", elts
);
348 bool has_notehead
= false;
349 for (vsize i
= 0; i
< elts
.size (); i
++)
351 if (Rhythmic_head::has_interface (elts
[i
]))
354 if (dynamic_cast<Item
*> (elts
[i
])->get_column () == me
)
362 ADD_INTERFACE (Paper_column
,
363 "@code{Paper_column} objects form the top-most X@tie{}parents"
364 " for items. There are two types of columns: musical and"
365 " non-musical, to which musical and non-musical objects are"
366 " attached respectively. The spacing engine determines the"
367 " X@tie{}positions of these objects.\n"
369 "They are numbered, the first (leftmost) is column@tie{}0."
370 " Numbering happens before line breaking, and columns are not"
371 " renumbered after line breaking. Since many columns go"
372 " unused, you should only use the rank field to get ordering"
373 " information. Two adjacent columns may have non-adjacent"
379 "full-measure-extra-space "
382 "line-break-system-details "
383 "line-break-penalty "
384 "line-break-permission "
386 "page-break-penalty "
387 "page-break-permission "
389 "page-turn-permission "
391 "shortest-playing-duration "
392 "shortest-starter-duration "