]> git.donarmstrong.com Git - lilypond.git/blob - lily/flag.cc
Web-es: partial completion of Community.
[lilypond.git] / lily / flag.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1996--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5   Jan Nieuwenhuizen <janneke@gnu.org>
6
7   LilyPond is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   LilyPond is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "stem.hh"
22
23 #include "directional-element-interface.hh"
24 #include "font-interface.hh"
25 #include "grob.hh"
26 #include "international.hh"
27 #include "output-def.hh"
28 #include "staff-symbol-referencer.hh"
29 #include "stencil.hh"
30 #include "warn.hh"
31
32 class Flag
33 {
34 public:
35   DECLARE_SCHEME_CALLBACK (print, (SCM));
36   DECLARE_SCHEME_CALLBACK (glyph_name, (SCM));
37   DECLARE_SCHEME_CALLBACK (width, (SCM));
38   DECLARE_SCHEME_CALLBACK (calc_y_offset, (SCM));
39   DECLARE_SCHEME_CALLBACK (pure_calc_y_offset, (SCM, SCM, SCM));
40   DECLARE_SCHEME_CALLBACK (calc_x_offset, (SCM));
41
42   static SCM internal_calc_y_offset (SCM smob, bool pure);
43 };
44
45 MAKE_SCHEME_CALLBACK (Flag, width, 1);
46 SCM
47 Flag::width (SCM smob)
48 {
49   Grob *me = unsmob<Grob> (smob);
50   Stencil *sten = unsmob<Stencil> (me->get_property ("stencil"));
51   if (!sten)
52     return ly_interval2scm (Interval (0.0, 0.0));
53
54   Grob *stem = me->get_parent (X_AXIS);
55
56   /*
57     TODO:
58     This reproduces a bad hard-coding that has been in the code for quite some time:
59     the bounding boxes for the flags are slightly off and need to be fixed.
60   */
61
62   return ly_interval2scm (sten->extent (X_AXIS) - stem->extent (stem, X_AXIS)[RIGHT]);
63 }
64
65 MAKE_SCHEME_CALLBACK (Flag, glyph_name, 1);
66 SCM
67 Flag::glyph_name (SCM smob)
68 {
69   Grob *me = unsmob<Grob> (smob);
70   Grob *stem = me->get_parent (X_AXIS);
71
72   Direction d = get_grob_direction (stem);
73   int log = Stem::duration_log (stem);
74   string flag_style;
75
76   SCM flag_style_scm = me->get_property ("style");
77   if (scm_is_symbol (flag_style_scm))
78     flag_style = ly_symbol2string (flag_style_scm);
79
80   bool adjust = true;
81
82   string staffline_offs;
83   if (flag_style == "mensural")
84     /* Mensural notation: For notes on staff lines, use different
85        flags than for notes between staff lines.  The idea is that
86        flags are always vertically aligned with the staff lines,
87        regardless if the note head is on a staff line or between two
88        staff lines.  In other words, the inner end of a flag always
89        touches a staff line.
90     */
91     {
92       if (adjust)
93         {
94           Real ss = Staff_symbol_referencer::staff_space (me);
95           int p = (int) (rint (stem->extent (stem, Y_AXIS)[d] * 2 / ss));
96           staffline_offs
97             = Staff_symbol_referencer::on_line (stem, p) ? "0" : "1";
98         }
99       else
100         staffline_offs = "2";
101     }
102   else
103     staffline_offs = "";
104
105   char dir = (d == UP) ? 'u' : 'd';
106   string font_char = flag_style
107                      + ::to_string (dir) + staffline_offs + ::to_string (log);
108   return ly_string2scm ("flags." + font_char);
109 }
110
111 MAKE_SCHEME_CALLBACK (Flag, print, 1);
112 SCM
113 Flag::print (SCM smob)
114 {
115   Grob *me = unsmob<Grob> (smob);
116   Grob *stem = me->get_parent (X_AXIS);
117
118   Direction d = get_grob_direction (stem);
119   string flag_style;
120
121   SCM flag_style_scm = me->get_property ("style");
122   if (scm_is_symbol (flag_style_scm))
123     flag_style = ly_symbol2string (flag_style_scm);
124
125   if (flag_style == "no-flag")
126     return Stencil ().smobbed_copy ();
127
128   char dir = (d == UP) ? 'u' : 'd';
129   Font_metric *fm = Font_interface::get_default_font (me);
130   string font_char = robust_scm2string (me->get_property ("glyph-name"), "");
131   Stencil flag = fm->find_by_name (font_char);
132   if (flag.is_empty ())
133     me->warning (_f ("flag `%s' not found", font_char));
134
135   /*
136     TODO: maybe property stroke-style should take different values,
137     e.g. "" (i.e. no stroke), "single" and "double" (currently, it's
138     '() or "grace").  */
139   SCM stroke_style_scm = me->get_property ("stroke-style");
140   if (scm_is_string (stroke_style_scm))
141     {
142       string stroke_style = ly_scm2string (stroke_style_scm);
143       if (!stroke_style.empty ())
144         {
145           string font_char = flag_style + ::to_string (dir) + stroke_style;
146           Stencil stroke = fm->find_by_name ("flags." + font_char);
147           if (stroke.is_empty ())
148             {
149               font_char = ::to_string (dir) + stroke_style;
150               stroke = fm->find_by_name ("flags." + font_char);
151             }
152           if (stroke.is_empty ())
153             me->warning (_f ("flag stroke `%s' not found", font_char));
154           else
155             flag.add_stencil (stroke);
156         }
157     }
158
159   return flag.smobbed_copy ();
160 }
161
162 MAKE_SCHEME_CALLBACK (Flag, pure_calc_y_offset, 3);
163 SCM
164 Flag::pure_calc_y_offset (SCM smob,
165                           SCM /* beg */,
166                           SCM /* end */)
167 {
168   return internal_calc_y_offset (smob, true);
169 }
170
171 MAKE_SCHEME_CALLBACK (Flag, calc_y_offset, 1);
172 SCM
173 Flag::calc_y_offset (SCM smob)
174 {
175   return internal_calc_y_offset (smob, false);
176 }
177
178 SCM
179 Flag::internal_calc_y_offset (SCM smob, bool pure)
180 {
181   Grob *me = unsmob<Grob> (smob);
182   Grob *stem = me->get_parent (X_AXIS);
183   Direction d = get_grob_direction (stem);
184
185   Real blot
186     = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
187
188   Interval stem_extent = pure
189                          ? stem->pure_y_extent (stem, 0, INT_MAX)
190                          : stem->extent (stem, Y_AXIS);
191
192   return scm_from_double (stem_extent.is_empty ()
193                           ? 0.0
194                           : stem_extent[d] - d * blot / 2);
195 }
196
197 MAKE_SCHEME_CALLBACK (Flag, calc_x_offset, 1);
198 SCM
199 Flag::calc_x_offset (SCM smob)
200 {
201   Grob *me = unsmob<Grob> (smob);
202   Grob *stem = me->get_parent (X_AXIS);
203   return scm_from_double (stem->extent (stem, X_AXIS)[RIGHT]);
204 }
205
206 ADD_INTERFACE (Flag,
207                "A flag that gets attached to a stem."
208                "The style property is  symbol determining"
209                " what style of flag glyph is typeset on a"
210                " @code{Stem}.  Valid options include @code{'()}"
211                " for standard flags, @code{'mensural} and"
212                " @code{'no-flag}, which switches off the flag.",
213
214                /* properties */
215                "glyph-name "
216                "style "
217                "stroke-style "
218               );