Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / separation-item.cc
blob013e457034bea442ae397211d431178888f0357c
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1998--2011 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"
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"
33 void
34 Separation_item::add_item (Grob *s, Item *i)
36 assert (i);
37 Pointer_group_interface::add_grob (s, ly_symbol2scm ("elements"), i);
40 void
41 Separation_item::add_conditional_item (Grob *me, Grob *e)
43 Pointer_group_interface::add_grob (me, ly_symbol2scm ("conditional-elements"), e);
46 Real
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);
55 if (dist > 0)
57 Rod rod;
59 rod.item_drul_ = Drul_array<Item*> (l, r);
61 rod.distance_ = dist;
62 rod.add_to_cols ();
65 return max (dist, 0.0);
68 bool
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
77 the LEFT.
79 Skyline
80 Separation_item::conditional_skyline (Grob *me, Grob *left)
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);
88 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines,1);
89 SCM
90 Separation_item::calc_skylines (SCM smob)
92 Item *me = unsmob_item (smob);
93 vector<Box> bs = boxes (me, 0);
94 Real horizon_padding = robust_scm2double (me->get_property ("skyline-vertical-padding"), 0.0);
95 return Skyline_pair (bs, horizon_padding, Y_AXIS).smobbed_copy ();
98 /* if left is non-NULL, get the boxes corresponding to the
99 conditional-elements (conditioned on the grob LEFT). This
100 sounds more general than it is: conditional-elements are
101 always accidentals attached to a tied note.
103 vector<Box>
104 Separation_item::boxes (Grob *me, Grob *left)
106 Item *item = dynamic_cast<Item *> (me);
108 int very_large = INT_MAX;
109 Paper_column *pc = item->get_column ();
110 vector<Box> out;
111 extract_grob_set (me, left ? "conditional-elements" : "elements", read_only_elts);
112 vector<Grob*> elts;
114 if (left)
115 elts = Accidental_placement::get_relevant_accidentals (read_only_elts, left);
116 else
118 elts = read_only_elts;
120 /* This is a special-case for NoteColumn: we want to include arpeggio in its
121 skyline (so spacing takes it into account) but we don't want to include it
122 in the NoteColumn's extent because some spanners (eg. Hairpin) bound themselves
123 on the NoteColumn and we don't want them to include arpeggios in their bounds.
125 if (Grob *a = Note_column::arpeggio (me)) {
126 elts.push_back (a);
130 Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
132 for (vsize i = 0; i < elts.size (); i++)
134 Item *il = dynamic_cast<Item *> (elts[i]);
135 if (pc != il->get_column ())
136 continue;
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;
147 Interval y (il->pure_height (ycommon, 0, very_large));
148 Interval x (il->extent (pc, X_AXIS));
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));
155 x[LEFT] += extra_width[LEFT];
156 x[RIGHT] += extra_width[RIGHT];
157 y[DOWN] += extra_height[DOWN];
158 y[UP] += extra_height[UP];
160 if (!x.is_empty () && !y.is_empty ())
161 out.push_back (Box (x, y));
164 return out;
167 MAKE_SCHEME_CALLBACK (Separation_item, print, 1)
169 Separation_item::print (SCM smob)
171 if (!debug_skylines)
172 return SCM_BOOL_F;
174 Grob *me = unsmob_grob (smob);
175 Stencil ret;
176 if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
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));
181 return ret.smobbed_copy ();
184 ADD_INTERFACE (Separation_item,
185 "Item that computes widths to generate spacing rods.",
187 /* properties */
188 "X-extent "
189 "conditional-elements "
190 "elements "
191 "padding "
192 "horizontal-skylines "
193 "skyline-vertical-padding "