2 plet-spanner.cc -- implement Tuplet_bracket
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2001 Jan Nieuwenhuizen <janneke@gnu.org>
14 #include "font-interface.hh"
15 #include "molecule.hh"
16 #include "paper-column.hh"
17 #include "paper-def.hh"
18 #include "text-item.hh"
19 #include "tuplet-spanner.hh"
21 #include "note-column.hh"
22 #include "dimensions.hh"
23 #include "group-interface.hh"
24 #include "directional-element-interface.hh"
26 #include "staff-symbol-referencer.hh"
30 staff-line collisions for horizontal tuplet brackets.
36 Tuplet_bracket::set_interface (Grob
*me
)
38 me
->set_interface (ly_symbol2scm ("tuplet-bracket"));
42 TODO: use stem->beam fields to find Beams. Autobeams aren't found
43 through the engraver mechanism. */
44 MAKE_SCHEME_CALLBACK (Tuplet_bracket
,brew_molecule
,1);
46 Tuplet_bracket::brew_molecule (SCM smob
)
48 Grob
*me
= unsmob_grob (smob
);
50 Link_array
<Grob
> column_arr
=
51 Pointer_group_interface__extract_elements (me
, (Grob
*)0, "columns");
54 if (!column_arr
.size ())
55 return mol
.smobbed_copy ();
58 Grob
*b1
= Note_column::stem_l (column_arr
[0]);
59 Grob
*b2
= Note_column::stem_l (column_arr
.top());
61 b1
= b1
? Stem::beam_l (b1
) : 0;
62 b2
= b2
? Stem::beam_l (b2
) : 0;
65 Spanner
*sp
= dynamic_cast<Spanner
*> (me
);
67 // Default behaviour: number always, bracket when no beam!
68 bool par_beam
= b1
&& (b1
== b2
) && !sp
->broken_b() ;
70 bool bracket_visibility
= !par_beam
;
71 bool number_visibility
= true;
73 SCM bracket
= me
->get_grob_property ("tuplet-bracket-visibility");
74 if (gh_boolean_p (bracket
))
76 bracket_visibility
= gh_scm2bool (bracket
);
78 else if (bracket
== ly_symbol2scm ("if-no-beam"))
79 bracket_visibility
= !par_beam
;
81 SCM numb
= me
->get_grob_property ("tuplet-number-visibility");
82 if (gh_boolean_p (numb
))
84 number_visibility
= gh_scm2bool (numb
);
86 else if (numb
== ly_symbol2scm ("if-no-beam"))
87 number_visibility
= !par_beam
;
90 Real ncw
= column_arr
.top ()->extent (column_arr
.top (), X_AXIS
).length ();
91 Real w
= sp
->spanner_length () + ncw
;
93 Direction dir
= Directional_element_interface::get (me
);
94 Real dy
= gh_scm2double (me
->get_grob_property ("delta-y"));
95 SCM number
= me
->get_grob_property ("text");
96 if (gh_string_p (number
) && number_visibility
)
98 SCM properties
= Font_interface::font_alist_chain (me
);
99 Molecule num
= Text_item::text2molecule (me
, number
, properties
);
100 num
.align_to (X_AXIS
, CENTER
);
101 num
.translate_axis (w
/2, X_AXIS
);
102 num
.align_to (Y_AXIS
, CENTER
);
104 num
.translate_axis (dy
/2, Y_AXIS
);
106 mol
.add_molecule (num
);
109 if (bracket_visibility
)
111 Real lt
= me
->paper_l ()->get_var ("stafflinethickness");
113 SCM thick
= me
->get_grob_property ("thick");
114 SCM gap
= me
->get_grob_property ("number-gap");
116 SCM at
=gh_list (ly_symbol2scm ("tuplet"),
121 gh_double2scm (gh_scm2double (thick
)* lt
),
126 mol
.add_molecule (Molecule (b
, at
));
129 return mol
.smobbed_copy ();
136 use first -> last note for slope, and then correct for disturbing
139 Tuplet_bracket::calc_position_and_height (Grob
*me
,Real
*offset
, Real
* dy
)
141 Link_array
<Grob
> column_arr
=
142 Pointer_group_interface__extract_elements (me
, (Grob
*)0, "columns");
145 Grob
* commony
= me
->common_refpoint (me
->get_grob_property ("columns"), Y_AXIS
);
146 Grob
* commonx
= me
->common_refpoint (me
->get_grob_property ("columns"), X_AXIS
);
148 Direction d
= Directional_element_interface::get (me
);
151 Use outer non-rest columns to determine slope
154 while (l
<column_arr
.size () && Note_column::rest_b (column_arr
[l
]))
157 int r
= column_arr
.size ()- 1;
158 while (r
>= l
&& Note_column::rest_b (column_arr
[r
]))
163 *dy
= column_arr
[r
]->extent (commony
, Y_AXIS
) [d
]
164 - column_arr
[l
]->extent (commony
, Y_AXIS
) [d
] ;
170 *offset
= - d
* infinity_f
;
172 if (!column_arr
.size ())
175 Real x0
= column_arr
[0]->relative_coordinate (commonx
, X_AXIS
);
176 Real x1
= column_arr
.top ()->relative_coordinate (commonx
, X_AXIS
);
178 Real factor
= column_arr
.size () > 1 ? 1/ (x1
- x0
) : 1.0;
180 for (int i
= 0; i
< column_arr
.size (); i
++)
182 Real notey
= column_arr
[i
]->extent (commony
, Y_AXIS
)[d
]
183 - me
->relative_coordinate (commony
, Y_AXIS
);
185 Real x
= column_arr
[i
]->relative_coordinate (commonx
, X_AXIS
) - x0
;
186 Real tuplety
= *dy
* x
* factor
;
188 if (notey
* d
> (*offset
+ tuplety
) * d
)
189 *offset
= notey
- tuplety
;
197 horizontal brackets should not collide with staff lines.
203 // quantize, then do collision check.
204 Real ss
= Staff_symbol_referencer::staff_space (me
);
207 *offset
= rint (*offset
);
208 if (Staff_symbol_referencer::on_staffline (me
, (int) rint (*offset
)))
217 use first -> last note for slope,
220 Tuplet_bracket::calc_dy (Grob
*me
,Real
* dy
)
222 Link_array
<Grob
> column_arr
=
223 Pointer_group_interface__extract_elements (me
, (Grob
*)0, "columns");
228 Direction d
= Directional_element_interface::get (me
);
229 *dy
= column_arr
.top ()->extent (column_arr
.top (), Y_AXIS
) [d
]
230 - column_arr
[0]->extent (column_arr
[0], Y_AXIS
) [d
];
232 MAKE_SCHEME_CALLBACK (Tuplet_bracket
,after_line_breaking
,1);
235 Tuplet_bracket::after_line_breaking (SCM smob
)
237 Grob
* me
= unsmob_grob (smob
);
238 Link_array
<Note_column
> column_arr
=
239 Pointer_group_interface__extract_elements (me
, (Note_column
*)0, "columns");
241 if (!column_arr
.size ())
244 return SCM_UNSPECIFIED
;
247 Direction d
= Directional_element_interface::get (me
);
250 d
= Tuplet_bracket::get_default_dir (me
);
251 Directional_element_interface::set (me
, d
);
256 calc_position_and_height (me
,&offset
,&dy
);
258 me
->set_grob_property ("delta-y", gh_double2scm (dy
));
260 me
->translate_axis (offset
, Y_AXIS
);
261 return SCM_UNSPECIFIED
;
266 Tuplet_bracket::get_default_dir (Grob
*me
)
269 SCM dir_sym
=me
->get_grob_property ("dir-forced");
270 if (isdir_b (dir_sym
))
278 for (SCM s
= me
->get_grob_property ("columns"); gh_pair_p (s
); s
= gh_cdr (s
))
280 Grob
* nc
= unsmob_grob (gh_car (s
));
281 if (Note_column::dir (nc
) < 0)
292 Tuplet_bracket::add_column (Grob
*me
, Item
*n
)
294 Pointer_group_interface::add_element (me
, "columns",n
);
295 me
->add_dependency (n
);
297 add_bound_item (dynamic_cast<Spanner
*> (me
), n
);