2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2011 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"
44 Tie::less (Grob
*const &s1
, Grob
*const &s2
)
46 return Tie::get_position (s1
) < Tie::get_position (s2
);
50 Tie::set_head (Grob
*me
, Direction d
, Grob
*h
)
52 dynamic_cast<Spanner
*> (me
)->set_bound (d
, h
);
56 Tie::head (Grob
*me
, Direction d
)
58 if (is_direction (me
->get_property ("head-direction")))
60 Direction hd
= to_dir (me
->get_property ("head-direction"));
63 ? unsmob_grob (me
->get_object ("note-head"))
67 Item
*it
= dynamic_cast<Spanner
*> (me
)->get_bound (d
);
68 if (Note_head::has_interface (it
))
75 Tie::get_column_rank (Grob
*me
, Direction d
)
78 Spanner
*span
= dynamic_cast<Spanner
*> (me
);
80 col
= dynamic_cast<Item
*> (me
)->get_column ();
83 Grob
*h
= head (me
, d
);
85 h
= span
->get_bound (d
);
87 col
= dynamic_cast<Item
*> (h
)->get_column ();
89 return Paper_column::get_rank (col
);
93 Tie::get_position (Grob
*me
)
98 Grob
*h
= head (me
, d
);
100 return (int) rint (Staff_symbol_referencer::get_position (h
));
102 while (flip (&d
) != LEFT
);
105 TODO: this is theoretically possible for ties across more than 2
106 systems.. We should look at the first broken copy.
109 programming_error ("Tie without heads. Suicide");
115 Default: Put the tie oppositie of the stem [Wanske p231]
117 In case of chords: Tie_column takes over
119 The direction of the Tie is more complicated (See [Ross] p136 and
122 (what about linebreaks? )
125 Tie::get_default_dir (Grob
*me
)
127 Drul_array
<Grob
*> stems
;
131 Grob
*one_head
= head (me
, d
);
132 if (!one_head
&& dynamic_cast<Spanner
*> (me
))
133 one_head
= Tie::head (dynamic_cast<Spanner
*> (me
)->broken_neighbor (d
), d
);
135 Grob
*stem
= one_head
? Rhythmic_head::get_stem (one_head
) : 0;
137 stem
= Stem::is_invisible (stem
) ? 0 : stem
;
141 while (flip (&d
) != LEFT
);
143 if (stems
[LEFT
] && stems
[RIGHT
])
145 if (get_grob_direction (stems
[LEFT
]) == UP
146 && get_grob_direction (stems
[RIGHT
]) == UP
)
149 else if (stems
[LEFT
] || stems
[RIGHT
])
151 Grob
*s
= stems
[LEFT
] ? stems
[LEFT
] : stems
[RIGHT
];
152 return -get_grob_direction (s
);
154 else if (int p
= get_position (me
))
155 return Direction (sign (p
));
157 return to_dir (me
->get_property ("neutral-direction"));
160 MAKE_SCHEME_CALLBACK (Tie
, calc_direction
, 1);
162 Tie::calc_direction (SCM smob
)
164 Grob
*me
= unsmob_grob (smob
);
165 Grob
*yparent
= me
->get_parent (Y_AXIS
);
166 if ((Tie_column::has_interface (yparent
)
167 || Semi_tie_column::has_interface (yparent
))
168 && unsmob_grob_array (yparent
->get_object ("ties"))
169 // && unsmob_grob_array (yparent->get_object ("ties"))->size () > 1
172 /* trigger positioning. */
173 (void) yparent
->get_property ("positioning-done");
175 return me
->get_property_data ("direction");
178 return scm_from_int (Tie::get_default_dir (me
));
182 Tie::get_default_control_points (Grob
*me_grob
)
184 Spanner
*me
= dynamic_cast<Spanner
*> (me_grob
);
186 common
= me
->get_bound (LEFT
)->common_refpoint (common
, X_AXIS
);
187 common
= me
->get_bound (RIGHT
)->common_refpoint (common
, X_AXIS
);
189 Tie_formatting_problem problem
;
190 problem
.from_tie (me
);
192 Tie_specification spec
= problem
.get_tie_specification (0);
196 Ties_configuration conf
197 = problem
.generate_optimal_configuration ();
199 return get_control_points (me
, problem
.common_x_refpoint (),
200 conf
[0], problem
.details_
);
204 Tie::get_control_points (Grob
*me
,
206 Tie_configuration
const &conf
,
207 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
));
240 /* trigger positioning. */
241 (void) yparent
->get_property ("positioning-done");
244 SCM cp
= me
->get_property_data ("control-points");
245 if (!scm_is_pair (cp
))
246 cp
= get_default_control_points (me
);
252 TODO: merge with Slur::print.
254 MAKE_SCHEME_CALLBACK (Tie
, print
, 1);
256 Tie::print (SCM smob
)
258 Grob
*me
= unsmob_grob (smob
);
260 SCM cp
= me
->get_property ("control-points");
262 Real staff_thick
= Staff_symbol_referencer::line_thickness (me
);
263 Real base_thick
= staff_thick
* robust_scm2double (me
->get_property ("thickness"), 1);
264 Real line_thick
= staff_thick
* robust_scm2double (me
->get_property ("line-thickness"), 1);
268 for (SCM s
= cp
; scm_is_pair (s
); s
= scm_cdr (s
))
270 b
.control_
[i
] = ly_scm2offset (scm_car (s
));
276 SCM dash_definition
= me
->get_property ("dash-definition");
278 get_grob_direction (me
) * base_thick
,
282 #if DEBUG_TIE_SCORING
283 SCM annotation
= me
->get_property ("annotation");
284 if (scm_is_string (annotation
))
287 SCM properties
= Font_interface::text_font_alist_chain (me
);
289 Stencil tm
= *unsmob_stencil (Text_interface::interpret_markup
290 (me
->layout ()->self_scm (), properties
,
292 tm
.translate (Offset (b
.control_
[3][X_AXIS
] + 0.5,
293 b
.control_
[0][Y_AXIS
] * 2));
294 tm
= tm
.in_color (1, 0, 0);
297 It would be nice if we could put this in a different layer,
298 but alas, this must be done with a Tie override.
304 return a
.smobbed_copy ();
308 "A horizontal curve connecting two noteheads.",
312 "avoid-slur " // UGH.