]> git.donarmstrong.com Git - lilypond.git/blob - lily/rest.cc
Merge branch 'master' of git://git.sv.gnu.org/lilypond
[lilypond.git] / lily / rest.cc
1 /*
2   rest.cc -- implement Rest
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "rest.hh"
10
11 #include "directional-element-interface.hh"
12 #include "dots.hh"
13 #include "font-interface.hh"
14 #include "international.hh"
15 #include "output-def.hh"
16 #include "paper-score.hh"
17 #include "staff-symbol-referencer.hh"
18 #include "stencil.hh"
19 #include "grob.hh"
20
21 // -> offset callback
22 MAKE_SCHEME_CALLBACK (Rest, y_offset_callback, 1);
23 SCM
24 Rest::y_offset_callback (SCM smob)
25 {
26   Grob *me = unsmob_grob (smob);
27   int duration_log = scm_to_int (me->get_property ("duration-log"));
28   int line_count = Staff_symbol_referencer::line_count (me);
29   Real ss = Staff_symbol_referencer::staff_space (me);
30
31   bool position_override = scm_is_number (me->get_property ("staff-position"));
32   Real amount = robust_scm2double (me->get_property ("staff-position"), 0)
33     * 0.5 * ss;
34   
35   if (line_count % 2)
36     {
37       if (duration_log == 0 && line_count > 1)
38         amount += ss;
39     }
40   else
41     amount += ss / 2;
42
43   Grob *dot = unsmob_grob (me->get_object ("dot"));
44   if (dot && duration_log > 4) // UGH.
45     {
46       dot->set_property ("staff-position",
47                        scm_from_int ((duration_log == 7) ? 4 : 3));
48     }
49   if (dot && duration_log >= -1 && duration_log <= 1) // UGH again.
50     {
51       dot->set_property ("staff-position",
52                          scm_from_int ((duration_log == 0) ? -1 : 1));
53     }
54
55   if (!position_override)
56     amount += 2 * ss * get_grob_direction (me);; 
57   
58   return scm_from_double (amount);
59 }
60
61 /*
62   make this function easily usable in C++
63 */
64 string
65 Rest::glyph_name (Grob *me, int balltype, string style, bool try_ledgers)
66 {
67   bool is_ledgered = false;
68   if (try_ledgers && (balltype == 0 || balltype == 1))
69     {
70       Real rad = Staff_symbol_referencer::staff_radius (me) * 2.0;
71       Real pos = Staff_symbol_referencer::get_position (me);
72
73       /*
74         Figure out when the rest is far enough outside the staff. This
75         could bemore generic, but hey, we understand this even after
76         dinner.
77       */
78       is_ledgered |= (balltype == 0) && (pos >= +rad + 2 || pos < -rad);
79       is_ledgered |= (balltype == 1) && (pos <= -rad - 2 || pos > +rad);
80     }
81
82   string actual_style (style.c_str ());
83
84   if ((style == "mensural") || (style == "neomensural"))
85     {
86
87       /*
88         FIXME: Currently, ancient font does not provide ledgered rests;
89         hence the "o" suffix in the glyph name is bogus.  But do we need
90         ledgered rests at all now that we can draw ledger lines with
91         variable width, length and blotdiameter? -- jr
92       */
93       is_ledgered = 0;
94
95       /*
96         There are no 32th/64th/128th mensural/neomensural rests.  In
97         these cases, revert back to default style.
98       */
99       if (balltype > 4)
100         actual_style = "";
101     }
102
103   if ((style == "classical") && (balltype != 2))
104     {
105       /*
106         classical style: revert back to default style for any rest other
107         than quarter rest
108       */
109       actual_style = "";
110     }
111
112   if (style == "default")
113     {
114       /*
115         Some parts of lily still prefer style "default" over "".
116         Correct this here. -- jr
117       */
118       actual_style = "";
119     }
120
121   return ("rests." + to_string (balltype) + (is_ledgered ? "o" : "")
122           + actual_style);
123 }
124
125 MAKE_SCHEME_CALLBACK (Rest, print, 1);
126 SCM
127 Rest::brew_internal_stencil (Grob *me, bool ledgered)
128 {
129   SCM balltype_scm = me->get_property ("duration-log");
130   if (!scm_is_number (balltype_scm))
131     return Stencil ().smobbed_copy ();
132
133   int balltype = scm_to_int (balltype_scm);
134
135   string style;
136   SCM style_scm = me->get_property ("style");
137   if (scm_is_symbol (style_scm))
138     style = ly_scm2string (scm_symbol_to_string (style_scm));
139
140   Font_metric *fm = Font_interface::get_default_font (me);
141   string font_char = glyph_name (me, balltype, style, ledgered);
142   Stencil out = fm->find_by_name (font_char);
143   if (out.is_empty ())
144     me->warning (_f ("rest `%s' not found", font_char.c_str ()));
145
146   return out.smobbed_copy ();
147 }
148
149 SCM
150 Rest::print (SCM smob)
151 {
152   return brew_internal_stencil (unsmob_grob (smob), true);
153 }
154
155 MAKE_SCHEME_CALLBACK (Rest, width, 1);
156 /*
157   We need the callback. The real stencil has ledgers depending on
158   Y-position. The Y-position is known only after line breaking.  */
159 SCM
160 Rest::width (SCM smob)
161 {
162   return generic_extent_callback (unsmob_grob (smob), X_AXIS);
163 }
164
165 MAKE_SCHEME_CALLBACK (Rest, height, 1);
166 SCM
167 Rest::height (SCM smob)
168 {
169   return generic_extent_callback (unsmob_grob (smob), Y_AXIS);
170 }
171
172 /*
173   We need the callback. The real stencil has ledgers depending on
174   Y-position. The Y-position is known only after line breaking.  */
175 SCM
176 Rest::generic_extent_callback (Grob *me, Axis a)
177 {
178   /*
179     Don't want ledgers: ledgers depend on Y position, which depends on
180     rest collision, which depends on stem size which depends on beam
181     slop of opposite note column.
182
183     consequence: we get too small extents and potential collisions
184     with ledgered rests.
185   */
186   SCM m = brew_internal_stencil (me, a != X_AXIS);
187   return ly_interval2scm (unsmob_stencil (m)->extent (a));
188 }
189
190 MAKE_SCHEME_CALLBACK (Rest, pure_height, 3);
191 SCM
192 Rest::pure_height (SCM smob, SCM start, SCM end)
193 {
194   (void) start;
195   (void) end;
196   
197   Grob *me = unsmob_grob (smob);
198   SCM m = brew_internal_stencil (me, false);
199   return ly_interval2scm (unsmob_stencil (m)->extent (Y_AXIS));
200 }
201
202 ADD_INTERFACE (Rest,
203                "A rest symbol.",
204
205                /* properties */
206                   
207                "direction "
208                "minimum-distance "
209                "style "
210                );
211