]> git.donarmstrong.com Git - lilypond.git/blob - lily/flag.cc
Merge branch 'lilypond/translation' into staging
[lilypond.git] / lily / flag.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1996--2012 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 (width, (SCM));
37   DECLARE_SCHEME_CALLBACK (calc_y_offset, (SCM));
38   DECLARE_SCHEME_CALLBACK (pure_calc_y_offset, (SCM, SCM, SCM));
39   DECLARE_SCHEME_CALLBACK (calc_x_offset, (SCM));
40   DECLARE_GROB_INTERFACE ();
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 MAKE_SCHEME_CALLBACK (Flag, print, 1);
65 SCM
66 Flag::print (SCM smob)
67 {
68   Grob *me = unsmob_grob (smob);
69   Grob *stem = me->get_parent (X_AXIS);
70
71   Direction d = get_grob_direction (stem);
72   int log = Stem::duration_log (stem);
73   string flag_style;
74
75   SCM flag_style_scm = me->get_property ("style");
76   if (scm_is_symbol (flag_style_scm))
77     flag_style = ly_symbol2string (flag_style_scm);
78
79   if (flag_style == "no-flag")
80     return Stencil ().smobbed_copy ();
81
82   bool adjust = true;
83
84   string staffline_offs;
85   if (flag_style == "mensural")
86     /* Mensural notation: For notes on staff lines, use different
87        flags than for notes between staff lines.  The idea is that
88        flags are always vertically aligned with the staff lines,
89        regardless if the note head is on a staff line or between two
90        staff lines.  In other words, the inner end of a flag always
91        touches a staff line.
92     */
93     {
94       if (adjust)
95         {
96           Real ss = Staff_symbol_referencer::staff_space (me);
97           int p = (int) (rint (stem->extent (stem, Y_AXIS)[d] * 2 / ss));
98           staffline_offs
99             = Staff_symbol_referencer::on_line (stem, p) ? "0" : "1";
100         }
101       else
102         staffline_offs = "2";
103     }
104   else
105     staffline_offs = "";
106
107   char dir = (d == UP) ? 'u' : 'd';
108   string font_char = flag_style
109                      + to_string (dir) + staffline_offs + to_string (log);
110   Font_metric *fm = Font_interface::get_default_font (me);
111   Stencil flag = fm->find_by_name ("flags." + font_char);
112   if (flag.is_empty ())
113     me->warning (_f ("flag `%s' not found", font_char));
114
115   /*
116     TODO: maybe property stroke-style should take different values,
117     e.g. "" (i.e. no stroke), "single" and "double" (currently, it's
118     '() or "grace").  */
119   SCM stroke_style_scm = me->get_property ("stroke-style");
120   if (scm_is_string (stroke_style_scm))
121     {
122       string stroke_style = ly_scm2string (stroke_style_scm);
123       if (!stroke_style.empty ())
124         {
125           string font_char = flag_style + to_string (dir) + stroke_style;
126           Stencil stroke = fm->find_by_name ("flags." + font_char);
127           if (stroke.is_empty ())
128             {
129               font_char = to_string (dir) + stroke_style;
130               stroke = fm->find_by_name ("flags." + font_char);
131             }
132           if (stroke.is_empty ())
133             me->warning (_f ("flag stroke `%s' not found", font_char));
134           else
135             flag.add_stencil (stroke);
136         }
137     }
138
139   return flag.smobbed_copy ();
140 }
141
142 MAKE_SCHEME_CALLBACK (Flag, pure_calc_y_offset, 3);
143 SCM
144 Flag::pure_calc_y_offset (SCM smob,
145                           SCM /* beg */,
146                           SCM /* end */)
147 {
148   return internal_calc_y_offset (smob, true);
149 }
150
151 MAKE_SCHEME_CALLBACK (Flag, calc_y_offset, 1);
152 SCM
153 Flag::calc_y_offset (SCM smob)
154 {
155   return internal_calc_y_offset (smob, false);
156 }
157
158 SCM
159 Flag::internal_calc_y_offset (SCM smob, bool pure)
160 {
161   Grob *me = unsmob_grob (smob);
162   Grob *stem = me->get_parent (X_AXIS);
163   Direction d = get_grob_direction (stem);
164
165   Real blot
166     = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
167
168   Real y2 = pure
169             ? stem->pure_height (stem, 0, INT_MAX)[d]
170             : stem->extent (stem, Y_AXIS)[d];
171
172   return scm_from_double (y2 - d * blot / 2);
173 }
174
175 MAKE_SCHEME_CALLBACK (Flag, calc_x_offset, 1);
176 SCM
177 Flag::calc_x_offset (SCM smob)
178 {
179   Grob *me = unsmob_grob (smob);
180   Grob *stem = me->get_parent (X_AXIS);
181   return scm_from_double (stem->extent (stem, X_AXIS)[RIGHT]);
182 }
183
184 ADD_INTERFACE (Flag,
185                "A flag that gets attached to a stem."
186                "The style property is  symbol determining"
187                " what style of flag glyph is typeset on a"
188                " @code{Stem}.  Valid options include @code{'()}"
189                " for standard flags, @code{'mensural} and"
190                " @code{'no-flag}, which switches off the flag.",
191
192                /* properties */
193                "style "
194                "stroke-style "
195               );