2 spanner.cc -- implement Spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include <libc-extension.hh>
14 #include "paper-column.hh"
15 #include "paper-score.hh"
16 #include "molecule.hh"
17 #include "paper-outputter.hh"
18 #include "paper-column.hh"
19 #include "line-of-score.hh"
20 #include "break-align-item.hh"
24 Spanner::do_break_processing ()
27 Item
* left
= spanned_drul_
[LEFT
];
28 Item
* right
= spanned_drul_
[RIGHT
];
34 Check if our parent in X-direction spans equally wide
37 for (int a
= X_AXIS
; a
< NO_AXES
; a
++)
39 if (Spanner
* parent
= dynamic_cast<Spanner
*> (parent_l ((Axis
)a
)))
41 if (!parent
->spanned_rank_iv ().contains_b (this->spanned_rank_iv ()))
43 programming_error (to_str ("Spanner `%s' is not fully contained in parent spanner `%s'.",
50 if (line_l () || broken_b ())
56 If we have a spanner spanning one column, we must break it
57 anyway because it might provide a parent for another item. */
61 Item
* bound
= left
->find_prebroken_piece (d
);
63 programming_error ("no broken bound");
64 else if (bound
->line_l ())
66 Spanner
* span_p
= dynamic_cast<Spanner
*>( clone ());
67 span_p
->set_bound (LEFT
, bound
);
68 span_p
->set_bound (RIGHT
, bound
);
70 assert (span_p
->line_l ());
71 span_p
->line_l ()->typeset_element (span_p
);
72 broken_into_l_arr_
.push (span_p
);
75 while ((flip(&d
))!= LEFT
);
79 Link_array
<Item
> break_points
= pscore_l_
->line_l_
->broken_col_range (left
,right
);
81 break_points
.insert (left
,0);
82 break_points
.push (right
);
84 for (int i
=1; i
< break_points
.size(); i
++)
86 Drul_array
<Item
*> bounds
;
87 bounds
[LEFT
] = break_points
[i
-1];
88 bounds
[RIGHT
] = break_points
[i
];
92 if (!bounds
[d
]->line_l())
93 bounds
[d
] = bounds
[d
]->find_prebroken_piece(- d
);
95 while ((flip(&d
))!= LEFT
);
97 if (!bounds
[LEFT
] || ! bounds
[RIGHT
])
99 programming_error ("bounds of this piece aren't breakable. ");
103 Spanner
*span_p
= dynamic_cast<Spanner
*>(clone ());
104 span_p
->set_bound(LEFT
,bounds
[LEFT
]);
105 span_p
->set_bound(RIGHT
,bounds
[RIGHT
]);
108 assert (bounds
[LEFT
]->line_l () ==
109 bounds
[RIGHT
]->line_l ());
111 bounds
[LEFT
]->line_l ()->typeset_element (span_p
);
112 broken_into_l_arr_
.push (span_p
);
115 broken_into_l_arr_
.sort (Spanner::compare
);
119 Spanner::set_my_columns()
121 Direction i
= (Direction
) LEFT
;
124 if (!spanned_drul_
[i
]->line_l())
125 set_bound(i
,spanned_drul_
[i
]->find_prebroken_piece((Direction
) -i
));
127 while (flip(&i
) != LEFT
);
131 Spanner::spanned_rank_iv ()
133 Interval_t
<int> iv (0, 0);
135 if (spanned_drul_
[LEFT
])
137 iv
[LEFT
] = Paper_column::rank_i (spanned_drul_
[LEFT
]->column_l ());
139 if (spanned_drul_
[RIGHT
])
141 iv
[RIGHT
] = Paper_column::rank_i (spanned_drul_
[RIGHT
]->column_l ());
147 Spanner::get_bound (Direction d
) const
149 return spanned_drul_
[d
];
153 Spanner::set_bound(Direction d
, Score_element
*s
)
155 Item
* i
= dynamic_cast<Item
*> (s
);
158 programming_error ("Must have Item for spanner bound.");
165 We check for Line_of_score to prevent the column -> line_of_score
166 -> column -> line_of_score -> etc situation */
167 if (d
== LEFT
&& !dynamic_cast<Line_of_score
*> (this))
169 set_parent (i
, X_AXIS
);
174 Spanner::Spanner (SCM s
)
177 spanned_drul_
[LEFT
]=0;
178 spanned_drul_
[RIGHT
]=0;
181 Spanner::Spanner (Spanner
const &s
)
184 spanned_drul_
[LEFT
] = spanned_drul_
[RIGHT
] =0;
189 Spanner::spanner_length() const
191 Real l
= spanned_drul_
[LEFT
]->relative_coordinate (0, X_AXIS
);
192 Real r
= spanned_drul_
[RIGHT
]->relative_coordinate (0, X_AXIS
);
195 programming_error ("spanner with negative length");
201 Spanner::line_l() const
203 if (!spanned_drul_
[LEFT
] || !spanned_drul_
[RIGHT
])
205 if (spanned_drul_
[LEFT
]->line_l () != spanned_drul_
[RIGHT
]->line_l ())
207 return spanned_drul_
[LEFT
]->line_l();
212 Spanner::find_broken_piece (Line_of_score
*l
) const
214 int idx
= binsearch_link_array (broken_into_l_arr_
, (Spanner
*)l
, Spanner::compare
);
219 return broken_into_l_arr_
[idx
];
224 Spanner::compare (Spanner
* const &p1
, Spanner
* const &p2
)
226 return p1
->line_l ()->rank_i_
- p2
->line_l ()->rank_i_
;
230 Spanner::broken_b() const
232 return broken_into_l_arr_
.size();
236 Spanner::get_rods () const
243 Spanner::get_springs () const
250 Spanner::do_space_processing ()
252 Array
<Rod
> rs (get_rods ());
253 for (int i
=0; i
< rs
.size (); i
++)
255 rs
[i
].add_to_cols ();
258 Array
<Spring
> ss (get_springs ());
259 for (int i
=0; i
< ss
.size (); i
++)
261 if (isinf (ss
[i
].distance_f_
))
262 programming_error ("weird spring");
264 ss
[i
].add_to_cols ();
269 If this is a broken spanner, return the amount the left end is to be
270 shifted horizontally so that the spanner starts after the initial
271 clef and key on the staves. This is necessary for ties, slurs,
272 crescendo and decrescendo signs, for example.
275 Spanner::get_broken_left_end_align () const
277 Paper_column
*sc
= dynamic_cast<Paper_column
*> (spanned_drul_
[LEFT
]->column_l());
279 // Relevant only if left span point is first column in line
281 sc
->break_status_dir () == RIGHT
)
285 We used to do a full search for the Break_align_item.
286 But that doesn't make a difference, since the Paper_column
287 is likely to contain only a Break_align_item.
289 return sc
->extent (X_AXIS
)[RIGHT
];
296 Spanner::do_derived_mark ()
300 if (spanned_drul_
[d
])
301 scm_gc_mark (spanned_drul_
[d
]->self_scm_
);
302 while (flip (&d
) != LEFT
);
304 for (int i
= broken_into_l_arr_
.size () ; i
--;)
305 scm_gc_mark (broken_into_l_arr_
[i
]->self_scm_
);
309 add_bound_item (Spanner
* sp
, Item
*it
)
311 if (!sp
->get_bound (LEFT
))
312 sp
->set_bound (LEFT
, it
);
314 sp
->set_bound (RIGHT
, it
);