Issue 1037: Links to old manuals
[lilypond/mpolesky.git] / lily / paper-column.cc
blob24d76a163abbacbafa63eabc06948b0a08da79b2
1 /*
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"
26 #include "lookup.hh"
27 #include "lookup.hh"
28 #include "moment.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"
36 #include "spring.hh"
37 #include "string-convert.hh"
38 #include "system.hh"
39 #include "text-interface.hh"
40 #include "warn.hh"
42 Grob *
43 Paper_column::clone () const
45 return new Paper_column (*this);
48 void
49 Paper_column::do_break_processing ()
51 Item::do_break_processing ();
54 int
55 Paper_column::get_rank (Grob const *me)
57 return dynamic_cast<Paper_column const *> (me)->rank_;
60 void
61 Paper_column::set_rank (int rank)
63 rank_ = rank;
66 System *
67 Paper_column::get_system () const
69 return system_;
72 void
73 Paper_column::set_system (System *s)
75 system_ = s;
78 Paper_column *
79 Paper_column::get_column () const
81 return (Paper_column *) (this);
84 Paper_column::Paper_column (SCM l)
85 : Item (l)
87 system_ = 0;
88 rank_ = -1;
91 Paper_column::Paper_column (Paper_column const &src)
92 : Item (src)
94 system_ = 0;
95 rank_ = src.rank_;
98 int
99 Paper_column::compare (Grob * const &a,
100 Grob * const &b)
102 return sign (dynamic_cast<Paper_column*> (a)->rank_
103 - dynamic_cast<Paper_column*> (b)->rank_);
106 bool
107 Paper_column::less_than (Grob *const &a,
108 Grob *const &b)
110 Paper_column *pa = dynamic_cast<Paper_column*> (a);
111 Paper_column *pb = dynamic_cast<Paper_column*> (b);
113 return pa->rank_ < pb->rank_;
116 Moment
117 Paper_column::when_mom (Grob *me)
119 SCM m = me->get_property ("when");
120 if (Moment *when = unsmob_moment (m))
121 return *when;
122 return Moment (0);
125 bool
126 Paper_column::is_musical (Grob *me)
128 SCM m = me->get_property ("shortest-starter-duration");
129 Moment s (0);
130 if (unsmob_moment (m))
131 s = *unsmob_moment (m);
132 return s != Moment (0);
135 bool
136 Paper_column::is_used (Grob *me)
138 extract_grob_set (me, "elements", elts);
139 if (elts.size ())
140 return true;
142 extract_grob_set (me, "bounded-by-me", bbm);
143 if (bbm.size ())
144 return true;
146 if (Paper_column::is_breakable (me))
147 return true;
149 if (to_boolean (me->get_property ("used")))
150 return true;
151 return false;
154 bool
155 Paper_column::is_breakable (Grob *me)
157 return scm_is_symbol (me->get_property ("line-break-permission"));
160 Real
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));
166 Direction d = LEFT;
169 Skyline_pair *sp = Skyline_pair::unsmob (cols[d]->get_property ("horizontal-skylines"));
170 if (sp)
171 skys[d] = (*sp)[-d];
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]));
180 Interval
181 Paper_column::break_align_width (Grob *me)
183 Grob *p = me->get_parent (X_AXIS);
185 if (is_musical (me))
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);
193 if (!align)
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 (),
217 properties,
218 ly_string2scm (r));
219 SCM when_mol = Text_interface::interpret_markup (me->layout ()->self_scm (),
220 properties,
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),
228 Interval (-2, -1)));
230 SCM small_letters = scm_cons (scm_acons (ly_symbol2scm ("font-size"),
231 scm_from_int (-6), SCM_EOL),
232 properties);
234 int j = 0;
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 ())
241 continue;
243 j++;
244 Real y = -j * 1 -3;
245 vector<Offset> pts;
246 pts.push_back (Offset (0, y));
248 Offset p2 (sp->distance (), y);
249 pts.push_back (p2);
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 (),
255 small_letters,
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 ())
270 continue;
272 j++;
274 Real y = -j * 1.0 -3.5;
275 vector<Offset> pts;
276 pts.push_back (Offset (0, y));
278 Offset p2 (dist, y);
279 pts.push_back (p2);
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 (),
287 small_letters,
288 ly_string2scm (String_convert::form_string ("%5.2lf",
289 dist)));
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);
297 t.add_stencil (l);
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
305 bounded-by-me
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);
317 if (!ga)
318 return SCM_UNSPECIFIED;
320 vector<Grob*> &array (ga->array_reference ());
322 for (vsize i = array.size (); i--;)
324 Grob *g = array[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.
339 bool
340 Paper_column::is_extraneous_column_from_ligature (Grob *me)
342 if (!is_musical (me))
343 return false;
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]))
353 has_notehead = true;
354 if (dynamic_cast<Item*> (elts[i])->get_column () == me)
355 return false;
358 return has_notehead;
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"
368 "\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"
374 " numbers.",
376 /* properties */
377 "between-cols "
378 "bounded-by-me "
379 "full-measure-extra-space "
380 "grace-spacing "
381 "labels "
382 "line-break-system-details "
383 "line-break-penalty "
384 "line-break-permission "
385 "maybe-loose "
386 "page-break-penalty "
387 "page-break-permission "
388 "page-turn-penalty "
389 "page-turn-permission "
390 "rhythmic-location "
391 "shortest-playing-duration "
392 "shortest-starter-duration "
393 "spacing "
394 "used "
395 "when "