]> git.donarmstrong.com Git - lilypond.git/blob - lily/staff-symbol.cc
Merge branch 'lilypond/translation' of ssh://git.sv.gnu.org/srv/git/lilypond
[lilypond.git] / lily / staff-symbol.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2010 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
114 int
115 Staff_symbol::get_steps (Grob *me)
116 {
117   return line_count (me) * 2;
118 }
119
120 int
121 Staff_symbol::line_count (Grob *me)
122 {
123   SCM c = me->get_property ("line-count");
124   if (scm_is_number (c))
125     return scm_to_int (c);
126   else
127     return 0;
128 }
129
130 Real
131 Staff_symbol::staff_space (Grob *me)
132 {
133   return robust_scm2double (me->get_property ("staff-space"), 1.0);
134 }
135
136 Real
137 Staff_symbol::get_line_thickness (Grob *me)
138 {
139   Real lt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
140
141   return robust_scm2double (me->get_property ("thickness"), 1.0) * lt;
142 }
143
144 Real
145 Staff_symbol::get_ledger_line_thickness (Grob *me)
146 {
147   SCM lt_pair = me->get_property ("ledger-line-thickness");
148   Offset z = robust_scm2offset (lt_pair, Offset (1.0, 0.1));
149
150   return z[X_AXIS] * get_line_thickness (me) + z[Y_AXIS] * staff_space (me);
151 }
152
153 MAKE_SCHEME_CALLBACK (Staff_symbol, height,1);
154 SCM
155 Staff_symbol::height  (SCM smob)
156 {
157   Grob *me = unsmob_grob (smob);
158   Real t = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
159   t *= robust_scm2double (me->get_property ("thickness"), 1.0);
160   
161   SCM line_positions = me->get_property ("line-positions");
162
163   Interval y_ext;
164   Real space = staff_space (me);
165   if (scm_is_pair (line_positions))
166     {
167       for (SCM s = line_positions; scm_is_pair (s);
168            s = scm_cdr (s))
169         y_ext.add_point (scm_to_double (scm_car (s)) * 0.5 * space);
170     }
171   else
172     {
173       int l = Staff_symbol::line_count (me);
174       Real height = (l - 1) * staff_space (me) / 2;
175       y_ext = Interval (-height, height);
176     }
177   y_ext.widen (t/2);
178   return ly_interval2scm (y_ext);
179 }
180
181 bool
182 Staff_symbol::on_line (Grob *me, int pos)
183 {
184   SCM line_positions = me->get_property ("line-positions");
185   if (scm_is_pair (line_positions))
186     {
187       Real min_line = HUGE_VAL;
188       Real max_line = -HUGE_VAL;
189       for (SCM s = line_positions; scm_is_pair (s); s = scm_cdr (s))
190         {
191           Real current_line = scm_to_double (scm_car (s));
192           if (pos == current_line)
193             return true;
194           if (current_line > max_line)
195             max_line = current_line;
196           if (current_line < min_line)
197             min_line = current_line;
198         
199         }
200       if (pos < min_line)
201         return (( (int) (rint (pos - min_line)) % 2) == 0);
202       if (pos > max_line)
203         return (( (int) (rint (pos - max_line)) % 2) == 0);
204
205       return false;
206     }
207   else
208     return ((abs (pos + line_count (me)) % 2) == 1);
209 }
210
211 ADD_INTERFACE (Staff_symbol,
212                "This spanner draws the lines of a staff.  A staff symbol"
213                " defines a vertical unit, the @emph{staff space}.  Quantities"
214                " that go by a half staff space are called @emph{positions}."
215                "  The center (i.e., middle line or space) is position@tie{}0."
216                " The length of the symbol may be set by hand through the"
217                " @code{width} property.",
218
219                /* properties */
220                "ledger-line-thickness "
221                "line-count "
222                "line-positions "
223                "staff-space "
224                "thickness "
225                "width "
226                );