2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2010 Han-Wen Nienhuys <hanwen@xs4all.nl>
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.
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.
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/>.
24 #include "directional-element-interface.hh"
25 #include "font-interface.hh"
26 #include "grob-array.hh"
28 #include "note-head.hh"
29 #include "output-def.hh"
30 #include "paper-column.hh"
31 #include "pointer-group-interface.hh"
32 #include "rhythmic-head.hh"
34 #include "staff-symbol-referencer.hh"
36 #include "text-interface.hh"
37 #include "tie-column.hh"
38 #include "tie-configuration.hh"
39 #include "tie-formatting-problem.hh"
41 #include "semi-tie-column.hh"
45 Tie::less (Grob
*const &s1
, Grob
*const &s2
)
47 return Tie::get_position (s1
) < Tie::get_position (s2
);
51 Tie::set_head (Grob
*me
, Direction d
, Grob
*h
)
53 dynamic_cast<Spanner
*> (me
)->set_bound (d
, h
);
57 Tie::head (Grob
*me
, Direction d
)
59 if (is_direction (me
->get_property ("head-direction")))
61 Direction hd
= to_dir (me
->get_property ("head-direction"));
64 ? unsmob_grob (me
->get_object ("note-head"))
68 Item
*it
= dynamic_cast<Spanner
*> (me
)->get_bound (d
);
69 if (Note_head::has_interface (it
))
76 Tie::get_column_rank (Grob
*me
, Direction d
)
78 Spanner
*span
= dynamic_cast<Spanner
*> (me
);
79 Grob
*h
= head (me
, d
);
81 h
= span
->get_bound (d
);
83 Grob
*col
= dynamic_cast<Item
*> (h
)->get_column ();
84 return Paper_column::get_rank (col
);
88 Tie::get_position (Grob
*me
)
93 Grob
*h
= head (me
, d
);
95 return (int) rint (Staff_symbol_referencer::get_position (h
));
97 while (flip (&d
) != LEFT
);
101 TODO: this is theoretically possible for ties across more than 2
102 systems.. We should look at the first broken copy.
105 programming_error ("Tie without heads. Suicide");
111 Default: Put the tie oppositie of the stem [Wanske p231]
113 In case of chords: Tie_column takes over
115 The direction of the Tie is more complicated (See [Ross] p136 and
118 (what about linebreaks? )
121 Tie::get_default_dir (Grob
*me
)
123 Drul_array
<Grob
*> stems
;
127 Grob
*one_head
= head (me
, d
);
128 if (!one_head
&& dynamic_cast<Spanner
*> (me
))
129 one_head
= Tie::head (dynamic_cast<Spanner
*> (me
)->broken_neighbor (d
), d
);
131 Grob
*stem
= one_head
? Rhythmic_head::get_stem (one_head
) : 0;
133 stem
= Stem::is_invisible (stem
) ? 0 : stem
;
137 while (flip (&d
)!= LEFT
);
139 if (stems
[LEFT
] && stems
[RIGHT
])
141 if (get_grob_direction (stems
[LEFT
]) == UP
142 && get_grob_direction (stems
[RIGHT
]) == UP
)
145 else if (stems
[LEFT
] || stems
[RIGHT
])
147 Grob
*s
= stems
[LEFT
] ? stems
[LEFT
] : stems
[RIGHT
];
148 return -get_grob_direction (s
);
150 else if (int p
= get_position (me
))
151 return Direction (sign (p
));
153 return to_dir (me
->get_property("neutral-direction"));
157 MAKE_SCHEME_CALLBACK (Tie
, calc_direction
, 1);
159 Tie::calc_direction (SCM smob
)
161 Grob
*me
= unsmob_grob (smob
);
162 Grob
*yparent
= me
->get_parent (Y_AXIS
);
163 if ((Tie_column::has_interface (yparent
)
164 || Semi_tie_column::has_interface (yparent
))
165 && unsmob_grob_array (yparent
->get_object ("ties"))
166 // && unsmob_grob_array (yparent->get_object ("ties"))->size () > 1
169 /* trigger positioning. */
170 (void) yparent
->get_property ("positioning-done");
172 return me
->get_property_data ("direction");
175 return scm_from_int (Tie::get_default_dir (me
));
180 Tie::get_default_control_points (Grob
*me_grob
)
182 Spanner
*me
= dynamic_cast<Spanner
*> (me_grob
);
184 common
= me
->get_bound (LEFT
)->common_refpoint (common
, X_AXIS
);
185 common
= me
->get_bound (RIGHT
)->common_refpoint (common
, X_AXIS
);
187 Tie_formatting_problem problem
;
188 problem
.from_tie (me
);
190 Tie_specification spec
= problem
.get_tie_specification (0);
195 Ties_configuration conf
196 = problem
.generate_optimal_configuration ();
198 return get_control_points (me
, problem
.common_x_refpoint (),
199 conf
[0], problem
.details_
);
203 Tie::get_control_points (Grob
*me
,
205 Tie_configuration
const &conf
,
206 Tie_details
const &details
209 Bezier b
= conf
.get_transformed_bezier (details
);
210 b
.translate (Offset (- me
->relative_coordinate (common
, X_AXIS
), 0));
212 SCM controls
= SCM_EOL
;
213 for (int i
= 4; i
--;)
215 if (!b
.control_
[i
].is_sane ())
216 programming_error ("Insane offset");
217 controls
= scm_cons (ly_offset2scm (b
.control_
[i
]), controls
);
222 MAKE_SCHEME_CALLBACK (Tie
, calc_control_points
, 1);
224 Tie::calc_control_points (SCM smob
)
226 Grob
*me
= unsmob_grob (smob
);
228 Grob
*yparent
= me
->get_parent (Y_AXIS
);
229 if ((Tie_column::has_interface (yparent
)
230 || Semi_tie_column::has_interface (yparent
))
231 && unsmob_grob_array (yparent
->get_object ("ties")))
233 extract_grob_set (yparent
, "ties", ties
);
234 if (me
->original() && ties
.size() == 1
235 && !to_dir (me
->get_property_data ("direction")))
237 assert (ties
[0] == me
);
238 set_grob_direction (me
, Tie::get_default_dir (me
));
241 /* trigger positioning. */
242 (void) yparent
->get_property ("positioning-done");
245 SCM cp
= me
->get_property_data ("control-points");
246 if (!scm_is_pair (cp
))
248 cp
= get_default_control_points (me
);
255 TODO: merge with Slur::print.
257 MAKE_SCHEME_CALLBACK (Tie
, print
, 1);
259 Tie::print (SCM smob
)
261 Grob
*me
= unsmob_grob (smob
);
263 SCM cp
= me
->get_property ("control-points");
265 Real staff_thick
= Staff_symbol_referencer::line_thickness (me
);
266 Real base_thick
= staff_thick
* robust_scm2double (me
->get_property ("thickness"), 1);
267 Real line_thick
= staff_thick
* robust_scm2double (me
->get_property ("line-thickness"), 1);
271 for (SCM s
= cp
; scm_is_pair (s
); s
= scm_cdr (s
))
273 b
.control_
[i
] = ly_scm2offset (scm_car (s
));
279 SCM dash_definition
= me
->get_property ("dash-definition");
281 get_grob_direction (me
) * base_thick
,
285 #if DEBUG_TIE_SCORING
286 SCM annotation
= me
->get_property ("annotation");
287 if (!scm_is_string (annotation
))
289 SCM debug
= me
->layout ()->lookup_variable (ly_symbol2scm ("debug-tie-scoring"));
290 if (to_boolean (debug
))
291 annotation
= me
->get_property ("quant-score");
293 if (scm_is_string (annotation
))
296 SCM properties
= Font_interface::text_font_alist_chain (me
);
298 Stencil tm
= *unsmob_stencil (Text_interface::interpret_markup
299 (me
->layout ()->self_scm (), properties
,
301 tm
.translate (Offset (b
.control_
[3][X_AXIS
] + 0.5,
302 b
.control_
[0][Y_AXIS
] * 2));
303 tm
= tm
.in_color (1, 0, 0);
306 It would be nice if we could put this in a different layer,
307 but alas, this must be done with a Tie override.
313 return a
.smobbed_copy ();
317 "A horizontal curve connecting two noteheads.",
321 "avoid-slur " // UGH.