]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
patch::: 1.3.9.hwn2
[lilypond.git] / lily / spanner.cc
1 /*
2   spanner.cc -- implement Spanner
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1996, 1997--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "dimension-cache.hh"
10 #include "debug.hh"
11 #include "spanner.hh"
12 #include "paper-column.hh"
13 #include "paper-score.hh"
14 #include "molecule.hh"
15 #include "paper-outputter.hh"
16 #include "score-column.hh"
17 #include "line-of-score.hh"
18
19 void
20 Spanner::break_into_pieces ()
21 {
22   if (line_l () || broken_b ())
23     return;
24   
25   Item * left = spanned_drul_[LEFT];
26   Item * right = spanned_drul_[RIGHT];
27
28   if  (left == right)
29     {
30       warning (_ ("Left spanpoint is right spanpoint"));
31       return;
32     }
33   
34   Link_array<Item> break_points = pscore_l_->broken_col_range (left,right);
35
36   break_points.insert (left,0);
37   break_points.push (right);
38
39   for (int i=1; i < break_points.size(); i++) 
40     {
41       Drul_array<Item*> bounds;
42       bounds[LEFT] = break_points[i-1];
43       bounds[RIGHT] = break_points[i];
44       Direction d = LEFT;
45       do
46         {
47           Item *&pc_l = bounds[d] ;
48           if (!pc_l->line_l())
49             pc_l =  pc_l->find_broken_piece(- d);
50           
51           assert (pc_l);
52         }
53       while ((flip(&d))!= LEFT);
54
55       Spanner *span_p = dynamic_cast<Spanner*>(clone ());
56       span_p->set_bounds(LEFT,bounds[LEFT]);
57       span_p->set_bounds(RIGHT,bounds[RIGHT]);
58       
59       pscore_l_->typeset_element (span_p);
60       span_p->handle_broken_dependencies();
61
62       broken_into_l_arr_.push (span_p);
63     }
64
65   broken_into_l_arr_.sort (Spanner::compare);
66 }
67
68 void
69 Spanner::set_my_columns()
70 {
71   Direction i = (Direction) LEFT;
72   do 
73     {
74       if (!spanned_drul_[i]->line_l())
75         set_bounds(i,spanned_drul_[i]->find_broken_piece((Direction) -i));
76     } 
77   while (flip(&i) != LEFT);
78 }       
79
80 void
81 Spanner::set_bounds(Direction d, Item*i)
82 {
83   spanned_drul_[d] =i;
84   if (i)
85     {
86       i->used_b_ = true;
87     }
88
89   /**
90      Prevent the column -> line_of_score -> column -> line_of_score -> etc situation
91   */
92   if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
93     {
94       set_parent (i, X_AXIS);
95     }
96   
97   if (spanned_drul_[Direction(-d)] == spanned_drul_[d]
98        && i)
99     warning (_f ("Spanner `%s' has equal left and right spanpoints", classname (this)));
100 }
101
102
103
104 void
105 Spanner::do_break_processing()
106 {
107   break_into_pieces ();
108   handle_broken_dependencies();
109 }
110
111 Spanner::Spanner ()
112 {
113   spanned_drul_[LEFT]=0;
114   spanned_drul_[RIGHT]=0;
115 }
116
117 Spanner::Spanner (Spanner const &s)
118   : Score_element (s)
119 {
120   spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
121 }
122
123
124 Real
125 Spanner::spanner_length() const
126 {  
127   Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
128   Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
129
130   if (r< l)
131     warning (_ ("spanner with negative length"));
132         
133   return r-l;
134 }
135
136 Line_of_score *
137 Spanner::line_l() const
138 {
139   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
140     return 0;
141   if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
142     return 0;
143   return spanned_drul_[LEFT]->line_l();
144 }
145
146
147 Score_element*
148 Spanner::find_broken_piece (Line_of_score*l) const
149 {
150   Spanner* me = (Spanner*) this;
151   break_into_pieces ();
152   
153   int idx = binsearch_link_array (broken_into_l_arr_,  (Spanner*)l, Spanner::compare);
154   
155   if (idx < 0)
156     return 0;
157   else
158     return broken_into_l_arr_ [idx];
159 }
160
161
162 int
163 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
164 {
165   return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
166 }
167
168 bool
169 Spanner::broken_b() const
170 {
171   return broken_into_l_arr_.size();
172 }
173
174 Array<Rod>
175 Spanner::get_rods () const
176 {
177   Array<Rod> r;
178   return r;
179 }
180
181 Array<Spring>
182 Spanner::get_springs () const
183 {
184   Array<Spring> s;
185   return s;    
186 }
187
188 void
189 Spanner::do_space_processing ()
190 {
191   Array<Rod> rs (get_rods ());
192   for (int i=0; i < rs.size (); i++)
193     {
194       rs[i].add_to_cols ();
195     }
196
197   Array<Spring> ss (get_springs ());
198   for (int i=0; i < ss.size (); i++)
199     {
200       ss[i].add_to_cols ();
201     }
202 }
203
204 #if 0
205 /*
206   UGH.
207  */
208 void
209 Spanner::handle_broken_dependents ()
210 {
211   Spanner *unbrok = dynamic_cast<Spanner*> (original_l_);
212   if (!unbrok || parent_l(Y_AXIS))
213     return;
214   
215   Spanner *refpoint = dynamic_cast<Spanner*> (unbrok->parent_l (Y_AXIS));
216   
217   if (refpoint)
218     {
219       Score_element * broken_refpoint = refpoint->find_broken_piece (line_l ());
220       if (broken_refpoint)
221         set_parent (broken_refpoint,Y_AXIS);
222       else
223         programming_error ("Spanner y -refpoint lost.");
224     }
225 }
226 #endif
227
228 /*
229   If this is a broken spanner, return the amount the left end is to be
230   shifted horizontally so that the spanner starts after the initial
231   clef and key on the staves. This is necessary for ties, slurs,
232   crescendo and decrescendo signs, for example.
233 */
234 Real
235 Spanner::get_broken_left_end_align () const
236 {
237   int i;
238
239   Score_column *sc = dynamic_cast<Score_column*> (spanned_drul_[LEFT]->column_l());
240
241   // Relevant only if left span point is first column in line
242   if(sc != NULL &&
243      sc->break_status_dir () == RIGHT)
244     {
245       // We could possibly return the right edge of the whole Score_column here,
246       // but we do a full search for the Break_align_item.
247       for(i = 0; i < sc->elem_l_arr_.size (); i++)
248         {
249           if(0 == strcmp (classname (sc->elem_l_arr_[i]), "Break_align_item"))
250             {
251               return sc->elem_l_arr_[i]->extent (X_AXIS) [RIGHT];
252             }
253         }
254     }
255
256   return 0.0;
257 }