]> git.donarmstrong.com Git - lilypond.git/blob - lily/text-spanner.cc
254ee1fe29e6cde31af8b9d6f2d5af7844b461f0
[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 #if 0
79   /*
80     FIXME. - this switch   sucks. --hwn
81    */
82   // FIXME: ecs tells us -- only for (de)cresc. spanners
83   width += gh_scm2double (me->get_grob_property ("width-correct"));
84 #endif
85
86   SCM properties = Font_interface::font_alist_chain (me);
87   SCM edge_text = me->get_grob_property ("edge-text");
88   Drul_array<Molecule> edge;
89   if (gh_pair_p (edge_text))
90     {
91       Direction d = LEFT;
92       do
93         {
94           /*  Don't repeat edge text for broken end */
95           if (broken[d])
96             continue;
97           
98           SCM text = index_get_cell (edge_text, d);
99
100           /*
101             TODO: use markup.
102            */
103           
104           edge[d] = Text_item::interpret_new_markup (smob, properties, text);
105           if (!edge[d].empty_b ())
106             edge[d].align_to (Y_AXIS, CENTER);
107         }
108       while (flip (&d) != LEFT);
109     }
110
111
112   Drul_array<Real> shorten;
113   shorten[LEFT] = 0;
114   shorten[RIGHT] = 0;
115
116   SCM s = me->get_grob_property ("shorten-pair");
117   if (gh_pair_p (s))
118     {
119       span_points[LEFT] += gh_scm2double (ly_car (s));
120       span_points[RIGHT] -= gh_scm2double (ly_cdr (s));
121     }
122   
123   Real thick = me->get_paper ()->get_var ("linethickness");  
124   SCM st = me->get_grob_property ("thickness");
125   if (gh_number_p (st))
126     {
127       thick *=  gh_scm2double (st);
128     }
129   
130   Drul_array<Molecule> edge_line;
131   s = me->get_grob_property ("edge-height");
132   SCM ew = me->get_grob_property ("edge-widen");
133   if (gh_pair_p (s))
134     {
135       Direction d = LEFT;
136       int dir = to_dir (me->get_grob_property ("direction"));
137       do
138         {
139           if (broken[d])
140             continue;
141           
142           Real dx = 0.0;
143           if (gh_pair_p (ew))
144             dx = gh_scm2double (index_get_cell (ew, d)) * d;
145
146           Real dy = gh_scm2double (index_get_cell (s, d)) * - dir;
147           if (dy)
148             edge_line[d] = Line_spanner::line_molecule (me, thick, dx, dy);
149         }
150       while (flip (&d) != LEFT);
151     }
152   
153   Molecule m;
154   do
155     {
156       Interval ext = edge[d].extent (X_AXIS);
157
158       edge[d].translate_axis (span_points[d], X_AXIS);
159       m.add_molecule (edge[d]);
160       edge_line[d].translate_axis (span_points[d], X_AXIS);
161       m.add_molecule (edge_line[d]);
162       if (!ext.empty_b ())
163         span_points[d] += -d *  ext[-d];
164     }
165   while (flip (&d) != LEFT);
166
167   Molecule l =Line_spanner::line_molecule (me, thick,
168                                            span_points.length (), 0);
169   l.translate_axis (span_points[LEFT], X_AXIS); 
170   m.add_molecule (l);
171
172   m.translate_axis (- me->relative_coordinate (common, X_AXIS), X_AXIS);
173   return m.smobbed_copy ();
174 }
175
176
177
178
179 /* 
180    Piano pedal brackets are a special case of a text spanner.
181    Pedal up-down (restart) indicated by the angled right and left edges 
182    of consecutive pedals touching exactly to form an __/\__
183    Chris Jackson <chris@fluffhouse.org.uk>
184 */
185 /*
186   TODO: this should be moved somewhere else (?).
187
188   Perhaps make separate function for pedal-bracket.
189  */
190
191 void 
192 Text_spanner::setup_pedal_bracket(Spanner *me)
193 {
194
195   Real thick = me->get_paper ()->get_var ("linethickness");  
196   SCM st = me->get_grob_property ("thickness");
197   if (gh_number_p (st))
198     {
199       thick *=  gh_scm2double (st);
200     }  
201
202   Drul_array<bool> broken;
203   Drul_array<Real> height, width, shorten, r;
204
205   SCM pa = me->get_grob_property ("if-text-padding");
206   SCM ew = me->get_grob_property ("edge-widen");
207   SCM eh = me->get_grob_property ("edge-height");
208   SCM sp = me->get_grob_property ("shorten-pair");
209   
210   Direction d = LEFT;
211   Interval e;
212   Real padding = 0;
213
214   if (gh_number_p (pa) )
215     padding = gh_scm2double (pa);
216
217   do
218     {
219       Item *b = me->get_bound (d);
220
221       e = b->extent (b, X_AXIS);
222       if (!e.empty_b ())
223         r[d] = d * (e[-d] + padding);
224
225       broken[d] = b->break_status_dir () != CENTER;
226       width[d]  =  0;
227       height[d] =  0;
228       shorten[d] = 0;
229       if ( ly_number_pair_p (ew) )
230         width[d] +=  gh_scm2double (index_get_cell (ew, d));
231       if ( !broken[d] && (ly_number_pair_p (eh) ) )
232         height[d] += gh_scm2double (index_get_cell (eh, d));
233       if ( ly_number_pair_p (sp) )
234         shorten[d] +=  gh_scm2double (index_get_cell (sp, d));
235     }
236   while (flip (&d) != LEFT);
237   
238   Real extra_short = 0;
239   // For 'Mixed' style pedals, i.e.  a bracket preceded by text:  Ped._____|
240   // need to shorten by the extent of the text grob
241   if ( to_boolean (me->get_grob_property ("text-start")) )
242     {
243       height[LEFT] = 0;
244       extra_short = padding;
245       if (Grob *textbit = unsmob_grob (me->get_grob_property("pedal-text")))
246         {
247           if (textbit->internal_has_interface(ly_symbol2scm("text-interface")))
248             // for plain text, e.g., Sost. Ped.
249             {
250               SCM text  =  textbit->get_grob_property("text"); 
251               if (gh_string_p (text)) {
252                 SCM properties = Font_interface::font_alist_chain (me);
253                 
254                 Molecule mol = Text_item::interpret_new_markup (me->self_scm (),
255                                                                 properties, text);
256                 extra_short += mol.extent(X_AXIS).length() / 2;
257               }
258             }
259         }
260       shorten[RIGHT] -= thick;
261     }
262
263   shorten[LEFT] += extra_short ;
264   
265   if (broken[LEFT])
266     {
267       shorten[LEFT]  -=  me->get_broken_left_end_align () ;
268       shorten[RIGHT]  +=  abs(width[RIGHT])  +  thick  -  r[RIGHT];
269     }
270
271   else
272     {
273       // Shorten a ____/ on the right so that it will touch an adjoining \___
274       shorten[RIGHT]  +=  abs(width[LEFT])  +  abs(width[RIGHT])  +  thick;
275       // Also shorten so that it ends just before the spanned note.
276       shorten[RIGHT]  -=  (r[LEFT]  +  r[RIGHT]);
277     }
278
279   me->set_grob_property ("edge-height", ly_interval2scm (height));
280   me->set_grob_property ("edge-widen",  ly_interval2scm(width));
281   me->set_grob_property ("shorten-pair", ly_interval2scm (shorten));
282 }
283
284
285 struct Pianopedal
286 {
287   static bool has_interface (Grob*);
288 };
289 ADD_INTERFACE (Pianopedal,"piano-pedal-interface",
290                "",
291                "pedal-type edge-widen edge-height shorten-pair text-start left-widen right-widen pedal-text");
292
293 ADD_INTERFACE (Text_spanner,"text-spanner-interface",
294                "generic text spanner",
295                "dash-period if-text-padding dash-length edge-height edge-widen edge-text shorten-pair style thickness enclose-bounds width-correct");
296