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"
36 Separation_item::add_item (Grob *s, Item *i)
39 Pointer_group_interface::add_grob (s, ly_symbol2scm ("elements"), i);
43 Separation_item::add_conditional_item (Grob *me, Grob *e)
45 Pointer_group_interface::add_grob (me, ly_symbol2scm ("conditional-elements"), e);
49 Separation_item::set_distance (Item *l, Item *r, Real padding)
51 Drul_array<Skyline_pair *> lines (unsmob<Skyline_pair> (l->get_property ("horizontal-skylines")),
52 unsmob<Skyline_pair> (r->get_property ("horizontal-skylines")));
53 Skyline right = conditional_skyline (r, l);
54 right.merge ((*lines[RIGHT])[LEFT]);
56 Real dist = padding + (*lines[LEFT])[RIGHT].distance (right);
61 rod.item_drul_ = Drul_array<Item *> (l, r);
67 return std::max (dist, 0.0);
71 Separation_item::is_empty (Grob *me)
73 Skyline_pair *sky = unsmob<Skyline_pair> (me->get_property ("horizontal-skylines"));
74 return (!sky || sky->is_empty ());
78 Return the width of ME given that we are considering the object on
82 Separation_item::conditional_skyline (Grob *me, Grob *left)
84 vector<Box> bs = boxes (me, left);
85 return Skyline (bs, Y_AXIS, LEFT);
88 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines, 1);
90 Separation_item::calc_skylines (SCM smob)
92 Item *me = unsmob<Item> (smob);
93 vector<Box> bs = boxes (me, 0);
94 Skyline_pair sp (bs, Y_AXIS);
96 TODO: We need to decide if padding is 'intrinsic'
97 to a skyline or if it is something that is only added on in
98 distance calculations. Here, we make it intrinsic, which copies
99 the behavior from the old code but no longer corresponds to how
100 vertical skylines are handled (where padding is not built into
103 Real vp = robust_scm2double (me->get_property ("skyline-vertical-padding"), 0.0);
104 sp[LEFT] = sp[LEFT].padded (vp);
105 sp[RIGHT] = sp[RIGHT].padded (vp);
106 return sp.smobbed_copy ();
110 If left is non-NULL, get the boxes corresponding to the
111 conditional-elements (conditioned on the grob LEFT).
112 Conditional elements are, for now, arpeggios and accidental
113 placements. Based on the left grob, the accidentals will
114 be printed or not, so we filter using
115 Accidental_placement::get_relevant_accidentals.
118 Separation_item::boxes (Grob *me, Grob *left)
120 Item *item = dynamic_cast<Item *> (me);
122 int very_large = INT_MAX;
123 Paper_column *pc = item->get_column ();
125 extract_grob_set (me, left ? "conditional-elements" : "elements", read_only_elts);
130 vector<Grob *> accidental_elts;
131 vector<Grob *> other_elts; // for now only arpeggios
132 for (vsize i = 0; i < read_only_elts.size (); i++)
134 if (has_interface<Accidental_placement> (read_only_elts[i]))
135 accidental_elts.push_back (read_only_elts[i]);
137 other_elts.push_back (read_only_elts[i]);
139 elts = Accidental_placement::get_relevant_accidentals (accidental_elts, left);
140 elts.insert (elts.end (), other_elts.begin (), other_elts.end ());
143 elts = read_only_elts;
145 Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
147 for (vsize i = 0; i < elts.size (); i++)
149 Item *il = dynamic_cast<Item *> (elts[i]);
150 if (pc != il->get_column ())
153 /* ugh. We want to exclude groups of grobs (so that we insert each grob
154 individually into the skyline instead of adding a single box that
155 bounds all of them). However, we can't exclude an axis-group that
156 adds to its childrens' stencil. Currently, this is just TrillPitchGroup;
157 hence the check for note-head-interface. */
158 if (has_interface<Axis_group_interface> (il)
159 && !has_interface<Note_head> (il))
162 Interval y (il->pure_y_extent (ycommon, 0, very_large));
163 Interval x (il->extent (pc, X_AXIS));
165 Interval extra_width = robust_scm2interval (elts[i]->get_property ("extra-spacing-width"),
166 Interval (-0.1, 0.1));
167 Interval extra_height = robust_scm2interval (elts[i]->get_property ("extra-spacing-height"),
168 Interval (0.0, 0.0));
170 // The conventional empty extent is (+inf.0 . -inf.0)
171 // but (-inf.0 . +inf.0) is used as extra-spacing-height
172 // on items that must not overlap other note-columns.
173 // If these two uses of inf combine, leave the empty extent.
175 if (!isinf (x[LEFT]))
176 x[LEFT] += extra_width[LEFT];
177 if (!isinf (x[RIGHT]))
178 x[RIGHT] += extra_width[RIGHT];
179 if (!isinf (y[DOWN]))
180 y[DOWN] += extra_height[DOWN];
182 y[UP] += extra_height[UP];
184 if (!x.is_empty () && !y.is_empty ())
185 out.push_back (Box (x, y));
191 MAKE_DOCUMENTED_SCHEME_CALLBACK (Separation_item, print, 1,
192 "Optional stencil for @code{PaperColumn} or"
193 "@code{NonMusicalPaperColumn}.\n"
194 "Draws the @code{horizontal-skylines} of each"
195 " @code{PaperColumn}, showing the shapes used"
196 " to determine the minimum distances between"
197 " @code{PaperColumns} at the note-spacing step,"
198 " before staves have been spaced (vertically)"
201 Separation_item::print (SCM smob)
206 Grob *me = unsmob<Grob> (smob);
208 if (Skyline_pair *s = unsmob<Skyline_pair> (me->get_property ("horizontal-skylines")))
210 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[LEFT].to_points (Y_AXIS)).in_color (255, 255, 0));
211 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[RIGHT].to_points (Y_AXIS)).in_color (0, 255, 255));
213 return ret.smobbed_copy ();
216 ADD_INTERFACE (Separation_item,
217 "Item that computes widths to generate spacing rods.",
221 "conditional-elements "
224 "horizontal-skylines "
225 "skyline-vertical-padding "