]> git.donarmstrong.com Git - lilypond.git/blob - lily/flag.cc
Run grand-replace (issue 3765)
[lilypond.git] / lily / flag.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1996--2014 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   DECLARE_GROB_INTERFACE ();
42
43   static SCM internal_calc_y_offset (SCM smob, bool pure);
44 };
45
46 MAKE_SCHEME_CALLBACK (Flag, width, 1);
47 SCM
48 Flag::width (SCM smob)
49 {
50   Grob *me = unsmob_grob (smob);
51   Stencil *sten = unsmob_stencil (me->get_property ("stencil"));
52   if (!sten)
53     return ly_interval2scm (Interval (0.0, 0.0));
54
55   Grob *stem = me->get_parent (X_AXIS);
56
57   /*
58     TODO:
59     This reproduces a bad hard-coding that has been in the code for quite some time:
60     the bounding boxes for the flags are slightly off and need to be fixed.
61   */
62
63   return ly_interval2scm (sten->extent (X_AXIS) - stem->extent (stem, X_AXIS)[RIGHT]);
64 }
65
66 MAKE_SCHEME_CALLBACK (Flag, glyph_name, 1);
67 SCM
68 Flag::glyph_name (SCM smob)
69 {
70   Grob *me = unsmob_grob (smob);
71   Grob *stem = me->get_parent (X_AXIS);
72
73   Direction d = get_grob_direction (stem);
74   int log = Stem::duration_log (stem);
75   string flag_style;
76
77   SCM flag_style_scm = me->get_property ("style");
78   if (scm_is_symbol (flag_style_scm))
79     flag_style = ly_symbol2string (flag_style_scm);
80
81   bool adjust = true;
82
83   string staffline_offs;
84   if (flag_style == "mensural")
85     /* Mensural notation: For notes on staff lines, use different
86        flags than for notes between staff lines.  The idea is that
87        flags are always vertically aligned with the staff lines,
88        regardless if the note head is on a staff line or between two
89        staff lines.  In other words, the inner end of a flag always
90        touches a staff line.
91     */
92     {
93       if (adjust)
94         {
95           Real ss = Staff_symbol_referencer::staff_space (me);
96           int p = (int) (rint (stem->extent (stem, Y_AXIS)[d] * 2 / ss));
97           staffline_offs
98             = Staff_symbol_referencer::on_line (stem, p) ? "0" : "1";
99         }
100       else
101         staffline_offs = "2";
102     }
103   else
104     staffline_offs = "";
105
106   char dir = (d == UP) ? 'u' : 'd';
107   string font_char = flag_style
108                      + ::to_string (dir) + staffline_offs + ::to_string (log);
109   return ly_string2scm ("flags." + font_char);
110 }
111
112 MAKE_SCHEME_CALLBACK (Flag, print, 1);
113 SCM
114 Flag::print (SCM smob)
115 {
116   Grob *me = unsmob_grob (smob);
117   Grob *stem = me->get_parent (X_AXIS);
118
119   Direction d = get_grob_direction (stem);
120   string flag_style;
121
122   SCM flag_style_scm = me->get_property ("style");
123   if (scm_is_symbol (flag_style_scm))
124     flag_style = ly_symbol2string (flag_style_scm);
125
126   if (flag_style == "no-flag")
127     return Stencil ().smobbed_copy ();
128
129   char dir = (d == UP) ? 'u' : 'd';
130   Font_metric *fm = Font_interface::get_default_font (me);
131   string font_char = robust_scm2string (me->get_property ("glyph-name"), "");
132   Stencil flag = fm->find_by_name (font_char);
133   if (flag.is_empty ())
134     me->warning (_f ("flag `%s' not found", font_char));
135
136   /*
137     TODO: maybe property stroke-style should take different values,
138     e.g. "" (i.e. no stroke), "single" and "double" (currently, it's
139     '() or "grace").  */
140   SCM stroke_style_scm = me->get_property ("stroke-style");
141   if (scm_is_string (stroke_style_scm))
142     {
143       string stroke_style = ly_scm2string (stroke_style_scm);
144       if (!stroke_style.empty ())
145         {
146           string font_char = flag_style + ::to_string (dir) + stroke_style;
147           Stencil stroke = fm->find_by_name ("flags." + font_char);
148           if (stroke.is_empty ())
149             {
150               font_char = ::to_string (dir) + stroke_style;
151               stroke = fm->find_by_name ("flags." + font_char);
152             }
153           if (stroke.is_empty ())
154             me->warning (_f ("flag stroke `%s' not found", font_char));
155           else
156             flag.add_stencil (stroke);
157         }
158     }
159
160   return flag.smobbed_copy ();
161 }
162
163 MAKE_SCHEME_CALLBACK (Flag, pure_calc_y_offset, 3);
164 SCM
165 Flag::pure_calc_y_offset (SCM smob,
166                           SCM /* beg */,
167                           SCM /* end */)
168 {
169   return internal_calc_y_offset (smob, true);
170 }
171
172 MAKE_SCHEME_CALLBACK (Flag, calc_y_offset, 1);
173 SCM
174 Flag::calc_y_offset (SCM smob)
175 {
176   return internal_calc_y_offset (smob, false);
177 }
178
179 SCM
180 Flag::internal_calc_y_offset (SCM smob, bool pure)
181 {
182   Grob *me = unsmob_grob (smob);
183   Grob *stem = me->get_parent (X_AXIS);
184   Direction d = get_grob_direction (stem);
185
186   Real blot
187     = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
188
189   Interval stem_extent = pure
190                          ? stem->pure_height (stem, 0, INT_MAX)
191                          : stem->extent (stem, Y_AXIS);
192
193   return scm_from_double (stem_extent.is_empty ()
194                           ? 0.0
195                           : stem_extent[d] - d * blot / 2);
196 }
197
198 MAKE_SCHEME_CALLBACK (Flag, calc_x_offset, 1);
199 SCM
200 Flag::calc_x_offset (SCM smob)
201 {
202   Grob *me = unsmob_grob (smob);
203   Grob *stem = me->get_parent (X_AXIS);
204   return scm_from_double (stem->extent (stem, X_AXIS)[RIGHT]);
205 }
206
207 ADD_INTERFACE (Flag,
208                "A flag that gets attached to a stem."
209                "The style property is  symbol determining"
210                " what style of flag glyph is typeset on a"
211                " @code{Stem}.  Valid options include @code{'()}"
212                " for standard flags, @code{'mensural} and"
213                " @code{'no-flag}, which switches off the flag.",
214
215                /* properties */
216                "glyph-name "
217                "style "
218                "stroke-style "
219               );