]> git.donarmstrong.com Git - lilypond.git/blob - lily/tie-column.cc
new file.
[lilypond.git] / lily / tie-column.cc
1 /*   
2   tie-column.cc -- implement Tie_column
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2000--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "tie-column.hh"
11 #include "paper-column.hh"
12 #include "spanner.hh"
13 #include "group-interface.hh"
14 #include "tie.hh"
15 #include "directional-element-interface.hh"
16 #include "rhythmic-head.hh"
17
18 /*
19   tie dir depends on what Tie_column does.
20 */
21 /*
22   TODO: this doesn't follow standard pattern. Regularize.
23  */
24 void
25 Tie_column::add_tie (Grob*me, Grob *tie)
26 {
27   if (tie->get_parent (Y_AXIS)
28       && Tie_column::has_interface (tie->get_parent (Y_AXIS)))
29     return ;
30
31    
32   if (!Pointer_group_interface::count (me, ly_symbol2scm ("ties")))
33     {
34       dynamic_cast<Spanner*> (me)->set_bound (LEFT, Tie::head (tie, LEFT));
35       dynamic_cast<Spanner*> (me)->set_bound (RIGHT, Tie::head (tie, RIGHT));
36     }
37   
38    
39   tie->set_parent (me, Y_AXIS);
40   Pointer_group_interface::add_grob (me, ly_symbol2scm ("ties"), tie);
41   tie->add_dependency (me);
42 }
43
44 void
45 Tie_column::set_directions (Grob*me)
46 {
47   werner_directions (me);
48 }
49
50 int
51 tie_compare (Grob* const & s1,
52              Grob* const & s2)
53 {
54   return sign (Tie::get_position (s1) - Tie::get_position (s2));
55 }
56
57 /*
58 Werner:
59
60  . The algorithm to choose the direction of the ties doesn't work
61    properly.  I suggest the following for applying ties sequentially
62    from top to bottom:
63
64      + The topmost tie is always `up'.
65
66      + If there is a vertical gap to the last note above larger than
67        or equal to a fifth (or sixth?), the tie is `up', otherwise it
68        is `down'.
69
70      + The bottommost tie is always `down'.
71
72 */
73 void
74 Tie_column::werner_directions (Grob *me)
75 {
76   Link_array<Grob> ties =
77     Pointer_group_interface__extract_grobs (me, (Grob*)0, "ties");
78
79   if (!ties.size ())
80     return ;
81   
82   ties.sort (tie_compare);
83
84   Direction d = get_grob_direction (me);
85   if (d)
86     {
87       for (int i = ties.size (); i--;)
88         {
89           Grob *  t = ties[i];
90           if (!get_grob_direction (t))
91             set_grob_direction (t, d);
92         }
93       return ;
94     }
95   
96   if (ties.size () == 1)
97     {
98       Grob *  t = ties[0];
99       if (t->is_live ()
100           && !get_grob_direction (t))
101         set_grob_direction (t, Tie::get_default_dir (t));
102       return ;
103     }
104
105   Real last_down_pos = 10000;
106   if (!get_grob_direction (ties[0]))
107     set_grob_direction (ties[0], DOWN);
108
109   /*
110     Go downward.
111    */
112   Grob *last_tie = 0;
113   for (int i = ties.size (); i--;)
114     {
115       Grob *t = ties[i];
116       
117       Direction d = get_grob_direction (t);
118       Real p  = Tie::get_position (t);
119       if (!d)
120         {
121           if (last_tie
122               && Tie::get_column_rank (t, LEFT)
123                  < Tie::get_column_rank (last_tie, LEFT))
124             {
125               d = DOWN;
126             }
127           else if (last_down_pos - p > 5)
128             {
129               d = UP;
130             }
131           else
132             {
133               d = DOWN;
134             }
135
136           set_grob_direction (t, d);
137         }
138
139       if (d == DOWN)
140         last_down_pos = p;
141
142       last_tie = t;
143     }
144
145   return ;
146 }
147
148
149 MAKE_SCHEME_CALLBACK (Tie_column, after_line_breaking, 1);
150 SCM
151 Tie_column::after_line_breaking (SCM smob)
152 {
153   werner_directions (unsmob_grob (smob));
154   return SCM_UNSPECIFIED;
155 }
156
157 /*
158   Extend the spanner over its Tie constituents.
159  */
160 MAKE_SCHEME_CALLBACK (Tie_column, before_line_breaking, 1);
161 SCM
162 Tie_column::before_line_breaking (SCM smob)
163 {
164   Spanner *me = dynamic_cast<Spanner*> (unsmob_grob (smob));
165   for (SCM s = me->get_property ("ties"); scm_is_pair (s); s = scm_cdr (s))
166     {
167       Spanner *tie = dynamic_cast<Spanner*> (unsmob_grob (scm_car (s)));
168       Direction dir = LEFT;
169       do
170         {
171           if (dir * Paper_column::get_rank (tie->get_bound (dir)->get_column ()) 
172               > dir * Paper_column::get_rank (me->get_bound (dir)->get_column ()))
173             {
174               me->set_bound (dir, Tie::head (tie, dir));
175             }
176         }
177       while (flip (&dir) != LEFT);
178     }
179   return SCM_UNSPECIFIED;
180 }
181
182 ADD_INTERFACE (Tie_column, "tie-column-interface",
183   "Object that sets directions of multiple ties in a tied chord",
184   "direction");
185