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