/*
- system.cc -- implement System
+ This file is part of LilyPond, the GNU music typesetter.
- source file of the GNU LilyPond music typesetter
+ Copyright (C) 1996--2010 Han-Wen Nienhuys <hanwen@xs4all.nl>
- (c) 1996--2008 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ LilyPond is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ LilyPond is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.hh"
#include "all-font-metrics.hh"
#include "axis-group-interface.hh"
#include "grob-array.hh"
+#include "hara-kiri-group-spanner.hh"
#include "international.hh"
#include "lookup.hh"
#include "main.hh"
#include "output-def.hh"
+#include "page-layout-problem.hh"
#include "paper-column.hh"
#include "paper-score.hh"
#include "paper-system.hh"
}
static void
-fixup_refpoints (vector<Grob*> const &grobs)
+fixup_refpoints (vector<Grob *> const &grobs)
{
for (vsize i = grobs.size (); i--;)
grobs[i]->fixup_refpoint ();
that no duplicates are in the list. */
for (vsize i = 0; i < broken_intos_.size (); i++)
{
- System *child = dynamic_cast<System*> (broken_intos_[i]);
+ System *child = dynamic_cast<System *> (broken_intos_[i]);
child->all_elements_->remove_duplicates ();
+ for (vsize j = 0; j < child->all_elements_->size (); j++)
+ {
+ Grob *g = child->all_elements_->grob (j);
+
+ (void) g->get_property ("after-line-breaking");
+ }
}
if (be_verbose_global)
- message (_f ("Element count %d.", count + element_count ()));
+ message (_f ("Element count %d", count + element_count ()) + "\n");
}
SCM
System *system = dynamic_cast<System *> (clone ());
system->rank_ = broken_intos_.size ();
- vector<Grob*> c (breaking[i].cols_);
+ vector<Grob *> c (breaking[i].cols_);
pscore_->typeset_system (system);
int st = Paper_column::get_rank (c[0]);
for (vsize j = 0; j < c.size (); j++)
{
c[j]->translate_axis (breaking[i].config_[j], X_AXIS);
- dynamic_cast<Paper_column *> (c[j])->system_ = system;
+ dynamic_cast<Paper_column *> (c[j])->set_system (system);
/* collect the column labels */
SCM col_labels = c[j]->get_property ("labels");
if (scm_is_pair (col_labels))
system_labels = scm_append (scm_list_2 (col_labels, system_labels));
}
system->set_property ("labels", system_labels);
-
+
set_loose_columns (system, &breaking[i]);
broken_intos_.push_back (system);
}
ga = unsmob_grob_array (scm_ga);
}
- p->rank_ = ga->size ();
+ p->set_rank (ga->size ());
ga->add (p);
Axis_group_interface::add_element (this, p);
void
System::post_processing ()
{
- for (vsize i = 0; i < all_elements_->size (); i++)
- {
- Grob *g = all_elements_->grob (i);
-
- (void) g->get_property ("after-line-breaking");
- }
-
Interval iv (extent (this, Y_AXIS));
if (iv.is_empty ())
programming_error ("system with empty extent");
This might seem inefficient, but Stencils are cached per grob
anyway. */
- vector<Grob*> all_elts_sorted (all_elements_->array ());
- vector_sort (all_elts_sorted, std::less<Grob*> ());
+ vector<Grob *> all_elts_sorted (all_elements_->array ());
+ vector_sort (all_elts_sorted, std::less<Grob *> ());
uniq (all_elts_sorted);
this->get_stencil ();
for (vsize i = all_elts_sorted.size (); i--;)
return a.layer_ < b.layer_;
}
-
SCM
System::get_paper_system ()
{
Layer_entry e;
e.grob_ = all_elements_->grob (j);
e.layer_ = robust_scm2int (e.grob_->get_property ("layer"), 1);
-
- entries.push_back (e);
+
+ entries.push_back (e);
}
vector_sort (entries, std::less<Layer_entry> ());
if (st.expr () == SCM_EOL)
continue;
-
+
Offset o;
for (int a = X_AXIS; a < NO_AXES; a++)
o[Axis (a)] = g->relative_coordinate (this, Axis (a));
pl->set_property ("page-turn-penalty", right_bound->get_property ("page-turn-penalty"));
Interval staff_refpoints;
- extract_grob_set (this, "spaceable-staves", staves);
- for (vsize i = 0; i < staves.size (); i++)
- staff_refpoints.add_point (staves[i]->relative_coordinate (this, Y_AXIS));
+ if (Grob *align = get_vertical_alignment ())
+ {
+ extract_grob_set (align, "elements", staves);
+ for (vsize i = 0; i < staves.size (); i++)
+ if (staves[i]->is_live ()
+ && Page_layout_problem::is_spaceable (staves[i]))
+ staff_refpoints.add_point (staves[i]->relative_coordinate (this,
+ Y_AXIS));
+ }
pl->set_property ("staff-refpoint-extent", ly_interval2scm (staff_refpoints));
- pl->set_property ("system-grob", this->self_scm ());
+ pl->set_property ("system-grob", this->self_scm ());
return pl->unprotect ();
}
-vector<Item*>
+vector<Item *>
System::broken_col_range (Item const *left, Item const *right) const
{
- vector<Item*> ret;
+ vector<Item *> ret;
left = left->get_column ();
right = right->get_column ();
-
extract_grob_set (this, "columns", cols);
vsize i = Paper_column::get_rank (left);
&& Paper_column::get_rank (cols[i]) < end_rank)
{
Paper_column *c = dynamic_cast<Paper_column *> (cols[i]);
- if (Paper_column::is_breakable (c) && !c->system_)
+ if (Paper_column::is_breakable (c) && !c->get_system ())
ret.push_back (c);
i++;
}
return ret;
}
-
/** Return all columns, but filter out any unused columns , since they might
disrupt the spacing problem. */
-vector<Grob*>
+vector<Grob *>
System::used_columns () const
{
extract_grob_set (this, "columns", ro_columns);
break;
}
- vector<Grob*> columns;
+ vector<Grob *> columns;
for (int i = 0; i <= last_breakable; i++)
{
if (Paper_column::is_used (ro_columns[i]))
extract_grob_set (this, "columns", columns);
if (which >= columns.size ())
return 0;
-
- return dynamic_cast<Paper_column*> (columns[which]);
+
+ return dynamic_cast<Paper_column *> (columns[which]);
}
-Paper_score*
+Paper_score *
System::paper_score () const
{
return pscore_;
}
System *
-get_root_system (Grob *me)
+get_root_system (Grob *me)
{
Grob *system_grob = me;
-
+
while (system_grob->get_parent (Y_AXIS))
system_grob = system_grob->get_parent (Y_AXIS);
- return dynamic_cast<System*> (system_grob);
+ return dynamic_cast<System *> (system_grob);
+}
+
+Grob *
+System::get_vertical_alignment ()
+{
+ extract_grob_set (this, "elements", elts);
+ Grob *ret = 0;
+ for (vsize i = 0; i < elts.size (); i++)
+ if (Align_interface::has_interface (elts[i]))
+ {
+ if (ret)
+ programming_error ("found multiple vertical alignments in this system");
+ ret = elts[i];
+ }
+
+ if (!ret)
+ programming_error ("didn't find a vertical alignment in this system");
+ return ret;
+}
+
+// Finds the furthest staff in the given direction whose x-extent
+// overlaps with the given interval.
+Grob *
+System::get_extremal_staff (Direction dir, Interval const &iv)
+{
+ Grob *align = get_vertical_alignment ();
+ if (!align)
+ return 0;
+
+ extract_grob_set (align, "elements", elts);
+ vsize start = (dir == UP) ? 0 : elts.size () - 1;
+ vsize end = (dir == UP) ? elts.size () : VPOS;
+ for (vsize i = start; i != end; i += dir)
+ {
+ if (Hara_kiri_group_spanner::has_interface (elts[i]))
+ Hara_kiri_group_spanner::consider_suicide (elts[i]);
+
+ Interval intersection = elts[i]->extent (this, X_AXIS);
+ intersection.intersect (iv);
+ if (elts[i]->is_live () && !intersection.is_empty ())
+ return elts[i];
+ }
+ return 0;
+}
+
+Interval
+System::part_of_line_pure_height (vsize start, vsize end, bool begin)
+{
+ Grob *alignment = get_vertical_alignment ();
+ if (!alignment)
+ return Interval ();
+
+ extract_grob_set (alignment, "elements", staves);
+ vector<Real> offsets = Align_interface::get_minimum_translations (alignment, staves, Y_AXIS, true, start, end);
+
+ Interval ret;
+ for (vsize i = 0; i < staves.size (); ++i)
+ {
+ Interval iv = begin
+ ? Axis_group_interface::begin_of_line_pure_height (staves[i], start)
+ : Axis_group_interface::rest_of_line_pure_height (staves[i], start, end);
+ if (i < offsets.size ())
+ iv.translate (offsets[i]);
+ ret.unite (iv);
+ }
+
+ Interval other_elements = begin
+ ? Axis_group_interface::begin_of_line_pure_height (this, start)
+ : Axis_group_interface::rest_of_line_pure_height (this, start, end);
+
+ ret.unite (other_elements);
+
+ return ret;
+}
+
+Interval
+System::begin_of_line_pure_height (vsize start, vsize end)
+{
+ return part_of_line_pure_height (start, end, true);
+}
+
+Interval
+System::rest_of_line_pure_height (vsize start, vsize end)
+{
+ return part_of_line_pure_height (start, end, false);
+}
+
+// This differs from Axis_group_interface::calc_pure_relevant_grobs
+// because here, we are only interested in those few elements that aren't
+// descended from VerticalAlignment (ie. things like RehearsalMark, BarLine).
+MAKE_SCHEME_CALLBACK (System, calc_pure_relevant_grobs, 1);
+SCM
+System::calc_pure_relevant_grobs (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+
+ extract_grob_set (me, "elements", elts);
+ vector<Grob *> relevant_grobs;
+ SCM pure_relevant_p = ly_lily_module_constant ("pure-relevant?");
+
+ for (vsize i = 0; i < elts.size (); ++i)
+ {
+ if (!Axis_group_interface::has_interface (elts[i])
+ && to_boolean (scm_apply_1 (pure_relevant_p, elts[i]->self_scm (), SCM_EOL)))
+ relevant_grobs.push_back (elts[i]);
+ }
+
+ SCM grobs_scm = Grob_array::make_array ();
+
+ unsmob_grob_array (grobs_scm)->set_array (relevant_grobs);
+ return grobs_scm;
+}
+
+MAKE_SCHEME_CALLBACK (System, height, 1);
+SCM
+System::height (SCM smob)
+{
+ return Axis_group_interface::height (smob);
+}
+
+MAKE_SCHEME_CALLBACK (System, calc_pure_height, 3);
+SCM
+System::calc_pure_height (SCM smob, SCM start_scm, SCM end_scm)
+{
+ System *me = dynamic_cast<System *> (unsmob_grob (smob));
+ int start = scm_to_int (start_scm);
+ int end = scm_to_int (end_scm);
+
+ Interval begin = me->begin_of_line_pure_height (start, end);
+ Interval rest = me->rest_of_line_pure_height (start, end);
+ begin.unite (rest);
+
+ return ly_interval2scm (begin);
}
ADD_INTERFACE (System,
"columns "
"labels "
"pure-Y-extent "
- "spaceable-staves "
- "skyline-distance "
"skyline-horizontal-padding "
- )
+ );