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