1 /*
2 This file is part of LilyPond, the GNU music typesetter.
3
4 Copyright (C) 2009--2020 Joe Neeman <joeneeman@gmail.com>
5
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.
10
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.
15
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/>.
18 */
19
20 #include "staff-grouper-interface.hh"
21
22 #include "hara-kiri-group-spanner.hh"
23 #include "page-layout-problem.hh"
24 #include "pointer-group-interface.hh"
25
26 using std::vector;
27
28 // Find the furthest staff in the given direction whose x-extent overlaps with
29 // the given interval.
30 Grob *
get_extremal_staff(Grob * me,Grob * refpoint,Direction dir,Interval const & iv)31 Staff_grouper_interface::get_extremal_staff (Grob *me, Grob *refpoint, Direction dir, Interval const &iv)
32 {
33 // N.B. This is intended to work for a VerticalAlignment grob even though
34 // VerticalAlignment does not have the staff-grouper interface. StaffGrouper
35 // and VerticalAlignment grobs are both created by the
36 // Vertical_align_engraver and contain elements meeting a common set of
37 // criteria, yet they are not described as having a common interface. Should
38 // we treat staff grouping as a subset of vertical alignment? Should we
39 // factor out the shared subset of features into a new interface?
40
41 extract_grob_set (me, "elements", elts);
42 vsize start = (dir == UP) ? 0 : elts.size () - 1;
43 vsize end = (dir == UP) ? elts.size () : VPOS;
44 for (vsize i = start; i != end; i += dir)
45 {
46 if (has_interface<Hara_kiri_group_spanner> (elts[i]))
47 Hara_kiri_group_spanner::consider_suicide (elts[i]);
48
49 Interval intersection = elts[i]->extent (refpoint, X_AXIS);
50 intersection.intersect (iv);
51 if (elts[i]->is_live () && !intersection.is_empty ())
52 return elts[i];
53 }
54 return 0;
55 }
56
57 /* Checks whether the child grob is in the "interior" of this staff-grouper.
58 This is the case if the next spaceable, living child after the given one
59 belongs to the group.
60 */
61 bool
maybe_pure_within_group(Grob * me,Grob * child,bool pure,int start,int end)62 Staff_grouper_interface::maybe_pure_within_group (Grob *me, Grob *child, bool pure, int start, int end)
63 {
64 extract_grob_set (me, "elements", elts);
65
66 vector<Grob *>::const_iterator i = find (elts, child);
67
68 if (i == elts.end ())
69 return false;
70
71 for (++i; i != elts.end (); ++i)
72 if (Page_layout_problem::is_spaceable (*i)
73 && ((pure && !Hara_kiri_group_spanner::request_suicide (*i, start, end))
74 || (!pure && (*i)->is_live ())))
75 return me == unsmob <Grob> (get_object (*i, "staff-grouper"));
76
77 // If there was no spaceable, living child after me, I don't
78 // count as within the group.
79 return false;
80 }
81
82 ADD_INTERFACE (Staff_grouper_interface,
83 "A grob that collects staves together.",
84
85 /* properties */
86 "staff-staff-spacing "
87 "staffgroup-staff-spacing "
88 );
89
90