2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2007--2009 Joe Neeman <joeneeman@gmail.com>
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.
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.
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/>.
20 #include "spacing-interface.hh"
23 #include "grob-array.hh"
25 #include "note-column.hh"
26 #include "pointer-group-interface.hh"
27 #include "paper-column.hh"
28 #include "separation-item.hh"
30 #include "skyline-pair.hh"
33 /* return the right-pointing skyline of the left-items and the left-pointing
34 skyline of the right-items (with the skyline of the left-items in
37 Spacing_interface::skylines (Grob *me, Grob *right_col)
39 /* the logic here is a little convoluted.
40 A {Staff,Note}_spacing doesn't copy left-items when it clones,
41 so in order to find the separation items, we need to use the original
42 spacing grob. But once we find the separation items, we need to get back
46 Grob *orig = me->original () ? me->original () : me;
47 Drul_array<Direction> break_dirs (dynamic_cast<Item*> (me)->break_status_dir (),
48 dynamic_cast<Item*> (right_col)->break_status_dir ());
49 Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
50 Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
51 ly_scm2link_array (orig->get_object ("right-items")));
53 Grob *system = me->get_system ();
54 Grob *left_col = dynamic_cast<Item*> (me)->get_column ();
56 Drul_array<Grob*> columns (left_col, right_col);
61 for (vsize i = 0; i < items[d].size (); i++)
63 Item *g = dynamic_cast<Item*> (items[d][i]);
65 if (Item *piece = g->find_prebroken_piece (break_dirs[d]))
68 if (g && Separation_item::has_interface (g) && g->get_column () == columns[d])
70 SCM sky_scm = g->get_property ("horizontal-skylines");
71 Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
73 extract_grob_set (g, "elements", elts);
74 Grob *ycommon = common_refpoint_of_array (elts, g, Y_AXIS);
75 Real shift = ycommon->pure_relative_y_coordinate (system, 0, INT_MAX);
77 skylines[d].shift (-shift);
80 skylines[d].merge ((*sky)[-d]);
82 programming_error ("separation item has no skyline");
84 if (d == RIGHT && items[LEFT].size ())
85 skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
87 skylines[d].shift (shift);
91 while (flip (&d) != LEFT);
97 Spacing_interface::minimum_distance (Grob *me, Grob *right)
99 Drul_array<Skyline> skylines = Spacing_interface::skylines (me, right);
101 return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
105 Compute the left-most column of the right-items.
108 Spacing_interface::right_column (Grob *me)
113 Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
115 int min_rank = INT_MAX;
116 for (vsize i = 0; a && i < a->size (); i++)
118 Item *ri = a->item (i);
119 Item *col = ri->get_column ();
121 int rank = Paper_column::get_rank (col);
134 Spacing_interface::left_column (Grob *me)
139 return dynamic_cast<Item *> (me)->get_column ();
143 get_note_columns (vector<Grob*> const &elts)
147 for (vsize i = 0; i < elts.size (); i++)
149 if (Note_column::has_interface (elts[i]))
150 ret.push_back (dynamic_cast<Item*> (elts[i]));
151 else if (Separation_item::has_interface (elts[i]))
153 extract_grob_set (elts[i], "elements", more_elts);
154 vector<Item*> ncs = get_note_columns (more_elts);
156 ret.insert (ret.end (), ncs.begin (), ncs.end ());
164 Spacing_interface::right_note_columns (Grob *me)
166 extract_grob_set (me, "right-items", elts);
167 return get_note_columns (elts);
171 Spacing_interface::left_note_columns (Grob *me)
173 extract_grob_set (me, "left-items", elts);
174 return get_note_columns (elts);
178 Try to find the break-aligned symbol that belongs on the D-side
179 of ME, sticking out in direction -D. The x size is put in LAST_EXT
182 Spacing_interface::extremal_break_aligned_grob (Grob *me,
188 last_ext->set_empty ();
191 extract_grob_set (me, d == LEFT ? "left-break-aligned" : "right-break-aligned", elts);
193 for (vsize i = elts.size (); i--;)
195 Item *break_item = dynamic_cast<Item*> (elts[i]);
197 if (break_item->break_status_dir () != break_dir)
198 break_item = break_item->find_prebroken_piece (break_dir);
200 if (!break_item || !scm_is_pair (break_item->get_property ("space-alist")))
204 col = dynamic_cast<Item*> (elts[0])->get_column ()->find_prebroken_piece (break_dir);
206 Interval ext = break_item->extent (col, X_AXIS);
212 || (last_grob && d * (ext[-d]- (*last_ext)[-d]) < 0))
215 last_grob = break_item;
223 ADD_INTERFACE (Spacing_interface,
224 "This object calculates the desired and minimum distances"
225 " between two columns.",