]> git.donarmstrong.com Git - lilypond.git/blob - lily/separation-item.cc
Merge branch 'lilypond/translation' of ssh://git.sv.gnu.org/srv/git/lilypond
[lilypond.git] / lily / separation-item.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2010 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
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.
10
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.
15
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/>.
18 */
19
20 #include "separation-item.hh"
21
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"
32
33 void
34 Separation_item::add_item (Grob *s, Item *i)
35 {
36   assert (i);
37   Pointer_group_interface::add_grob (s, ly_symbol2scm ("elements"), i);
38 }
39
40 void
41 Separation_item::add_conditional_item (Grob *me, Grob *e)
42 {
43   Pointer_group_interface::add_grob (me, ly_symbol2scm ("conditional-elements"), e);
44 }
45
46 Real
47 Separation_item::set_distance (Item *l, Item *r, Real padding)
48 {
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]);
53   
54   Real dist = padding + (*lines[LEFT])[RIGHT].distance (right);
55   if (dist > 0)
56     {
57       Rod rod;
58
59       rod.item_drul_ = Drul_array<Item*> (l, r);
60
61       rod.distance_ = dist;
62       rod.add_to_cols ();
63     }
64
65   return max (dist, 0.0);
66 }
67
68 bool
69 Separation_item::is_empty (Grob *me)
70 {
71   Skyline_pair *sky = Skyline_pair::unsmob (me->get_property ("horizontal-skylines"));
72   return (!sky || sky->is_empty ());
73 }
74
75 /*
76   Return the width of ME given that we are considering the object on
77   the LEFT.
78 */
79 Skyline
80 Separation_item::conditional_skyline (Grob *me, Grob *left)
81 {
82   vector<Box> bs = boxes (me, left);
83   return Skyline (bs, 0.1, Y_AXIS, LEFT);
84 }
85
86
87 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines,1);
88 SCM
89 Separation_item::calc_skylines (SCM smob)
90 {
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.1, Y_AXIS).smobbed_copy ();
95 }
96
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.
101 */
102 vector<Box>
103 Separation_item::boxes (Grob *me, Grob *left)
104 {
105   Item *item = dynamic_cast<Item *> (me);
106
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;
112
113   if (left)
114     elts = Accidental_placement::get_relevant_accidentals (read_only_elts, left);
115   else
116     {
117       elts = read_only_elts;
118
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.
123       */
124       if (Grob *a = Note_column::arpeggio (me)) {
125         elts.push_back (a);
126       }
127     }
128
129   Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
130   
131   for (vsize i = 0; i < elts.size (); i++)
132     {
133       Item *il = dynamic_cast<Item *> (elts[i]);
134       if (pc != il->get_column ())
135         continue;
136
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;
145
146       Interval y (il->pure_height (ycommon, 0, very_large));
147       Interval x (il->extent (pc, X_AXIS));
148
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.1, 0.1));
153
154       x[LEFT] += extra_width[LEFT];
155       x[RIGHT] += extra_width[RIGHT];
156       y[DOWN] += extra_height[DOWN];
157       y[UP] += extra_height[UP];
158  
159       if (!x.is_empty () && !y.is_empty ())
160         out.push_back (Box (x, y));
161     }
162
163   return out;      
164 }
165
166 MAKE_SCHEME_CALLBACK (Separation_item, print, 1)
167 SCM
168 Separation_item::print (SCM smob)
169 {
170   if (!debug_skylines)
171     return SCM_BOOL_F;
172
173   Grob *me = unsmob_grob (smob);
174   Stencil ret;
175   if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
176     {
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));
179     }
180   return ret.smobbed_copy ();
181 }
182
183 ADD_INTERFACE (Separation_item,
184                "Item that computes widths to generate spacing rods.",
185
186                /* properties */
187                "X-extent "
188                "conditional-elements "
189                "elements "
190                "padding "
191                "horizontal-skylines "
192                );