Update from Andrew: tweaks for cross-staff chords snippet.
[lilypond.git] / lily / separation-item.cc
blob617c6fd4ebc9e25b641a2a83332f960e79d1427f
1 /*
2 separation-item.cc -- implement Separation_item
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
9 #include "separation-item.hh"
11 #include "accidental-placement.hh"
12 #include "axis-group-interface.hh"
13 #include "lookup.hh"
14 #include "note-column.hh"
15 #include "note-head.hh"
16 #include "paper-column.hh"
17 #include "pointer-group-interface.hh"
18 #include "skyline-pair.hh"
19 #include "stencil.hh"
20 #include "warn.hh"
22 void
23 Separation_item::add_item (Grob *s, Item *i)
25 assert (i);
26 Pointer_group_interface::add_grob (s, ly_symbol2scm ("elements"), i);
29 void
30 Separation_item::add_conditional_item (Grob *me, Grob *e)
32 Pointer_group_interface::add_grob (me, ly_symbol2scm ("conditional-elements"), e);
35 Real
36 Separation_item::set_distance (Item *l, Item *r, Real padding)
38 Drul_array<Skyline_pair*> lines (Skyline_pair::unsmob (l->get_property ("horizontal-skylines")),
39 Skyline_pair::unsmob (r->get_property ("horizontal-skylines")));
40 Skyline right = conditional_skyline (r, l);
41 right.merge ((*lines[RIGHT])[LEFT]);
43 Real dist = padding + (*lines[LEFT])[RIGHT].distance (right);
44 if (dist > 0)
46 Rod rod;
48 rod.item_drul_ = Drul_array<Item*> (l, r);
50 rod.distance_ = dist;
51 rod.add_to_cols ();
54 return max (dist, 0.0);
57 bool
58 Separation_item::is_empty (Grob *me)
60 Skyline_pair *sky = Skyline_pair::unsmob (me->get_property ("horizontal-skylines"));
61 return (!sky || sky->is_empty ());
65 Return the width of ME given that we are considering the object on
66 the LEFT.
68 Skyline
69 Separation_item::conditional_skyline (Grob *me, Grob *left)
71 vector<Box> bs = boxes (me, left);
72 return Skyline (bs, 0.1, Y_AXIS, LEFT);
76 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines,1);
77 SCM
78 Separation_item::calc_skylines (SCM smob)
80 Item *me = unsmob_item (smob);
81 vector<Box> bs = boxes (me, 0);
82 /* todo: the horizon_padding is somewhat arbitrary */
83 return Skyline_pair (bs, 0.1, Y_AXIS).smobbed_copy ();
86 /* if left is non-NULL, get the boxes corresponding to the
87 conditional-elements (conditioned on the grob LEFT). This
88 sounds more general than it is: conditional-elements are
89 always accidentals attached to a tied note.
91 vector<Box>
92 Separation_item::boxes (Grob *me, Grob *left)
94 Item *item = dynamic_cast<Item *> (me);
96 int very_large = INT_MAX;
97 Paper_column *pc = item->get_column ();
98 vector<Box> out;
99 extract_grob_set (me, left ? "conditional-elements" : "elements", read_only_elts);
100 vector<Grob*> elts;
102 if (left)
103 elts = Accidental_placement::get_relevant_accidentals (read_only_elts, left);
104 else
106 elts = read_only_elts;
108 /* This is a special-case for NoteColumn: we want to include arpeggio in its
109 skyline (so spacing takes it into account) but we don't want to include it
110 in the NoteColumn's extent because some spanners (eg. Hairpin) bound themselves
111 on the NoteColumn and we don't want them to include arpeggios in their bounds.
113 if (Grob *a = Note_column::arpeggio (me)) {
114 elts.push_back (a);
118 Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
120 for (vsize i = 0; i < elts.size (); i++)
122 Item *il = dynamic_cast<Item *> (elts[i]);
123 if (pc != il->get_column ())
124 continue;
126 /* ugh. We want to exclude groups of grobs (so that we insert each grob
127 individually into the skyline instead of adding a single box that
128 bounds all of them). However, we can't exclude an axis-group that
129 adds to its childrens' stencil. Currently, this is just TrillPitchGroup;
130 hence the check for note-head-interface. */
131 if (Axis_group_interface::has_interface (il)
132 && !Note_head::has_interface (il))
133 continue;
135 Interval y (il->pure_height (ycommon, 0, very_large));
136 Interval x (il->extent (pc, X_AXIS));
138 Interval extra_width = robust_scm2interval (elts[i]->get_property ("extra-spacing-width"),
139 Interval (-0.1, 0.1));
140 Interval extra_height = robust_scm2interval (elts[i]->get_property ("extra-spacing-height"),
141 Interval (-0.1, 0.1));
143 x[LEFT] += extra_width[LEFT];
144 x[RIGHT] += extra_width[RIGHT];
145 y[DOWN] += extra_height[DOWN];
146 y[UP] += extra_height[UP];
148 if (!x.is_empty () && !y.is_empty ())
149 out.push_back (Box (x, y));
152 return out;
155 MAKE_SCHEME_CALLBACK (Separation_item, print, 1)
157 Separation_item::print (SCM smob)
159 if (!debug_skylines)
160 return SCM_BOOL_F;
162 Grob *me = unsmob_grob (smob);
163 Stencil ret;
164 if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
166 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[LEFT].to_points (Y_AXIS)).in_color (255, 255, 0));
167 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[RIGHT].to_points (Y_AXIS)).in_color (0, 255, 255));
169 return ret.smobbed_copy ();
172 ADD_INTERFACE (Separation_item,
173 "Item that computes widths to generate spacing rods.",
175 /* properties */
176 "X-extent "
177 "conditional-elements "
178 "elements "
179 "padding "
180 "horizontal-skylines "