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"
21 /* return the right-pointing skyline of the left-items and the left-pointing
22 skyline of the right-items (with the skyline of the left-items in
25 Spacing_interface::skylines (Grob *me, Grob *right_col)
27 /* the logic here is a little convoluted.
28 A {Staff,Note}_spacing doesn't copy left-items when it clones,
29 so in order to find the separation items, we need to use the original
30 spacing grob. But once we find the separation items, we need to get back
34 Grob *orig = me->original () ? me->original () : me;
35 Drul_array<Direction> break_dirs (dynamic_cast<Item*> (me)->break_status_dir (),
36 dynamic_cast<Item*> (right_col)->break_status_dir ());
37 Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
38 Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
39 ly_scm2link_array (orig->get_object ("right-items")));
44 skylines[d].set_minimum_height (0.0);
46 for (vsize i = 0; i < items[d].size (); i++)
48 Grob *g = items[d][i];
49 if (Item *it = dynamic_cast<Item*> (g))
50 if (Grob *piece = it->find_prebroken_piece (break_dirs[d]))
53 if (Separation_item::has_interface (g))
55 SCM sky_scm = g->get_property ("horizontal-skylines");
56 Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
58 skylines[d].merge ((*sky)[-d]);
60 programming_error ("separation item has no skyline");
62 if (d == RIGHT && items[LEFT].size ())
63 skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
67 while (flip (&d) != LEFT);
73 Spacing_interface::minimum_distance (Grob *me, Grob *right)
75 Drul_array<Skyline> skylines = Spacing_interface::skylines (me, right);
77 return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
81 Compute the column of the right-items. This is a big function,
82 since RIGHT-ITEMS may span more columns (eg. if a clef is inserted,
83 this will add a new column to RIGHT-ITEMS. Here we look at the
84 columns, and return the left-most. If there are multiple columns, we
88 Spacing_interface::right_column (Grob *me)
93 Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
95 int min_rank = INT_MAX;
97 for (vsize i = 0; a && i < a->size (); i++)
99 Item *ri = a->item (i);
100 Item *col = ri->get_column ();
102 int rank = Paper_column::get_rank (col);
116 vector<Grob*> &right = a->array_reference ();
117 for (vsize i = right.size (); i--;)
119 if (dynamic_cast<Item *> (right[i])->get_column () != mincol)
120 right.erase (right.begin () + i);
128 Spacing_interface::left_column (Grob *me)
133 return dynamic_cast<Item *> (me)->get_column ();
137 get_note_columns (vector<Grob*> const &elts)
141 for (vsize i = 0; i < elts.size (); i++)
143 if (Note_column::has_interface (elts[i]))
144 ret.push_back (dynamic_cast<Item*> (elts[i]));
145 else if (Separation_item::has_interface (elts[i]))
147 extract_grob_set (elts[i], "elements", more_elts);
148 vector<Item*> ncs = get_note_columns (more_elts);
150 ret.insert (ret.end (), ncs.begin (), ncs.end ());
158 Spacing_interface::right_note_columns (Grob *me)
160 extract_grob_set (me, "right-items", elts);
161 return get_note_columns (elts);
165 Spacing_interface::left_note_columns (Grob *me)
167 extract_grob_set (me, "left-items", elts);
168 return get_note_columns (elts);
172 Try to find the break-aligned symbol that belongs on the D-side
173 of ME, sticking out in direction -D. The x size is put in LAST_EXT
176 Spacing_interface::extremal_break_aligned_grob (Grob *me,
182 last_ext->set_empty ();
185 extract_grob_set (me, d == LEFT ? "left-break-aligned" : "right-break-aligned", elts);
187 for (vsize i = elts.size (); i--;)
189 Item *break_item = dynamic_cast<Item*> (elts[i]);
191 if (break_item->break_status_dir () != break_dir)
192 break_item = break_item->find_prebroken_piece (break_dir);
194 if (!break_item || !scm_is_pair (break_item->get_property ("space-alist")))
198 col = dynamic_cast<Item*> (elts[0])->get_column ()->find_prebroken_piece (break_dir);
200 Interval ext = break_item->extent (col, X_AXIS);
206 || (last_grob && d * (ext[-d]- (*last_ext)[-d]) < 0))
209 last_grob = break_item;
217 ADD_INTERFACE (Spacing_interface,
218 "This object calculates the desired and minimum distances between two columns.",