]> git.donarmstrong.com Git - lilypond.git/blob - lily/text-spanner.cc
* buildscripts/lilypond-profile.sh: error message if script is not
[lilypond.git] / lily / text-spanner.cc
1 /*
2
3   text-spanner.cc -- implement Text_spanner
4
5   source file of the GNU LilyPond music typesetter
6
7   (c) 2000--2003 Jan Nieuwenhuizen <janneke@gnu.org>
8 */
9
10 #include "molecule.hh"
11 #include "text-item.hh"
12 #include "text-spanner.hh"
13 #include "line-spanner.hh"
14 #include "spanner.hh"
15 #include "font-interface.hh"
16 #include "dimensions.hh"
17 #include "paper-def.hh"
18 #include "warn.hh"
19 #include "paper-column.hh"
20 #include "staff-symbol-referencer.hh"
21
22 /*
23   TODO:
24   - vertical start / vertical end (fixme-name) |
25   - contination types (vert. star, vert. end)  |-> eat volta-bracket
26   - more styles
27   - more texts/positions
28 */
29
30 MAKE_SCHEME_CALLBACK (Text_spanner, brew_molecule, 1);
31
32 /*
33   TODO: this function is too long
34 */
35 SCM
36 Text_spanner::brew_molecule (SCM smob) 
37 {
38   Grob *me= unsmob_grob (smob);
39   Spanner *spanner = dynamic_cast<Spanner*> (me);
40   
41   if (spanner->internal_has_interface (ly_symbol2scm ("piano-pedal-interface")))
42     {
43       setup_pedal_bracket(spanner);
44     }
45
46   /* Ugh, must be same as Hairpin::brew_molecule.  */
47   Real padding = 0.0;
48   SCM itp= me->get_grob_property ("if-text-padding");
49   if (gh_number_p (itp))
50     padding = gh_scm2double (itp);
51
52   Grob *common = spanner->get_bound (LEFT)->common_refpoint (spanner->get_bound (RIGHT), X_AXIS);
53   
54   Interval span_points;
55   Drul_array<bool> broken;
56   Direction d = LEFT;
57   do
58     {
59       Item *b = spanner->get_bound (d);
60       broken[d] = b->break_status_dir () != CENTER;
61
62       if (broken[d])
63         {
64         if (d == LEFT)
65           span_points[d] = spanner->get_broken_left_end_align ();
66         else
67           span_points[d] = b->relative_coordinate (common, X_AXIS);
68         }
69       else
70           {
71             bool encl = to_boolean (me->get_grob_property ("enclose-bounds"));
72             span_points[d] = b->extent (common, X_AXIS)[encl ? d : -d];
73           }
74     }
75   while (flip (&d) != LEFT);
76
77
78
79   SCM properties = Font_interface::font_alist_chain (me);
80   SCM edge_text = me->get_grob_property ("edge-text");
81   Drul_array<Molecule> edge;
82   if (gh_pair_p (edge_text))
83     {
84       Direction d = LEFT;
85       do
86         {
87           /*  Don't repeat edge text for broken end */
88           if (broken[d])
89             continue;
90           
91           SCM text = index_get_cell (edge_text, d);
92
93           /*
94             TODO: use markup.
95            */
96           
97           edge[d] = Text_item::interpret_new_markup (smob, properties, text);
98           if (!edge[d].empty_b ())
99             edge[d].align_to (Y_AXIS, CENTER);
100         }
101       while (flip (&d) != LEFT);
102     }
103
104
105   Drul_array<Real> shorten;
106   shorten[LEFT] = 0;
107   shorten[RIGHT] = 0;
108
109   SCM ew = me->get_grob_property ("edge-flare");
110   SCM s = me->get_grob_property ("shorten-pair");
111   if (gh_pair_p (s))
112     {
113       span_points[LEFT] += gh_scm2double (ly_car (s));
114       span_points[RIGHT] -= gh_scm2double (ly_cdr (s));
115     }
116   if (gh_pair_p (ew))
117     {
118       span_points[LEFT] += gh_scm2double (ly_car (ew));
119       span_points[RIGHT] -= gh_scm2double (ly_cdr (ew));
120     }
121   
122   Real thick = me->get_paper ()->get_var ("linethickness");  
123   SCM st = me->get_grob_property ("thickness");
124   if (gh_number_p (st))
125     {
126       thick *=  gh_scm2double (st);
127     }
128   
129   Drul_array<Molecule> edge_line;
130   s = me->get_grob_property ("edge-height");
131   if (gh_pair_p (s))
132     {
133       Direction d = LEFT;
134       int dir = to_dir (me->get_grob_property ("direction"));
135       do
136         {
137           if (broken[d])
138             continue;
139           
140           Real dx = 0.0;
141           if (gh_pair_p (ew))
142             dx = gh_scm2double (index_get_cell (ew, d)) * d;
143
144           Real dy = gh_scm2double (index_get_cell (s, d)) * - dir;
145           if (dy)
146             edge_line[d] = Line_spanner::line_molecule (me, thick, dx, dy);
147         }
148       while (flip (&d) != LEFT);
149     }
150   
151   Molecule m;
152   do
153     {
154       Interval ext = edge[d].extent (X_AXIS);
155
156       edge[d].translate_axis (span_points[d], X_AXIS);
157       m.add_molecule (edge[d]);
158       edge_line[d].translate_axis (span_points[d], X_AXIS);
159       m.add_molecule (edge_line[d]);
160       if (!ext.empty_b ())
161         span_points[d] += -d *  ext[-d];
162     }
163   while (flip (&d) != LEFT);
164
165   Molecule l =Line_spanner::line_molecule (me, thick,
166                                            span_points.length (), 0);
167   l.translate_axis (span_points[LEFT], X_AXIS); 
168   m.add_molecule (l);
169
170   m.translate_axis (- me->relative_coordinate (common, X_AXIS), X_AXIS);
171   return m.smobbed_copy ();
172 }
173
174
175
176
177 /* 
178    Piano pedal brackets are a special case of a text spanner.
179    Pedal up-down (restart) indicated by the angled right and left edges 
180    of consecutive pedals touching exactly to form an __/\__
181    Chris Jackson <chris@fluffhouse.org.uk>
182 */
183 /*
184   TODO: this should be moved somewhere else (?).
185
186   Perhaps make separate function for pedal-bracket.
187  */
188 /*
189   UGH UGH UGH .
190
191   This is broken broken.
192
193   All the tweak props should be unnecessary.
194
195   This should not be linked with Text_spanner.
196  */
197
198 void 
199 Text_spanner::setup_pedal_bracket(Spanner *me)
200 {
201
202   Real thick = me->get_paper ()->get_var ("linethickness");  
203   SCM st = me->get_grob_property ("thickness");
204   if (gh_number_p (st))
205     {
206       thick *=  gh_scm2double (st);
207     }  
208
209   Drul_array<bool> broken;
210   Drul_array<Real> height, width, shorten, r;
211
212   SCM pa = me->get_grob_property ("if-text-padding");
213   SCM eh = me->get_grob_property ("edge-height");
214   SCM sp = me->get_grob_property ("shorten-pair");
215   
216   Direction d = LEFT;
217   Interval e;
218   Real padding = 0;
219
220   if (gh_number_p (pa))
221     padding = gh_scm2double (pa);
222
223   do
224     {
225       Item *b = me->get_bound (d);
226
227       e = b->extent (b, X_AXIS);
228       if (!e.empty_b ())
229         r[d] = d * (e[-d] + padding);
230
231       broken[d] = b->break_status_dir () != CENTER;
232       width[d]  =  0;
233       height[d] =  0;
234       shorten[d] = 0;
235       if (!broken[d] && (ly_number_pair_p (eh)))
236         height[d] += gh_scm2double (index_get_cell (eh, d));
237       if (ly_number_pair_p (sp))
238         shorten[d] +=  gh_scm2double (index_get_cell (sp, d));
239     }
240   while (flip (&d) != LEFT);
241   
242   Real extra_short = 0;
243   
244   // For 'Mixed' style pedals, i.e.  a bracket preceded by text:  Ped._____|
245   // need to shorten by the extent of the text grob
246   if (to_boolean (me->get_grob_property ("text-start")))
247     {
248       height[LEFT] = 0;
249       extra_short = padding;
250       if (Grob *textbit = unsmob_grob (me->get_grob_property("pedal-text")))
251         {
252           if (textbit->internal_has_interface(ly_symbol2scm("text-interface")))
253             // for plain text, e.g., Sost. Ped.
254             {
255               SCM text  =  textbit->get_grob_property("text"); 
256               if (gh_string_p (text)) {
257                 SCM properties = Font_interface::font_alist_chain (me);
258                 
259                 Molecule mol = Text_item::interpret_new_markup (me->self_scm (),
260                                                                 properties, text);
261                 extra_short += mol.extent(X_AXIS).length() / 2;
262               }
263             }
264         }
265       shorten[RIGHT] -= thick;
266     }
267
268   shorten[LEFT] += extra_short ;
269   
270   if (broken[LEFT])
271     {
272       shorten[LEFT]  -=  me->get_broken_left_end_align () ;
273       shorten[RIGHT]  +=  abs(width[RIGHT])  +  thick  -  r[RIGHT];
274     }
275
276   else
277     {
278       // Shorten a ____/ on the right so that it will touch an adjoining \___
279       shorten[RIGHT]  +=  abs(width[LEFT])  +  abs(width[RIGHT])  +  thick;
280       // Also shorten so that it ends just before the spanned note.
281       shorten[RIGHT]  -=  (r[LEFT]  +  r[RIGHT]);
282     }
283
284   me->set_grob_property ("edge-height", ly_interval2scm (height));
285   me->set_grob_property ("shorten-pair", ly_interval2scm (shorten));
286 }
287
288
289 struct Pianopedal
290 {
291   static bool has_interface (Grob*);
292 };
293 ADD_INTERFACE (Pianopedal,"piano-pedal-interface",
294                "",
295                "pedal-type edge-widen edge-height shorten-pair text-start left-widen right-widen pedal-text");
296
297 ADD_INTERFACE (Text_spanner,"text-spanner-interface",
298                "generic text spanner",
299                "dash-period if-text-padding dash-length edge-height edge-widen edge-text shorten-pair style thickness enclose-bounds width-correct");
300