2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1998--2015 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 "separation-item.hh"
22 #include "accidental-placement.hh"
23 #include "axis-group-interface.hh"
25 #include "note-column.hh"
26 #include "note-head.hh"
27 #include "paper-column.hh"
28 #include "pointer-group-interface.hh"
29 #include "skyline-pair.hh"
34 Separation_item::add_item (Grob *s, Item *i)
37 Pointer_group_interface::add_grob (s, ly_symbol2scm ("elements"), i);
41 Separation_item::add_conditional_item (Grob *me, Grob *e)
43 Pointer_group_interface::add_grob (me, ly_symbol2scm ("conditional-elements"), e);
47 Separation_item::set_distance (Item *l, Item *r, Real padding)
49 Drul_array<Skyline_pair *> lines (Skyline_pair::unsmob (l->get_property ("horizontal-skylines")),
50 Skyline_pair::unsmob (r->get_property ("horizontal-skylines")));
51 Skyline right = conditional_skyline (r, l);
52 right.merge ((*lines[RIGHT])[LEFT]);
54 Real dist = padding + (*lines[LEFT])[RIGHT].distance (right);
59 rod.item_drul_ = Drul_array<Item *> (l, r);
65 return max (dist, 0.0);
69 Separation_item::is_empty (Grob *me)
71 Skyline_pair *sky = Skyline_pair::unsmob (me->get_property ("horizontal-skylines"));
72 return (!sky || sky->is_empty ());
76 Return the width of ME given that we are considering the object on
80 Separation_item::conditional_skyline (Grob *me, Grob *left)
82 vector<Box> bs = boxes (me, left);
83 return Skyline (bs, Y_AXIS, LEFT);
86 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines, 1);
88 Separation_item::calc_skylines (SCM smob)
90 Item *me = Item::unsmob (smob);
91 vector<Box> bs = boxes (me, 0);
92 Skyline_pair sp (bs, Y_AXIS);
94 TODO: We need to decide if padding is 'intrinsic'
95 to a skyline or if it is something that is only added on in
96 distance calculations. Here, we make it intrinsic, which copies
97 the behavior from the old code but no longer corresponds to how
98 vertical skylines are handled (where padding is not built into
101 Real vp = robust_scm2double (me->get_property ("skyline-vertical-padding"), 0.0);
102 sp[LEFT] = sp[LEFT].padded (vp);
103 sp[RIGHT] = sp[RIGHT].padded (vp);
104 return sp.smobbed_copy ();
108 If left is non-NULL, get the boxes corresponding to the
109 conditional-elements (conditioned on the grob LEFT).
110 Conditional elements are, for now, arpeggios and accidental
111 placements. Based on the left grob, the accidentals will
112 be printed or not, so we filter using
113 Accidental_placement::get_relevant_accidentals.
116 Separation_item::boxes (Grob *me, Grob *left)
118 Item *item = dynamic_cast<Item *> (me);
120 int very_large = INT_MAX;
121 Paper_column *pc = item->get_column ();
123 extract_grob_set (me, left ? "conditional-elements" : "elements", read_only_elts);
128 vector<Grob *> accidental_elts;
129 vector<Grob *> other_elts; // for now only arpeggios
130 for (vsize i = 0; i < read_only_elts.size (); i++)
132 if (Accidental_placement::has_interface (read_only_elts[i]))
133 accidental_elts.push_back (read_only_elts[i]);
135 other_elts.push_back (read_only_elts[i]);
137 elts = Accidental_placement::get_relevant_accidentals (accidental_elts, left);
138 elts.insert (elts.end (), other_elts.begin (), other_elts.end ());
141 elts = read_only_elts;
143 Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
145 for (vsize i = 0; i < elts.size (); i++)
147 Item *il = dynamic_cast<Item *> (elts[i]);
148 if (pc != il->get_column ())
151 /* ugh. We want to exclude groups of grobs (so that we insert each grob
152 individually into the skyline instead of adding a single box that
153 bounds all of them). However, we can't exclude an axis-group that
154 adds to its childrens' stencil. Currently, this is just TrillPitchGroup;
155 hence the check for note-head-interface. */
156 if (Axis_group_interface::has_interface (il)
157 && !Note_head::has_interface (il))
160 Interval y (il->pure_height (ycommon, 0, very_large));
161 Interval x (il->extent (pc, X_AXIS));
163 Interval extra_width = robust_scm2interval (elts[i]->get_property ("extra-spacing-width"),
164 Interval (-0.1, 0.1));
165 Interval extra_height = robust_scm2interval (elts[i]->get_property ("extra-spacing-height"),
166 Interval (0.0, 0.0));
168 // The conventional empty extent is (+inf.0 . -inf.0)
169 // but (-inf.0 . +inf.0) is used as extra-spacing-height
170 // on items that must not overlap other note-columns.
171 // If these two uses of inf combine, leave the empty extent.
173 if (!isinf (x[LEFT]))
174 x[LEFT] += extra_width[LEFT];
175 if (!isinf (x[RIGHT]))
176 x[RIGHT] += extra_width[RIGHT];
177 if (!isinf (y[DOWN]))
178 y[DOWN] += extra_height[DOWN];
180 y[UP] += extra_height[UP];
182 if (!x.is_empty () && !y.is_empty ())
183 out.push_back (Box (x, y));
189 MAKE_DOCUMENTED_SCHEME_CALLBACK (Separation_item, print, 1,
190 "Optional stencil for @code{PaperColumn} or"
191 "@code{NonMusicalPaperColumn}.\n"
192 "Draws the @code{horizontal-skylines} of each"
193 " @code{PaperColumn}, showing the shapes used"
194 " to determine the minimum distances between"
195 " @code{PaperColumns} at the note-spacing step,"
196 " before staves have been spaced (vertically)"
199 Separation_item::print (SCM smob)
204 Grob *me = Grob::unsmob (smob);
206 if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
208 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[LEFT].to_points (Y_AXIS)).in_color (255, 255, 0));
209 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[RIGHT].to_points (Y_AXIS)).in_color (0, 255, 255));
211 return ret.smobbed_copy ();
214 ADD_INTERFACE (Separation_item,
215 "Item that computes widths to generate spacing rods.",
219 "conditional-elements "
222 "horizontal-skylines "
223 "skyline-vertical-padding "