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();
237 If this is a broken spanner, return the amount the left end is to be
238 shifted horizontally so that the spanner starts after the initial
239 clef and key on the staves. This is necessary for ties, slurs,
240 crescendo and decrescendo signs, for example.
243 Spanner::get_broken_left_end_align () const
245 Paper_column
*sc
= dynamic_cast<Paper_column
*> (spanned_drul_
[LEFT
]->column_l());
247 // Relevant only if left span point is first column in line
249 sc
->break_status_dir () == RIGHT
)
253 We used to do a full search for the Break_align_item.
254 But that doesn't make a difference, since the Paper_column
255 is likely to contain only a Break_align_item.
257 return sc
->extent (X_AXIS
)[RIGHT
];
264 Spanner::do_derived_mark ()
267 We'd be fucked if this is called before spanned_drul_[] is inited. */
268 if (status_i_
== ORPHAN
)
273 if (spanned_drul_
[d
])
274 scm_gc_mark (spanned_drul_
[d
]->self_scm ());
275 while (flip (&d
) != LEFT
);
277 for (int i
= broken_into_l_arr_
.size () ; i
--;)
278 scm_gc_mark (broken_into_l_arr_
[i
]->self_scm ());
284 add_bound_item (Spanner
* sp
, Item
*it
)
286 if (!sp
->get_bound (LEFT
))
287 sp
->set_bound (LEFT
, it
);
289 sp
->set_bound (RIGHT
, it
);