2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2007--2015 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);
58 for (LEFT_and_RIGHT (d))
60 for (vsize i = 0; i < items[d].size (); i++)
62 Item *g = dynamic_cast<Item *> (items[d][i]);
64 if (Item *piece = g->find_prebroken_piece (break_dirs[d]))
67 if (g && Separation_item::has_interface (g) && g->get_column () == columns[d])
69 SCM sky_scm = g->get_property ("horizontal-skylines");
70 Skyline_pair *sky = unsmob<Skyline_pair> (sky_scm);
72 extract_grob_set (g, "elements", elts);
73 Grob *ycommon = common_refpoint_of_array (elts, g, Y_AXIS);
74 Real shift = ycommon->pure_relative_y_coordinate (system, 0, INT_MAX);
76 skylines[d].shift (-shift);
79 skylines[d].merge ((*sky)[-d]);
81 programming_error ("separation item has no skyline");
83 if (d == RIGHT && items[LEFT].size ())
84 skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
86 skylines[d].shift (shift);
95 Spacing_interface::minimum_distance (Grob *me, Grob *right)
97 Drul_array<Skyline> skylines = Spacing_interface::skylines (me, right);
99 return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
103 Compute the left-most column of the right-items.
106 Spacing_interface::right_column (Grob *me)
111 Grob_array *a = unsmob<Grob_array> (me->get_object ("right-items"));
113 int min_rank = INT_MAX;
114 for (vsize i = 0; a && i < a->size (); i++)
116 Item *ri = a->item (i);
117 Item *col = ri->get_column ();
119 int rank = Paper_column::get_rank (col);
132 Spacing_interface::left_column (Grob *me)
137 return dynamic_cast<Item *> (me)->get_column ();
140 static vector<Item *>
141 get_note_columns (vector<Grob *> const &elts)
145 for (vsize i = 0; i < elts.size (); i++)
147 if (Note_column::has_interface (elts[i]))
148 ret.push_back (dynamic_cast<Item *> (elts[i]));
149 else if (Separation_item::has_interface (elts[i]))
151 extract_grob_set (elts[i], "elements", more_elts);
152 vector<Item *> ncs = get_note_columns (more_elts);
154 ret.insert (ret.end (), ncs.begin (), ncs.end ());
162 Spacing_interface::right_note_columns (Grob *me)
164 extract_grob_set (me, "right-items", elts);
165 return get_note_columns (elts);
169 Spacing_interface::left_note_columns (Grob *me)
171 extract_grob_set (me, "left-items", elts);
172 return get_note_columns (elts);
176 Try to find the break-aligned symbol that belongs on the D-side
177 of ME, sticking out in direction -D. The x size is put in LAST_EXT
180 Spacing_interface::extremal_break_aligned_grob (Grob *me,
186 last_ext->set_empty ();
189 extract_grob_set (me, d == LEFT ? "left-break-aligned" : "right-break-aligned", elts);
191 for (vsize i = elts.size (); i--;)
193 Item *break_item = dynamic_cast<Item *> (elts[i]);
195 if (break_item->break_status_dir () != break_dir)
196 break_item = break_item->find_prebroken_piece (break_dir);
198 if (!break_item || !scm_is_pair (break_item->get_property ("space-alist")))
202 col = dynamic_cast<Item *> (elts[0])->get_column ()->find_prebroken_piece (break_dir);
204 Interval ext = break_item->extent (col, X_AXIS);
210 || (last_grob && d * (ext[-d] - (*last_ext)[-d]) < 0))
213 last_grob = break_item;
220 ADD_INTERFACE (Spacing_interface,
221 "This object calculates the desired and minimum distances"
222 " between two columns.",