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