]> git.donarmstrong.com Git - lilypond.git/blob - lily/lookup.cc
patch::: 1.3.32.jcn3: jcn3, weetjewat?
[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 #include "lookup.hh"
16 #include "debug.hh"
17 #include "dimensions.hh"
18
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 Molecule
79 Lookup::simple_bar (String type, Real h, Paper_def* paper_l) const
80 {
81   SCM thick = ly_symbol2scm (("barthick_" + type).ch_C());
82   Real w = 0.0;
83   
84   if (paper_l->scope_p_->elem_b (thick))
85     {
86       w = paper_l->get_realvar (thick);
87     }
88   else
89     {
90       programming_error ("No bar thickness set ! ");
91       w = 1 PT;
92     }
93   return filledbox (Box (Interval(0,w), Interval(-h/2, h/2)));
94 }
95
96   
97 Molecule
98 Lookup::bar (String str, Real h, Paper_def *paper_l) const
99 {
100   if (str == "bracket")
101     return staff_bracket (h, paper_l);
102   else if (str == "brace")
103     {
104       Real staffht  = paper_l->get_var ("staffheight");
105       return staff_brace (h,staffht);
106     }
107   Real kern = paper_l->get_var ("bar_kern");
108   Real thinkern = paper_l->get_var ("bar_thinkern");
109
110   Molecule thin = simple_bar ("thin", h, paper_l);
111   Molecule thick = simple_bar ("thick", h, paper_l);
112   Molecule colon = afm_find ("dots-repeatcolon", paper_l);  
113
114   Molecule m;
115   
116   if (str == "")
117     {
118       return fill (Box (Interval(0, 0), Interval (-h/2, h/2)));
119     }
120   if (str == "scorepostbreak")
121     {
122       return simple_bar ("score", h, paper_l);
123     }
124   else if (str == "|")
125     {
126       return thin;
127     }
128   else if (str == "|.")
129     {
130       m.add_at_edge (X_AXIS, LEFT, thick, 0);      
131       m.add_at_edge (X_AXIS, LEFT, thin, kern);
132     }
133   else if (str == ".|")
134     {
135       m.add_at_edge (X_AXIS, RIGHT, thick, 0);
136       m.add_at_edge (X_AXIS, RIGHT, thin, kern);
137     }
138   else if (str == ":|")
139     {
140       m.add_at_edge (X_AXIS, LEFT, thick, 0);
141       m.add_at_edge (X_AXIS, LEFT, thin, kern);
142       m.add_at_edge (X_AXIS, LEFT, colon, kern);      
143     }
144   else if (str == "|:")
145     {
146       m.add_at_edge (X_AXIS, RIGHT, thick, 0);
147       m.add_at_edge (X_AXIS, RIGHT, thin, kern);
148       m.add_at_edge (X_AXIS, RIGHT, colon, kern);      
149     }
150   else if (str == ":|:")
151     {
152       m.add_at_edge (X_AXIS, LEFT, thick, thinkern);
153       m.add_at_edge (X_AXIS, LEFT, colon, kern);      
154       m.add_at_edge (X_AXIS, RIGHT, thick, kern);
155       m.add_at_edge (X_AXIS, RIGHT, colon, kern);      
156     }
157   else if (str == ".|.")
158     {
159       m.add_at_edge (X_AXIS, LEFT, thick, thinkern);
160       m.add_at_edge (X_AXIS, RIGHT, thick, kern);      
161     }
162   else if (str == "||")
163     {
164       m.add_at_edge (X_AXIS, RIGHT, thin, 0);
165       m.add_at_edge (X_AXIS, RIGHT, thin, thinkern);      
166     }
167
168   return m;
169 }
170
171 Molecule 
172 Lookup::beam (Real slope, Real width, Real thick) 
173 {
174   Real height = slope * width; 
175   Real min_y = (0 <? height) - thick/2;
176   Real max_y = (0 >? height) + thick/2;
177
178   
179
180   Box b( Interval (0, width),
181          Interval (min_y, max_y));
182
183   
184   SCM at = gh_list (ly_symbol2scm ("beam"),
185                     gh_double2scm (width),
186                     gh_double2scm (slope),
187                     gh_double2scm (thick),
188                     SCM_UNDEFINED);
189   return Molecule (b, at);
190 }
191
192
193
194 Molecule
195 Lookup::dashed_slur (Bezier b, Real thick, Real dash)
196 {
197   SCM l = SCM_EOL;
198   // this is silly, we have array_to_scm
199   for (int i= 4; i -- ;)
200     {
201       l = gh_cons (to_scm (b.control_[i]), l);
202     }
203
204   SCM at = (gh_list (ly_symbol2scm ("dashed-slur"),
205                                gh_double2scm (thick), 
206                                gh_double2scm (dash),
207                                ly_quote_scm (l),
208                                SCM_UNDEFINED));
209
210   Box box (Interval(0,0),Interval( 0,0));
211   return   Molecule (box, at);
212 }
213
214
215
216
217 Molecule
218 Lookup::fill (Box b) 
219 {
220   Molecule m;
221   m.dim_ = b;
222   return m;
223 }
224
225
226 Molecule
227 Lookup::filledbox (Box b ) 
228 {
229   SCM  at  = (gh_list (ly_symbol2scm ("filledbox"),
230                      gh_double2scm (-b[X_AXIS][LEFT]),
231                      gh_double2scm (b[X_AXIS][RIGHT]),                 
232                      gh_double2scm (-b[Y_AXIS][DOWN]),
233                      gh_double2scm (b[Y_AXIS][UP]),                    
234                      SCM_UNDEFINED));
235
236   return Molecule ( b,at);
237 }
238
239 Molecule
240 Lookup::frame (Box b, Real thick)
241 {
242   Molecule m;
243   Direction d = LEFT;
244   Axis a = X_AXIS;
245   while (a < NO_AXES)
246     {
247       do
248         {
249           Axis o = Axis ((a+1)%NO_AXES);
250
251           Box edges;
252           edges[a] = b[a][d] + 0.5 * thick * Interval (-1, 1);
253           edges[o][DOWN] = b[o][DOWN] - thick/2;
254           edges[o][UP] = b[o][UP] + thick/2;      
255           
256           
257           m.add_molecule (filledbox (edges));
258         }
259       while (flip (&d) != LEFT);
260     }
261   return m;
262   
263 }
264
265
266 /*
267    TODO: THIS IS UGLY.
268    Since the user has direct access to TeX marcos,
269    that currently provide the  only way to do
270    font selection, accents etc,
271    we try some halfbaked attempt to detect this TeX trickery.
272  */
273 String
274 sanitise_TeX_string (String text)
275 {
276   int brace_count =0;
277   for (int i= 0; i < text.length_i (); i++)
278     {
279       if (text[i] == '\\')
280         continue;
281       
282       if (text[i] == '{')
283         brace_count ++;
284       else if (text[i] == '}')
285         brace_count --;
286     }
287   
288   if(brace_count)
289     {
290       warning (_f ("Non-matching braces in text `%s', adding braces", text.ch_C()));
291
292       if (brace_count < 0)
293         {
294           text = to_str ('{', -brace_count) + text;
295         }
296       else 
297         {
298           text = text + to_str ('}', brace_count);
299         }
300     }
301     
302   return text;
303 }
304
305 /**
306    TODO!
307  */
308 String
309 sanitise_PS_string (String t)
310 {
311   return t;
312 }
313
314 /**
315
316 */
317 Molecule
318 Lookup::text (String style, String text, Paper_def *paper_l) 
319 {
320   if (style.empty_b ())
321     style = "roman";
322   
323   int font_mag = 0;
324   Real font_h = paper_l->get_var ("font_normal");
325   if (paper_l->scope_p_->elem_b ("font_" + style))
326     {
327       font_h = paper_l->get_var ("font_" + style);
328     }
329
330
331   if (paper_l->scope_p_->elem_b ("magnification_" + style))
332     {
333       font_mag = (int)paper_l->get_var ("magnification_" + style);
334     }
335
336   /*
337     UGH.
338   */
339   SCM l = ly_eval_str (("(style-to-cmr \"" + style + "\")").ch_C());
340   if (l != SCM_BOOL_F)
341     {
342       style = ly_scm2string (gh_cdr(l)) +to_str  ((int)font_h);
343     }
344
345   
346
347   Font_metric* metric_l = 0;
348
349   if (font_mag)
350     metric_l = all_fonts_global_p->find_scaled (style, font_mag);
351   else
352     metric_l = all_fonts_global_p->find_font (style);
353   
354   
355     
356
357   int i = text.index_i ("\\n");
358   while (i >=0 )
359     {
360       text = text.left_str (i) + "\n" + text.right_str (text.length_i () - i - 2);
361       i = text.index_i ("\\n");
362     }
363   
364   Array<String> lines = String_convert::split_arr (text, '\n');
365   
366   Molecule mol;
367   
368   Real kern = paper_l->get_var ("line_kern");
369   
370   for (i = 0; i< lines.size (); i++)
371     {
372       /*
373         Huh?  This way we'll still see \foo sequences in ps output.
374        */
375       String str = lines[i];
376       if (output_global_ch == "tex")
377         str = sanitise_TeX_string  (str);
378       else if (output_global_ch == "ps")
379         str = sanitise_PS_string (str);
380
381       SCM line = (gh_list (ly_symbol2scm ("text"),
382                            ly_str02scm (str.ch_C ()),
383                            SCM_UNDEFINED));
384       line = fontify_atom (metric_l, line);
385       mol.add_at_edge (Y_AXIS, DOWN,
386                        Molecule (metric_l->text_dimension (str), line),
387                        kern);
388     }
389
390   return mol;
391 }
392   
393
394
395 Molecule
396 Lookup::staff_brace (Real y, int staff_size) 
397 {
398   // URG
399   Real step  = 1.0;
400   int minht  = 2 * staff_size;
401   int maxht = 7 *  minht;
402   int idx = int (((maxht - step) <? y - minht) / step);
403   idx = idx >? 0;
404
405   SCM l = ly_eval_str ("(style-to-cmr \"brace\")");
406   String nm = "feta-braces";
407   if (l != SCM_BOOL_F)
408     nm = ly_scm2string (gh_cdr (l));
409   nm += to_str (staff_size);
410   SCM e =gh_list (ly_symbol2scm ("char"), gh_int2scm (idx), SCM_UNDEFINED);
411   SCM at = (e);
412
413   at = fontify_atom (all_fonts_global_p->find_font (nm), at);
414   
415   Box b ( Interval (-y/2,y/2),
416            Interval (0,0));
417   return Molecule(b, at);
418 }
419  
420
421 /*
422   Make a smooth curve along the points 
423  */
424 Molecule
425 Lookup::slur (Bezier curve, Real curvethick, Real linethick) 
426 {
427   Real alpha = (curve.control_[3] - curve.control_[0]).arg ();
428   Bezier back = curve;
429
430   back.reverse ();
431   back.control_[1] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));
432   back.control_[2] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));  
433
434   SCM scontrols[8];
435   // this is silly, we have array_to_scm
436   for (int i=4; i--;)
437     scontrols[ i ] = to_scm (back.control_[i]);
438   for (int i=4 ; i--;)
439     scontrols[i+4] = to_scm (curve.control_[i]);
440
441   /*
442     Need the weird order b.o. the way PS want its arguments  
443    */
444   int indices[]= {5, 6, 7, 4, 1, 2, 3, 0};
445   SCM list = SCM_EOL;
446   for (int i= 8; i--;  )
447     {
448       list = gh_cons (scontrols[indices[i]], list);
449     }
450   
451   
452   SCM at = (gh_list (ly_symbol2scm ("bezier-sandwich"),
453                      ly_quote_scm (list),
454                      gh_double2scm (linethick),
455                      SCM_UNDEFINED));
456
457   Box b ( curve.extent (X_AXIS), curve.extent (Y_AXIS));
458   return Molecule (b, at);
459 }
460
461 Molecule
462 Lookup::staff_bracket (Real height, Paper_def* paper_l)
463 {
464   SCM at = ( gh_list (ly_symbol2scm ("bracket"),
465                       gh_double2scm (paper_l->get_var("bracket_arch_angle")),
466                       gh_double2scm (paper_l->get_var("bracket_arch_width")),
467                       gh_double2scm (paper_l->get_var("bracket_arch_height")),
468                       gh_double2scm (paper_l->get_var("bracket_width")),
469                       gh_double2scm (height),
470                       gh_double2scm (paper_l->get_var("bracket_arch_thick")),
471                       gh_double2scm (paper_l->get_var("bracket_thick")),
472                       SCM_UNDEFINED));
473
474   Real staff_space = paper_l->get_var ("interline");
475   Box b (Interval (0, 1.5 * staff_space), Interval (-height/2,height/2));
476   Molecule mol (b, at);
477
478   mol.translate_axis (- mol.dim_[X_AXIS].length () / 2, X_AXIS);
479   return mol;
480 }
481
482
483 Molecule
484 Lookup::accordion (SCM s, Real staff_space) const
485 {
486   Molecule m;
487   String sym = ly_scm2string(gh_car (s));
488   String reg = ly_scm2string(gh_car (gh_cdr(s)));
489
490   if (sym == "Discant")
491     {
492       Molecule r = afm_find("scripts-accDiscant");
493       m.add_molecule(r);
494       if (reg.left_str(1) == "F")
495         {
496           Molecule d = afm_find("scripts-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       int eflag = 0x00;
502       if (reg.left_str(3) == "EEE")
503         {
504           eflag = 0x07;
505           reg = reg.right_str(reg.length_i()-3);
506         }
507       else if (reg.left_str(2) == "EE")
508         {
509           eflag = 0x05;
510           reg = reg.right_str(reg.length_i()-2);
511         }
512       else if (reg.left_str(2) == "Eh")
513         {
514           eflag = 0x04;
515           reg = reg.right_str(reg.length_i()-2);
516         }
517       else if (reg.left_str(1) == "E")
518         {
519           eflag = 0x02;
520           reg = reg.right_str(reg.length_i()-1);
521         }
522       if (eflag & 0x02)
523         {
524           Molecule d = afm_find("scripts-accDot");
525           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
526           m.add_molecule(d);
527         }
528       if (eflag & 0x04)
529         {
530           Molecule d = afm_find("scripts-accDot");
531           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
532           d.translate_axis(0.8 * staff_space PT, X_AXIS);
533           m.add_molecule(d);
534         }
535       if (eflag & 0x01)
536         {
537           Molecule d = afm_find("scripts-accDot");
538           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
539           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
540           m.add_molecule(d);
541         }
542       if (reg.left_str(2) == "SS")
543         {
544           Molecule d = afm_find("scripts-accDot");
545           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
546           d.translate_axis(0.4 * staff_space PT, X_AXIS);
547           m.add_molecule(d);
548           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
549           m.add_molecule(d);
550           reg = reg.right_str(reg.length_i()-2);
551         }
552       if (reg.left_str(1) == "S")
553         {
554           Molecule d = afm_find("scripts-accDot");
555           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
556           m.add_molecule(d);
557           reg = reg.right_str(reg.length_i()-1);
558         }
559     }
560   else if (sym == "Freebase")
561     {
562       Molecule r = afm_find("scripts-accFreebase");
563       m.add_molecule(r);
564       if (reg.left_str(1) == "F")
565         {
566           Molecule d = afm_find("scripts-accDot");
567           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
568           m.add_molecule(d);
569           reg = reg.right_str(reg.length_i()-1);
570         }
571       if (reg == "E")
572         {
573           Molecule d = afm_find("scripts-accDot");
574           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
575           m.add_molecule(d);
576         }
577     }
578   else if (sym == "Bayanbase")
579     {
580       Molecule r = afm_find("scripts-accBayanbase");
581       m.add_molecule(r);
582       if (reg.left_str(1) == "T")
583         {
584           Molecule d = afm_find("scripts-accDot");
585           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
586           m.add_molecule(d);
587           reg = reg.right_str(reg.length_i()-1);
588         }
589       /* include 4' reed just for completeness. You don't want to use this. */
590       if (reg.left_str(1) == "F")
591         {
592           Molecule d = afm_find("scripts-accDot");
593           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
594           m.add_molecule(d);
595           reg = reg.right_str(reg.length_i()-1);
596         }
597       if (reg.left_str(2) == "EE")
598         {
599           Molecule d = afm_find("scripts-accDot");
600           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
601           d.translate_axis(0.4 * staff_space PT, X_AXIS);
602           m.add_molecule(d);
603           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
604           m.add_molecule(d);
605           reg = reg.right_str(reg.length_i()-2);
606         }
607       if (reg.left_str(1) == "E")
608         {
609           Molecule d = afm_find("scripts-accDot");
610           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
611           m.add_molecule(d);
612           reg = reg.right_str(reg.length_i()-1);
613         }
614     }
615   else if (sym == "Stdbase")
616     {
617       Molecule r = afm_find("scripts-accStdbase");
618       m.add_molecule(r);
619       if (reg.left_str(1) == "T")
620         {
621           Molecule d = afm_find("scripts-accDot");
622           d.translate_axis(staff_space * 3.5 PT, Y_AXIS);
623           m.add_molecule(d);
624           reg = reg.right_str(reg.length_i()-1);
625         }
626       if (reg.left_str(1) == "F")
627         {
628           Molecule d = afm_find("scripts-accDot");
629           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
630           m.add_molecule(d);
631           reg = reg.right_str(reg.length_i()-1);
632         }
633       if (reg.left_str(1) == "M")
634         {
635           Molecule d = afm_find("scripts-accDot");
636           d.translate_axis(staff_space * 2 PT, Y_AXIS);
637           d.translate_axis(staff_space PT, X_AXIS);
638           m.add_molecule(d);
639           reg = reg.right_str(reg.length_i()-1);
640         }
641       if (reg.left_str(1) == "E")
642         {
643           Molecule d = afm_find("scripts-accDot");
644           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
645           m.add_molecule(d);
646           reg = reg.right_str(reg.length_i()-1);
647         }
648       if (reg.left_str(1) == "S")
649         {
650           Molecule d = afm_find("scripts-accDot");
651           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
652           m.add_molecule(d);
653           reg = reg.right_str(reg.length_i()-1);
654         }
655     }
656   /* ugh maybe try to use regular font for S.B. and B.B and only use one font
657      for the rectangle */
658   else if (sym == "SB")
659     {
660       Molecule r = afm_find("scripts-accSB");
661       m.add_molecule(r);
662     }
663   else if (sym == "BB")
664     {
665       Molecule r = afm_find("scripts-accBB");
666       m.add_molecule(r);
667     }
668   else if (sym == "OldEE")
669     {
670       Molecule r = afm_find("scripts-accOldEE");
671       m.add_molecule(r);
672     }
673   else if (sym == "OldEES")
674     {
675       Molecule r = afm_find("scripts-accOldEES");
676       m.add_molecule(r);
677     }
678   return m;  
679 }
680