]> git.donarmstrong.com Git - lilypond.git/blob - lily/flag.cc
Add newlines at EOF where appropriate.
[lilypond.git] / lily / flag.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1996--2011 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
43
44 MAKE_SCHEME_CALLBACK (Flag, width, 1);
45 SCM
46 Flag::width (SCM smob)
47 {
48   Grob *me = unsmob_grob (smob);
49   Stencil *sten = unsmob_stencil (me->get_property ("stencil"));
50   if (!sten)
51     return ly_interval2scm (Interval (0.0, 0.0));
52
53   Grob *stem = me->get_parent (X_AXIS);
54
55   /*
56     TODO:
57     This reproduces a bad hard-coding that has been in the code for quite some time:
58     the bounding boxes for the flags are slightly off and need to be fixed.
59   */
60
61   return ly_interval2scm (sten->extent (X_AXIS) - stem->extent (stem, X_AXIS)[RIGHT]);
62 }
63 MAKE_SCHEME_CALLBACK (Flag, print, 1);
64 SCM
65 Flag::print (SCM smob)
66 {
67   Grob *me = unsmob_grob (smob);
68   Grob *stem = me->get_parent (X_AXIS);
69
70   Direction d = get_grob_direction (stem);
71   int log = Stem::duration_log (stem);
72   string flag_style;
73
74   SCM flag_style_scm = me->get_property ("style");
75   if (scm_is_symbol (flag_style_scm))
76     flag_style = ly_symbol2string (flag_style_scm);
77
78   if (flag_style == "no-flag")
79     return Stencil ().smobbed_copy ();
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   Font_metric *fm = Font_interface::get_default_font (me);
110   Stencil flag = fm->find_by_name ("flags." + font_char);
111   if (flag.is_empty ())
112     me->warning (_f ("flag `%s' not found", font_char));
113
114   /*
115     TODO: maybe property stroke-style should take different values,
116     e.g. "" (i.e. no stroke), "single" and "double" (currently, it's
117     '() or "grace").  */
118   SCM stroke_style_scm = me->get_property ("stroke-style");
119   if (scm_is_string (stroke_style_scm))
120     {
121       string stroke_style = ly_scm2string (stroke_style_scm);
122       if (!stroke_style.empty ())
123         {
124           string font_char = flag_style + to_string (dir) + stroke_style;
125           Stencil stroke = fm->find_by_name ("flags." + font_char);
126           if (stroke.is_empty ())
127             {
128               font_char = to_string (dir) + stroke_style;
129               stroke = fm->find_by_name ("flags." + font_char);
130             }
131           if (stroke.is_empty ())
132             me->warning (_f ("flag stroke `%s' not found", font_char));
133           else
134             flag.add_stencil (stroke);
135         }
136     }
137
138   return flag.smobbed_copy ();
139 }
140
141 MAKE_SCHEME_CALLBACK (Flag, calc_y_offset, 1);
142 SCM
143 Flag::calc_y_offset (SCM smob)
144 {
145   Grob *me = unsmob_grob (smob);
146   Grob *stem = me->get_parent (X_AXIS);
147   Direction d = get_grob_direction (stem);
148
149   Real blot
150     = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
151
152   Real y2 = stem->extent (stem, Y_AXIS)[d];
153
154   return scm_from_double (y2 - d * blot / 2);
155 }
156
157 MAKE_SCHEME_CALLBACK (Flag, calc_x_offset, 1);
158 SCM
159 Flag::calc_x_offset (SCM smob)
160 {
161   Grob *me = unsmob_grob (smob);
162   Grob *stem = me->get_parent (X_AXIS);
163   return scm_from_double (stem->extent (stem, X_AXIS)[RIGHT]);
164 }
165
166 ADD_INTERFACE (Flag,
167                "A flag that gets attached to a stem."
168                "The style property is  symbol determining"
169                " what style of flag glyph is typeset on a"
170                " @code{Stem}.  Valid options include @code{'()}"
171                " for standard flags, @code{'mensural} and"
172                " @code{'no-flag}, which switches off the flag.",
173
174                /* properties */
175                "style "
176                "stroke-style "
177               );