]> git.donarmstrong.com Git - lilypond.git/blob - lily/span-bar.cc
* lily/system.cc (do_derived_mark): don't mark from object_alist_
[lilypond.git] / lily / span-bar.cc
1 /*
2   span-bar.cc -- implement Span_bar
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "span-bar.hh"
10
11 #include "font-interface.hh"
12 #include "dimensions.hh"
13 #include "output-def.hh"
14 #include "stencil.hh"
15 #include "warn.hh"
16 #include "axis-group-interface.hh"
17 #include "bar-line.hh"
18 #include "grob.hh"
19
20 void
21 Span_bar::add_bar (Grob *me, Grob *b)
22 {
23   Pointer_group_interface::add_grob (me, ly_symbol2scm ("elements"), b);
24
25   me->add_dependency (b);
26 }
27
28 MAKE_SCHEME_CALLBACK (Span_bar, print, 1);
29
30 /* Limitations/Bugs:
31
32 (1) Elements from 'me->get_object ("elements")' must be
33 ordered according to their y coordinates relative to their common
34 axis group parent.  Otherwise, the computation goes mad.
35
36 (2) This method depends on bar_engraver not being removed from
37 staff context.  If bar_engraver is removed, the size of the staff
38 lines is evaluated as 0, which results in a solid span bar line
39 with faulty y coordinate. */
40
41 /* This routine was originally by Juergen Reuter, but it was a on the
42    bulky side. Rewritten by Han-Wen. */
43 SCM
44 Span_bar::print (SCM smobbed_me)
45 {
46   Grob *me = unsmob_grob (smobbed_me);
47   extract_grob_set (me, "elements", elements);
48   Grob *refp = common_refpoint_of_array (elements, me, Y_AXIS);
49
50   Span_bar::evaluate_glyph (me);
51   SCM glyph = me->get_property ("glyph");
52
53   /* glyph may not be a string, when ME is killed by Hara Kiri in
54      between. */
55   if (!scm_is_string (glyph))
56     return SCM_EOL;
57
58   String glyph_string = ly_scm2string (glyph);
59
60   /* compose span_bar_mol */
61   Array<Interval> extents;
62   Grob *model_bar = 0;
63   for (int i = elements.size (); i--;)
64     {
65       Grob *bar = elements[i];
66       Interval ext = bar->extent (refp, Y_AXIS);
67       if (ext.is_empty ())
68         continue;
69
70       extents.push (ext);
71       model_bar = bar;
72     }
73
74   if (!model_bar)
75     model_bar = me;
76   
77   extents.sort (&Interval::left_comparison);
78
79   Stencil span_bar;
80   for (int i = 1; i < extents.size (); i ++)
81     {
82       Interval prev_extent = extents[i-1];
83       Interval ext = extents[i]; 
84       if (!prev_extent.is_empty ())
85         {
86           Interval l (prev_extent [UP],
87                       ext[DOWN]);
88
89           if (l.is_empty ())
90             {
91               /* There is overlap between the bar lines.  Do nothing. */
92             }
93           else
94             {
95               Stencil interbar = Bar_line::compound_barline (model_bar,
96                                                              glyph_string,
97                                                              l.length (),
98                                                              false);
99               interbar.translate_axis (l.center (), Y_AXIS);
100               span_bar.add_stencil (interbar);
101             }
102         }
103       prev_extent = ext;
104     }
105
106   span_bar.translate_axis (- me->relative_coordinate (refp, Y_AXIS),
107                                Y_AXIS);
108
109   return span_bar.smobbed_copy ();
110 }
111
112 MAKE_SCHEME_CALLBACK (Span_bar, width_callback, 2);
113 SCM
114 Span_bar::width_callback (SCM element_smob, SCM scm_axis)
115 {
116   Grob *se = unsmob_grob (element_smob);
117   (void) scm_axis;
118
119   assert ( (Axis) scm_to_int (scm_axis) == X_AXIS);
120   String gl = ly_scm2string (se->get_property ("glyph"));
121
122   /*
123     urg.
124   */
125   Stencil m = Bar_line::compound_barline (se, gl, 40 PT, false);
126
127   return ly_interval2scm (m.extent (X_AXIS));
128 }
129
130 MAKE_SCHEME_CALLBACK (Span_bar, before_line_breaking, 1);
131 SCM
132 Span_bar::before_line_breaking (SCM smob)
133 {
134   Grob *g = unsmob_grob (smob);
135   evaluate_empty (g);
136   evaluate_glyph (g);
137
138   /* No need to call Bar_line::before_line_breaking (), because the info
139      in ELEMENTS already has been procced by
140      Bar_line::before_line_breaking (). */
141   return SCM_UNSPECIFIED;
142 }
143
144 MAKE_SCHEME_CALLBACK (Span_bar, center_on_spanned_callback, 2);
145
146 SCM
147 Span_bar::center_on_spanned_callback (SCM element_smob, SCM axis)
148 {
149   Grob *me = unsmob_grob (element_smob);
150   (void) axis;
151   assert (scm_to_int (axis) == Y_AXIS);
152   Interval i (get_spanned_interval (me));
153
154   /* Bar_line::print delivers a barline of y-extent (-h/2, h/2), so
155      we have to translate ourselves to be in the center of the
156      interval that we span. */
157   if (i.is_empty ())
158     {
159       me->suicide ();
160       return scm_make_real (0.0);
161     }
162
163   return scm_make_real (i.center ());
164 }
165
166 void
167 Span_bar::evaluate_empty (Grob *me)
168 {
169   /* TODO: filter all hara-kiried out of ELEMENS list, and then
170      optionally do suicide. Call this cleanage function from
171      center_on_spanned_callback () as well. */
172
173   extract_grob_set (me, "elements", elements);
174   if (elements.is_empty ())
175     {
176       me->suicide ();
177     }
178 }
179
180 void
181 Span_bar::evaluate_glyph (Grob *me)
182 {
183   SCM gl = me->get_property ("glyph");
184
185   if (scm_is_string (gl))
186     return;
187
188   extract_grob_set (me, "elements", elements);
189   for (int i = elements.size();
190        i-- && !scm_is_string (gl); )
191     {
192       gl = elements[i]->get_property ("glyph");
193     }
194
195   if (!scm_is_string (gl))
196     {
197       me->suicide ();
198       return;
199     }
200
201   String type = ly_scm2string (gl);
202   if (type == "|:")
203     {
204       type = ".|";
205     }
206   else if (type == ":|")
207     {
208       type = "|.";
209     }
210   else if (type == ":|:")
211     {
212       type = ".|.";
213     }
214
215   gl = scm_makfrom0str (type.to_str0 ());
216   if (scm_equal_p (me->get_property ("glyph"), gl)
217       != SCM_BOOL_T)
218     me->set_property ("glyph", gl);
219 }
220
221 Interval
222 Span_bar::get_spanned_interval (Grob *me)
223 {
224   return ly_scm2interval (Axis_group_interface::group_extent_callback
225                           (me->self_scm (), scm_int2num (Y_AXIS)));
226 }
227
228 MAKE_SCHEME_CALLBACK (Span_bar, get_bar_size, 1);
229 SCM
230 Span_bar::get_bar_size (SCM smob)
231 {
232   Grob *me = unsmob_grob (smob);
233   Interval iv (get_spanned_interval (me));
234   if (iv.is_empty ())
235     {
236       /* This happens if the bars are hara-kiried from under us. */
237       me->suicide ();
238       return scm_make_real (-1);
239     }
240   return scm_make_real (iv.length ());
241 }
242
243 ADD_INTERFACE (Span_bar, "span-bar-interface",
244                "A bar line that spanned between other barlines. This interface is "
245                " used for  bar lines that connect different staves.",
246                "elements");
247