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