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