Use ly:staff-symbol-staff-space.
[lilypond/mpolesky.git] / lily / spacing-interface.cc
blob6e8027bc8c31b445833bc842593c188651175aa7
1 /*
2 spacing-interface.cc -- functionality that is shared between Note_spacing
3 and Staff_spacing
5 source file of the GNU LilyPond music typesetter
7 (c) 2007--2009 Joe Neeman <joeneeman@gmail.com>
8 */
10 #include "spacing-interface.hh"
12 #include "grob.hh"
13 #include "grob-array.hh"
14 #include "item.hh"
15 #include "note-column.hh"
16 #include "pointer-group-interface.hh"
17 #include "paper-column.hh"
18 #include "separation-item.hh"
19 #include "skyline.hh"
20 #include "skyline-pair.hh"
21 #include "system.hh"
23 /* return the right-pointing skyline of the left-items and the left-pointing
24 skyline of the right-items (with the skyline of the left-items in
25 ret[LEFT]) */
26 Drul_array<Skyline>
27 Spacing_interface::skylines (Grob *me, Grob *right_col)
29 /* the logic here is a little convoluted.
30 A {Staff,Note}_spacing doesn't copy left-items when it clones,
31 so in order to find the separation items, we need to use the original
32 spacing grob. But once we find the separation items, we need to get back
33 the broken piece.
36 Grob *orig = me->original () ? me->original () : me;
37 Drul_array<Direction> break_dirs (dynamic_cast<Item*> (me)->break_status_dir (),
38 dynamic_cast<Item*> (right_col)->break_status_dir ());
39 Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
40 Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
41 ly_scm2link_array (orig->get_object ("right-items")));
43 Grob *system = me->get_system ();
44 Grob *left_col = dynamic_cast<Item*> (me)->get_column ();
46 Drul_array<Grob*> columns (left_col, right_col);
48 Direction d = LEFT;
51 for (vsize i = 0; i < items[d].size (); i++)
53 Item *g = dynamic_cast<Item*> (items[d][i]);
54 if (g)
55 if (Item *piece = g->find_prebroken_piece (break_dirs[d]))
56 g = piece;
58 if (g && Separation_item::has_interface (g) && g->get_column () == columns[d])
60 SCM sky_scm = g->get_property ("horizontal-skylines");
61 Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
63 extract_grob_set (g, "elements", elts);
64 Grob *ycommon = common_refpoint_of_array (elts, g, Y_AXIS);
65 Real shift = ycommon->pure_relative_y_coordinate (system, 0, INT_MAX);
67 skylines[d].shift (-shift);
69 if (sky)
70 skylines[d].merge ((*sky)[-d]);
71 else
72 programming_error ("separation item has no skyline");
74 if (d == RIGHT && items[LEFT].size ())
75 skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
77 skylines[d].shift (shift);
81 while (flip (&d) != LEFT);
83 return skylines;
86 Real
87 Spacing_interface::minimum_distance (Grob *me, Grob *right)
89 Drul_array<Skyline> skylines = Spacing_interface::skylines (me, right);
91 return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
95 Compute the left-most column of the right-items.
97 Item *
98 Spacing_interface::right_column (Grob *me)
100 if (!me->is_live ())
101 return 0;
103 Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
104 Item *mincol = 0;
105 int min_rank = INT_MAX;
106 for (vsize i = 0; a && i < a->size (); i++)
108 Item *ri = a->item (i);
109 Item *col = ri->get_column ();
111 int rank = Paper_column::get_rank (col);
113 if (rank < min_rank)
115 min_rank = rank;
116 mincol = col;
120 return mincol;
123 Item *
124 Spacing_interface::left_column (Grob *me)
126 if (!me->is_live ())
127 return 0;
129 return dynamic_cast<Item *> (me)->get_column ();
132 static vector<Item*>
133 get_note_columns (vector<Grob*> const &elts)
135 vector<Item*> ret;
137 for (vsize i = 0; i < elts.size (); i++)
139 if (Note_column::has_interface (elts[i]))
140 ret.push_back (dynamic_cast<Item*> (elts[i]));
141 else if (Separation_item::has_interface (elts[i]))
143 extract_grob_set (elts[i], "elements", more_elts);
144 vector<Item*> ncs = get_note_columns (more_elts);
146 ret.insert (ret.end (), ncs.begin (), ncs.end ());
150 return ret;
153 vector<Item*>
154 Spacing_interface::right_note_columns (Grob *me)
156 extract_grob_set (me, "right-items", elts);
157 return get_note_columns (elts);
160 vector<Item*>
161 Spacing_interface::left_note_columns (Grob *me)
163 extract_grob_set (me, "left-items", elts);
164 return get_note_columns (elts);
168 Try to find the break-aligned symbol that belongs on the D-side
169 of ME, sticking out in direction -D. The x size is put in LAST_EXT
171 Grob *
172 Spacing_interface::extremal_break_aligned_grob (Grob *me,
173 Direction d,
174 Direction break_dir,
175 Interval *last_ext)
177 Grob *col = 0;
178 last_ext->set_empty ();
179 Grob *last_grob = 0;
181 extract_grob_set (me, d == LEFT ? "left-break-aligned" : "right-break-aligned", elts);
183 for (vsize i = elts.size (); i--;)
185 Item *break_item = dynamic_cast<Item*> (elts[i]);
187 if (break_item->break_status_dir () != break_dir)
188 break_item = break_item->find_prebroken_piece (break_dir);
190 if (!break_item || !scm_is_pair (break_item->get_property ("space-alist")))
191 continue;
193 if (!col)
194 col = dynamic_cast<Item*> (elts[0])->get_column ()->find_prebroken_piece (break_dir);
196 Interval ext = break_item->extent (col, X_AXIS);
198 if (ext.is_empty ())
199 continue;
201 if (!last_grob
202 || (last_grob && d * (ext[-d]- (*last_ext)[-d]) < 0))
204 *last_ext = ext;
205 last_grob = break_item;
209 return last_grob;
213 ADD_INTERFACE (Spacing_interface,
214 "This object calculates the desired and minimum distances"
215 " between two columns.",
217 /* properties */
218 "left-items "
219 "right-items "