]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
release: 1.3.10
[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       span_p->handle_broken_dependencies();
62
63       broken_into_l_arr_.push (span_p);
64     }
65
66   broken_into_l_arr_.sort (Spanner::compare);
67 }
68
69 void
70 Spanner::set_my_columns()
71 {
72   Direction i = (Direction) LEFT;
73   do 
74     {
75       if (!spanned_drul_[i]->line_l())
76         set_bounds(i,spanned_drul_[i]->find_broken_piece((Direction) -i));
77     } 
78   while (flip(&i) != LEFT);
79 }       
80
81 void
82 Spanner::set_bounds(Direction d, Item*i)
83 {
84   spanned_drul_[d] =i;
85   if (i)
86     {
87       i->used_b_ = true;
88     }
89
90   /**
91      Prevent the column -> line_of_score -> column -> line_of_score -> etc situation
92   */
93   if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
94     {
95       set_parent (i, X_AXIS);
96     }
97   
98   if (spanned_drul_[Direction(-d)] == spanned_drul_[d]
99        && i)
100     warning (_f ("Spanner `%s' has equal left and right spanpoints", classname (this)));
101 }
102
103
104
105 void
106 Spanner::do_break_processing()
107 {
108   break_into_pieces ();
109   handle_broken_dependencies();
110 }
111
112 Spanner::Spanner ()
113 {
114   spanned_drul_[LEFT]=0;
115   spanned_drul_[RIGHT]=0;
116 }
117
118 Spanner::Spanner (Spanner const &s)
119   : Score_element (s)
120 {
121   spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
122 }
123
124
125 Real
126 Spanner::spanner_length() const
127 {  
128   Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
129   Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
130
131   if (r< l)
132     warning (_ ("spanner with negative length"));
133         
134   return r-l;
135 }
136
137 Line_of_score *
138 Spanner::line_l() const
139 {
140   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
141     return 0;
142   if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
143     return 0;
144   return spanned_drul_[LEFT]->line_l();
145 }
146
147
148 Score_element*
149 Spanner::find_broken_piece (Line_of_score*l) const
150 {
151   Spanner* me = (Spanner*) this;
152   break_into_pieces ();
153   
154   int idx = binsearch_link_array (broken_into_l_arr_,  (Spanner*)l, Spanner::compare);
155   
156   if (idx < 0)
157     return 0;
158   else
159     return broken_into_l_arr_ [idx];
160 }
161
162
163 int
164 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
165 {
166   return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
167 }
168
169 bool
170 Spanner::broken_b() const
171 {
172   return broken_into_l_arr_.size();
173 }
174
175 Array<Rod>
176 Spanner::get_rods () const
177 {
178   Array<Rod> r;
179   return r;
180 }
181
182 Array<Spring>
183 Spanner::get_springs () const
184 {
185   Array<Spring> s;
186   return s;    
187 }
188
189 void
190 Spanner::do_space_processing ()
191 {
192   Array<Rod> rs (get_rods ());
193   for (int i=0; i < rs.size (); i++)
194     {
195       rs[i].add_to_cols ();
196     }
197
198   Array<Spring> ss (get_springs ());
199   for (int i=0; i < ss.size (); i++)
200     {
201       ss[i].add_to_cols ();
202     }
203 }
204
205 /*
206   If this is a broken spanner, return the amount the left end is to be
207   shifted horizontally so that the spanner starts after the initial
208   clef and key on the staves. This is necessary for ties, slurs,
209   crescendo and decrescendo signs, for example.
210 */
211 Real
212 Spanner::get_broken_left_end_align () const
213 {
214   Score_column *sc = dynamic_cast<Score_column*> (spanned_drul_[LEFT]->column_l());
215
216   // Relevant only if left span point is first column in line
217   if(sc != NULL &&
218      sc->break_status_dir () == RIGHT)
219     {
220       // We could possibly return the right edge of the whole Score_column here,
221       // but we do a full search for the Break_align_item.
222
223       /*
224         In fact that doesn't make a difference, since the Score_column
225         is likely to contain only a Break_align_item.
226       */
227 #if 0
228       for(SCM s = sc->get_elt_property ("elements"); gh_pair_p (s);
229           s = gh_cdr (s))
230         {
231           Score_element *e = SMOB_TO_TYPE (Score_element, gh_car (s));
232           if(dynamic_cast<Break_align_item*> (e))
233             {
234               return e->extent (X_AXIS) [RIGHT];
235             }
236         }
237 #endif
238       return sc->extent (X_AXIS)[RIGHT];
239     }
240
241   return 0.0;
242 }