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