]> git.donarmstrong.com Git - lilypond.git/blob - lily/tie-column.cc
* Documentation/user/instrument-notation.itely (Laissez vibrer
[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 #include "tie-column.hh"
10
11 #include <math.h>
12 #include <map>
13
14 #include "skyline.hh"
15 #include "warn.hh"
16 #include "paper-column.hh"
17 #include "spanner.hh"
18 #include "pointer-group-interface.hh"
19 #include "tie.hh"
20 #include "directional-element-interface.hh"
21 #include "tie-column-format.hh"
22
23 void
24 Tie_column::add_tie (Grob *me, Grob *tie)
25 {
26   if (tie->get_parent (Y_AXIS)
27       && Tie_column::has_interface (tie->get_parent (Y_AXIS)))
28     return;
29
30   if (!Pointer_group_interface::count (me, ly_symbol2scm ("ties")))
31     {
32       dynamic_cast<Spanner *> (me)->set_bound (LEFT, Tie::head (tie, LEFT));
33       dynamic_cast<Spanner *> (me)->set_bound (RIGHT, Tie::head (tie, RIGHT));
34     }
35
36   tie->set_parent (me, Y_AXIS);
37   Pointer_group_interface::add_grob (me, ly_symbol2scm ("ties"), tie);
38   tie->add_dependency (me);
39 }
40
41 void
42 Tie_column::set_directions (Grob *me)
43 {
44   if (!to_boolean (me->get_property ("positioning-done")))
45     {
46       me->set_property ("positioning-done", SCM_BOOL_T); 
47       new_directions (me);
48     }
49 }
50
51
52
53 MAKE_SCHEME_CALLBACK (Tie_column, after_line_breaking, 1);
54 SCM
55 Tie_column::after_line_breaking (SCM smob)
56 {
57   set_directions (unsmob_grob (smob));
58   return SCM_UNSPECIFIED;
59 }
60
61 /*
62   Extend the spanner over its Tie constituents.
63 */
64 MAKE_SCHEME_CALLBACK (Tie_column, before_line_breaking, 1);
65 SCM
66 Tie_column::before_line_breaking (SCM smob)
67 {
68   Spanner *me = dynamic_cast<Spanner *> (unsmob_grob (smob));
69   for (SCM s = me->get_property ("ties"); scm_is_pair (s); s = scm_cdr (s))
70     {
71       Spanner *tie = dynamic_cast<Spanner *> (unsmob_grob (scm_car (s)));
72       Direction dir = LEFT;
73       do
74         {
75           if (dir * tie->get_bound (dir)->get_column ()->get_rank ()
76               > dir * me->get_bound (dir)->get_column ()->get_rank ())
77             me->set_bound (dir, Tie::head (tie, dir));
78         }
79       while (flip (&dir) != LEFT);
80     }
81   return SCM_UNSPECIFIED;
82 }
83
84
85 void
86 Tie_column::new_directions (Grob *me)
87 {
88   extract_grob_set (me, "ties", ro_ties);
89   Link_array<Grob> ties (ro_ties);
90   if (!ties.size ())
91     return;
92
93   if (ties.size() == 1)
94     {
95       Tie::set_default_control_points (ties[0]);
96       return ;
97     }
98   
99   ties.sort (&Tie::compare);
100
101   Array<Tie_configuration> tie_configs;
102   for (int i = 0; i < ties.size (); i++)
103     {
104       Tie_configuration conf;
105       conf.dir_ = get_grob_direction (ties[i]);
106       conf.position_ = Tie::get_position (ties[i]);
107       tie_configs.push (conf);
108     }
109
110   SCM manual_configs = me->get_property ("tie-configuration");
111   bool manual_override = false;
112   set_manual_tie_configuration (&tie_configs,
113                                 &manual_override,
114                                 manual_configs);
115   set_tie_config_directions (&tie_configs);
116
117   Grob *common = me;
118   for (int i = 0; i < ties.size (); i++)
119     {
120       common = dynamic_cast<Spanner*> (ties[i])->get_bound (LEFT)->common_refpoint (common, X_AXIS); 
121       common = dynamic_cast<Spanner*> (ties[i])->get_bound (RIGHT)->common_refpoint (common, X_AXIS); 
122     }
123
124   Drul_array< Array<Skyline_entry> > skylines;
125   set_chord_outlines (&skylines, ties, common);
126   
127   Tie_details details;
128   details.init (ties[0]);
129
130   /*
131     Let the ties flow out, according to our single-tie formatting.
132    */
133   if (!manual_override)
134     {
135       Tie::get_configuration (ties[0], common, &tie_configs.elem_ref (0),
136                               &skylines,
137                               details
138                               );
139       Tie::get_configuration (ties.top (), common,
140                               &tie_configs.elem_ref (tie_configs.size()-1),
141                               &skylines,
142                               details
143                               );
144     }
145
146   /*
147     Calculate final width and shape of the ties.
148    */
149   for (int i = 0; i < ties.size(); i++)
150     {
151       if (!manual_override
152           && (i == 0 || i == ties.size () -1))
153         continue;
154
155
156       final_shape_adjustment (tie_configs[i],
157                               skylines,
158                               ties[0],
159                               details);
160     }
161
162   
163   /*
164     Try to shift small ties into available spaces.
165    */
166   if (!manual_override)
167     {
168       shift_small_ties (&tie_configs, ties[0], details);
169     }
170   
171   for (int i = 0; i < ties.size(); i++)
172     {
173       Tie::set_control_points (ties[i], common, tie_configs[i],
174                                details
175                                );
176       set_grob_direction (ties[i], tie_configs[i].dir_);
177     }
178 }
179
180
181
182 ADD_INTERFACE (Tie_column, "tie-column-interface",
183                "Object that sets directions of multiple ties in a tied chord",
184
185                /* properties */
186                "positioning-done "
187                "tie-configuration "
188                );
189