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