]> git.donarmstrong.com Git - lilypond.git/blob - lily/lookup.cc
61326091ea5dceaf7ce15a701a1b23d4d7fb3880
[lilypond.git] / lily / lookup.cc
1 /*
2   lookup.cc -- implement simple Lookup methods.
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7
8   Jan Nieuwenhuizen <janneke@gnu.org>
9
10   TODO
11       Glissando
12 */
13 #include <math.h>
14 #include <ctype.h>
15
16 #include "lookup.hh"
17 #include "debug.hh"
18 #include "dimensions.hh"
19 #include "bezier.hh"
20 #include "paper-def.hh"
21 #include "string-convert.hh"
22 #include "file-path.hh"
23 #include "main.hh"
24 #include "lily-guile.hh"
25 #include "all-font-metrics.hh"
26 #include "afm.hh"
27 #include "scope.hh"
28 #include "molecule.hh"
29
30 #include "lily-guile.hh"
31
32
33 Lookup::Lookup ()
34 {
35   afm_l_ = 0;  
36 }
37
38 Lookup::Lookup (Lookup const& s)
39 {
40   font_name_ = s.font_name_;
41   afm_l_ = 0;  
42 }
43
44
45
46
47 Molecule
48 Lookup::afm_find (String s, bool warn) const
49 {
50   if (!afm_l_)      
51     {
52       Lookup * me = (Lookup*)(this);
53       me->afm_l_ = all_fonts_global_p->find_afm (font_name_);
54       if (!me->afm_l_)
55         {
56           warning (_f ("can't find font: `%s'", font_name_));
57           warning (_f ("(search path: `%s')", global_path.str ().ch_C()));
58           error (_ ("Aborting"));
59         }
60     }
61   AFM_CharMetricInfo const *cm = afm_l_->find_char_metric (s, warn);
62
63   if (!cm)
64     {
65       Molecule m;
66       m.set_empty (false);
67       return m;
68     }
69   
70   SCM at =  (gh_list (ly_symbol2scm ("char"),
71                     gh_int2scm (cm->code),
72                     SCM_UNDEFINED));
73
74   at= fontify_atom (afm_l_,at);
75   return Molecule ( afm_bbox_to_box (cm->charBBox), at);
76 }
77
78   
79
80
81 Molecule 
82 Lookup::beam (Real slope, Real width, Real thick) 
83 {
84   Real height = slope * width; 
85   Real min_y = (0 <? height) - thick/2;
86   Real max_y = (0 >? height) + thick/2;
87
88   
89
90   Box b( Interval (0, width),
91          Interval (min_y, max_y));
92
93   
94   SCM at = gh_list (ly_symbol2scm ("beam"),
95                     gh_double2scm (width),
96                     gh_double2scm (slope),
97                     gh_double2scm (thick),
98                     SCM_UNDEFINED);
99   return Molecule (b, at);
100 }
101
102
103
104 Molecule
105 Lookup::dashed_slur (Bezier b, Real thick, Real dash)
106 {
107   SCM l = SCM_EOL;
108
109   for (int i= 4; i -- ;)
110     {
111       l = gh_cons (ly_offset2scm (b.control_[i]), l);
112     }
113
114   SCM at = (gh_list (ly_symbol2scm ("dashed-slur"),
115                                gh_double2scm (thick), 
116                                gh_double2scm (dash),
117                                ly_quote_scm (l),
118                                SCM_UNDEFINED));
119
120   Box box (Interval(0,0),Interval( 0,0));
121   return   Molecule (box, at);
122 }
123
124
125
126
127 Molecule
128 Lookup::blank (Box b) 
129 {
130   return Molecule (b, SCM_EOL);
131 }
132
133
134 Molecule
135 Lookup::filledbox (Box b ) 
136 {
137   SCM  at  = (gh_list (ly_symbol2scm ("filledbox"),
138                      gh_double2scm (-b[X_AXIS][LEFT]),
139                      gh_double2scm (b[X_AXIS][RIGHT]),                 
140                      gh_double2scm (-b[Y_AXIS][DOWN]),
141                      gh_double2scm (b[Y_AXIS][UP]),                    
142                      SCM_UNDEFINED));
143
144   return Molecule ( b,at);
145 }
146
147 Molecule
148 Lookup::frame (Box b, Real thick)
149 {
150   Molecule m;
151   Direction d = LEFT;
152   Axis a = X_AXIS;
153   while (a < NO_AXES)
154     {
155       do
156         {
157           Axis o = Axis ((a+1)%NO_AXES);
158
159           Box edges;
160           edges[a] = b[a][d] + 0.5 * thick * Interval (-1, 1);
161           edges[o][DOWN] = b[o][DOWN] - thick/2;
162           edges[o][UP] = b[o][UP] + thick/2;      
163           
164           
165           m.add_molecule (filledbox (edges));
166         }
167       while (flip (&d) != LEFT);
168     }
169   return m;
170   
171 }
172
173
174 /*
175    TODO: THIS IS UGLY.
176    Since the user has direct access to TeX marcos,
177    that currently provide the  only way to do
178    font selection, accents etc,
179    we try some halfbaked attempt to detect this TeX trickery.
180  */
181 String
182 sanitise_TeX_string (String text)
183 {
184   int brace_count =0;
185   for (int i= 0; i < text.length_i (); i++)
186     {
187       if (text[i] == '\\')
188         continue;
189       
190       if (text[i] == '{')
191         brace_count ++;
192       else if (text[i] == '}')
193         brace_count --;
194     }
195   
196   if(brace_count)
197     {
198       warning (_f ("Non-matching braces in text `%s', adding braces", text.ch_C()));
199
200       if (brace_count < 0)
201         {
202           text = to_str ('{', -brace_count) + text;
203         }
204       else 
205         {
206           text = text + to_str ('}', brace_count);
207         }
208     }
209     
210   return text;
211 }
212
213 /**
214    TODO!
215  */
216 String
217 sanitise_PS_string (String t)
218 {
219   return t;
220 }
221
222 /**
223 TODO: move into Text_item
224 */
225 Molecule
226 Lookup::text (String style, String text, Paper_def *paper_l) 
227 {
228   if (style.empty_b ())
229     style = "roman";
230   
231   int font_mag = 0;
232   Real font_h = paper_l->get_var ("font_normal");
233   if (paper_l->scope_p_->elem_b ("font_" + style))
234     {
235       font_h = paper_l->get_var ("font_" + style);
236     }
237
238
239   if (paper_l->scope_p_->elem_b ("magnification_" + style))
240     {
241       font_mag = (int)paper_l->get_var ("magnification_" + style);
242     }
243
244   SCM l = scm_assoc (ly_str02scm (style.ch_C()),
245                      scm_eval (ly_symbol2scm ("cmr-alist")));
246
247   if (l != SCM_BOOL_F)
248     {
249       style = ly_scm2string (gh_cdr(l)) +to_str  ((int)font_h);
250     }
251
252   Font_metric* metric_l = 0;
253
254   if (font_mag)
255     metric_l = all_fonts_global_p->find_scaled (style, font_mag);
256   else
257     metric_l = all_fonts_global_p->find_font (style);
258   
259   
260     
261
262   int i = text.index_i ("\\n");
263   while (i >=0 )
264     {
265       text = text.left_str (i) + "\n" + text.right_str (text.length_i () - i - 2);
266       i = text.index_i ("\\n");
267     }
268   
269   Array<String> lines = String_convert::split_arr (text, '\n');
270   
271   Real kern = paper_l->get_var ("line_kern");
272   
273   for (int i=0; i < lines.size (); i++)
274     {
275       String str (lines[i]);
276       if (output_global_ch == "tex")
277         str = sanitise_TeX_string  (str);
278       else if (output_global_ch == "ps")
279         str = sanitise_PS_string (str);
280       lines[i] = str;
281     }
282
283   if (!lines.size())
284         return Molecule();
285
286   SCM first = gh_list (ly_symbol2scm ("text"),
287                          ly_str02scm (lines[0].ch_C()),
288                          SCM_UNDEFINED);
289   first = fontify_atom (metric_l, first);
290
291   
292
293   Molecule mol (metric_l->text_dimension (lines[0]), first);
294
295   for (i = 1; i < lines.size (); i++)
296     {
297       SCM line = (gh_list (ly_symbol2scm ("text"),
298                            ly_str02scm (lines[i].ch_C ()),
299                            SCM_UNDEFINED));
300       line = fontify_atom (metric_l, line);
301       mol.add_at_edge (Y_AXIS, DOWN,
302                        Molecule (metric_l->text_dimension (lines[i]), line),
303                        kern);
304     }
305
306   return mol;
307 }
308   
309
310
311 /*
312   Make a smooth curve along the points 
313  */
314 Molecule
315 Lookup::slur (Bezier curve, Real curvethick, Real linethick) 
316 {
317   Real alpha = (curve.control_[3] - curve.control_[0]).arg ();
318   Bezier back = curve;
319
320   back.reverse ();
321   back.control_[1] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));
322   back.control_[2] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));  
323
324   SCM scontrols[8];
325
326   for (int i=4; i--;)
327     scontrols[ i ] = ly_offset2scm(back.control_[i]);
328   for (int i=4 ; i--;)
329     scontrols[i+4] = ly_offset2scm (curve.control_[i]);
330
331   /*
332     Need the weird order b.o. the way PS want its arguments  
333    */
334   int indices[]= {5, 6, 7, 4, 1, 2, 3, 0};
335   SCM list = SCM_EOL;
336   for (int i= 8; i--;  )
337     {
338       list = gh_cons (scontrols[indices[i]], list);
339     }
340   
341   
342   SCM at = (gh_list (ly_symbol2scm ("bezier-sandwich"),
343                      ly_quote_scm (list),
344                      gh_double2scm (linethick),
345                      SCM_UNDEFINED));
346
347   Box b ( curve.extent (X_AXIS), curve.extent (Y_AXIS));
348   return Molecule (b, at);
349 }
350
351 Molecule
352 Lookup::accordion (SCM s, Real staff_space) const
353 {
354   Molecule m;
355   String sym = ly_scm2string(gh_car (s));
356   String reg = ly_scm2string(gh_car (gh_cdr(s)));
357
358   if (sym == "Discant")
359     {
360       Molecule r = afm_find("accordion-accDiscant");
361       m.add_molecule(r);
362       if (reg.left_str(1) == "F")
363         {
364           Molecule d = afm_find("accordion-accDot");
365           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
366           m.add_molecule(d);
367           reg = reg.right_str(reg.length_i()-1);
368         }
369       int eflag = 0x00;
370       if (reg.left_str(3) == "EEE")
371         {
372           eflag = 0x07;
373           reg = reg.right_str(reg.length_i()-3);
374         }
375       else if (reg.left_str(2) == "EE")
376         {
377           eflag = 0x05;
378           reg = reg.right_str(reg.length_i()-2);
379         }
380       else if (reg.left_str(2) == "Eh")
381         {
382           eflag = 0x04;
383           reg = reg.right_str(reg.length_i()-2);
384         }
385       else if (reg.left_str(1) == "E")
386         {
387           eflag = 0x02;
388           reg = reg.right_str(reg.length_i()-1);
389         }
390       if (eflag & 0x02)
391         {
392           Molecule d = afm_find("accordion-accDot");
393           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
394           m.add_molecule(d);
395         }
396       if (eflag & 0x04)
397         {
398           Molecule d = afm_find("accordion-accDot");
399           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
400           d.translate_axis(0.8 * staff_space PT, X_AXIS);
401           m.add_molecule(d);
402         }
403       if (eflag & 0x01)
404         {
405           Molecule d = afm_find("accordion-accDot");
406           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
407           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
408           m.add_molecule(d);
409         }
410       if (reg.left_str(2) == "SS")
411         {
412           Molecule d = afm_find("accordion-accDot");
413           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
414           d.translate_axis(0.4 * staff_space PT, X_AXIS);
415           m.add_molecule(d);
416           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
417           m.add_molecule(d);
418           reg = reg.right_str(reg.length_i()-2);
419         }
420       if (reg.left_str(1) == "S")
421         {
422           Molecule d = afm_find("accordion-accDot");
423           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
424           m.add_molecule(d);
425           reg = reg.right_str(reg.length_i()-1);
426         }
427     }
428   else if (sym == "Freebase")
429     {
430       Molecule r = afm_find("accordion-accFreebase");
431       m.add_molecule(r);
432       if (reg.left_str(1) == "F")
433         {
434           Molecule d = afm_find("accordion-accDot");
435           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
436           m.add_molecule(d);
437           reg = reg.right_str(reg.length_i()-1);
438         }
439       if (reg == "E")
440         {
441           Molecule d = afm_find("accordion-accDot");
442           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
443           m.add_molecule(d);
444         }
445     }
446   else if (sym == "Bayanbase")
447     {
448       Molecule r = afm_find("accordion-accBayanbase");
449       m.add_molecule(r);
450       if (reg.left_str(1) == "T")
451         {
452           Molecule d = afm_find("accordion-accDot");
453           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
454           m.add_molecule(d);
455           reg = reg.right_str(reg.length_i()-1);
456         }
457       /* include 4' reed just for completeness. You don't want to use this. */
458       if (reg.left_str(1) == "F")
459         {
460           Molecule d = afm_find("accordion-accDot");
461           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
462           m.add_molecule(d);
463           reg = reg.right_str(reg.length_i()-1);
464         }
465       if (reg.left_str(2) == "EE")
466         {
467           Molecule d = afm_find("accordion-accDot");
468           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
469           d.translate_axis(0.4 * staff_space PT, X_AXIS);
470           m.add_molecule(d);
471           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
472           m.add_molecule(d);
473           reg = reg.right_str(reg.length_i()-2);
474         }
475       if (reg.left_str(1) == "E")
476         {
477           Molecule d = afm_find("accordion-accDot");
478           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
479           m.add_molecule(d);
480           reg = reg.right_str(reg.length_i()-1);
481         }
482     }
483   else if (sym == "Stdbase")
484     {
485       Molecule r = afm_find("accordion-accStdbase");
486       m.add_molecule(r);
487       if (reg.left_str(1) == "T")
488         {
489           Molecule d = afm_find("accordion-accDot");
490           d.translate_axis(staff_space * 3.5 PT, Y_AXIS);
491           m.add_molecule(d);
492           reg = reg.right_str(reg.length_i()-1);
493         }
494       if (reg.left_str(1) == "F")
495         {
496           Molecule d = afm_find("accordion-accDot");
497           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
498           m.add_molecule(d);
499           reg = reg.right_str(reg.length_i()-1);
500         }
501       if (reg.left_str(1) == "M")
502         {
503           Molecule d = afm_find("accordion-accDot");
504           d.translate_axis(staff_space * 2 PT, Y_AXIS);
505           d.translate_axis(staff_space PT, X_AXIS);
506           m.add_molecule(d);
507           reg = reg.right_str(reg.length_i()-1);
508         }
509       if (reg.left_str(1) == "E")
510         {
511           Molecule d = afm_find("accordion-accDot");
512           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
513           m.add_molecule(d);
514           reg = reg.right_str(reg.length_i()-1);
515         }
516       if (reg.left_str(1) == "S")
517         {
518           Molecule d = afm_find("accordion-accDot");
519           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
520           m.add_molecule(d);
521           reg = reg.right_str(reg.length_i()-1);
522         }
523     }
524   /* ugh maybe try to use regular font for S.B. and B.B and only use one font
525      for the rectangle */
526   else if (sym == "SB")
527     {
528       Molecule r = afm_find("accordion-accSB");
529       m.add_molecule(r);
530     }
531   else if (sym == "BB")
532     {
533       Molecule r = afm_find("accordion-accBB");
534       m.add_molecule(r);
535     }
536   else if (sym == "OldEE")
537     {
538       Molecule r = afm_find("accordion-accOldEE");
539       m.add_molecule(r);
540     }
541   else if (sym == "OldEES")
542     {
543       Molecule r = afm_find("accordion-accOldEES");
544       m.add_molecule(r);
545     }
546   return m;  
547 }
548