]> git.donarmstrong.com Git - lilypond.git/blob - lily/separation-item.cc
Another attempt at removing separating-group-spanner.
[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 "lookup.hh"
12 #include "stencil.hh"
13 #include "skyline.hh"
14 #include "paper-column.hh"
15 #include "warn.hh"
16 #include "pointer-group-interface.hh"
17 #include "accidental-placement.hh"
18
19 void
20 Separation_item::add_item (Grob *s, Item *i)
21 {
22   assert (i);
23   Pointer_group_interface::add_grob (s, ly_symbol2scm ("elements"), i);
24 }
25
26 void
27 Separation_item::add_conditional_item (Grob *me, Grob *e)
28 {
29   Pointer_group_interface::add_grob (me, ly_symbol2scm ("conditional-elements"), e);
30 }
31
32 void
33 Separation_item::set_distance (Drul_array<Item *> items,
34                                        Real padding)
35 {
36   Drul_array<Skyline_pair*> lines (Skyline_pair::unsmob (items[LEFT]->get_property ("horizontal-skylines")),
37                                    Skyline_pair::unsmob (items[RIGHT]->get_property ("horizontal-skylines")));
38   Skyline right = conditional_skyline (items[RIGHT], items[LEFT]);
39   right.merge ((*lines[RIGHT])[LEFT]);
40   
41   Real dist = padding + (*lines[LEFT])[RIGHT].distance (right);
42   if (dist > 0)
43     {
44       Rod rod;
45
46       rod.item_drul_ = items;
47
48       rod.distance_ = dist;
49       rod.add_to_cols ();
50     }  
51 }
52
53 bool
54 Separation_item::is_empty (Grob *me)
55 {
56   Skyline_pair *sky = Skyline_pair::unsmob (me->get_property ("horizontal-skylines"));
57   return (!sky || sky->is_empty ());
58 }
59
60 /*
61   Return the width of ME given that we are considering the object on
62   the LEFT.
63 */
64 Skyline
65 Separation_item::conditional_skyline (Grob *me, Grob *left)
66 {
67   vector<Box> bs = boxes (me, left);
68   return Skyline (bs, 0.1, Y_AXIS, LEFT);
69 }
70
71
72 MAKE_SCHEME_CALLBACK (Separation_item, calc_skylines,1);
73 SCM
74 Separation_item::calc_skylines (SCM smob)
75 {
76   Item *me = unsmob_item (smob);
77   vector<Box> bs = boxes (me, 0);
78   /* todo: the horizon_padding is somewhat arbitrary */
79   return Skyline_pair (bs, 0.1, Y_AXIS).smobbed_copy ();
80 }
81
82 /* if left is non-NULL, get the boxes corresponding to the
83    conditional-elements (conditioned on the grob LEFT). This
84    sounds more general than it is: conditional-elements are
85    always accidentals attached to a tied note.
86 */
87 vector<Box>
88 Separation_item::boxes (Grob *me, Grob *left)
89 {
90   Item *item = dynamic_cast<Item *> (me);
91
92   int very_large = INT_MAX;
93   Paper_column *pc = item->get_column ();
94   vector<Box> out;
95   extract_grob_set (me, left ? "conditional-elements" : "elements", read_only_elts);
96   vector<Grob*> elts;
97
98   if (left)
99     elts = Accidental_placement::get_relevant_accidentals (read_only_elts, left);
100   else
101     elts = read_only_elts;
102
103   Grob *ycommon = common_refpoint_of_array (elts, me, Y_AXIS);
104   
105   for (vsize i = 0; i < elts.size (); i++)
106     {
107       Item *il = dynamic_cast<Item *> (elts[i]);
108       if (pc != il->get_column ())
109         {
110           continue;
111         }
112
113       Interval y (il->pure_height (ycommon, 0, very_large));
114       Interval x (il->extent (pc, X_AXIS));
115
116       Interval extra = robust_scm2interval (elts[i]->get_property ("extra-spacing-width"),
117                                             Interval (0, 0));
118       x[LEFT] += extra[LEFT];
119       x[RIGHT] += extra[RIGHT];
120       if (to_boolean (elts[i]->get_property ("infinite-spacing-height")))
121         y = Interval (-infinity_f, infinity_f);
122  
123       out.push_back (Box (x, y));
124     }
125
126   return out;      
127 }
128
129 /*
130   Try to find the break-aligned symbol in SEPARATION_ITEM that is
131   sticking out at direction D. The x size is put in LAST_EXT
132 */
133 Grob *
134 Separation_item::extremal_break_aligned_grob (Grob *me,
135                                               Direction d,
136                                               Interval *last_ext)
137 {
138   Grob *col = dynamic_cast<Item *> (me)->get_column ();
139   last_ext->set_empty ();
140   Grob *last_grob = 0;
141
142   extract_grob_set (me, "elements", elts);
143   for (vsize i = elts.size (); i--;)
144     {
145       Grob *break_item = elts[i];
146       if (!scm_is_symbol (break_item->get_property ("break-align-symbol")))
147         continue;
148
149       if (!scm_is_pair (break_item->get_property ("space-alist")))
150         continue;
151
152       Interval ext = break_item->extent (col, X_AXIS);
153
154       if (ext.is_empty ())
155         continue;
156
157       if (!last_grob
158           || (last_grob && d * (ext[d]- (*last_ext)[d]) > 0))
159         {
160           *last_ext = ext;
161           last_grob = break_item;
162         }
163     }
164
165   return last_grob;
166 }
167
168 extern bool debug_skylines;
169 MAKE_SCHEME_CALLBACK (Separation_item, print, 1)
170 SCM
171 Separation_item::print (SCM smob)
172 {
173   if (!debug_skylines)
174     return SCM_BOOL_F;
175
176   Grob *me = unsmob_grob (smob);
177   Stencil ret;
178   if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
179     {
180       ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[LEFT].to_points (Y_AXIS)).in_color (255, 255, 0));
181       ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[RIGHT].to_points (Y_AXIS)).in_color (0, 255, 255));
182     }
183   return ret.smobbed_copy ();
184 }
185
186 ADD_INTERFACE (Separation_item,
187                "Item that computes widths to generate spacing rods. "
188                ,
189
190                "X-extent "
191                "conditional-elements "
192                "elements "
193                "padding "
194                "horizontal-skylines "
195                );