]> git.donarmstrong.com Git - lilypond.git/blob - lily/lookup.cc
release: 1.3.34
[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   Real kern = paper_l->get_var ("line_kern");
277   
278   for (int i=0; i < lines.size (); i++)
279     {
280       String str (lines[i]);
281       if (output_global_ch == "tex")
282         str = sanitise_TeX_string  (str);
283       else if (output_global_ch == "ps")
284         str = sanitise_PS_string (str);
285       lines[i] = str;
286     }
287
288
289   SCM first = gh_list (ly_symbol2scm ("text"),
290                          ly_str02scm (lines[0].ch_C()),
291                          SCM_UNDEFINED);
292   first = fontify_atom (metric_l, first);
293
294   
295
296   Molecule mol (metric_l->text_dimension (lines[0]), first);
297
298   for (i = 1; i < lines.size (); i++)
299     {
300       SCM line = (gh_list (ly_symbol2scm ("text"),
301                            ly_str02scm (lines[i].ch_C ()),
302                            SCM_UNDEFINED));
303       line = fontify_atom (metric_l, line);
304       mol.add_at_edge (Y_AXIS, DOWN,
305                        Molecule (metric_l->text_dimension (lines[i]), line),
306                        kern);
307     }
308
309   return mol;
310 }
311   
312
313
314 /*
315   Make a smooth curve along the points 
316  */
317 Molecule
318 Lookup::slur (Bezier curve, Real curvethick, Real linethick) 
319 {
320   Real alpha = (curve.control_[3] - curve.control_[0]).arg ();
321   Bezier back = curve;
322
323   back.reverse ();
324   back.control_[1] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));
325   back.control_[2] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));  
326
327   SCM scontrols[8];
328   // this is silly, we have array_to_scm
329   for (int i=4; i--;)
330     scontrols[ i ] = to_scm (back.control_[i]);
331   for (int i=4 ; i--;)
332     scontrols[i+4] = to_scm (curve.control_[i]);
333
334   /*
335     Need the weird order b.o. the way PS want its arguments  
336    */
337   int indices[]= {5, 6, 7, 4, 1, 2, 3, 0};
338   SCM list = SCM_EOL;
339   for (int i= 8; i--;  )
340     {
341       list = gh_cons (scontrols[indices[i]], list);
342     }
343   
344   
345   SCM at = (gh_list (ly_symbol2scm ("bezier-sandwich"),
346                      ly_quote_scm (list),
347                      gh_double2scm (linethick),
348                      SCM_UNDEFINED));
349
350   Box b ( curve.extent (X_AXIS), curve.extent (Y_AXIS));
351   return Molecule (b, at);
352 }
353
354 Molecule
355 Lookup::accordion (SCM s, Real staff_space) const
356 {
357   Molecule m;
358   String sym = ly_scm2string(gh_car (s));
359   String reg = ly_scm2string(gh_car (gh_cdr(s)));
360
361   if (sym == "Discant")
362     {
363       Molecule r = afm_find("scripts-accDiscant");
364       m.add_molecule(r);
365       if (reg.left_str(1) == "F")
366         {
367           Molecule d = afm_find("scripts-accDot");
368           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
369           m.add_molecule(d);
370           reg = reg.right_str(reg.length_i()-1);
371         }
372       int eflag = 0x00;
373       if (reg.left_str(3) == "EEE")
374         {
375           eflag = 0x07;
376           reg = reg.right_str(reg.length_i()-3);
377         }
378       else if (reg.left_str(2) == "EE")
379         {
380           eflag = 0x05;
381           reg = reg.right_str(reg.length_i()-2);
382         }
383       else if (reg.left_str(2) == "Eh")
384         {
385           eflag = 0x04;
386           reg = reg.right_str(reg.length_i()-2);
387         }
388       else if (reg.left_str(1) == "E")
389         {
390           eflag = 0x02;
391           reg = reg.right_str(reg.length_i()-1);
392         }
393       if (eflag & 0x02)
394         {
395           Molecule d = afm_find("scripts-accDot");
396           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
397           m.add_molecule(d);
398         }
399       if (eflag & 0x04)
400         {
401           Molecule d = afm_find("scripts-accDot");
402           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
403           d.translate_axis(0.8 * staff_space PT, X_AXIS);
404           m.add_molecule(d);
405         }
406       if (eflag & 0x01)
407         {
408           Molecule d = afm_find("scripts-accDot");
409           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
410           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
411           m.add_molecule(d);
412         }
413       if (reg.left_str(2) == "SS")
414         {
415           Molecule d = afm_find("scripts-accDot");
416           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
417           d.translate_axis(0.4 * staff_space PT, X_AXIS);
418           m.add_molecule(d);
419           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
420           m.add_molecule(d);
421           reg = reg.right_str(reg.length_i()-2);
422         }
423       if (reg.left_str(1) == "S")
424         {
425           Molecule d = afm_find("scripts-accDot");
426           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
427           m.add_molecule(d);
428           reg = reg.right_str(reg.length_i()-1);
429         }
430     }
431   else if (sym == "Freebase")
432     {
433       Molecule r = afm_find("scripts-accFreebase");
434       m.add_molecule(r);
435       if (reg.left_str(1) == "F")
436         {
437           Molecule d = afm_find("scripts-accDot");
438           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
439           m.add_molecule(d);
440           reg = reg.right_str(reg.length_i()-1);
441         }
442       if (reg == "E")
443         {
444           Molecule d = afm_find("scripts-accDot");
445           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
446           m.add_molecule(d);
447         }
448     }
449   else if (sym == "Bayanbase")
450     {
451       Molecule r = afm_find("scripts-accBayanbase");
452       m.add_molecule(r);
453       if (reg.left_str(1) == "T")
454         {
455           Molecule d = afm_find("scripts-accDot");
456           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
457           m.add_molecule(d);
458           reg = reg.right_str(reg.length_i()-1);
459         }
460       /* include 4' reed just for completeness. You don't want to use this. */
461       if (reg.left_str(1) == "F")
462         {
463           Molecule d = afm_find("scripts-accDot");
464           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
465           m.add_molecule(d);
466           reg = reg.right_str(reg.length_i()-1);
467         }
468       if (reg.left_str(2) == "EE")
469         {
470           Molecule d = afm_find("scripts-accDot");
471           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
472           d.translate_axis(0.4 * staff_space PT, X_AXIS);
473           m.add_molecule(d);
474           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
475           m.add_molecule(d);
476           reg = reg.right_str(reg.length_i()-2);
477         }
478       if (reg.left_str(1) == "E")
479         {
480           Molecule d = afm_find("scripts-accDot");
481           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
482           m.add_molecule(d);
483           reg = reg.right_str(reg.length_i()-1);
484         }
485     }
486   else if (sym == "Stdbase")
487     {
488       Molecule r = afm_find("scripts-accStdbase");
489       m.add_molecule(r);
490       if (reg.left_str(1) == "T")
491         {
492           Molecule d = afm_find("scripts-accDot");
493           d.translate_axis(staff_space * 3.5 PT, Y_AXIS);
494           m.add_molecule(d);
495           reg = reg.right_str(reg.length_i()-1);
496         }
497       if (reg.left_str(1) == "F")
498         {
499           Molecule d = afm_find("scripts-accDot");
500           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
501           m.add_molecule(d);
502           reg = reg.right_str(reg.length_i()-1);
503         }
504       if (reg.left_str(1) == "M")
505         {
506           Molecule d = afm_find("scripts-accDot");
507           d.translate_axis(staff_space * 2 PT, Y_AXIS);
508           d.translate_axis(staff_space PT, X_AXIS);
509           m.add_molecule(d);
510           reg = reg.right_str(reg.length_i()-1);
511         }
512       if (reg.left_str(1) == "E")
513         {
514           Molecule d = afm_find("scripts-accDot");
515           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
516           m.add_molecule(d);
517           reg = reg.right_str(reg.length_i()-1);
518         }
519       if (reg.left_str(1) == "S")
520         {
521           Molecule d = afm_find("scripts-accDot");
522           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
523           m.add_molecule(d);
524           reg = reg.right_str(reg.length_i()-1);
525         }
526     }
527   /* ugh maybe try to use regular font for S.B. and B.B and only use one font
528      for the rectangle */
529   else if (sym == "SB")
530     {
531       Molecule r = afm_find("scripts-accSB");
532       m.add_molecule(r);
533     }
534   else if (sym == "BB")
535     {
536       Molecule r = afm_find("scripts-accBB");
537       m.add_molecule(r);
538     }
539   else if (sym == "OldEE")
540     {
541       Molecule r = afm_find("scripts-accOldEE");
542       m.add_molecule(r);
543     }
544   else if (sym == "OldEES")
545     {
546       Molecule r = afm_find("scripts-accOldEES");
547       m.add_molecule(r);
548     }
549   return m;  
550 }
551