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