2 line-spanner.cc -- implement Line_spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2007 Jan Nieuwenhuizen <janneke@gnu.org>
9 #include "line-spanner.hh"
13 #include "output-def.hh"
14 #include "paper-column.hh"
15 #include "staff-symbol-referencer.hh"
16 #include "font-interface.hh"
18 #include "align-interface.hh"
20 #include "line-interface.hh"
22 MAKE_SCHEME_CALLBACK (Line_spanner, after_line_breaking, 1);
24 Line_spanner::after_line_breaking (SCM g)
26 Grob *me = unsmob_grob (g);
27 Spanner *sp = dynamic_cast<Spanner *> (me);
30 We remove the line at the start of the line. For piano voice
31 indicators, it makes no sense to have them at the start of the
34 I'm not sure what the official rules for glissandi are, but
35 usually the 2nd note of the glissando is "exact", so when playing
36 from the start of the line, there is no need to glide.
38 From a typographical p.o.v. this makes sense, since the amount of
39 space left of a note at the start of a line is very small.
44 if (sp->get_bound (LEFT)->break_status_dir ()
45 && !sp->get_bound (RIGHT)->break_status_dir ())
48 Can't do suicide, since this mucks up finding the trend.
50 me->set_property ("transparent", SCM_BOOL_T);
56 Line_spanner::line_stencil (Grob *me,
60 Stencil line = Line_interface::line (me, from, to);
62 if (to_boolean (me->get_property ("arrow")))
63 line.add_stencil (Line_interface::arrows (me, from, to, false, true));
69 Find a common Y parent, which --if found-- should be the
70 fixed-distance alignment.
73 line_spanner_common_parent (Grob *me)
75 Grob *common = find_fixed_alignment_parent (me);
78 common = Staff_symbol_referencer::get_staff_symbol (me);
80 common = common->get_parent (Y_AXIS);
82 common = me->get_parent (Y_AXIS);
89 Warning: this thing is a cross-staff object, so it should have empty Y-dimensions.
91 (If not, you risk that this is called from the staff-alignment
92 routine, via stencil_extent. At this point, the staves aren't
93 separated yet, so it doesn't work cross-staff.
95 (huh? crossable staves have fixed distance? --hwn)
98 MAKE_SCHEME_CALLBACK (Line_spanner, print, 1);
100 Line_spanner::print (SCM smob)
102 Spanner *me = dynamic_cast<Spanner *> (unsmob_grob (smob));
104 Drul_array<Item *> bound (me->get_bound (LEFT),
105 me->get_bound (RIGHT));
107 Real gap = robust_scm2double (me->get_property ("gap"), 0.0);
109 Offset ofxy (gap, 0); /* offset from start point to start of line */
114 Real extra_dy = robust_scm2double (me->get_property ("extra-dy"),
117 if (bound[RIGHT]->break_status_dir ())
119 if (bound[LEFT]->break_status_dir ())
121 programming_error ("line-spanner with two broken ends. Farewell sweet world.");
128 This is hairy. For the normal case, we simply find common
129 parents, and draw a line between the bounds. When two note
130 heads are on different systems, there is no common parent
131 anymore. We have to find the piano-staff object.
134 Spanner *next_sp = me->broken_neighbor (RIGHT);
135 Item *next_bound = next_sp->get_bound (RIGHT);
137 if (next_bound->break_status_dir ())
139 programming_error ("no note heads for the line spanner on next line?"
145 Grob *commonx = bound[LEFT]->common_refpoint (bound[RIGHT], X_AXIS);
146 commonx = me->common_refpoint (commonx, X_AXIS);
148 Grob *next_common_y = line_spanner_common_parent (next_bound);
149 Grob *this_common_y = line_spanner_common_parent (bound[LEFT]);
151 Grob *all_common_y = me->common_refpoint (this_common_y, Y_AXIS);
153 Interval next_ext = next_bound->extent (next_common_y, Y_AXIS);
154 Interval this_ext = bound[LEFT]->extent (this_common_y, Y_AXIS);
156 Real yoff = this_common_y->relative_coordinate (all_common_y, Y_AXIS);
158 Offset p1 (bound[LEFT]->extent (commonx, X_AXIS)[RIGHT],
159 this_ext.center () + yoff - extra_dy / 2);
160 Offset p2 (bound[RIGHT]->extent (commonx, X_AXIS)[LEFT],
161 next_ext.center () + yoff + extra_dy / 2);
164 Real len = dz.length ();
166 Offset dir = dz * (1 / len);
167 dz = (dz.length () - 2 * gap) * dir;
169 Stencil l (line_stencil (me, Offset (0, 0), dz));
171 l.translate (dir * gap + p1
172 - Offset (me->relative_coordinate (commonx, X_AXIS),
173 me->relative_coordinate (all_common_y, Y_AXIS)));
175 return l.smobbed_copy ();
179 Grob *common[] = { me, me };
180 for (int a = X_AXIS; a < NO_AXES; a++)
182 common[a] = me->common_refpoint (bound[RIGHT], Axis (a));
183 common[a] = common[a]->common_refpoint (bound[LEFT], Axis (a));
186 // distance from center to start of line
187 Real off = gap + ((bound[LEFT]->extent (bound[LEFT], X_AXIS).length () * 3) / 4);
189 for (int a = X_AXIS; a < NO_AXES; a++)
193 = + robust_relative_extent (bound[RIGHT], common[X_AXIS], ax).center ()
194 - robust_relative_extent (bound[LEFT], common[X_AXIS], ax).center ();
196 my_off[ax] = me->relative_coordinate (common[a], ax);
197 his_off[ax] = bound[LEFT]->relative_coordinate (common[a], ax);
200 ofxy = dxy * (off / dxy.length ()) ;
203 dxy[Y_AXIS] += extra_dy;
205 Stencil line = line_stencil (me, Offset (0, 0), dxy);
207 line.translate_axis (bound[LEFT]->extent (bound[LEFT], X_AXIS).length () / 2, X_AXIS);
208 line.translate (ofxy - my_off + his_off + Offset (0, -extra_dy/2));
209 return line.smobbed_copy ();
213 ADD_INTERFACE (Line_spanner,
214 "Generic line drawn between two objects, e.g. for use with glissandi.\n"
215 "The property @code{style} can be @code{line}, "
216 "@code{dashed-line}, @code{trill}, \n"
217 "@code{dotted-line} or @code{zigzag}.\n"