]> git.donarmstrong.com Git - lilypond.git/blob - lily/hairpin.cc
(DynamicLineSpanner): Add
[lilypond.git] / lily / hairpin.cc
1 /*
2   hairpin.cc -- implement Hairpin
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "hairpin.hh"
10
11 #include "staff-symbol-referencer.hh"
12 #include "line-interface.hh"
13 #include "spanner.hh"
14 #include "font-interface.hh"
15 #include "dimensions.hh"
16 #include "output-def.hh"
17 #include "warn.hh"
18 #include "paper-column.hh"
19 #include "lookup.hh"
20 #include "text-interface.hh"
21 #include "pointer-group-interface.hh"
22
23 MAKE_SCHEME_CALLBACK (Hairpin, after_line_breaking, 1);
24 SCM
25 Hairpin::after_line_breaking (SCM smob)
26 {
27   Spanner *me = dynamic_cast<Spanner *> (unsmob_grob (smob));
28
29   Drul_array<bool> broken;
30   Drul_array<Item *> bounds;
31   Direction d = LEFT;
32   do
33     {
34       bounds[d] = me->get_bound (d);
35       broken[d] = bounds[d]->break_status_dir () != CENTER;
36     }
37   while (flip (&d) != LEFT);
38
39   if (broken[LEFT]
40       && ly_is_equal (bounds[RIGHT]->get_column ()->get_property ("when"),
41                       bounds[LEFT]->get_property ("when")))
42     me->suicide ();
43   return SCM_UNSPECIFIED;
44 }
45
46 MAKE_SCHEME_CALLBACK (Hairpin, print, 1);
47
48 SCM
49 Hairpin::print (SCM smob)
50 {
51   Spanner *me = dynamic_cast<Spanner *> (unsmob_grob (smob));
52
53   SCM s = me->get_property ("grow-direction");
54   if (!is_direction (s))
55     {
56       me->suicide ();
57       return SCM_EOL;
58     }
59
60   Direction grow_dir = to_dir (s);
61   Real padding = robust_scm2double (me->get_property ("bound-padding"), 0.5);
62
63   Drul_array<bool> broken;
64   Drul_array<Item *> bounds;
65   Direction d = LEFT;
66   do
67     {
68       bounds[d] = me->get_bound (d);
69       broken[d] = bounds[d]->break_status_dir () != CENTER;
70     }
71   while (flip (&d) != LEFT);
72
73   Grob *common = bounds[LEFT]->common_refpoint (bounds[RIGHT], X_AXIS);
74   Drul_array<Real> x_points;
75
76   do
77     {
78       Item *b = bounds[d];
79       x_points[d] = b->relative_coordinate (common, X_AXIS);
80       if (broken [d])
81         {
82           if (d == LEFT)
83             x_points[d] = b->extent (common, X_AXIS)[RIGHT];
84         }
85       else
86         {
87           if (Text_interface::has_interface (b))
88             {
89               Interval e = b->extent (common, X_AXIS);
90               if (!e.is_empty ())
91                 x_points[d] = e[-d] - d * padding;
92             }
93           else
94             {
95               bool neighbor_found = false;
96               extract_grob_set (me, "adjacent-hairpins", pins);
97               for (int i = 0; i < pins.size (); i++)
98                 {
99                   /*
100                     FIXME: this will fuck up in case of polyphonic
101                     notes in other voices. Need to look at note-columns
102                     in the current staff/voice.
103                   */
104
105                   Spanner *pin = dynamic_cast<Spanner *> (pins[i]);
106                   if (pin
107                       && (pin->get_bound (LEFT)->get_column () == b->get_column ()
108                           || pin->get_bound (RIGHT)->get_column () == b->get_column ()))
109                     neighbor_found = true;
110                 }
111
112               /*
113                 If we're hung on a paper column, that means we're not
114                 adjacent to a text-dynamic, and we may move closer. We
115                 make the padding a little smaller, here.
116               */
117               Interval e = robust_relative_extent (b, common, X_AXIS);
118               x_points[d]
119                 = neighbor_found ? e.center () - d * padding / 3 : e[d];
120             }
121         }
122     }
123   while (flip (&d) != LEFT);
124
125   Real width = x_points[RIGHT] - x_points[LEFT];
126   if (width < 0)
127     {
128       me->warning (_ ((grow_dir < 0) ? "decrescendo too small"
129                       : "crescendo too small"));
130       width = 0;
131     }
132
133   bool continued = broken[Direction (-grow_dir)];
134   Real height = robust_scm2double (me->get_property ("height"), 0.2) *
135     Staff_symbol_referencer::staff_space (me);
136
137   Real starth, endh;
138   if (grow_dir < 0)
139     {
140       starth = height;
141       endh = continued ? height / 2 : 0.0;
142     }
143   else
144     {
145       starth = continued ? height / 2 : 0.0;
146       endh = height;
147     }
148
149   /*
150     should do relative to staff-symbol staff-space?
151   */
152
153   Stencil mol;
154   mol = Line_interface::line (me, Offset (0, starth), Offset (width, endh));
155   mol.add_stencil (Line_interface::line (me,
156                                          Offset (0, -starth),
157                                          Offset (width, -endh)));
158
159   mol.translate_axis (x_points[LEFT]
160                       - bounds[LEFT]->relative_coordinate (common, X_AXIS),
161                       X_AXIS);
162   return mol.smobbed_copy ();
163 }
164
165 ADD_INTERFACE (Hairpin, "hairpin-interface",
166                "A hairpin crescendo/decrescendo.",
167                "adjacent-hairpins "
168                "bound-padding "
169                "grow-direction "
170                "height "
171                );
172