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