3 text-spanner.cc -- implement Text_spanner
5 source file of the GNU LilyPond music typesetter
7 (c) 2000--2003 Jan Nieuwenhuizen <janneke@gnu.org>
10 #include "molecule.hh"
11 #include "text-item.hh"
12 #include "text-spanner.hh"
13 #include "line-spanner.hh"
15 #include "font-interface.hh"
16 #include "dimensions.hh"
17 #include "paper-def.hh"
19 #include "paper-column.hh"
20 #include "staff-symbol-referencer.hh"
24 - vertical start / vertical end (fixme-name) |
25 - contination types (vert. star, vert. end) |-> eat volta-bracket
27 - more texts/positions
30 MAKE_SCHEME_CALLBACK (Text_spanner
, brew_molecule
, 1);
33 TODO: this function is too long, too hairy.
35 TODO: document this. What the heck is happening here?
38 Text_spanner::brew_molecule (SCM smob
)
40 Grob
*me
= unsmob_grob (smob
);
41 Spanner
*spanner
= dynamic_cast<Spanner
*> (me
);
43 if (spanner
->internal_has_interface (ly_symbol2scm ("piano-pedal-interface")))
45 setup_pedal_bracket(spanner
);
48 /* Ugh, must be same as Hairpin::brew_molecule. */
49 Real padding
= gh_scm2double (me
->get_grob_property ("if-text-padding"));
50 Real broken_left
= spanner
->get_broken_left_end_align ();
51 Real width
= spanner
->spanner_length ();
54 Drul_array
<bool> broken
;
55 Drul_array
<Real
> extra_off
;
60 Item
*b
= spanner
->get_bound (d
);
61 broken
[d
] = b
->break_status_dir () != CENTER
;
66 Interval e
= b
->extent (b
, X_AXIS
);
71 /* Text spanners such as ottava, should span from outer limits of
72 noteheads, iso (de)cresc. spanners that span the inner space */
73 if (me
->get_grob_property ("outer") != SCM_EOL
)
84 while (flip (&d
) != LEFT
);
86 // FIXME: ecs tells us -- only for (de)cresc. spanners
87 width
+= gh_scm2double (me
->get_grob_property ("width-correct"));
92 SCM properties
= Font_interface::font_alist_chain (me
);
94 SCM edge_text
= me
->get_grob_property ("edge-text");
95 Drul_array
<Molecule
> edge
;
96 if (gh_pair_p (edge_text
))
101 /* Don't repeat edge text for broken end */
104 SCM text
= index_get_cell (edge_text
, d
);
105 edge
[d
] = Text_item::text2molecule (me
, text
, properties
);
106 if (!edge
[d
].empty_b ())
107 edge
[d
].align_to (Y_AXIS
, CENTER
);
110 while (flip (&d
) != LEFT
);
112 width
-= edge
[LEFT
].extent (X_AXIS
).length ()
113 + edge
[RIGHT
].extent (X_AXIS
).length ();
115 Drul_array
<Real
> shorten
;
119 SCM s
= me
->get_grob_property ("shorten-pair");
122 shorten
[LEFT
] = gh_scm2double (ly_car (s
));
123 shorten
[RIGHT
] = gh_scm2double (ly_cdr (s
));
126 width
-= shorten
[LEFT
] + shorten
[RIGHT
];
130 me
->warning (_ ("Text_spanner too small"));
136 Real thick
= me
->get_paper ()->get_var ("linethickness");
137 SCM st
= me
->get_grob_property ("thickness");
138 if (gh_number_p (st
))
140 thick
*= gh_scm2double (st
);
143 Molecule line
= Line_spanner::line_molecule (me
, thick
, width
, 0);
145 Drul_array
<Molecule
> edge_line
;
146 s
= me
->get_grob_property ("edge-height");
147 SCM ew
= me
->get_grob_property ("edge-widen");
151 int dir
= to_dir (me
->get_grob_property ("direction"));
154 Real dx
= ( gh_pair_p (ew
) ?
155 gh_scm2double (index_get_cell (ew
, d
)) * d
:
157 Real dy
= gh_scm2double (index_get_cell (s
, d
)) * - dir
;
160 edge_line
[d
] = Line_spanner::line_molecule (me
, thick
, dx
, dy
);
163 while (flip (&d
) != LEFT
);
167 if (!edge
[LEFT
].empty_b ())
170 if (!edge_line
[LEFT
].empty_b ())
171 m
.add_at_edge (X_AXIS
, RIGHT
, edge_line
[LEFT
], 0,0);
172 if (!line
.empty_b ())
173 m
.add_at_edge (X_AXIS
, RIGHT
, line
,
174 edge_line
[LEFT
].empty_b () ? 0 : -thick
/2, 0);
175 if (!edge_line
[RIGHT
].empty_b ())
176 m
.add_at_edge (X_AXIS
, RIGHT
, edge_line
[RIGHT
], -thick
/2, 0);
177 if (!edge
[RIGHT
].empty_b ())
178 m
.add_at_edge (X_AXIS
, RIGHT
, edge
[RIGHT
], 0, 0);
179 m
.translate_axis (broken_left
+ extra_off
[LEFT
] + shorten
[LEFT
], X_AXIS
);
181 return m
.smobbed_copy ();
188 Piano pedal brackets are a special case of a text spanner.
189 Pedal up-down (restart) indicated by the angled right and left edges
190 of consecutive pedals touching exactly to form an __/\__
191 Chris Jackson <chris@fluffhouse.org.uk>
195 Text_spanner::setup_pedal_bracket(Spanner
*me
)
198 Real thick
= me
->get_paper ()->get_var ("linethickness");
199 SCM st
= me
->get_grob_property ("thickness");
200 if (gh_number_p (st
))
202 thick
*= gh_scm2double (st
);
205 Drul_array
<bool> broken
;
206 Drul_array
<Real
> height
, width
, shorten
, r
;
208 SCM pa
= me
->get_grob_property ("if-text-padding");
209 SCM ew
= me
->get_grob_property ("edge-widen");
210 SCM eh
= me
->get_grob_property ("edge-height");
211 SCM sp
= me
->get_grob_property ("shorten-pair");
217 if (gh_number_p (pa
) )
218 padding
= gh_scm2double (pa
);
222 Item
*b
= me
->get_bound (d
);
224 e
= b
->extent (b
, X_AXIS
);
226 r
[d
] = d
* (e
[-d
] + padding
);
228 broken
[d
] = b
->break_status_dir () != CENTER
;
232 if ( ly_number_pair_p (ew
) )
233 width
[d
] += gh_scm2double (index_get_cell (ew
, d
));
234 if ( !broken
[d
] && (ly_number_pair_p (eh
) ) )
235 height
[d
] += gh_scm2double (index_get_cell (eh
, d
));
236 if ( ly_number_pair_p (sp
) )
237 shorten
[d
] += gh_scm2double (index_get_cell (sp
, d
));
239 while (flip (&d
) != LEFT
);
241 Real extra_short
= 0;
242 // For 'Mixed' style pedals, i.e. a bracket preceded by text: Ped._____|
243 // need to shorten by the extent of the text grob
244 if ( to_boolean (me
->get_grob_property ("text-start")) )
247 extra_short
= padding
;
248 if (Grob
*textbit
= unsmob_grob (me
->get_grob_property("pedal-text")))
250 if (textbit
->internal_has_interface(ly_symbol2scm("text-interface")))
251 // for plain text, e.g., Sost. Ped.
253 SCM text
= textbit
->get_grob_property("text");
254 if (gh_string_p (text
)) {
255 SCM properties
= Font_interface::font_alist_chain (me
);
256 Molecule mol
= Text_item::text2molecule (me
, text
, properties
);
257 extra_short
+= mol
.extent(X_AXIS
).length() / 2;
261 shorten
[RIGHT
] -= thick
;
264 shorten
[LEFT
] += extra_short
;
268 shorten
[LEFT
] -= me
->get_broken_left_end_align () ;
269 shorten
[RIGHT
] += abs(width
[RIGHT
]) + thick
- r
[RIGHT
];
274 // Shorten a ____/ on the right so that it will touch an adjoining \___
275 shorten
[RIGHT
] += abs(width
[LEFT
]) + abs(width
[RIGHT
]) + thick
;
276 // Also shorten so that it ends just before the spanned note.
277 shorten
[RIGHT
] -= (r
[LEFT
] + r
[RIGHT
]);
280 me
->set_grob_property ("edge-height", ly_interval2scm (height
));
281 me
->set_grob_property ("edge-widen", ly_interval2scm(width
));
282 me
->set_grob_property ("shorten-pair", ly_interval2scm (shorten
));
288 static bool has_interface (Grob
*);
290 ADD_INTERFACE (Pianopedal
,"piano-pedal-interface",
292 "pedal-type edge-widen edge-height shorten-pair text-start left-widen right-widen pedal-text");
294 ADD_INTERFACE (Text_spanner
,"text-spanner-interface",
295 "generic text spanner",
296 "dash-period if-text-padding dash-length edge-height edge-widen edge-text shorten-pair type thickness outer width-correct");