]> git.donarmstrong.com Git - lilypond.git/blob - lily/staff-symbol.cc
Merge branch 'lilypond/translation'
[lilypond.git] / lily / staff-symbol.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "staff-symbol.hh"
21
22 #include "lookup.hh"
23 #include "dimensions.hh"
24 #include "output-def.hh"
25 #include "warn.hh"
26 #include "item.hh"
27 #include "staff-symbol-referencer.hh"
28 #include "spanner.hh"
29
30 MAKE_SCHEME_CALLBACK (Staff_symbol, print, 1);
31
32 SCM
33 Staff_symbol::print (SCM smob)
34 {
35   Grob *me = unsmob_grob (smob);
36   Spanner *sp = dynamic_cast<Spanner *> (me);
37   Grob *common
38     = sp->get_bound (LEFT)->common_refpoint (sp->get_bound (RIGHT), X_AXIS);
39
40   Interval span_points (0, 0);
41
42   /*
43     For raggedright without ragged staves, simply set width to the linewidth.
44
45     (ok -- lousy UI, since width is in staff spaces)
46
47     --hwn.
48   */
49   Real t = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
50   t *= robust_scm2double (me->get_property ("thickness"), 1.0);
51
52   Direction d = LEFT;
53   do
54     {
55       SCM width_scm = me->get_property ("width");
56       if (d == RIGHT && scm_is_number (width_scm))
57         {
58           /*
59             don't multiply by Staff_symbol_referencer::staff_space (me),
60             since that would make aligning staff symbols of different sizes to
61             one right margin hell.
62           */
63           span_points[RIGHT] = scm_to_double (width_scm);
64         }
65       else
66         {
67           Item *x = sp->get_bound (d);
68
69           span_points[d] = x->relative_coordinate (common, X_AXIS);
70           if (!x->break_status_dir ()
71               && !x->extent (x, X_AXIS).is_empty ())
72             span_points[d] += x->extent (x, X_AXIS)[d];
73         }
74
75       span_points[d] -= d * t / 2;
76     }
77   while (flip (&d) != LEFT);
78
79   Stencil m;
80
81   SCM line_positions = me->get_property ("line-positions");
82   Stencil line
83     = Lookup::horizontal_line (span_points
84                                - me->relative_coordinate (common, X_AXIS),
85                                t);
86
87   Real space = staff_space (me);
88   if (scm_is_pair (line_positions))
89     {
90       for (SCM s = line_positions; scm_is_pair (s);
91            s = scm_cdr (s))
92         {
93           Stencil b (line);
94           b.translate_axis (scm_to_double (scm_car (s))
95                             * 0.5 * space, Y_AXIS);
96           m.add_stencil (b);
97         }
98     }
99   else
100     {
101       int l = Staff_symbol::line_count (me);
102       Real height = (l - 1) * staff_space (me) / 2;
103       for (int i = 0; i < l; i++)
104         {
105           Stencil b (line);
106           b.translate_axis (height - i * space, Y_AXIS);
107           m.add_stencil (b);
108         }
109     }
110   return m.smobbed_copy ();
111 }
112
113 int
114 Staff_symbol::get_steps (Grob *me)
115 {
116   return line_count (me) * 2;
117 }
118
119 int
120 Staff_symbol::line_count (Grob *me)
121 {
122   SCM c = me->get_property ("line-count");
123   if (scm_is_number (c))
124     return scm_to_int (c);
125   else
126     return 0;
127 }
128
129 Real
130 Staff_symbol::staff_space (Grob *me)
131 {
132   return robust_scm2double (me->get_property ("staff-space"), 1.0);
133 }
134
135 Real
136 Staff_symbol::get_line_thickness (Grob *me)
137 {
138   Real lt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
139
140   return robust_scm2double (me->get_property ("thickness"), 1.0) * lt;
141 }
142
143 Real
144 Staff_symbol::get_ledger_line_thickness (Grob *me)
145 {
146   SCM lt_pair = me->get_property ("ledger-line-thickness");
147   Offset z = robust_scm2offset (lt_pair, Offset (1.0, 0.1));
148
149   return z[X_AXIS] * get_line_thickness (me) + z[Y_AXIS] * staff_space (me);
150 }
151
152 MAKE_SCHEME_CALLBACK (Staff_symbol, height, 1);
153 SCM
154 Staff_symbol::height (SCM smob)
155 {
156   Grob *me = unsmob_grob (smob);
157   Real t = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
158   t *= robust_scm2double (me->get_property ("thickness"), 1.0);
159
160   SCM line_positions = me->get_property ("line-positions");
161
162   Interval y_ext;
163   Real space = staff_space (me);
164   if (scm_is_pair (line_positions))
165     {
166       for (SCM s = line_positions; scm_is_pair (s);
167            s = scm_cdr (s))
168         y_ext.add_point (scm_to_double (scm_car (s)) * 0.5 * space);
169     }
170   else
171     {
172       int l = Staff_symbol::line_count (me);
173       Real height = (l - 1) * staff_space (me) / 2;
174       y_ext = Interval (-height, height);
175     }
176   y_ext.widen (t / 2);
177   return ly_interval2scm (y_ext);
178 }
179
180 bool
181 Staff_symbol::on_line (Grob *me, int pos)
182 {
183   SCM line_positions = me->get_property ("line-positions");
184   if (scm_is_pair (line_positions))
185     {
186       Real min_line = HUGE_VAL;
187       Real max_line = -HUGE_VAL;
188       for (SCM s = line_positions; scm_is_pair (s); s = scm_cdr (s))
189         {
190           Real current_line = scm_to_double (scm_car (s));
191           if (pos == current_line)
192             return true;
193           if (current_line > max_line)
194             max_line = current_line;
195           if (current_line < min_line)
196             min_line = current_line;
197
198         }
199       if (pos < min_line)
200         return (( (int) (rint (pos - min_line)) % 2) == 0);
201       if (pos > max_line)
202         return (( (int) (rint (pos - max_line)) % 2) == 0);
203
204       return false;
205     }
206   else
207     return ((abs (pos + line_count (me)) % 2) == 1);
208 }
209
210 Interval
211 Staff_symbol::line_span (Grob *me)
212 {
213   SCM line_positions = me->get_property ("line-positions");
214   Interval iv;
215
216   if (scm_is_pair (line_positions))
217     for (SCM s = line_positions; scm_is_pair (s); s = scm_cdr (s))
218       iv.add_point (scm_to_double (scm_car (s)));
219   else
220     {
221       int count = line_count (me);
222       return Interval (-count + 1, count - 1);
223     }
224
225   return iv;
226 }
227
228 ADD_INTERFACE (Staff_symbol,
229                "This spanner draws the lines of a staff.  A staff symbol"
230                " defines a vertical unit, the @emph{staff space}.  Quantities"
231                " that go by a half staff space are called @emph{positions}."
232                "  The center (i.e., middle line or space) is position@tie{}0."
233                " The length of the symbol may be set by hand through the"
234                " @code{width} property.",
235
236                /* properties */
237                "ledger-line-thickness "
238                "line-count "
239                "line-positions "
240                "staff-space "
241                "thickness "
242                "width "
243               );