LSR: Update.
[lilypond/mpolesky.git] / lily / separation-item.cc
blob56ed817e170987566f4e31be1e70d22159260b86
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1998--2010 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 return Skyline (bs, 0.0, Y_AXIS, LEFT);
87 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines,1);
88 SCM
89 Separation_item::calc_skylines (SCM smob)
91 Item *me = unsmob_item (smob);
92 vector<Box> bs = boxes (me, 0);
93 /* todo: the horizon_padding is somewhat arbitrary */
94 return Skyline_pair (bs, 0.0, Y_AXIS).smobbed_copy ();
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.
102 vector<Box>
103 Separation_item::boxes (Grob *me, Grob *left)
105 Item *item = dynamic_cast<Item *> (me);
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;
113 if (left)
114 elts = Accidental_placement::get_relevant_accidentals (read_only_elts, left);
115 else
117 elts = read_only_elts;
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.
124 if (Grob *a = Note_column::arpeggio (me)) {
125 elts.push_back (a);
129 Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
131 for (vsize i = 0; i < elts.size (); i++)
133 Item *il = dynamic_cast<Item *> (elts[i]);
134 if (pc != il->get_column ())
135 continue;
137 /* ugh. We want to exclude groups of grobs (so that we insert each grob
138 individually into the skyline instead of adding a single box that
139 bounds all of them). However, we can't exclude an axis-group that
140 adds to its childrens' stencil. Currently, this is just TrillPitchGroup;
141 hence the check for note-head-interface. */
142 if (Axis_group_interface::has_interface (il)
143 && !Note_head::has_interface (il))
144 continue;
146 Interval y (il->pure_height (ycommon, 0, very_large));
147 Interval x (il->extent (pc, X_AXIS));
149 Interval extra_width = robust_scm2interval (elts[i]->get_property ("extra-spacing-width"),
150 Interval (-0.1, 0.1));
151 Interval extra_height = robust_scm2interval (elts[i]->get_property ("extra-spacing-height"),
152 Interval (0.0, 0.0));
154 x[LEFT] += extra_width[LEFT];
155 x[RIGHT] += extra_width[RIGHT];
156 y[DOWN] += extra_height[DOWN];
157 y[UP] += extra_height[UP];
159 if (!x.is_empty () && !y.is_empty ())
160 out.push_back (Box (x, y));
163 return out;
166 MAKE_SCHEME_CALLBACK (Separation_item, print, 1)
168 Separation_item::print (SCM smob)
170 if (!debug_skylines)
171 return SCM_BOOL_F;
173 Grob *me = unsmob_grob (smob);
174 Stencil ret;
175 if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
177 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[LEFT].to_points (Y_AXIS)).in_color (255, 255, 0));
178 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[RIGHT].to_points (Y_AXIS)).in_color (0, 255, 255));
180 return ret.smobbed_copy ();
183 ADD_INTERFACE (Separation_item,
184 "Item that computes widths to generate spacing rods.",
186 /* properties */
187 "X-extent "
188 "conditional-elements "
189 "elements "
190 "padding "
191 "horizontal-skylines "