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