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