2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1996--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
22 #include "align-interface.hh"
23 #include "all-font-metrics.hh"
24 #include "axis-group-interface.hh"
25 #include "break-align-interface.hh"
26 #include "grob-array.hh"
27 #include "hara-kiri-group-spanner.hh"
28 #include "international.hh"
31 #include "output-def.hh"
32 #include "page-layout-problem.hh"
33 #include "paper-column.hh"
34 #include "paper-score.hh"
35 #include "paper-system.hh"
36 #include "pointer-group-interface.hh"
37 #include "skyline-pair.hh"
38 #include "staff-symbol-referencer.hh"
39 #include "system-start-delimiter.hh"
40 #include "text-interface.hh"
42 #include "unpure-pure-container.hh"
43 #include "lily-imports.hh"
47 System::System (System const &src)
56 System::System (SCM s)
65 System::init_elements ()
67 SCM scm_arr = Grob_array::make_array ();
68 all_elements_ = unsmob<Grob_array> (scm_arr);
69 all_elements_->set_ordered (false);
70 set_object ("all-elements", scm_arr);
74 System::clone () const
76 return new System (*this);
80 System::element_count () const
82 return all_elements_->size ();
86 System::spanner_count () const
89 for (vsize i = all_elements_->size (); i--;)
90 if (dynamic_cast<Spanner *> (all_elements_->grob (i)))
96 System::typeset_grob (Grob *elem)
99 programming_error ("adding element twice");
102 elem->layout_ = pscore_->layout ();
103 all_elements_->add (elem);
109 System::derived_mark () const
111 const vector <Grob *> &arr = all_elements_->array ();
112 for (vsize i = arr.size (); i--;)
113 scm_gc_mark (arr[i]->self_scm ());
116 scm_gc_mark (pscore_->self_scm ());
118 Spanner::derived_mark ();
122 fixup_refpoints (vector<Grob *> const &grobs)
124 for (vsize i = grobs.size (); i--;)
125 grobs[i]->fixup_refpoint ();
129 System::do_break_substitution_and_fixup_refpoints ()
131 for (vsize i = 0; i < all_elements_->size (); i++)
133 Grob *g = all_elements_->grob (i);
134 if (g->internal_has_interface (ly_symbol2scm ("only-prebreak-interface")))
137 Kill no longer needed grobs.
139 Item *it = dynamic_cast<Item *> (g);
140 if (it && Item::is_non_musical (it))
142 it->find_prebroken_piece (LEFT)->suicide ();
143 it->find_prebroken_piece (RIGHT)->suicide ();
147 else if (g->is_live ())
148 g->do_break_processing ();
152 fixups must be done in broken line_of_scores, because new elements
153 are put over there. */
155 for (vsize i = 0; i < broken_intos_.size (); i++)
157 Grob *se = broken_intos_[i];
159 extract_grob_set (se, "all-elements", all_elts);
160 for (vsize j = 0; j < all_elts.size (); j++)
162 Grob *g = all_elts[j];
163 g->fixup_refpoint ();
166 count += all_elts.size ();
170 needed for doing items.
172 fixup_refpoints (all_elements_->array ());
174 for (vsize i = 0; i < all_elements_->size (); i++)
175 all_elements_->grob (i)->handle_broken_dependencies ();
177 handle_broken_dependencies ();
179 /* Because the get_property (all-elements) contains items in 3
180 versions, handle_broken_dependencies () will leave duplicated
181 items in all-elements. Strictly speaking this is harmless, but
182 it leads to duplicated symbols in the output. uniq makes sure
183 that no duplicates are in the list. */
184 for (vsize i = 0; i < broken_intos_.size (); i++)
186 System *child = dynamic_cast<System *> (broken_intos_[i]);
187 child->all_elements_->remove_duplicates ();
189 for (vsize j = 0; j < child->all_elements_->size (); j++)
191 Grob *g = child->all_elements_->grob (j);
193 (void) g->get_property ("after-line-breaking");
197 debug_output (_f ("Element count %d", count + element_count ()) + "\n");
201 System::get_broken_system_grobs ()
204 for (vsize i = 0; i < broken_intos_.size (); i++)
205 ret = scm_cons (broken_intos_[i]->self_scm (), ret);
206 return scm_reverse_x (ret, SCM_EOL);
210 System::get_paper_systems ()
212 SCM lines = scm_c_make_vector (broken_intos_.size (), SCM_EOL);
213 for (vsize i = 0; i < broken_intos_.size (); i++)
215 debug_output ("[", false);
217 System *system = dynamic_cast<System *> (broken_intos_[i]);
219 scm_vector_set_x (lines, scm_from_int (i),
220 system->get_paper_system ());
222 debug_output (::to_string (i) + "]", false);
228 System::get_footnote_grobs_in_range (vsize start, vsize end)
231 extract_grob_set (this, "footnotes-before-line-breaking", footnote_grobs);
232 for (vsize i = 0; i < footnote_grobs.size (); i++)
234 Grob *at_bat = footnote_grobs[i];
235 int pos = at_bat->spanned_rank_interval ()[LEFT];
236 bool end_of_line_visible = true;
237 if (Spanner *s = dynamic_cast<Spanner *>(at_bat))
239 Direction spanner_placement = robust_scm2dir (s->get_property ("spanner-placement"), LEFT);
240 if (spanner_placement == CENTER)
241 spanner_placement = LEFT;
243 pos = s->spanned_rank_interval ()[spanner_placement];
246 Spanner *orig = dynamic_cast<Spanner *>(s->original ());
247 at_bat = spanner_placement == LEFT ? orig->broken_intos_[0] : orig->broken_intos_.back ();
248 pos = at_bat->spanned_rank_interval ()[RIGHT];
252 if (Item *item = dynamic_cast<Item *>(at_bat))
255 We use this to weed out grobs that fall at the end
256 of the line when we want grobs at the beginning.
258 end_of_line_visible = item->break_status_dir () == LEFT;
260 if (!Item::break_visible (item))
262 // safeguard to bring down the column rank so that end of line footnotes show up on the correct line
263 if (pos == int (start) && item->break_status_dir () != RIGHT)
265 if (pos == int (end) && item->break_status_dir () != LEFT)
267 if (pos != int (end) && pos != int (start) && item->break_status_dir () != CENTER)
271 if (pos < int (start))
275 if (pos == int (start) && end_of_line_visible)
277 if (pos == int (end) && !end_of_line_visible)
279 if (!at_bat->is_live ())
283 Sometimes, there are duplicate entries in the all_elements_
284 list. In a separate patch, this practice should be squashed
285 so that the check below can be eliminated.
287 if (find (out.begin (), out.end (), at_bat) != out.end ())
290 out.push_back (at_bat);
296 System::get_footnote_heights_in_range (vsize start, vsize end)
298 return internal_get_note_heights_in_range (start, end, true);
302 System::get_in_note_heights_in_range (vsize start, vsize end)
304 return internal_get_note_heights_in_range (start, end, false);
308 System::internal_get_note_heights_in_range (vsize start, vsize end, bool foot)
310 vector<Grob *> footnote_grobs = get_footnote_grobs_in_range (start, end);
313 for (vsize i = footnote_grobs.size (); i--;)
315 ? !to_boolean (footnote_grobs[i]->get_property ("footnote"))
316 : to_boolean (footnote_grobs[i]->get_property ("footnote")))
317 footnote_grobs.erase (footnote_grobs.begin () + i);
319 for (vsize i = 0; i < footnote_grobs.size (); i++)
321 SCM footnote_markup = footnote_grobs[i]->get_property ("footnote-text");
323 if (!Text_interface::is_markup (footnote_markup))
327 Lily::layout_extract_page_properties (pscore_->layout ()->self_scm ());
329 SCM footnote_stl = Text_interface::interpret_markup (pscore_->layout ()->self_scm (),
330 props, footnote_markup);
332 Stencil *footnote_stencil = unsmob<Stencil> (footnote_stl);
333 out.push_back (footnote_stencil->extent (Y_AXIS).length ());
340 System::num_footnotes ()
342 extract_grob_set (this, "footnotes-after-line-breaking", footnote_grobs);
343 return footnote_grobs.size ();
347 grob_2D_less (Grob *g1, Grob *g2)
350 Grob *gs[] = {g1, g2};
352 for (int i = 0; i < 2; i++)
354 sri[i] = gs[i]->spanned_rank_interval ()[LEFT];
355 if (Spanner *s = dynamic_cast<Spanner *> (gs[i]))
357 if (s->broken_intos_.size ())
358 s = (scm_to_int (s->broken_intos_[0]->get_property ("spanner-placement")) == LEFT
359 ? s->broken_intos_[0]
360 : s->broken_intos_.back ());
362 if (robust_scm2double (s->get_property ("X-offset"), 0.0) > 0)
363 sri[i] = s->spanned_rank_interval ()[RIGHT];
367 if (sri[0] == sri[1])
368 return Grob::vertical_less (gs[0], gs[1]);
370 return sri[0] < sri[1];
373 MAKE_SCHEME_CALLBACK (System, footnotes_before_line_breaking, 1);
375 System::footnotes_before_line_breaking (SCM smob)
377 Grob *me = unsmob<Grob> (smob);
378 vector<Grob *> footnotes;
379 SCM grobs_scm = Grob_array::make_array ();
380 extract_grob_set (me, "all-elements", elts);
381 for (vsize i = 0; i < elts.size (); i++)
382 if (elts[i]->internal_has_interface (ly_symbol2scm ("footnote-interface")))
383 footnotes.push_back (elts[i]);
385 unsmob<Grob_array> (grobs_scm)->set_array (footnotes);
389 MAKE_SCHEME_CALLBACK (System, footnotes_after_line_breaking, 1);
391 System::footnotes_after_line_breaking (SCM smob)
393 Spanner *sys_span = unsmob<Spanner> (smob);
394 System *sys = dynamic_cast<System *> (sys_span);
395 Interval_t<int> sri = sys->spanned_rank_interval ();
396 vector<Grob *> footnote_grobs = sys->get_footnote_grobs_in_range (sri[LEFT], sri[RIGHT]);
397 vector_sort (footnote_grobs, grob_2D_less);
399 SCM grobs_scm = Grob_array::make_array ();
400 unsmob<Grob_array> (grobs_scm)->set_array (footnote_grobs);
404 MAKE_SCHEME_CALLBACK (System, vertical_skyline_elements, 1);
406 System::vertical_skyline_elements (SCM smob)
408 Grob *me_grob = unsmob<Grob> (smob);
409 vector<Grob *> vertical_skyline_grobs;
410 extract_grob_set (me_grob, "elements", my_elts);
411 for (vsize i = 0; i < my_elts.size (); i++)
412 if (has_interface<System_start_delimiter> (my_elts[i]))
413 vertical_skyline_grobs.push_back (my_elts[i]);
415 System *me = dynamic_cast<System *> (me_grob);
416 Grob *align = unsmob<Grob> (me->get_object ("vertical-alignment"));
419 SCM grobs_scm = Grob_array::make_array ();
420 unsmob<Grob_array> (grobs_scm)->set_array (vertical_skyline_grobs);
424 extract_grob_set (align, "elements", elts);
426 for (vsize i = 0; i < elts.size (); i++)
427 if (has_interface<Hara_kiri_group_spanner> (elts[i]))
428 vertical_skyline_grobs.push_back (elts[i]);
430 SCM grobs_scm = Grob_array::make_array ();
431 unsmob<Grob_array> (grobs_scm)->set_array (vertical_skyline_grobs);
436 System::break_into_pieces (vector<Column_x_positions> const &breaking)
438 for (vsize i = 0; i < breaking.size (); i++)
440 System *system = dynamic_cast<System *> (clone ());
441 system->rank_ = broken_intos_.size ();
443 vector<Grob *> c (breaking[i].cols_);
444 pscore_->typeset_system (system);
446 int st = Paper_column::get_rank (c[0]);
447 int end = Paper_column::get_rank (c.back ());
448 Interval iv (pure_y_extent (this, st, end));
449 system->set_property ("pure-Y-extent", ly_interval2scm (iv));
451 system->set_bound (LEFT, c[0]);
452 system->set_bound (RIGHT, c.back ());
453 SCM system_labels = SCM_EOL;
454 for (vsize j = 0; j < c.size (); j++)
456 c[j]->translate_axis (breaking[i].config_[j], X_AXIS);
457 dynamic_cast<Paper_column *> (c[j])->set_system (system);
458 /* collect the column labels */
459 collect_labels (c[j], &system_labels);
462 Collect labels from any loose columns too: theses will be set on
463 an empty bar line or a column which is otherwise unused mid-line
465 vector<Grob *> loose (breaking[i].loose_cols_);
466 for (vsize j = 0; j < loose.size (); j++)
467 collect_labels (loose[j], &system_labels);
469 system->set_property ("labels", system_labels);
471 set_loose_columns (system, &breaking[i]);
472 broken_intos_.push_back (system);
477 System::collect_labels (Grob const *col, SCM *labels)
479 SCM col_labels = col->get_property ("labels");
480 if (scm_is_pair (col_labels))
481 *labels = scm_append (scm_list_2 (col_labels, *labels));
485 System::add_column (Paper_column *p)
488 Grob_array *ga = unsmob<Grob_array> (me->get_object ("columns"));
491 SCM scm_ga = Grob_array::make_array ();
492 me->set_object ("columns", scm_ga);
493 ga = unsmob<Grob_array> (scm_ga);
496 p->set_rank (ga->size ());
499 Axis_group_interface::add_element (this, p);
503 System::pre_processing ()
505 for (vsize i = 0; i < all_elements_->size (); i++)
506 all_elements_->grob (i)->discretionary_processing ();
508 debug_output (_f ("Grob count %d", element_count ()));
511 order is significant: broken grobs are added to the end of the
512 array, and should be processed before the original is potentially
515 for (vsize i = all_elements_->size (); i--;)
516 all_elements_->grob (i)->handle_prebroken_dependencies ();
518 fixup_refpoints (all_elements_->array ());
520 for (vsize i = 0; i < all_elements_->size (); i++)
522 Grob *g = all_elements_->grob (i);
523 (void) g->get_property ("before-line-breaking");
526 for (vsize i = 0; i < all_elements_->size (); i++)
528 Grob *e = all_elements_->grob (i);
529 (void) e->get_property ("springs-and-rods");
534 System::post_processing ()
536 Interval iv (extent (this, Y_AXIS));
538 programming_error ("system with empty extent");
540 translate_axis (-iv[MAX], Y_AXIS);
542 /* Generate all stencils to trigger font loads.
543 This might seem inefficient, but Stencils are cached per grob
546 vector<Grob *> all_elts_sorted (all_elements_->array ());
547 uniquify (all_elts_sorted);
549 for (vsize i = all_elts_sorted.size (); i--;)
551 Grob *g = all_elts_sorted[i];
563 operator < (Layer_entry const &a,
564 Layer_entry const &b)
566 return a.layer_ < b.layer_;
570 System::get_paper_system ()
577 vector<Layer_entry> entries;
578 for (vsize j = 0; j < all_elements_->size (); j++)
581 e.grob_ = all_elements_->grob (j);
582 e.layer_ = robust_scm2int (e.grob_->get_property ("layer"), 1);
584 entries.push_back (e);
587 vector_sort (entries, std::less<Layer_entry> ());
588 for (vsize j = 0; j < entries.size (); j++)
590 Grob *g = entries[j].grob_;
591 Stencil st = g->get_print_stencil ();
593 if (scm_is_null (st.expr ()))
597 for (int a = X_AXIS; a < NO_AXES; a++)
598 o[Axis (a)] = g->relative_coordinate (this, Axis (a));
600 Offset extra = robust_scm2offset (g->get_property ("extra-offset"),
602 * Staff_symbol_referencer::staff_space (g);
604 /* Must copy the stencil, for we cannot change the stencil
607 st.translate (o + extra);
609 *tail = scm_cons (st.expr (), SCM_EOL);
610 tail = SCM_CDRLOC (*tail);
613 if (Stencil *me = get_stencil ())
614 exprs = scm_cons (me->expr (), exprs);
616 Interval x (extent (this, X_AXIS));
617 Interval y (extent (this, Y_AXIS));
618 Stencil sys_stencil (Box (x, y),
619 scm_cons (ly_symbol2scm ("combine-stencil"),
623 Skyline_pair *skylines = unsmob<Skyline_pair> (get_property ("vertical-skylines"));
627 = Lookup::points_to_line_stencil (0.1, (*skylines)[UP].to_points (X_AXIS));
629 = Lookup::points_to_line_stencil (0.1, (*skylines)[DOWN].to_points (X_AXIS));
630 sys_stencil.add_stencil (up.in_color (255, 0, 0));
631 sys_stencil.add_stencil (down.in_color (0, 255, 0));
635 Grob *left_bound = get_bound (LEFT);
636 SCM prop_init = left_bound->get_property ("line-break-system-details");
637 Prob *pl = make_paper_system (prop_init);
638 paper_system_set_stencil (pl, sys_stencil);
640 /* information that the page breaker might need */
641 Grob *right_bound = get_bound (RIGHT);
642 pl->set_property ("vertical-skylines", get_property ("vertical-skylines"));
643 pl->set_property ("page-break-permission", right_bound->get_property ("page-break-permission"));
644 pl->set_property ("page-turn-permission", right_bound->get_property ("page-turn-permission"));
645 pl->set_property ("page-break-penalty", right_bound->get_property ("page-break-penalty"));
646 pl->set_property ("page-turn-penalty", right_bound->get_property ("page-turn-penalty"));
648 if (right_bound->original () == dynamic_cast<System *> (original ())->get_bound (RIGHT))
649 pl->set_property ("last-in-score", SCM_BOOL_T);
651 Interval staff_refpoints;
652 if (Grob *align = unsmob<Grob> (get_object ("vertical-alignment")))
654 extract_grob_set (align, "elements", staves);
655 for (vsize i = 0; i < staves.size (); i++)
656 if (staves[i]->is_live ()
657 && Page_layout_problem::is_spaceable (staves[i]))
658 staff_refpoints.add_point (staves[i]->relative_coordinate (this,
662 pl->set_property ("staff-refpoint-extent", ly_interval2scm (staff_refpoints));
663 pl->set_property ("system-grob", self_scm ());
665 return pl->unprotect ();
669 System::broken_col_range (Item const *left, Item const *right) const
673 left = left->get_column ();
674 right = right->get_column ();
676 extract_grob_set (this, "columns", cols);
678 vsize i = Paper_column::get_rank (left);
679 int end_rank = Paper_column::get_rank (right);
680 if (i < cols.size ())
683 while (i < cols.size ()
684 && Paper_column::get_rank (cols[i]) < end_rank)
686 Paper_column *c = dynamic_cast<Paper_column *> (cols[i]);
687 if (Paper_column::is_breakable (c) && !c->get_system ())
695 /** Return all columns, but filter out any unused columns , since they might
696 disrupt the spacing problem. */
698 System::used_columns () const
700 extract_grob_set (this, "columns", ro_columns);
702 int last_breakable = ro_columns.size ();
704 while (last_breakable--)
706 if (Paper_column::is_breakable (ro_columns [last_breakable]))
710 vector<Grob *> columns;
711 for (int i = 0; i <= last_breakable; i++)
713 if (Paper_column::is_used (ro_columns[i]))
714 columns.push_back (ro_columns[i]);
721 System::column (vsize which) const
723 extract_grob_set (this, "columns", columns);
724 if (which >= columns.size ())
727 return dynamic_cast<Paper_column *> (columns[which]);
731 System::paper_score () const
737 System::get_rank () const
743 get_root_system (Grob *me)
745 Grob *system_grob = me;
747 while (system_grob->get_parent (Y_AXIS))
748 system_grob = system_grob->get_parent (Y_AXIS);
750 return dynamic_cast<System *> (system_grob);
753 MAKE_SCHEME_CALLBACK (System, get_vertical_alignment, 1);
755 System::get_vertical_alignment (SCM smob)
757 Grob *me = unsmob<Grob> (smob);
758 extract_grob_set (me, "elements", elts);
760 for (vsize i = 0; i < elts.size (); i++)
761 if (has_interface<Align_interface> (elts[i]))
764 me->programming_error ("found multiple vertical alignments in this system");
770 me->programming_error ("didn't find a vertical alignment in this system");
773 return ret->self_scm ();
776 // Finds the furthest staff in the given direction whose x-extent
777 // overlaps with the given interval.
779 System::get_extremal_staff (Direction dir, Interval const &iv)
781 Grob *align = unsmob<Grob> (get_object ("vertical-alignment"));
785 extract_grob_set (align, "elements", elts);
786 vsize start = (dir == UP) ? 0 : elts.size () - 1;
787 vsize end = (dir == UP) ? elts.size () : VPOS;
788 for (vsize i = start; i != end; i += dir)
790 if (has_interface<Hara_kiri_group_spanner> (elts[i]))
791 Hara_kiri_group_spanner::consider_suicide (elts[i]);
793 Interval intersection = elts[i]->extent (this, X_AXIS);
794 intersection.intersect (iv);
795 if (elts[i]->is_live () && !intersection.is_empty ())
801 // Finds the neighboring staff in the given direction over bounds
803 System::get_neighboring_staff (Direction dir, Grob *vertical_axis_group, Interval_t<int> bounds)
805 Grob *align = unsmob<Grob> (get_object ("vertical-alignment"));
809 extract_grob_set (align, "elements", elts);
810 vsize start = (dir == UP) ? 0 : elts.size () - 1;
811 vsize end = (dir == UP) ? elts.size () : VPOS;
815 for (vsize i = start; i != end; i += dir)
817 if (elts[i] == vertical_axis_group)
820 if (has_interface<Hara_kiri_group_spanner> (elts[i]))
821 Hara_kiri_group_spanner::consider_suicide (elts[i]);
823 bounds.intersect (elts[i]->spanned_rank_interval ());
824 if (elts[i]->is_live () && !bounds.is_empty ())
832 System::pure_refpoint_extent (vsize start, vsize end)
835 Grob *alignment = unsmob<Grob> (get_object ("vertical-alignment"));
839 extract_grob_set (alignment, "elements", staves);
840 vector<Real> offsets = Align_interface::get_pure_minimum_translations (alignment, staves, Y_AXIS, start, end);
842 for (vsize i = 0; i < offsets.size (); ++i)
843 if (Page_layout_problem::is_spaceable (staves[i]))
845 ret[UP] = offsets[i];
849 for (vsize i = offsets.size (); i--;)
850 if (Page_layout_problem::is_spaceable (staves[i]))
852 ret[DOWN] = offsets[i];
860 System::part_of_line_pure_height (vsize start, vsize end, bool begin)
862 Grob *alignment = unsmob<Grob> (get_object ("vertical-alignment"));
866 extract_grob_set (alignment, "elements", staves);
867 vector<Real> offsets = Align_interface::get_pure_minimum_translations (alignment, staves, Y_AXIS, start, end);
870 for (vsize i = 0; i < staves.size (); ++i)
873 ? Axis_group_interface::begin_of_line_pure_height (staves[i], start)
874 : Axis_group_interface::rest_of_line_pure_height (staves[i], start, end);
875 if (i < offsets.size ())
876 iv.translate (offsets[i]);
880 Interval other_elements = begin
881 ? Axis_group_interface::begin_of_line_pure_height (this, start)
882 : Axis_group_interface::rest_of_line_pure_height (this, start, end);
884 ret.unite (other_elements);
890 System::begin_of_line_pure_height (vsize start, vsize end)
892 return part_of_line_pure_height (start, end, true);
896 System::rest_of_line_pure_height (vsize start, vsize end)
898 return part_of_line_pure_height (start, end, false);
901 // This differs from Axis_group_interface::calc_pure_relevant_grobs
902 // because here, we are only interested in those few elements that aren't
903 // descended from VerticalAlignment (ie. things like RehearsalMark, BarLine).
904 MAKE_SCHEME_CALLBACK (System, calc_pure_relevant_grobs, 1);
906 System::calc_pure_relevant_grobs (SCM smob)
908 Grob *me = unsmob<Grob> (smob);
910 extract_grob_set (me, "elements", elts);
911 vector<Grob *> relevant_grobs;
913 for (vsize i = 0; i < elts.size (); ++i)
915 if (!has_interface<Axis_group_interface> (elts[i]))
917 relevant_grobs.push_back (elts[i]);
919 if (Item *it = dynamic_cast<Item *> (elts[i]))
921 for (LEFT_and_RIGHT (d))
923 Item *piece = it->find_prebroken_piece (d);
924 if (piece && piece->is_live ())
925 relevant_grobs.push_back (piece);
931 SCM grobs_scm = Grob_array::make_array ();
933 unsmob<Grob_array> (grobs_scm)->set_array (relevant_grobs);
937 MAKE_SCHEME_CALLBACK (System, height, 1);
939 System::height (SCM smob)
941 return Axis_group_interface::height (smob);
944 MAKE_SCHEME_CALLBACK (System, calc_pure_height, 3);
946 System::calc_pure_height (SCM smob, SCM start_scm, SCM end_scm)
948 System *me = unsmob<System> (smob);
949 int start = scm_to_int (start_scm);
950 int end = scm_to_int (end_scm);
952 Interval begin = me->begin_of_line_pure_height (start, end);
953 Interval rest = me->rest_of_line_pure_height (start, end);
956 return ly_interval2scm (begin);
960 System::get_pure_bound (Direction d, int start, int end)
962 vector<vsize> ranks = pscore_->get_break_ranks ();
963 vector<vsize> indices = pscore_->get_break_indices ();
964 vector<Grob *> cols = pscore_->get_columns ();
966 vsize target_rank = (d == LEFT ? start : end);
967 vector<vsize>::const_iterator i
968 = lower_bound (ranks.begin (), ranks.end (), target_rank, std::less<vsize> ());
970 if (i != ranks.end () && (*i) == target_rank)
971 return cols[indices[i - ranks.begin ()]];
977 System::get_maybe_pure_bound (Direction d, bool pure, int start, int end)
979 return pure ? get_pure_bound (d, start, end) : get_bound (d);
990 get_maybe_spaceable_staves (SCM smob, int filter)
992 System *me = unsmob<System> (smob);
993 Grob *align = unsmob<Grob> (me->get_object ("vertical_alignment"));
999 extract_grob_set (align, "elements", staves);
1001 for (vsize i = 0; i < staves.size (); ++i)
1003 bool spaceable = Page_layout_problem::is_spaceable (staves[i]);
1004 if (staves[i]->is_live ()
1005 && ((filter == ALL_STAVES)
1006 || (filter == SPACEABLE_STAVES && spaceable)
1007 || (filter == NONSPACEABLE_STAVES && !spaceable)))
1009 *tail = scm_cons (staves[i]->self_scm (), SCM_EOL);
1010 tail = SCM_CDRLOC (*tail);
1018 MAKE_SCHEME_CALLBACK (System, get_staves, 1)
1020 System::get_staves (SCM smob)
1022 return get_maybe_spaceable_staves (smob, ALL_STAVES);
1025 MAKE_SCHEME_CALLBACK (System, get_spaceable_staves, 1)
1027 System::get_spaceable_staves (SCM smob)
1029 return get_maybe_spaceable_staves (smob, SPACEABLE_STAVES);
1032 MAKE_SCHEME_CALLBACK (System, get_nonspaceable_staves, 1)
1034 System::get_nonspaceable_staves (SCM smob)
1036 return get_maybe_spaceable_staves (smob, NONSPACEABLE_STAVES);
1039 ADD_INTERFACE (System,
1040 "This is the top-level object: Each object in a score"
1041 " ultimately has a @code{System} object as its X and"
1048 "footnotes-before-line-breaking "
1049 "footnotes-after-line-breaking "
1050 "in-note-direction "
1055 "vertical-alignment "