]> git.donarmstrong.com Git - lilypond.git/blob - lily/span-bar.cc
Update source file headers. Fixes using standard GNU package conventions.
[lilypond.git] / lily / span-bar.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
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 "span-bar.hh"
21
22 #include "font-interface.hh"
23 #include "dimensions.hh"
24 #include "output-def.hh"
25 #include "stencil.hh"
26 #include "warn.hh"
27 #include "axis-group-interface.hh"
28 #include "bar-line.hh"
29 #include "grob.hh"
30 #include "pointer-group-interface.hh"
31
32 void
33 Span_bar::add_bar (Grob *me, Grob *b)
34 {
35   Pointer_group_interface::add_grob (me, ly_symbol2scm ("elements"), b);
36 }
37
38 MAKE_SCHEME_CALLBACK (Span_bar, print, 1);
39
40 /* Limitations/Bugs:
41
42 (1) Elements from 'me->get_object ("elements")' must be
43 ordered according to their y coordinates relative to their common
44 axis group parent.  Otherwise, the computation goes mad.
45
46 (2) This method depends on bar_engraver not being removed from
47 staff context.  If bar_engraver is removed, the size of the staff
48 lines is evaluated as 0, which results in a solid span bar line
49 with faulty y coordinate. */
50
51 /* This routine was originally by Juergen Reuter, but it was a on the
52    bulky side. Rewritten by Han-Wen. */
53 SCM
54 Span_bar::print (SCM smobbed_me)
55 {
56   Grob *me = unsmob_grob (smobbed_me);
57   extract_grob_set (me, "elements", elements);
58   Grob *refp = common_refpoint_of_array (elements, me, Y_AXIS);
59
60   SCM glyph = me->get_property ("glyph-name");
61
62   /* glyph may not be a string, when ME is killed by Hara Kiri in
63      between. */
64   if (!scm_is_string (glyph))
65     return SCM_EOL;
66
67   string glyph_string = ly_scm2string (glyph);
68
69   /* compose span_bar_mol */
70   vector<Interval> extents;
71   vector<bool> make_span_bar;
72   Grob *model_bar = 0;
73   for (vsize i = elements.size (); i--;)
74     {
75       Grob *bar = elements[i];
76       Interval ext = Bar_line::bar_y_extent (bar, refp);
77       if (ext.is_empty ())
78         continue;
79
80       extents.push_back (ext);
81       make_span_bar.push_back (to_boolean (bar->get_property ("allow-span-bar")));
82       model_bar = bar;
83     }
84
85   if (!model_bar)
86     model_bar = me;
87
88   vector_sort (extents, Interval::left_less);
89
90   Stencil span_bar;
91   for (vsize i = 1; i < extents.size (); i++)
92     {
93       Interval prev_extent = extents[i - 1];
94       Interval ext = extents[i];
95       if (!prev_extent.is_empty ())
96         {
97           Interval l (prev_extent [UP],
98                       ext[DOWN]);
99
100           if (l.is_empty () || !make_span_bar[i])
101             {
102               /* There is overlap between the bar lines.  Do nothing. */
103             }
104           else
105             {
106               Stencil interbar = Bar_line::compound_barline (model_bar,
107                                                              glyph_string,
108                                                              l.length (),
109                                                              false);
110               interbar.translate_axis (l.center (), Y_AXIS);
111               span_bar.add_stencil (interbar);
112             }
113         }
114       prev_extent = ext;
115     }
116
117   span_bar.translate_axis (- me->relative_coordinate (refp, Y_AXIS),
118                            Y_AXIS);
119
120   return span_bar.smobbed_copy ();
121 }
122
123 MAKE_SCHEME_CALLBACK (Span_bar, width, 1);
124 SCM
125 Span_bar::width (SCM smob)
126 {
127   Grob *me = unsmob_grob (smob);
128   SCM gn = me->get_property ("glyph-name");
129   if (!me->is_live ())
130     return ly_interval2scm (Interval ());
131   
132   string gl = ly_scm2string (gn);
133
134   /*
135     urg.
136   */
137   Stencil m = Bar_line::compound_barline (me, gl, 40 PT, false);
138
139   return ly_interval2scm (m.extent (X_AXIS));
140 }
141
142 MAKE_SCHEME_CALLBACK (Span_bar, before_line_breaking, 1);
143 SCM
144 Span_bar::before_line_breaking (SCM smob)
145 {
146   Grob *me = unsmob_grob (smob);
147   extract_grob_set (me, "elements", elements);
148   if (elements.empty ())
149     me->suicide ();
150
151   return SCM_UNSPECIFIED;
152 }
153
154 MAKE_SCHEME_CALLBACK (Span_bar, center_on_spanned_callback, 1);
155
156 SCM
157 Span_bar::center_on_spanned_callback (SCM smob)
158 {
159   Grob *me = unsmob_grob (smob);
160   Interval i (get_spanned_interval (me));
161
162   /* Bar_line::print delivers a barline of y-extent (-h/2, h/2), so
163      we have to translate ourselves to be in the center of the
164      interval that we span. */
165   if (i.is_empty ())
166     {
167       me->suicide ();
168       return scm_from_double (0.0);
169     }
170
171   return scm_from_double (i.center ());
172 }
173
174
175
176 MAKE_SCHEME_CALLBACK(Span_bar, calc_glyph_name, 1);
177 SCM
178 Span_bar::calc_glyph_name (SCM smob)
179 {
180   Grob *me = unsmob_grob (smob);
181   extract_grob_set (me, "elements", elements);
182   SCM gl = SCM_EOL;
183   for (vsize i = elements.size ();
184        i-- && !scm_is_string (gl);)
185     gl = elements[i]->get_property ("glyph-name");
186
187   if (!scm_is_string (gl))
188     {
189       me->suicide ();
190       return SCM_UNSPECIFIED;
191     }
192
193   string type = ly_scm2string (gl);
194   if (type == "|:")
195     type = ".|";
196   else if (type == ":|")
197     type = "|.";
198   else if (type == ":|:")
199     type = ".|.";
200   else if (type == ":|.|:")
201     type = "|.|";
202   else if (type == ":|.:")
203     type = "|.";
204   else if (type == "'")
205     type = "";
206
207   return ly_string2scm (type);
208 }
209
210 Interval
211 Span_bar::get_spanned_interval (Grob *me)
212 {
213   return ly_scm2interval (Axis_group_interface::generic_group_extent (me, Y_AXIS));
214 }
215
216 MAKE_SCHEME_CALLBACK (Span_bar, calc_bar_size, 1);
217 SCM
218 Span_bar::calc_bar_size (SCM smob)
219 {
220   Grob *me = unsmob_grob (smob);
221   Interval iv (get_spanned_interval (me));
222   if (iv.is_empty ())
223     {
224       /* This happens if the bars are hara-kiried from under us. */
225       me->suicide ();
226       return scm_from_double (-1);
227     }
228   return scm_from_double (iv.length ());
229 }
230
231 ADD_INTERFACE (Span_bar,
232                "A bar line that is spanned between other barlines.  This"
233                " interface is used for bar lines that connect different"
234                " staves.",
235
236                /* properties */
237                "glyph-name "
238                "elements "
239                );
240