]> git.donarmstrong.com Git - lilypond.git/blob - lily/separation-item.cc
Merge remote branch 'origin' into release/unstable
[lilypond.git] / lily / separation-item.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2011 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   Real horizon_padding = robust_scm2double (me->get_property ("skyline-vertical-padding"), 0.0);
84   return Skyline (bs, horizon_padding, Y_AXIS, LEFT);
85 }
86
87 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines, 1);
88 SCM
89 Separation_item::calc_skylines (SCM smob)
90 {
91   Item *me = unsmob_item (smob);
92   vector<Box> bs = boxes (me, 0);
93   Real horizon_padding = robust_scm2double (me->get_property ("skyline-vertical-padding"), 0.0);
94   return Skyline_pair (bs, horizon_padding, Y_AXIS).smobbed_copy ();
95 }
96
97 /* if left is non-NULL, get the boxes corresponding to the
98    conditional-elements (conditioned on the grob LEFT). This
99    sounds more general than it is: conditional-elements are
100    always accidentals attached to a tied note.
101 */
102 vector<Box>
103 Separation_item::boxes (Grob *me, Grob *left)
104 {
105   Item *item = dynamic_cast<Item *> (me);
106
107   int very_large = INT_MAX;
108   Paper_column *pc = item->get_column ();
109   vector<Box> out;
110   extract_grob_set (me, left ? "conditional-elements" : "elements", read_only_elts);
111   vector<Grob *> elts;
112
113   if (left)
114     elts = Accidental_placement::get_relevant_accidentals (read_only_elts, left);
115   else
116     {
117       elts = read_only_elts;
118
119       /* This is a special-case for NoteColumn: we want to include arpeggio in its
120          skyline (so spacing takes it into account) but we don't want to include it
121          in the NoteColumn's extent because some spanners (eg. Hairpin) bound themselves
122          on the NoteColumn and we don't want them to include arpeggios in their bounds.
123       */
124       if (Grob *a = Note_column::arpeggio (me))
125         {
126           elts.push_back (a);
127         }
128     }
129
130   Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
131
132   for (vsize i = 0; i < elts.size (); i++)
133     {
134       Item *il = dynamic_cast<Item *> (elts[i]);
135       if (pc != il->get_column ())
136         continue;
137
138       /* ugh. We want to exclude groups of grobs (so that we insert each grob
139          individually into the skyline instead of adding a single box that
140          bounds all of them). However, we can't exclude an axis-group that
141          adds to its childrens' stencil. Currently, this is just TrillPitchGroup;
142          hence the check for note-head-interface. */
143       if (Axis_group_interface::has_interface (il)
144           && !Note_head::has_interface (il))
145         continue;
146
147       Interval y (il->pure_height (ycommon, 0, very_large));
148       Interval x (il->extent (pc, X_AXIS));
149
150       Interval extra_width = robust_scm2interval (elts[i]->get_property ("extra-spacing-width"),
151                                                   Interval (-0.1, 0.1));
152       Interval extra_height = robust_scm2interval (elts[i]->get_property ("extra-spacing-height"),
153                                                    Interval (0.0, 0.0));
154
155       x[LEFT] += extra_width[LEFT];
156       x[RIGHT] += extra_width[RIGHT];
157       y[DOWN] += extra_height[DOWN];
158       y[UP] += extra_height[UP];
159
160       if (!x.is_empty () && !y.is_empty ())
161         out.push_back (Box (x, y));
162     }
163
164   return out;
165 }
166
167 MAKE_SCHEME_CALLBACK (Separation_item, print, 1)
168 SCM
169 Separation_item::print (SCM smob)
170 {
171   if (!debug_skylines)
172     return SCM_BOOL_F;
173
174   Grob *me = unsmob_grob (smob);
175   Stencil ret;
176   if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
177     {
178       ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[LEFT].to_points (Y_AXIS)).in_color (255, 255, 0));
179       ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[RIGHT].to_points (Y_AXIS)).in_color (0, 255, 255));
180     }
181   return ret.smobbed_copy ();
182 }
183
184 ADD_INTERFACE (Separation_item,
185                "Item that computes widths to generate spacing rods.",
186
187                /* properties */
188                "X-extent "
189                "conditional-elements "
190                "elements "
191                "padding "
192                "horizontal-skylines "
193                "skyline-vertical-padding "
194               );