2 spacing-interface.cc -- functionality that is shared between Note_spacing
5 source file of the GNU LilyPond music typesetter
7 (c) 2007 Joe Neeman <joeneeman@gmail.com>
10 #include "spacing-interface.hh"
13 #include "grob-array.hh"
15 #include "note-column.hh"
16 #include "pointer-group-interface.hh"
17 #include "paper-column.hh"
18 #include "separation-item.hh"
22 /* return the right-pointing skyline of the left-items and the left-pointing
23 skyline of the right-items (with the skyline of the left-items in
26 Spacing_interface::skylines (Grob *me, Grob *right_col)
28 /* the logic here is a little convoluted.
29 A {Staff,Note}_spacing doesn't copy left-items when it clones,
30 so in order to find the separation items, we need to use the original
31 spacing grob. But once we find the separation items, we need to get back
35 Grob *orig = me->original () ? me->original () : me;
36 Drul_array<Direction> break_dirs (dynamic_cast<Item*> (me)->break_status_dir (),
37 dynamic_cast<Item*> (right_col)->break_status_dir ());
38 Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
39 Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
40 ly_scm2link_array (orig->get_object ("right-items")));
42 Grob *system = me->get_system ();
43 Grob *left_col = dynamic_cast<Item*> (me)->get_column ();
45 Drul_array<Grob*> columns (left_col, right_col);
50 for (vsize i = 0; i < items[d].size (); i++)
52 Item *g = dynamic_cast<Item*> (items[d][i]);
54 if (Item *piece = g->find_prebroken_piece (break_dirs[d]))
57 if (g && Separation_item::has_interface (g) && g->get_column () == columns[d])
59 SCM sky_scm = g->get_property ("horizontal-skylines");
60 Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
62 extract_grob_set (g, "elements", elts);
63 Grob *ycommon = common_refpoint_of_array (elts, g, Y_AXIS);
64 Real shift = ycommon->pure_relative_y_coordinate (system, 0, INT_MAX);
66 skylines[d].shift (-shift);
69 skylines[d].merge ((*sky)[-d]);
71 programming_error ("separation item has no skyline");
73 if (d == RIGHT && items[LEFT].size ())
74 skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
76 skylines[d].shift (shift);
80 while (flip (&d) != LEFT);
86 Spacing_interface::minimum_distance (Grob *me, Grob *right)
88 Drul_array<Skyline> skylines = Spacing_interface::skylines (me, right);
90 return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
94 Compute the column of the right-items. This is a big function,
95 since RIGHT-ITEMS may span more columns (eg. if a clef is inserted,
96 this will add a new column to RIGHT-ITEMS. Here we look at the
97 columns, and return the left-most. If there are multiple columns, we
101 Spacing_interface::right_column (Grob *me)
106 Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
108 int min_rank = INT_MAX;
110 for (vsize i = 0; a && i < a->size (); i++)
112 Item *ri = a->item (i);
113 Item *col = ri->get_column ();
115 int rank = Paper_column::get_rank (col);
129 vector<Grob*> &right = a->array_reference ();
130 for (vsize i = right.size (); i--;)
132 if (dynamic_cast<Item *> (right[i])->get_column () != mincol)
133 right.erase (right.begin () + i);
141 Spacing_interface::left_column (Grob *me)
146 return dynamic_cast<Item *> (me)->get_column ();
150 get_note_columns (vector<Grob*> const &elts)
154 for (vsize i = 0; i < elts.size (); i++)
156 if (Note_column::has_interface (elts[i]))
157 ret.push_back (dynamic_cast<Item*> (elts[i]));
158 else if (Separation_item::has_interface (elts[i]))
160 extract_grob_set (elts[i], "elements", more_elts);
161 vector<Item*> ncs = get_note_columns (more_elts);
163 ret.insert (ret.end (), ncs.begin (), ncs.end ());
171 Spacing_interface::right_note_columns (Grob *me)
173 extract_grob_set (me, "right-items", elts);
174 return get_note_columns (elts);
178 Spacing_interface::left_note_columns (Grob *me)
180 extract_grob_set (me, "left-items", elts);
181 return get_note_columns (elts);
185 Try to find the break-aligned symbol that belongs on the D-side
186 of ME, sticking out in direction -D. The x size is put in LAST_EXT
189 Spacing_interface::extremal_break_aligned_grob (Grob *me,
195 last_ext->set_empty ();
198 extract_grob_set (me, d == LEFT ? "left-break-aligned" : "right-break-aligned", elts);
200 for (vsize i = elts.size (); i--;)
202 Item *break_item = dynamic_cast<Item*> (elts[i]);
204 if (break_item->break_status_dir () != break_dir)
205 break_item = break_item->find_prebroken_piece (break_dir);
207 if (!break_item || !scm_is_pair (break_item->get_property ("space-alist")))
211 col = dynamic_cast<Item*> (elts[0])->get_column ()->find_prebroken_piece (break_dir);
213 Interval ext = break_item->extent (col, X_AXIS);
219 || (last_grob && d * (ext[-d]- (*last_ext)[-d]) < 0))
222 last_grob = break_item;
230 ADD_INTERFACE (Spacing_interface,
231 "This object calculates the desired and minimum distances between two columns.",