]> git.donarmstrong.com Git - lilypond.git/blob - lily/mensural-ligature.cc
* lily/vaticana-ligature-engraver.cc (need_extra_space): renamed
[lilypond.git] / lily / mensural-ligature.cc
1 /*
2   mensural-ligature.cc -- implement Mensural_ligature
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2002--2005 Juergen Reuter <reuter@ipd.uka.de>,
7   Pal Benko <benkop@freestart.hu>
8 */
9
10 #include <math.h>
11
12 #include "mensural-ligature.hh"
13 #include "item.hh"
14 #include "font-interface.hh"
15 #include "lookup.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "note-head.hh"
18 #include "output-def.hh"
19 #include "warn.hh"
20
21 /*
22  * TODO: divide this function into mensural and neo-mensural style.
23  *
24  * TODO: move this function to class Lookup?
25  */
26 Stencil
27 brew_flexa (Grob *me,
28             Real interval,
29             bool solid,
30             Real width,
31             Real vertical_line_thickness)
32 {
33   Real staff_space = Staff_symbol_referencer::staff_space (me);
34   Real slope = (interval / 2.0 * staff_space) / width;
35
36   // Compensate optical illusion regarding vertical position of left
37   // and right endings due to slope.
38   Real ypos_correction = -0.1 * staff_space * sign (slope);
39   Real slope_correction = 0.2 * staff_space * sign (slope);
40   Real corrected_slope = slope + slope_correction / width;
41
42   Stencil stencil;
43   if (solid) // colorated flexae
44     {
45       Stencil solid_head
46         = Lookup::beam (corrected_slope, width, staff_space, 0.0);
47       stencil.add_stencil (solid_head);
48     }
49   else // outline
50     {
51       /*
52         The thickness of the horizontal lines of the flexa shape
53         should be equal to that of the horizontal lines of the
54         neomensural brevis note head (see mf/parmesan-heads.mf).
55       */
56       Real const horizontal_line_thickness = staff_space * 0.35;
57
58       // URGH!  vertical_line_thickness is adjustable (via thickness
59       // property), while horizontal_line_thickness is constant.
60       // Maybe both should be adjustable independently?
61
62       Real height = staff_space - horizontal_line_thickness;
63
64       Stencil left_edge
65         = Lookup::beam (corrected_slope, vertical_line_thickness, height, 0.0);
66       stencil.add_stencil (left_edge);
67
68       Stencil right_edge
69         = Lookup::beam (corrected_slope, vertical_line_thickness, height, 0.0);
70       right_edge.translate_axis (width - vertical_line_thickness, X_AXIS);
71       right_edge.translate_axis ((width - vertical_line_thickness) *
72                                  corrected_slope, Y_AXIS);
73       stencil.add_stencil (right_edge);
74
75       Stencil bottom_edge
76         = Lookup::beam (corrected_slope, width,
77                         horizontal_line_thickness, 0.0);
78       bottom_edge.translate_axis (-0.5 * height, Y_AXIS);
79       stencil.add_stencil (bottom_edge);
80
81       Stencil top_edge
82         = Lookup::beam (corrected_slope, width,
83                         horizontal_line_thickness, 0.0);
84       top_edge.translate_axis (+0.5 * height, Y_AXIS);
85       stencil.add_stencil (top_edge);
86     }
87   stencil.translate_axis (ypos_correction, Y_AXIS);
88   return stencil;
89 }
90
91 Stencil
92 internal_brew_primitive (Grob *me)
93 {
94   SCM primitive_scm = me->get_property ("primitive");
95   if (primitive_scm == SCM_EOL)
96     {
97       programming_error ("Mensural_ligature: "
98                          "undefined primitive -> ignoring grob");
99       return Stencil ();
100     }
101   int primitive = scm_to_int (primitive_scm);
102
103   Stencil out;
104   int delta_pitch = 0;
105   Real thickness = 0.0;
106   Real width = 0.0;
107   Real staff_space = Staff_symbol_referencer::staff_space (me);
108   if (primitive & MLP_ANY)
109     {
110       thickness = robust_scm2double (me->get_property ("thickness"), .14);
111     }
112
113   if (primitive & MLP_FLEXA)
114     {
115       delta_pitch = robust_scm2int (me->get_property ("delta-pitch"),
116                                     0);
117       width
118         = robust_scm2double (me->get_property ("flexa-width"), 2.0 * staff_space);
119     }
120   if (primitive & MLP_SINGLE_HEAD)
121     {
122       width = robust_scm2double (me->get_property ("head-width"), staff_space);
123     }
124
125   switch (primitive & MLP_ANY)
126     {
127     case MLP_NONE:
128       return Stencil ();
129     case MLP_LONGA: // mensural brevis head with right cauda
130       out = Font_interface::get_default_font (me)->find_by_name
131         ("noteheads.s-2mensural");
132       break;
133     case MLP_BREVIS: // mensural brevis head
134       out = Font_interface::get_default_font (me)->find_by_name
135         ("noteheads.s-1mensural");
136       break;
137     case MLP_MAXIMA: // should be mensural maxima head without stem
138       out = Font_interface::get_default_font (me)->find_by_name
139         ("noteheads.s-1neomensural");
140       break;
141     case MLP_FLEXA:
142       out = brew_flexa (me, delta_pitch, false, width, thickness);
143       break;
144     default:
145       programming_error (_f ("Mensural_ligature: "
146                              "unexpected case fall-through"));
147       return Stencil ();
148     }
149
150   Real blotdiameter
151     = (me->get_layout ()->get_dimension (ly_symbol2scm ("blotdiameter")));
152
153   if (primitive & MLP_STEM)
154     {
155       // assume MLP_UP
156       Real y_bottom = 0.0, y_top = 3.0 * staff_space;
157
158       if (primitive & MLP_DOWN)
159         {
160           y_bottom = -y_top;
161           y_top = 0.0;
162         }
163
164       Interval x_extent (0, thickness);
165       Interval y_extent (y_bottom, y_top);
166       Box join_box (x_extent, y_extent);
167
168       Stencil join = Lookup::round_filled_box (join_box, blotdiameter);
169       out.add_stencil (join);
170     }
171
172   SCM join_right_scm = me->get_property ("join-right-amount");
173
174   if (join_right_scm != SCM_EOL)
175     {
176       int join_right = scm_to_int (join_right_scm);
177       if (join_right)
178         {
179           Real y_top = join_right * 0.5 * staff_space;
180           Real y_bottom = 0.0;
181
182           if (y_top < 0.0)
183             {
184               y_bottom = y_top;
185               y_top = 0.0;
186             }
187
188           Interval x_extent (width - thickness, width);
189           Interval y_extent (y_bottom, y_top);
190           Box join_box (x_extent, y_extent);
191           Stencil join = Lookup::round_filled_box (join_box, blotdiameter);
192
193           out.add_stencil (join);
194         }
195       else
196         {
197           programming_error (_f ("Mensural_ligature: (join_right == 0)"));
198         }
199     }
200
201 #if 0 // what happend with the ledger lines?
202   int pos = Staff_symbol_referencer::get_rounded_position (me);
203   if (primitive & MLP_FLEXA)
204     {
205       pos += delta_pitch;
206       add_ledger_lines (me, &out, pos, 0.5 * delta_pitch, ledger_take_space);
207     }
208 #endif
209
210   return out;
211 }
212
213 MAKE_SCHEME_CALLBACK (Mensural_ligature, brew_ligature_primitive, 1);
214 SCM
215 Mensural_ligature::brew_ligature_primitive (SCM smob)
216 {
217   Grob *me = unsmob_grob (smob);
218   return internal_brew_primitive (me).smobbed_copy ();
219 }
220
221 MAKE_SCHEME_CALLBACK (Mensural_ligature, print, 1);
222 SCM
223 Mensural_ligature::print (SCM)
224 {
225   return SCM_EOL;
226 }
227
228 ADD_INTERFACE (Mensural_ligature, "mensural-ligature-interface",
229                "A mensural ligature",
230                "delta-pitch flexa-width head-width join-right-amount " // "add-join "
231                "ligature-primitive-callback primitive thickness");