]> git.donarmstrong.com Git - lilypond.git/blob - lily/separation-item.cc
restore regression tests for time-signature styles; issue 4176
[lilypond.git] / lily / separation-item.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
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.
10
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.
15
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/>.
18 */
19
20 #include "separation-item.hh"
21
22 #include "accidental-placement.hh"
23 #include "axis-group-interface.hh"
24 #include "lookup.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"
30 #include "stencil.hh"
31 #include "warn.hh"
32
33 void
34 Separation_item::add_item (Grob *s, Item *i)
35 {
36   assert (i);
37   Pointer_group_interface::add_grob (s, ly_symbol2scm ("elements"), i);
38 }
39
40 void
41 Separation_item::add_conditional_item (Grob *me, Grob *e)
42 {
43   Pointer_group_interface::add_grob (me, ly_symbol2scm ("conditional-elements"), e);
44 }
45
46 Real
47 Separation_item::set_distance (Item *l, Item *r, Real padding)
48 {
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]);
53
54   Real dist = padding + (*lines[LEFT])[RIGHT].distance (right);
55   if (dist > 0)
56     {
57       Rod rod;
58
59       rod.item_drul_ = Drul_array<Item *> (l, r);
60
61       rod.distance_ = dist;
62       rod.add_to_cols ();
63     }
64
65   return max (dist, 0.0);
66 }
67
68 bool
69 Separation_item::is_empty (Grob *me)
70 {
71   Skyline_pair *sky = Skyline_pair::unsmob (me->get_property ("horizontal-skylines"));
72   return (!sky || sky->is_empty ());
73 }
74
75 /*
76   Return the width of ME given that we are considering the object on
77   the LEFT.
78 */
79 Skyline
80 Separation_item::conditional_skyline (Grob *me, Grob *left)
81 {
82   vector<Box> bs = boxes (me, left);
83   return Skyline (bs, Y_AXIS, LEFT);
84 }
85
86 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines, 1);
87 SCM
88 Separation_item::calc_skylines (SCM smob)
89 {
90   Item *me = Item::unsmob (smob);
91   vector<Box> bs = boxes (me, 0);
92   Skyline_pair sp (bs, Y_AXIS);
93   /*
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
99     the skyline).
100   */
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 ();
105 }
106
107 /*
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.
114 */
115 vector<Box>
116 Separation_item::boxes (Grob *me, Grob *left)
117 {
118   Item *item = dynamic_cast<Item *> (me);
119
120   int very_large = INT_MAX;
121   Paper_column *pc = item->get_column ();
122   vector<Box> out;
123   extract_grob_set (me, left ? "conditional-elements" : "elements", read_only_elts);
124   vector<Grob *> elts;
125
126   if (left)
127     {
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++)
131         {
132           if (Accidental_placement::has_interface (read_only_elts[i]))
133             accidental_elts.push_back (read_only_elts[i]);
134           else
135             other_elts.push_back (read_only_elts[i]);
136         }
137       elts = Accidental_placement::get_relevant_accidentals (accidental_elts, left);
138       elts.insert (elts.end (), other_elts.begin (), other_elts.end ());
139     }
140   else
141     elts = read_only_elts;
142
143   Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
144
145   for (vsize i = 0; i < elts.size (); i++)
146     {
147       Item *il = dynamic_cast<Item *> (elts[i]);
148       if (pc != il->get_column ())
149         continue;
150
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))
158         continue;
159
160       Interval y (il->pure_height (ycommon, 0, very_large));
161       Interval x (il->extent (pc, X_AXIS));
162
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));
167
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.
172
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];
179       if (!isinf (y[UP]))
180         y[UP] += extra_height[UP];
181
182       if (!x.is_empty () && !y.is_empty ())
183         out.push_back (Box (x, y));
184     }
185
186   return out;
187 }
188
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)"
197                                  " on the page.")
198 SCM
199 Separation_item::print (SCM smob)
200 {
201   if (!debug_skylines)
202     return SCM_BOOL_F;
203
204   Grob *me = Grob::unsmob (smob);
205   Stencil ret;
206   if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
207     {
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));
210     }
211   return ret.smobbed_copy ();
212 }
213
214 ADD_INTERFACE (Separation_item,
215                "Item that computes widths to generate spacing rods.",
216
217                /* properties */
218                "X-extent "
219                "conditional-elements "
220                "elements "
221                "padding "
222                "horizontal-skylines "
223                "skyline-vertical-padding "
224               );