]> git.donarmstrong.com Git - lilypond.git/blob - lily/separation-item.cc
Merge branch 'master' of ssh://jneem@git.sv.gnu.org/srv/git/lilypond
[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--2008 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_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));
142
143       x[LEFT] += extra_width[LEFT];
144       x[RIGHT] += extra_width[RIGHT];
145       y[DOWN] += extra_height[DOWN];
146       y[UP] += extra_height[UP];
147  
148       if (!x.is_empty () && !y.is_empty ())
149         out.push_back (Box (x, y));
150     }
151
152   return out;      
153 }
154
155 MAKE_SCHEME_CALLBACK (Separation_item, print, 1)
156 SCM
157 Separation_item::print (SCM smob)
158 {
159   if (!debug_skylines)
160     return SCM_BOOL_F;
161
162   Grob *me = unsmob_grob (smob);
163   Stencil ret;
164   if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
165     {
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));
168     }
169   return ret.smobbed_copy ();
170 }
171
172 ADD_INTERFACE (Separation_item,
173                "Item that computes widths to generate spacing rods.",
174
175                /* properties */
176                "X-extent "
177                "conditional-elements "
178                "elements "
179                "padding "
180                "horizontal-skylines "
181                );