]> git.donarmstrong.com Git - lilypond.git/blob - lily/accidental.cc
Merge branch 'master' of git://git.sv.gnu.org/lilypond
[lilypond.git] / lily / accidental.cc
1 /*
2   accidental.cc -- implement Accidental_interface
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2001--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "accidental-interface.hh"
10 #include "font-interface.hh"
11 #include "international.hh"
12 #include "item.hh"
13 #include "output-def.hh"
14 #include "pitch.hh"
15 #include "stencil.hh"
16
17 Stencil
18 parenthesize (Grob *me, Stencil m)
19 {
20   Font_metric * font
21     = Font_interface::get_default_font (me); 
22   Stencil open
23     = font->find_by_name ("accidentals.leftparen");
24   Stencil close
25     = font->find_by_name ("accidentals.rightparen");
26
27   m.add_at_edge (X_AXIS, LEFT, Stencil (open), 0, 0);
28   m.add_at_edge (X_AXIS, RIGHT, Stencil (close), 0, 0);
29
30   return m;
31 }
32
33 /*
34   Hmm. Need separate callback, or perhaps #'live bool property.
35  */
36 MAKE_SCHEME_CALLBACK (Accidental_interface, after_line_breaking, 1);
37 SCM
38 Accidental_interface::after_line_breaking (SCM smob)
39 {
40   Grob *me = unsmob_grob (smob);
41   Grob *tie = unsmob_grob (me->get_object ("tie"));
42
43   if (tie && !tie->original ()
44       && !to_boolean (me->get_property ("forced")))
45     {
46       me->suicide ();
47     }
48  
49   return SCM_UNSPECIFIED;
50 }
51
52 vector<Box>
53 Accidental_interface::accurate_boxes (Grob *me, Grob **common)
54 {
55   Box b;
56   b[X_AXIS] = me->extent (me, X_AXIS);
57   b[Y_AXIS] = me->extent (me, Y_AXIS);
58
59   vector<Box> boxes;
60
61   bool parens = to_boolean (me->get_property ("parenthesized"));
62
63   SCM scm_style = me->get_property ("style");
64   if (!scm_is_symbol (scm_style)
65       && !to_boolean (me->get_property ("restore-first"))
66       && !parens)
67     {
68       int acc = scm_to_int (me->get_property ("alteration"));
69       switch (acc)
70         {
71         case FLAT:
72           {
73             Box stem = b;
74             Box bulb = b;
75
76             /*
77               we could make the stem thinner, but that places the flats
78               really close.
79             */
80             stem[X_AXIS][RIGHT] *= .5;
81
82             /*
83               To prevent vertical alignment for 6ths
84             */
85             stem[Y_AXIS] *= 1.1;
86             bulb[Y_AXIS][UP] *= .35;
87
88             boxes.push_back (bulb);
89             boxes.push_back (stem);
90           }
91           break;
92         case NATURAL:
93           {
94             Box lstem = b;
95             Box rstem = b;
96             Box belly = b;
97
98             lstem[Y_AXIS] *= 1.1;
99             rstem[Y_AXIS] *= 1.1;
100
101             belly[Y_AXIS] *= 0.75;
102             lstem[X_AXIS][RIGHT] *= .33;
103             rstem[X_AXIS][LEFT] = rstem[X_AXIS].linear_combination (1.0 / 3.0);
104             lstem[Y_AXIS][DOWN] = belly[Y_AXIS][DOWN];
105             rstem[Y_AXIS][UP] = belly[Y_AXIS][UP];
106             boxes.push_back (belly);
107             boxes.push_back (lstem);
108             boxes.push_back (rstem);
109           }
110           break;
111           /*
112             TODO: add support for, double flat.
113           */
114         }
115     }
116
117   if (!boxes.size ())
118     boxes.push_back (b);
119
120   Offset o (me->relative_coordinate (common[X_AXIS], X_AXIS),
121             me->relative_coordinate (common[Y_AXIS], Y_AXIS));
122
123   for (vsize i = boxes.size (); i--;)
124     boxes[i].translate (o);
125
126   return boxes;
127 }
128
129 /*
130  * Some styles do not provide all flavours of accidentals, e.g. there
131  * is currently no sharp accidental in vaticana style.  In these cases
132  * this function falls back to one of the other styles.
133  */
134
135 /*
136   todo: this sort of stuff in Scheme. --hwn.
137 */
138 string
139 Accidental_interface::get_fontcharname (string style, int alteration)
140 {
141   if (alteration == DOUBLE_FLAT
142       || alteration == DOUBLE_SHARP)
143     return to_string (alteration);
144
145   if (style == "hufnagel")
146     switch (alteration)
147       {
148       case FLAT: return "hufnagel-1";
149       case 0: return "vaticana0";
150       case SHARP: return "mensural1";
151       }
152   if (style == "medicaea")
153     switch (alteration)
154       {
155       case FLAT: return "medicaea-1";
156       case 0: return "vaticana0";
157       case SHARP: return "mensural1";
158       }
159   if (style == "vaticana")
160     switch (alteration)
161       {
162       case FLAT: return "vaticana-1";
163       case 0: return "vaticana0";
164       case SHARP: return "mensural1";
165       }
166   if (style == "mensural")
167     switch (alteration)
168       {
169       case FLAT: return "mensural-1";
170       case 0: return "vaticana0";
171       case SHARP: return "mensural1";
172       }
173
174   if (style == "neomensural")
175     style = ""; // currently same as default
176   if (style == "default")
177     style = "";
178   
179   return style + to_string (alteration);
180 }
181
182 MAKE_SCHEME_CALLBACK (Accidental_interface, print, 1);
183 SCM
184 Accidental_interface::print (SCM smob)
185 {
186   Grob *me = unsmob_grob (smob);
187   bool parens = to_boolean (me->get_property ("parenthesized"));
188
189   SCM scm_style = me->get_property ("style");
190   string style;
191   if (scm_is_symbol (scm_style))
192     style = ly_symbol2string (scm_style);
193   else
194     /*
195       preferably no name for the default style.
196     */
197     style = "";
198
199   Font_metric *fm = Font_interface::get_default_font (me);
200
201   SCM stencils = me->get_property ("stencils");
202   if (!scm_is_pair (stencils)
203       || !unsmob_stencil (scm_car (stencils)))
204     return SCM_EOL;
205   
206   Stencil mol (*unsmob_stencil (scm_car (stencils)));
207   if (to_boolean (me->get_property ("restore-first")))
208     {
209       string font_char = get_fontcharname (style, 0);
210       Stencil acc (fm->find_by_name ("accidentals." + font_char));
211
212       if (acc.is_empty ())
213         me->warning (_f ("accidental `%s' not found", font_char));
214       else
215         mol.add_at_edge (X_AXIS, LEFT, acc, 0.1, 0);
216     }
217   
218   if (parens)
219     mol = parenthesize (me, mol);
220
221   return mol.smobbed_copy ();
222 }
223   
224 MAKE_SCHEME_CALLBACK (Accidental_interface, calc_stencils, 1);
225 SCM
226 Accidental_interface::calc_stencils (SCM smob)
227 {
228   Grob *me = unsmob_grob (smob);
229
230   SCM scm_style = me->get_property ("style");
231   string style;
232   if (scm_is_symbol (scm_style))
233     style = ly_symbol2string (scm_style);
234   else
235     /*
236       preferably no name for the default style.
237     */
238     style = "";
239
240
241   Font_metric *fm = Font_interface::get_default_font (me);
242   SCM acc = me->get_property ("alteration");
243   if (scm_is_number (acc))
244     {
245       string font_char = get_fontcharname (style, scm_to_int (acc));
246       
247       Stencil acc_stencil (fm->find_by_name ("accidentals." + font_char));
248
249       return scm_list_1 (acc_stencil.smobbed_copy ());
250     }
251   else
252     return SCM_EOL;
253 }
254
255   
256 ADD_INTERFACE (Accidental_interface,
257                "a single accidental",
258                
259                /* props */
260                "alteration "
261                "avoid-slur "
262                "forced "
263                "style "
264                "parenthesized "
265                "restore-first "
266                "tie "
267                );