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