2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2002--2010 Juergen Reuter <reuter@ipd.uka.de>
5 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 LilyPond is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 LilyPond is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
22 #include "international.hh"
25 #include "output-def.hh"
27 #include "pointer-group-interface.hh"
29 #include "staff-symbol-referencer.hh"
33 TODO: Add support for cubic spline segments.
36 brew_cluster_piece (Grob
*me
, vector
<Offset
> bottom_points
, vector
<Offset
> top_points
)
38 Real blotdiameter
= Staff_symbol_referencer::staff_space (me
) / 2;
40 Real padding
= robust_scm2double (me
->get_property ("padding"), 0.0);
42 Offset vpadding
= Offset (0, padding
);
43 Offset hpadding
= Offset (0.5 * blotdiameter
, 0);
44 Offset hvpadding
= 0.5 * hpadding
+ vpadding
;
46 SCM shape_scm
= me
->get_property ("style");
49 if (scm_is_symbol (shape_scm
))
50 shape
= ly_symbol2string (shape_scm
);
53 programming_error ("#'style should be symbol.");
59 vector
<Offset
> points
;
61 int size
= bottom_points
.size ();
62 if (shape
== "leftsided-stairs")
64 for (int i
= 0; i
< size
- 1; i
++)
67 box
.add_point (bottom_points
[i
] - hvpadding
);
68 box
.add_point (Offset (top_points
[i
+ 1][X_AXIS
],
69 top_points
[i
][Y_AXIS
]) + hvpadding
);
70 out
.add_stencil (Lookup::round_filled_box (box
, blotdiameter
));
73 else if (shape
== "rightsided-stairs")
75 for (int i
= 0; i
< size
- 1; i
++)
78 box
.add_point (Offset (bottom_points
[i
][X_AXIS
],
79 bottom_points
[i
+ 1][Y_AXIS
]) - hvpadding
);
80 box
.add_point (top_points
[i
+ 1] + hvpadding
);
81 out
.add_stencil (Lookup::round_filled_box (box
, blotdiameter
));
84 else if (shape
== "centered-stairs")
86 Real left_xmid
= bottom_points
[0][X_AXIS
];
87 for (int i
= 0; i
< size
- 1; i
++)
90 = 0.5 * (bottom_points
[i
][X_AXIS
] + bottom_points
[i
+ 1][X_AXIS
]);
92 box
.add_point (Offset (left_xmid
, bottom_points
[i
][Y_AXIS
])
94 box
.add_point (Offset (right_xmid
, top_points
[i
][Y_AXIS
])
96 out
.add_stencil (Lookup::round_filled_box (box
, blotdiameter
));
97 left_xmid
= right_xmid
;
99 Real right_xmid
= bottom_points
[size
- 1][X_AXIS
];
101 box
.add_point (Offset (left_xmid
, bottom_points
[size
- 1][Y_AXIS
])
103 box
.add_point (Offset (right_xmid
, top_points
[size
- 1][Y_AXIS
])
105 out
.add_stencil (Lookup::round_filled_box (box
, blotdiameter
));
107 else if (shape
== "ramp")
109 points
.push_back (bottom_points
[0] - vpadding
+ hpadding
);
110 for (int i
= 1; i
< size
- 1; i
++)
111 points
.push_back (bottom_points
[i
] - vpadding
);
112 points
.push_back (bottom_points
[size
- 1] - vpadding
- hpadding
);
113 points
.push_back (top_points
[size
- 1] + vpadding
- hpadding
);
114 for (int i
= size
- 2; i
> 0; i
--)
115 points
.push_back (top_points
[i
] + vpadding
);
116 points
.push_back (top_points
[0] + vpadding
+ hpadding
);
117 out
.add_stencil (Lookup::round_filled_polygon (points
, blotdiameter
));
120 me
->warning (_f ("unknown cluster style `%s'", shape
.c_str ()));
124 MAKE_SCHEME_CALLBACK (Cluster
, calc_cross_staff
, 1);
126 Cluster::calc_cross_staff (SCM smob
)
128 Grob
*me
= unsmob_grob (smob
);
130 extract_grob_set (me
, "columns", cols
);
131 Grob
*commony
= common_refpoint_of_array (cols
, me
, Y_AXIS
);
133 return scm_from_bool (commony
!= me
->get_parent (Y_AXIS
));
136 MAKE_SCHEME_CALLBACK (Cluster
, print
, 1);
138 Cluster::print (SCM smob
)
140 Grob
*me
= unsmob_grob (smob
);
142 Spanner
*spanner
= dynamic_cast<Spanner
*> (me
);
145 me
->programming_error ("Cluster::print (): not a spanner");
149 Item
*left_bound
= spanner
->get_bound (LEFT
);
150 Item
*right_bound
= spanner
->get_bound (RIGHT
);
152 Grob
*commonx
= left_bound
->common_refpoint (right_bound
, X_AXIS
);
154 vector
<Grob
*> const &cols
= extract_grob_array (me
, "columns");
157 me
->warning (_ ("junking empty cluster"));
163 commonx
= common_refpoint_of_array (cols
, commonx
, X_AXIS
);
164 Grob
*commony
= common_refpoint_of_array (cols
, me
, Y_AXIS
);
165 vector
<Offset
> bottom_points
;
166 vector
<Offset
> top_points
;
168 Real left_coord
= left_bound
->relative_coordinate (commonx
, X_AXIS
);
171 TODO: should we move the cluster a little to the right to be in
172 line with the center of the note heads?
175 for (vsize i
= 0; i
< cols
.size (); i
++)
179 Interval yext
= col
->extent (commony
, Y_AXIS
);
181 Real x
= col
->relative_coordinate (commonx
, X_AXIS
) - left_coord
;
182 bottom_points
.push_back (Offset (x
, yext
[DOWN
]));
183 top_points
.push_back (Offset (x
, yext
[UP
]));
187 Across a line break we anticipate on the next pitches.
189 if (Spanner
*next
= spanner
->broken_neighbor (RIGHT
))
191 extract_grob_set (next
, "columns", next_cols
);
192 if (next_cols
.size () > 0)
194 Grob
*next_commony
= common_refpoint_of_array (next_cols
, next
, Y_AXIS
);
195 Grob
*col
= next_cols
[0];
197 Interval v
= col
->extent (next_commony
, Y_AXIS
);
198 Real x
= right_bound
->relative_coordinate (commonx
, X_AXIS
) - left_coord
;
200 bottom_points
.push_back (Offset (x
, v
[DOWN
]));
201 top_points
.push_back (Offset (x
, v
[UP
]));
205 Stencil out
= brew_cluster_piece (me
, bottom_points
, top_points
);
206 out
.translate_axis (- me
->relative_coordinate (commony
, Y_AXIS
), Y_AXIS
);
207 return out
.smobbed_copy ();
210 ADD_INTERFACE (Cluster
,
211 "A graphically drawn musical cluster.\n"
213 "@code{padding} adds to the vertical extent of the shape (top"
216 "The property @code{style} controls the shape of cluster"
217 " segments. Valid values include @code{leftsided-stairs},"
218 " @code{rightsided-stairs}, @code{centered-stairs}, and"
227 struct Cluster_beacon
230 DECLARE_SCHEME_CALLBACK (height
, (SCM
));
231 DECLARE_GROB_INTERFACE ();
234 MAKE_SCHEME_CALLBACK (Cluster_beacon
, height
, 1);
236 Cluster_beacon::height (SCM g
)
238 Grob
*me
= unsmob_grob (g
);
239 Interval v
= robust_scm2interval (me
->get_property ("positions"),
241 return ly_interval2scm (Staff_symbol_referencer::staff_space (me
) * 0.5 * v
);
244 ADD_INTERFACE (Cluster_beacon
,
245 "A place holder for the cluster spanner to determine the"
246 " vertical extents of a cluster spanner at this"