]> git.donarmstrong.com Git - lilypond.git/blob - lily/lookup.cc
patch::: 1.3.96.jcn4
[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 "warn.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
31 #include "ly-smobs.icc"
32
33
34 Lookup::Lookup ()
35 {
36   afm_l_ = 0;  
37 }
38
39 Lookup::Lookup (Lookup const& s)
40 {
41   font_name_ = s.font_name_;
42   afm_l_ = 0;
43 }
44
45 SCM
46 Lookup::mark_smob (SCM s)
47 {
48   return s;  
49 }
50
51 int
52 Lookup::print_smob (SCM s, SCM p, scm_print_state*)
53 {
54   scm_puts ("#<Lookup >#", p);
55   return 1;
56 }
57
58
59 IMPLEMENT_UNSMOB(Lookup, lookup);
60 IMPLEMENT_SIMPLE_SMOBS(Lookup);
61 IMPLEMENT_DEFAULT_EQUAL_P(Lookup);
62
63 SCM
64 Lookup::make_lookup ()
65 {
66   Lookup * l = new Lookup;
67   return l->smobbed_self();
68 }
69
70
71 Molecule
72 Lookup::afm_find (String s, bool warn) const
73 {
74   if (!afm_l_)      
75     {
76       Lookup * me = (Lookup*)(this);
77       me->afm_l_ = all_fonts_global_p->find_afm (font_name_);
78       if (!me->afm_l_)
79         {
80           warning (_f ("can't find font: `%s'", font_name_));
81           warning (_f ("(search path: `%s')", global_path.str ().ch_C()));
82           error (_ ("Aborting"));
83         }
84     }
85   AFM_CharMetricInfo const *cm = afm_l_->find_char_metric (s, warn);
86
87   if (!cm)
88     {
89       Molecule m;
90       m.set_empty (false);
91       return m;
92     }
93   
94   SCM at =  (gh_list (ly_symbol2scm ("char"),
95                     gh_int2scm (cm->code),
96                     SCM_UNDEFINED));
97
98
99   at= fontify_atom (afm_l_,at);
100   return Molecule ( afm_bbox_to_box (cm->charBBox), at);
101 }
102
103   
104
105
106 Molecule 
107 Lookup::beam (Real slope, Real width, Real thick) 
108 {
109   Real height = slope * width; 
110   Real min_y = (0 <? height) - thick/2;
111   Real max_y = (0 >? height) + thick/2;
112
113   
114
115   Box b( Interval (0, width),
116          Interval (min_y, max_y));
117
118   
119   SCM at = gh_list (ly_symbol2scm ("beam"),
120                     gh_double2scm (width),
121                     gh_double2scm (slope),
122                     gh_double2scm (thick),
123                     SCM_UNDEFINED);
124   return Molecule (b, at);
125 }
126
127
128
129 Molecule
130 Lookup::dashed_slur (Bezier b, Real thick, Real dash)
131 {
132   SCM l = SCM_EOL;
133
134   for (int i= 4; i -- ;)
135     {
136       l = gh_cons (ly_offset2scm (b.control_[i]), l);
137     }
138
139   SCM at = (gh_list (ly_symbol2scm ("dashed-slur"),
140                                gh_double2scm (thick), 
141                                gh_double2scm (dash),
142                                ly_quote_scm (l),
143                                SCM_UNDEFINED));
144
145   Box box (Interval(0,0),Interval( 0,0));
146   return   Molecule (box, at);
147 }
148
149
150
151
152 Molecule
153 Lookup::blank (Box b) 
154 {
155   return Molecule (b, SCM_EOL);
156 }
157
158
159 Molecule
160 Lookup::filledbox (Box b ) 
161 {
162   SCM  at  = (gh_list (ly_symbol2scm ("filledbox"),
163                      gh_double2scm (-b[X_AXIS][LEFT]),
164                      gh_double2scm (b[X_AXIS][RIGHT]),                 
165                      gh_double2scm (-b[Y_AXIS][DOWN]),
166                      gh_double2scm (b[Y_AXIS][UP]),                    
167                      SCM_UNDEFINED));
168
169   return Molecule ( b,at);
170 }
171
172 Molecule
173 Lookup::frame (Box b, Real thick)
174 {
175   Molecule m;
176   Direction d = LEFT;
177   Axis a = X_AXIS;
178   while (a < NO_AXES)
179     {
180       do
181         {
182           Axis o = Axis ((a+1)%NO_AXES);
183
184           Box edges;
185           edges[a] = b[a][d] + 0.5 * thick * Interval (-1, 1);
186           edges[o][DOWN] = b[o][DOWN] - thick/2;
187           edges[o][UP] = b[o][UP] + thick/2;      
188           
189           
190           m.add_molecule (filledbox (edges));
191         }
192       while (flip (&d) != LEFT);
193     }
194   return m;
195   
196 }
197
198
199 /*
200   JUNKME
201  
202    TODO: THIS IS UGLY.
203    Since the user has direct access to TeX marcos,
204    that currently provide the  only way to do
205    font selection, accents etc,
206    we try some halfbaked attempt to detect this TeX trickery.
207  */
208 String
209 sanitise_TeX_string (String text)
210 {
211   int brace_count =0;
212   for (int i= 0; i < text.length_i (); i++)
213     {
214       if (text[i] == '\\')
215         continue;
216       
217       if (text[i] == '{')
218         brace_count ++;
219       else if (text[i] == '}')
220         brace_count --;
221     }
222   
223   if(brace_count)
224     {
225       warning (_f ("Non-matching braces in text `%s', adding braces", text.ch_C()));
226
227       if (brace_count < 0)
228         {
229           text = to_str ('{', -brace_count) + text;
230         }
231       else 
232         {
233           text = text + to_str ('}', brace_count);
234         }
235     }
236     
237   return text;
238 }
239
240 /**
241    JUNKME
242  */
243 String
244 sanitise_PS_string (String t)
245 {
246   return t;
247 }
248
249 /**
250    JUNKME
251 */
252 Molecule
253 Lookup::text (String style, String text, Paper_def *paper_l) 
254 {
255   if (style.empty_b ())
256     style = "roman";
257   
258   int font_mag = 0;
259   Real font_h = paper_l->get_var ("font_normal");
260   if (paper_l->scope_p_->elem_b ("font_" + style))
261     {
262       font_h = paper_l->get_var ("font_" + style);
263     }
264
265
266   if (paper_l->scope_p_->elem_b ("magnification_" + style))
267     {
268       font_mag = (int)paper_l->get_var ("magnification_" + style);
269     }
270
271   /*
272     FIXME !
273    */
274   
275   SCM l = scm_assoc (ly_str02scm (style.ch_C()),
276                      scm_eval2 (ly_symbol2scm ("cmr-alist"), SCM_EOL));
277
278   if (l != SCM_BOOL_F)
279     {
280       style = ly_scm2string (gh_cdr(l)) +to_str  ((int)font_h);
281     }
282
283   Font_metric* metric_l = 0;
284
285   if (font_mag)
286     metric_l = all_fonts_global_p->find_scaled (style, font_mag);
287   else
288     metric_l = all_fonts_global_p->find_font (style);
289   
290   
291     
292
293   int i = text.index_i ("\\n");
294   while (i >=0 )
295     {
296       text = text.left_str (i) + "\n" + text.right_str (text.length_i () - i - 2);
297       i = text.index_i ("\\n");
298     }
299   
300   Array<String> lines = String_convert::split_arr (text, '\n');
301   
302   Real kern = paper_l->get_var ("line_kern");
303   
304   for (int i=0; i < lines.size (); i++)
305     {
306       String str (lines[i]);
307       if (output_global_ch == "tex")
308         str = sanitise_TeX_string  (str);
309       else if (output_global_ch == "ps")
310         str = sanitise_PS_string (str);
311       lines[i] = str;
312     }
313
314   if (!lines.size())
315         return Molecule();
316
317   SCM first = gh_list (ly_symbol2scm ("text"),
318                          ly_str02scm (lines[0].ch_C()),
319                          SCM_UNDEFINED);
320   first = fontify_atom (metric_l, first);
321
322   
323
324   Molecule mol (metric_l->text_dimension (lines[0]), first);
325
326   for (i = 1; i < lines.size (); i++)
327     {
328       SCM line = (gh_list (ly_symbol2scm ("text"),
329                            ly_str02scm (lines[i].ch_C ()),
330                            SCM_UNDEFINED));
331       line = fontify_atom (metric_l, line);
332       mol.add_at_edge (Y_AXIS, DOWN,
333                        Molecule (metric_l->text_dimension (lines[i]), line),
334                        kern);
335     }
336
337   return mol;
338 }
339   
340
341
342 /*
343   Make a smooth curve along the points 
344  */
345 Molecule
346 Lookup::slur (Bezier curve, Real curvethick, Real linethick) 
347 {
348   Real alpha = (curve.control_[3] - curve.control_[0]).arg ();
349   Bezier back = curve;
350
351   back.reverse ();
352   back.control_[1] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));
353   back.control_[2] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));  
354
355   SCM scontrols[8];
356
357   for (int i=4; i--;)
358     scontrols[ i ] = ly_offset2scm(back.control_[i]);
359   for (int i=4 ; i--;)
360     scontrols[i+4] = ly_offset2scm (curve.control_[i]);
361
362   /*
363     Need the weird order b.o. the way PS want its arguments  
364    */
365   int indices[]= {5, 6, 7, 4, 1, 2, 3, 0};
366   SCM list = SCM_EOL;
367   for (int i= 8; i--;  )
368     {
369       list = gh_cons (scontrols[indices[i]], list);
370     }
371   
372   
373   SCM at = (gh_list (ly_symbol2scm ("bezier-sandwich"),
374                      ly_quote_scm (list),
375                      gh_double2scm (linethick),
376                      SCM_UNDEFINED));
377
378   Box b ( curve.extent (X_AXIS), curve.extent (Y_AXIS));
379   return Molecule (b, at);
380 }
381
382 Molecule
383 Lookup::accordion (SCM s, Real staff_space) const
384 {
385   Molecule m;
386   String sym = ly_scm2string(gh_car (s));
387   String reg = ly_scm2string(gh_car (gh_cdr(s)));
388
389   if (sym == "Discant")
390     {
391       Molecule r = afm_find("accordion-accDiscant");
392       m.add_molecule(r);
393       if (reg.left_str(1) == "F")
394         {
395           Molecule d = afm_find("accordion-accDot");
396           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
397           m.add_molecule(d);
398           reg = reg.right_str(reg.length_i()-1);
399         }
400       int eflag = 0x00;
401       if (reg.left_str(3) == "EEE")
402         {
403           eflag = 0x07;
404           reg = reg.right_str(reg.length_i()-3);
405         }
406       else if (reg.left_str(2) == "EE")
407         {
408           eflag = 0x05;
409           reg = reg.right_str(reg.length_i()-2);
410         }
411       else if (reg.left_str(2) == "Eh")
412         {
413           eflag = 0x04;
414           reg = reg.right_str(reg.length_i()-2);
415         }
416       else if (reg.left_str(1) == "E")
417         {
418           eflag = 0x02;
419           reg = reg.right_str(reg.length_i()-1);
420         }
421       if (eflag & 0x02)
422         {
423           Molecule d = afm_find("accordion-accDot");
424           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
425           m.add_molecule(d);
426         }
427       if (eflag & 0x04)
428         {
429           Molecule d = afm_find("accordion-accDot");
430           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
431           d.translate_axis(0.8 * staff_space PT, X_AXIS);
432           m.add_molecule(d);
433         }
434       if (eflag & 0x01)
435         {
436           Molecule d = afm_find("accordion-accDot");
437           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
438           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
439           m.add_molecule(d);
440         }
441       if (reg.left_str(2) == "SS")
442         {
443           Molecule d = afm_find("accordion-accDot");
444           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
445           d.translate_axis(0.4 * staff_space PT, X_AXIS);
446           m.add_molecule(d);
447           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
448           m.add_molecule(d);
449           reg = reg.right_str(reg.length_i()-2);
450         }
451       if (reg.left_str(1) == "S")
452         {
453           Molecule d = afm_find("accordion-accDot");
454           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
455           m.add_molecule(d);
456           reg = reg.right_str(reg.length_i()-1);
457         }
458     }
459   else if (sym == "Freebase")
460     {
461       Molecule r = afm_find("accordion-accFreebase");
462       m.add_molecule(r);
463       if (reg.left_str(1) == "F")
464         {
465           Molecule d = afm_find("accordion-accDot");
466           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
467           m.add_molecule(d);
468           reg = reg.right_str(reg.length_i()-1);
469         }
470       if (reg == "E")
471         {
472           Molecule d = afm_find("accordion-accDot");
473           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
474           m.add_molecule(d);
475         }
476     }
477   else if (sym == "Bayanbase")
478     {
479       Molecule r = afm_find("accordion-accBayanbase");
480       m.add_molecule(r);
481       if (reg.left_str(1) == "T")
482         {
483           Molecule d = afm_find("accordion-accDot");
484           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
485           m.add_molecule(d);
486           reg = reg.right_str(reg.length_i()-1);
487         }
488       /* include 4' reed just for completeness. You don't want to use this. */
489       if (reg.left_str(1) == "F")
490         {
491           Molecule d = afm_find("accordion-accDot");
492           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
493           m.add_molecule(d);
494           reg = reg.right_str(reg.length_i()-1);
495         }
496       if (reg.left_str(2) == "EE")
497         {
498           Molecule d = afm_find("accordion-accDot");
499           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
500           d.translate_axis(0.4 * staff_space PT, X_AXIS);
501           m.add_molecule(d);
502           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
503           m.add_molecule(d);
504           reg = reg.right_str(reg.length_i()-2);
505         }
506       if (reg.left_str(1) == "E")
507         {
508           Molecule d = afm_find("accordion-accDot");
509           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
510           m.add_molecule(d);
511           reg = reg.right_str(reg.length_i()-1);
512         }
513     }
514   else if (sym == "Stdbase")
515     {
516       Molecule r = afm_find("accordion-accStdbase");
517       m.add_molecule(r);
518       if (reg.left_str(1) == "T")
519         {
520           Molecule d = afm_find("accordion-accDot");
521           d.translate_axis(staff_space * 3.5 PT, Y_AXIS);
522           m.add_molecule(d);
523           reg = reg.right_str(reg.length_i()-1);
524         }
525       if (reg.left_str(1) == "F")
526         {
527           Molecule d = afm_find("accordion-accDot");
528           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
529           m.add_molecule(d);
530           reg = reg.right_str(reg.length_i()-1);
531         }
532       if (reg.left_str(1) == "M")
533         {
534           Molecule d = afm_find("accordion-accDot");
535           d.translate_axis(staff_space * 2 PT, Y_AXIS);
536           d.translate_axis(staff_space PT, X_AXIS);
537           m.add_molecule(d);
538           reg = reg.right_str(reg.length_i()-1);
539         }
540       if (reg.left_str(1) == "E")
541         {
542           Molecule d = afm_find("accordion-accDot");
543           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
544           m.add_molecule(d);
545           reg = reg.right_str(reg.length_i()-1);
546         }
547       if (reg.left_str(1) == "S")
548         {
549           Molecule d = afm_find("accordion-accDot");
550           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
551           m.add_molecule(d);
552           reg = reg.right_str(reg.length_i()-1);
553         }
554     }
555   /* ugh maybe try to use regular font for S.B. and B.B and only use one font
556      for the rectangle */
557   else if (sym == "SB")
558     {
559       Molecule r = afm_find("accordion-accSB");
560       m.add_molecule(r);
561     }
562   else if (sym == "BB")
563     {
564       Molecule r = afm_find("accordion-accBB");
565       m.add_molecule(r);
566     }
567   else if (sym == "OldEE")
568     {
569       Molecule r = afm_find("accordion-accOldEE");
570       m.add_molecule(r);
571     }
572   else if (sym == "OldEES")
573     {
574       Molecule r = afm_find("accordion-accOldEES");
575       m.add_molecule(r);
576     }
577   return m;  
578 }
579