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