]> git.donarmstrong.com Git - lilypond.git/blob - lily/lookup.cc
0f422458eea29ee76480df753352c08e08e63fa6
[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   // this is silly, we have array_to_scm
109   for (int i= 4; i -- ;)
110     {
111       l = gh_cons (to_scm (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   Molecule m;
131   m.dim_ = b;
132   return m;
133 }
134
135
136 Molecule
137 Lookup::filledbox (Box b ) 
138 {
139   SCM  at  = (gh_list (ly_symbol2scm ("filledbox"),
140                      gh_double2scm (-b[X_AXIS][LEFT]),
141                      gh_double2scm (b[X_AXIS][RIGHT]),                 
142                      gh_double2scm (-b[Y_AXIS][DOWN]),
143                      gh_double2scm (b[Y_AXIS][UP]),                    
144                      SCM_UNDEFINED));
145
146   return Molecule ( b,at);
147 }
148
149 Molecule
150 Lookup::frame (Box b, Real thick)
151 {
152   Molecule m;
153   Direction d = LEFT;
154   Axis a = X_AXIS;
155   while (a < NO_AXES)
156     {
157       do
158         {
159           Axis o = Axis ((a+1)%NO_AXES);
160
161           Box edges;
162           edges[a] = b[a][d] + 0.5 * thick * Interval (-1, 1);
163           edges[o][DOWN] = b[o][DOWN] - thick/2;
164           edges[o][UP] = b[o][UP] + thick/2;      
165           
166           
167           m.add_molecule (filledbox (edges));
168         }
169       while (flip (&d) != LEFT);
170     }
171   return m;
172   
173 }
174
175
176 /*
177    TODO: THIS IS UGLY.
178    Since the user has direct access to TeX marcos,
179    that currently provide the  only way to do
180    font selection, accents etc,
181    we try some halfbaked attempt to detect this TeX trickery.
182  */
183 String
184 sanitise_TeX_string (String text)
185 {
186   int brace_count =0;
187   for (int i= 0; i < text.length_i (); i++)
188     {
189       if (text[i] == '\\')
190         continue;
191       
192       if (text[i] == '{')
193         brace_count ++;
194       else if (text[i] == '}')
195         brace_count --;
196     }
197   
198   if(brace_count)
199     {
200       warning (_f ("Non-matching braces in text `%s', adding braces", text.ch_C()));
201
202       if (brace_count < 0)
203         {
204           text = to_str ('{', -brace_count) + text;
205         }
206       else 
207         {
208           text = text + to_str ('}', brace_count);
209         }
210     }
211     
212   return text;
213 }
214
215 /**
216    TODO!
217  */
218 String
219 sanitise_PS_string (String t)
220 {
221   return t;
222 }
223
224 /**
225
226 */
227 Molecule
228 Lookup::text (String style, String text, Paper_def *paper_l) 
229 {
230   if (style.empty_b ())
231     style = "roman";
232   
233   int font_mag = 0;
234   Real font_h = paper_l->get_var ("font_normal");
235   if (paper_l->scope_p_->elem_b ("font_" + style))
236     {
237       font_h = paper_l->get_var ("font_" + style);
238     }
239
240
241   if (paper_l->scope_p_->elem_b ("magnification_" + style))
242     {
243       font_mag = (int)paper_l->get_var ("magnification_" + style);
244     }
245
246   /*
247     UGH.
248   */
249   SCM l = ly_eval_str (("(style-to-cmr \"" + style + "\")").ch_C());
250   if (l != SCM_BOOL_F)
251     {
252       style = ly_scm2string (gh_cdr(l)) +to_str  ((int)font_h);
253     }
254
255   
256
257   Font_metric* metric_l = 0;
258
259   if (font_mag)
260     metric_l = all_fonts_global_p->find_scaled (style, font_mag);
261   else
262     metric_l = all_fonts_global_p->find_font (style);
263   
264   
265     
266
267   int i = text.index_i ("\\n");
268   while (i >=0 )
269     {
270       text = text.left_str (i) + "\n" + text.right_str (text.length_i () - i - 2);
271       i = text.index_i ("\\n");
272     }
273   
274   Array<String> lines = String_convert::split_arr (text, '\n');
275   
276   Molecule mol;
277   
278   Real kern = paper_l->get_var ("line_kern");
279   
280   for (i = 0; i< lines.size (); i++)
281     {
282       /*
283         Huh?  This way we'll still see \foo sequences in ps output.
284        */
285       String str = lines[i];
286       if (output_global_ch == "tex")
287         str = sanitise_TeX_string  (str);
288       else if (output_global_ch == "ps")
289         str = sanitise_PS_string (str);
290
291       SCM line = (gh_list (ly_symbol2scm ("text"),
292                            ly_str02scm (str.ch_C ()),
293                            SCM_UNDEFINED));
294       line = fontify_atom (metric_l, line);
295       mol.add_at_edge (Y_AXIS, DOWN,
296                        Molecule (metric_l->text_dimension (str), line),
297                        kern);
298     }
299
300   return mol;
301 }
302   
303
304
305 /*
306   Make a smooth curve along the points 
307  */
308 Molecule
309 Lookup::slur (Bezier curve, Real curvethick, Real linethick) 
310 {
311   Real alpha = (curve.control_[3] - curve.control_[0]).arg ();
312   Bezier back = curve;
313
314   back.reverse ();
315   back.control_[1] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));
316   back.control_[2] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));  
317
318   SCM scontrols[8];
319   // this is silly, we have array_to_scm
320   for (int i=4; i--;)
321     scontrols[ i ] = to_scm (back.control_[i]);
322   for (int i=4 ; i--;)
323     scontrols[i+4] = to_scm (curve.control_[i]);
324
325   /*
326     Need the weird order b.o. the way PS want its arguments  
327    */
328   int indices[]= {5, 6, 7, 4, 1, 2, 3, 0};
329   SCM list = SCM_EOL;
330   for (int i= 8; i--;  )
331     {
332       list = gh_cons (scontrols[indices[i]], list);
333     }
334   
335   
336   SCM at = (gh_list (ly_symbol2scm ("bezier-sandwich"),
337                      ly_quote_scm (list),
338                      gh_double2scm (linethick),
339                      SCM_UNDEFINED));
340
341   Box b ( curve.extent (X_AXIS), curve.extent (Y_AXIS));
342   return Molecule (b, at);
343 }
344
345 Molecule
346 Lookup::accordion (SCM s, Real staff_space) const
347 {
348   Molecule m;
349   String sym = ly_scm2string(gh_car (s));
350   String reg = ly_scm2string(gh_car (gh_cdr(s)));
351
352   if (sym == "Discant")
353     {
354       Molecule r = afm_find("scripts-accDiscant");
355       m.add_molecule(r);
356       if (reg.left_str(1) == "F")
357         {
358           Molecule d = afm_find("scripts-accDot");
359           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
360           m.add_molecule(d);
361           reg = reg.right_str(reg.length_i()-1);
362         }
363       int eflag = 0x00;
364       if (reg.left_str(3) == "EEE")
365         {
366           eflag = 0x07;
367           reg = reg.right_str(reg.length_i()-3);
368         }
369       else if (reg.left_str(2) == "EE")
370         {
371           eflag = 0x05;
372           reg = reg.right_str(reg.length_i()-2);
373         }
374       else if (reg.left_str(2) == "Eh")
375         {
376           eflag = 0x04;
377           reg = reg.right_str(reg.length_i()-2);
378         }
379       else if (reg.left_str(1) == "E")
380         {
381           eflag = 0x02;
382           reg = reg.right_str(reg.length_i()-1);
383         }
384       if (eflag & 0x02)
385         {
386           Molecule d = afm_find("scripts-accDot");
387           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
388           m.add_molecule(d);
389         }
390       if (eflag & 0x04)
391         {
392           Molecule d = afm_find("scripts-accDot");
393           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
394           d.translate_axis(0.8 * staff_space PT, X_AXIS);
395           m.add_molecule(d);
396         }
397       if (eflag & 0x01)
398         {
399           Molecule d = afm_find("scripts-accDot");
400           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
401           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
402           m.add_molecule(d);
403         }
404       if (reg.left_str(2) == "SS")
405         {
406           Molecule d = afm_find("scripts-accDot");
407           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
408           d.translate_axis(0.4 * staff_space PT, X_AXIS);
409           m.add_molecule(d);
410           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
411           m.add_molecule(d);
412           reg = reg.right_str(reg.length_i()-2);
413         }
414       if (reg.left_str(1) == "S")
415         {
416           Molecule d = afm_find("scripts-accDot");
417           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
418           m.add_molecule(d);
419           reg = reg.right_str(reg.length_i()-1);
420         }
421     }
422   else if (sym == "Freebase")
423     {
424       Molecule r = afm_find("scripts-accFreebase");
425       m.add_molecule(r);
426       if (reg.left_str(1) == "F")
427         {
428           Molecule d = afm_find("scripts-accDot");
429           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
430           m.add_molecule(d);
431           reg = reg.right_str(reg.length_i()-1);
432         }
433       if (reg == "E")
434         {
435           Molecule d = afm_find("scripts-accDot");
436           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
437           m.add_molecule(d);
438         }
439     }
440   else if (sym == "Bayanbase")
441     {
442       Molecule r = afm_find("scripts-accBayanbase");
443       m.add_molecule(r);
444       if (reg.left_str(1) == "T")
445         {
446           Molecule d = afm_find("scripts-accDot");
447           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
448           m.add_molecule(d);
449           reg = reg.right_str(reg.length_i()-1);
450         }
451       /* include 4' reed just for completeness. You don't want to use this. */
452       if (reg.left_str(1) == "F")
453         {
454           Molecule d = afm_find("scripts-accDot");
455           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
456           m.add_molecule(d);
457           reg = reg.right_str(reg.length_i()-1);
458         }
459       if (reg.left_str(2) == "EE")
460         {
461           Molecule d = afm_find("scripts-accDot");
462           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
463           d.translate_axis(0.4 * staff_space PT, X_AXIS);
464           m.add_molecule(d);
465           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
466           m.add_molecule(d);
467           reg = reg.right_str(reg.length_i()-2);
468         }
469       if (reg.left_str(1) == "E")
470         {
471           Molecule d = afm_find("scripts-accDot");
472           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
473           m.add_molecule(d);
474           reg = reg.right_str(reg.length_i()-1);
475         }
476     }
477   else if (sym == "Stdbase")
478     {
479       Molecule r = afm_find("scripts-accStdbase");
480       m.add_molecule(r);
481       if (reg.left_str(1) == "T")
482         {
483           Molecule d = afm_find("scripts-accDot");
484           d.translate_axis(staff_space * 3.5 PT, Y_AXIS);
485           m.add_molecule(d);
486           reg = reg.right_str(reg.length_i()-1);
487         }
488       if (reg.left_str(1) == "F")
489         {
490           Molecule d = afm_find("scripts-accDot");
491           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
492           m.add_molecule(d);
493           reg = reg.right_str(reg.length_i()-1);
494         }
495       if (reg.left_str(1) == "M")
496         {
497           Molecule d = afm_find("scripts-accDot");
498           d.translate_axis(staff_space * 2 PT, Y_AXIS);
499           d.translate_axis(staff_space PT, X_AXIS);
500           m.add_molecule(d);
501           reg = reg.right_str(reg.length_i()-1);
502         }
503       if (reg.left_str(1) == "E")
504         {
505           Molecule d = afm_find("scripts-accDot");
506           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
507           m.add_molecule(d);
508           reg = reg.right_str(reg.length_i()-1);
509         }
510       if (reg.left_str(1) == "S")
511         {
512           Molecule d = afm_find("scripts-accDot");
513           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
514           m.add_molecule(d);
515           reg = reg.right_str(reg.length_i()-1);
516         }
517     }
518   /* ugh maybe try to use regular font for S.B. and B.B and only use one font
519      for the rectangle */
520   else if (sym == "SB")
521     {
522       Molecule r = afm_find("scripts-accSB");
523       m.add_molecule(r);
524     }
525   else if (sym == "BB")
526     {
527       Molecule r = afm_find("scripts-accBB");
528       m.add_molecule(r);
529     }
530   else if (sym == "OldEE")
531     {
532       Molecule r = afm_find("scripts-accOldEE");
533       m.add_molecule(r);
534     }
535   else if (sym == "OldEES")
536     {
537       Molecule r = afm_find("scripts-accOldEES");
538       m.add_molecule(r);
539     }
540   return m;  
541 }
542