]> git.donarmstrong.com Git - lilypond.git/blob - lily/separation-item.cc
Issue 4550 (2/2) Avoid "using namespace std;" in included files
[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 using std::vector;
34
35 void
36 Separation_item::add_item (Grob *s, Item *i)
37 {
38   assert (i);
39   Pointer_group_interface::add_grob (s, ly_symbol2scm ("elements"), i);
40 }
41
42 void
43 Separation_item::add_conditional_item (Grob *me, Grob *e)
44 {
45   Pointer_group_interface::add_grob (me, ly_symbol2scm ("conditional-elements"), e);
46 }
47
48 Real
49 Separation_item::set_distance (Item *l, Item *r, Real padding)
50 {
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]);
55
56   Real dist = padding + (*lines[LEFT])[RIGHT].distance (right);
57   if (dist > 0)
58     {
59       Rod rod;
60
61       rod.item_drul_ = Drul_array<Item *> (l, r);
62
63       rod.distance_ = dist;
64       rod.add_to_cols ();
65     }
66
67   return std::max (dist, 0.0);
68 }
69
70 bool
71 Separation_item::is_empty (Grob *me)
72 {
73   Skyline_pair *sky = unsmob<Skyline_pair> (me->get_property ("horizontal-skylines"));
74   return (!sky || sky->is_empty ());
75 }
76
77 /*
78   Return the width of ME given that we are considering the object on
79   the LEFT.
80 */
81 Skyline
82 Separation_item::conditional_skyline (Grob *me, Grob *left)
83 {
84   vector<Box> bs = boxes (me, left);
85   return Skyline (bs, Y_AXIS, LEFT);
86 }
87
88 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines, 1);
89 SCM
90 Separation_item::calc_skylines (SCM smob)
91 {
92   Item *me = unsmob<Item> (smob);
93   vector<Box> bs = boxes (me, 0);
94   Skyline_pair sp (bs, Y_AXIS);
95   /*
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
101     the skyline).
102   */
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 ();
107 }
108
109 /*
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.
116 */
117 vector<Box>
118 Separation_item::boxes (Grob *me, Grob *left)
119 {
120   Item *item = dynamic_cast<Item *> (me);
121
122   int very_large = INT_MAX;
123   Paper_column *pc = item->get_column ();
124   vector<Box> out;
125   extract_grob_set (me, left ? "conditional-elements" : "elements", read_only_elts);
126   vector<Grob *> elts;
127
128   if (left)
129     {
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++)
133         {
134           if (has_interface<Accidental_placement> (read_only_elts[i]))
135             accidental_elts.push_back (read_only_elts[i]);
136           else
137             other_elts.push_back (read_only_elts[i]);
138         }
139       elts = Accidental_placement::get_relevant_accidentals (accidental_elts, left);
140       elts.insert (elts.end (), other_elts.begin (), other_elts.end ());
141     }
142   else
143     elts = read_only_elts;
144
145   Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
146
147   for (vsize i = 0; i < elts.size (); i++)
148     {
149       Item *il = dynamic_cast<Item *> (elts[i]);
150       if (pc != il->get_column ())
151         continue;
152
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))
160         continue;
161
162       Interval y (il->pure_y_extent (ycommon, 0, very_large));
163       Interval x (il->extent (pc, X_AXIS));
164
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));
169
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.
174
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];
181       if (!isinf (y[UP]))
182         y[UP] += extra_height[UP];
183
184       if (!x.is_empty () && !y.is_empty ())
185         out.push_back (Box (x, y));
186     }
187
188   return out;
189 }
190
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)"
199                                  " on the page.")
200 SCM
201 Separation_item::print (SCM smob)
202 {
203   if (!debug_skylines)
204     return SCM_BOOL_F;
205
206   Grob *me = unsmob<Grob> (smob);
207   Stencil ret;
208   if (Skyline_pair *s = unsmob<Skyline_pair> (me->get_property ("horizontal-skylines")))
209     {
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));
212     }
213   return ret.smobbed_copy ();
214 }
215
216 ADD_INTERFACE (Separation_item,
217                "Item that computes widths to generate spacing rods.",
218
219                /* properties */
220                "X-extent "
221                "conditional-elements "
222                "elements "
223                "padding "
224                "horizontal-skylines "
225                "skyline-vertical-padding "
226               );