]> git.donarmstrong.com Git - lilypond.git/blob - lily/separation-item.cc
2e46c597719bff580a14187c317561cd7d4e4f1b
[lilypond.git] / lily / separation-item.cc
1 /*
2   separation-item.cc -- implement Separation_item
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "separation-item.hh"
10
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"
21
22 void
23 Separation_item::add_item (Grob *s, Item *i)
24 {
25   assert (i);
26   Pointer_group_interface::add_grob (s, ly_symbol2scm ("elements"), i);
27 }
28
29 void
30 Separation_item::add_conditional_item (Grob *me, Grob *e)
31 {
32   Pointer_group_interface::add_grob (me, ly_symbol2scm ("conditional-elements"), e);
33 }
34
35 Real
36 Separation_item::set_distance (Item *l, Item *r, Real padding)
37 {
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]);
42   
43   Real dist = padding + (*lines[LEFT])[RIGHT].distance (right);
44   if (dist > 0)
45     {
46       Rod rod;
47
48       rod.item_drul_ = Drul_array<Item*> (l, r);
49
50       rod.distance_ = dist;
51       rod.add_to_cols ();
52     }
53
54   return max (dist, 0.0);
55 }
56
57 bool
58 Separation_item::is_empty (Grob *me)
59 {
60   Skyline_pair *sky = Skyline_pair::unsmob (me->get_property ("horizontal-skylines"));
61   return (!sky || sky->is_empty ());
62 }
63
64 /*
65   Return the width of ME given that we are considering the object on
66   the LEFT.
67 */
68 Skyline
69 Separation_item::conditional_skyline (Grob *me, Grob *left)
70 {
71   vector<Box> bs = boxes (me, left);
72   return Skyline (bs, 0.1, Y_AXIS, LEFT);
73 }
74
75
76 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines,1);
77 SCM
78 Separation_item::calc_skylines (SCM smob)
79 {
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 ();
84 }
85
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.
90 */
91 vector<Box>
92 Separation_item::boxes (Grob *me, Grob *left)
93 {
94   Item *item = dynamic_cast<Item *> (me);
95
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;
101
102   if (left)
103     elts = Accidental_placement::get_relevant_accidentals (read_only_elts, left);
104   else
105     {
106       elts = read_only_elts;
107
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.
112       */
113       if (Grob *a = Note_column::arpeggio (me)) {
114         elts.push_back (a);
115       }
116     }
117
118   Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
119   
120   for (vsize i = 0; i < elts.size (); i++)
121     {
122       Item *il = dynamic_cast<Item *> (elts[i]);
123       if (pc != il->get_column ())
124         continue;
125
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;
134
135       Interval y (il->pure_height (ycommon, 0, very_large));
136       Interval x (il->extent (pc, X_AXIS));
137
138       Interval extra = robust_scm2interval (elts[i]->get_property ("extra-spacing-width"),
139                                             Interval (-0.1, 0.1));
140       x[LEFT] += extra[LEFT];
141       x[RIGHT] += extra[RIGHT];
142       if (to_boolean (elts[i]->get_property ("infinite-spacing-height")))
143         y = Interval (-infinity_f, infinity_f);
144  
145       if (!x.is_empty () && !y.is_empty ())
146       out.push_back (Box (x, y));
147     }
148
149   return out;      
150 }
151
152 MAKE_SCHEME_CALLBACK (Separation_item, print, 1)
153 SCM
154 Separation_item::print (SCM smob)
155 {
156   if (!debug_skylines)
157     return SCM_BOOL_F;
158
159   Grob *me = unsmob_grob (smob);
160   Stencil ret;
161   if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
162     {
163       ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[LEFT].to_points (Y_AXIS)).in_color (255, 255, 0));
164       ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[RIGHT].to_points (Y_AXIS)).in_color (0, 255, 255));
165     }
166   return ret.smobbed_copy ();
167 }
168
169 ADD_INTERFACE (Separation_item,
170                "Item that computes widths to generate spacing rods.",
171
172                /* properties */
173                "X-extent "
174                "conditional-elements "
175                "elements "
176                "padding "
177                "horizontal-skylines "
178                );