]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
release: 1.3.11
[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 #include "break-align-item.hh"
19
20 void
21 Spanner::break_into_pieces ()
22 {
23   if (line_l () || broken_b ())
24     return;
25   
26   Item * left = spanned_drul_[LEFT];
27   Item * right = spanned_drul_[RIGHT];
28
29   if  (left == right)
30     {
31       warning (_ ("Left spanpoint is right spanpoint"));
32       return;
33     }
34   
35   Link_array<Item> break_points = pscore_l_->broken_col_range (left,right);
36
37   break_points.insert (left,0);
38   break_points.push (right);
39
40   for (int i=1; i < break_points.size(); i++) 
41     {
42       Drul_array<Item*> bounds;
43       bounds[LEFT] = break_points[i-1];
44       bounds[RIGHT] = break_points[i];
45       Direction d = LEFT;
46       do
47         {
48           Item *&pc_l = bounds[d] ;
49           if (!pc_l->line_l())
50             pc_l =  pc_l->find_broken_piece(- d);
51           
52           assert (pc_l);
53         }
54       while ((flip(&d))!= LEFT);
55
56       Spanner *span_p = dynamic_cast<Spanner*>(clone ());
57       span_p->set_bounds(LEFT,bounds[LEFT]);
58       span_p->set_bounds(RIGHT,bounds[RIGHT]);
59       
60       pscore_l_->typeset_element (span_p);
61       broken_into_l_arr_.push (span_p);
62     }
63
64   broken_into_l_arr_.sort (Spanner::compare);
65 }
66
67 void
68 Spanner::set_my_columns()
69 {
70   Direction i = (Direction) LEFT;
71   do 
72     {
73       if (!spanned_drul_[i]->line_l())
74         set_bounds(i,spanned_drul_[i]->find_broken_piece((Direction) -i));
75     } 
76   while (flip(&i) != LEFT);
77 }       
78
79 void
80 Spanner::set_bounds(Direction d, Item*i)
81 {
82   spanned_drul_[d] =i;
83   if (i)
84     {
85       i->used_b_ = true;
86     }
87
88   /**
89      Prevent the column -> line_of_score -> column -> line_of_score -> etc situation
90   */
91   if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
92     {
93       set_parent (i, X_AXIS);
94     }
95   
96   if (spanned_drul_[Direction(-d)] == spanned_drul_[d]
97        && i)
98     warning (_f ("Spanner `%s' has equal left and right spanpoints", classname (this)));
99 }
100
101
102
103 void
104 Spanner::do_break_processing()
105 {
106   break_into_pieces ();
107 }
108
109 Spanner::Spanner ()
110 {
111   spanned_drul_[LEFT]=0;
112   spanned_drul_[RIGHT]=0;
113 }
114
115 Spanner::Spanner (Spanner const &s)
116   : Score_element (s)
117 {
118   spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
119 }
120
121
122 Real
123 Spanner::spanner_length() const
124 {  
125   Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
126   Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
127
128   if (r< l)
129     warning (_ ("spanner with negative length"));
130         
131   return r-l;
132 }
133
134 Line_of_score *
135 Spanner::line_l() const
136 {
137   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
138     return 0;
139   if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
140     return 0;
141   return spanned_drul_[LEFT]->line_l();
142 }
143
144
145 Score_element*
146 Spanner::find_broken_piece (Line_of_score*l) const
147 {
148   Spanner* me = (Spanner*) this;
149   me->break_into_pieces ();
150   
151   int idx = binsearch_link_array (broken_into_l_arr_,  (Spanner*)l, Spanner::compare);
152   
153   if (idx < 0)
154     return 0;
155   else
156     return broken_into_l_arr_ [idx];
157 }
158
159
160 int
161 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
162 {
163   return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
164 }
165
166 bool
167 Spanner::broken_b() const
168 {
169   return broken_into_l_arr_.size();
170 }
171
172 Array<Rod>
173 Spanner::get_rods () const
174 {
175   Array<Rod> r;
176   return r;
177 }
178
179 Array<Spring>
180 Spanner::get_springs () const
181 {
182   Array<Spring> s;
183   return s;    
184 }
185
186 void
187 Spanner::do_space_processing ()
188 {
189   Array<Rod> rs (get_rods ());
190   for (int i=0; i < rs.size (); i++)
191     {
192       rs[i].add_to_cols ();
193     }
194
195   Array<Spring> ss (get_springs ());
196   for (int i=0; i < ss.size (); i++)
197     {
198       ss[i].add_to_cols ();
199     }
200 }
201
202 /*
203   If this is a broken spanner, return the amount the left end is to be
204   shifted horizontally so that the spanner starts after the initial
205   clef and key on the staves. This is necessary for ties, slurs,
206   crescendo and decrescendo signs, for example.
207 */
208 Real
209 Spanner::get_broken_left_end_align () const
210 {
211   Score_column *sc = dynamic_cast<Score_column*> (spanned_drul_[LEFT]->column_l());
212
213   // Relevant only if left span point is first column in line
214   if(sc != NULL &&
215      sc->break_status_dir () == RIGHT)
216     {
217       /*
218         
219         We used to do a full search for the Break_align_item.
220         But that doesn't make a difference, since the Score_column
221         is likely to contain only a Break_align_item.
222       */
223       return sc->extent (X_AXIS)[RIGHT];
224     }
225
226   return 0.0;
227 }