system is reevaluated in order to fill the page more evenly; if a page
has space left over, systems are stretched in order to fill that space.
The amount of stretching can be configured though the @code{max-stretch}
-property of the @internalsref{VerticalAlignment} grob. To disable this
-stretching entirely, set @code{max-stretch} to zero.
+property of the @internalsref{VerticalAlignment} grob. By default,
+@code{max-stretch} is set to zero, disabling stretching. To enable
+stretching, a sane value for @code{max-stretch}
+is @code{ly:align-interface::calc-max-stretch}.
In some situations, you may want to stretch most of a system while
leaving some parts fixed. For example, if a piano part occurs in the
ragged-last-bottom = ##f
}
-\score {
+\new Score \with
+{
+ \override VerticalAlignment #'max-stretch = #ly:align-interface::calc-max-stretch
+}
+{
\new GrandStaff
<<
\new StaffGroup
Real page_penalty_;
Real turn_penalty_;
+ bool title_;
+
Line_details ()
{
force_ = infinity_f;
break_penalty_ = 0;
page_penalty_ = 0;
turn_penalty_ = 0;
+ title_ = false;
}
Line_details (Prob *pb)
break_penalty_ = 0;
page_penalty_ = robust_scm2double (pb->get_property ("page-break-penalty"), 0);
turn_penalty_ = robust_scm2double (pb->get_property ("page-turn-penalty"), 0);
+ title_ = to_boolean (pb->get_property ("is-title"));
}
};
bool ragged_last () const;
bool is_last () const;
Real page_height (int page_number, bool last) const;
+ Real page_top_space () const;
protected:
Paper_book *book_;
vector<Constrained_breaking> line_breaking_;
bool ragged_;
bool ragged_last_;
+ Real page_top_space_;
vector<Line_division> current_configurations_;
vector<Break_position> current_chunks_;
Real rod_height_;
Real spring_len_;
Real inverse_spring_k_;
+ Real page_top_space_;
Line_details last_line_;
+ Line_details first_line_;
- Page_spacing (Real page_height)
+ Page_spacing (Real page_height, Real page_top_space)
{
page_height_ = page_height;
+ page_top_space_ = page_top_space;
clear ();
}
compressed.extent_[UP] = old.extent_[UP] + orig[i].extent_.length () + old.padding_;
compressed.space_ += old.space_;
compressed.inverse_hooke_ += old.inverse_hooke_;
+ compressed.title_ = old.title_;
/* we don't need the force_ field for the vertical spacing,
so we use force_ = n to signal that the line was compressed,
book_ = pb;
ragged_ = to_boolean (pb->paper_->c_variable ("ragged-bottom"));
ragged_last_ = to_boolean (pb->paper_->c_variable ("ragged-last-bottom"));
+ page_top_space_ = robust_scm2double (pb->paper_->c_variable ("page-top-space"), 0);
create_system_list ();
find_chunks_and_breaks (is_break);
}
return ragged_last_;
}
+Real
+Page_breaking::page_top_space () const
+{
+ return page_top_space_;
+}
+
/* translate indices into breaks_ into start-end parameters for the line breaker */
void
Page_breaking::line_breaker_args (vsize sys,
ly_symbol2scm ("is-last"), scm_from_bool (last),
SCM_UNDEFINED));
SCM height = scm_apply_1 (calc_height, page, SCM_EOL);
- return scm_to_double (height) - scm_to_double (book_->paper_->c_variable ("page-top-space"));
+ return scm_to_double (height) - page_top_space_;
}
SCM
Page_spacing_result res;
vsize page = 0;
vsize page_first_line = 0;
- Page_spacing space (page_height (first_page_num, false));
+ Page_spacing space (page_height (first_page_num, false), page_top_space_);
cache_line_details (configuration);
for (vsize line = 0; line < cached_line_details_.size (); line++)
Page_spacing_result
Page_breaking::space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged)
{
- Page_spacing space (page_height);
+ Page_spacing space (page_height, page_top_space_);
Page_spacing_result ret;
for (vsize i = 0; i < lines.size (); i++)
vector<Real> page1_force;
vector<Real> page2_force;
- Page_spacing page1 (page1_height);
- Page_spacing page2 (page2_height);
+ Page_spacing page1 (page1_height, page_top_space_);
+ Page_spacing page2 (page2_height, page_top_space_);
page1_force.resize (cached_line_details_.size () - 1, infinity_f);
page2_force.resize (cached_line_details_.size () - 1, infinity_f);
void
Page_spacing::calc_force ()
{
- if (rod_height_ + last_line_.bottom_padding_ >= page_height_)
+ /* If the first system is a title, we add back in the page-top-space. */
+ Real height = first_line_.title_ ? page_height_ + page_top_space_ : page_height_;
+
+ if (rod_height_ + last_line_.bottom_padding_ >= height)
force_ = infinity_f;
else
- force_ = (page_height_ - rod_height_ - last_line_.bottom_padding_ - spring_len_)
+ force_ = (height - rod_height_ - last_line_.bottom_padding_ - spring_len_)
/ max (0.1, inverse_spring_k_);
}
void
Page_spacing::append_system (const Line_details &line)
{
+ if (!rod_height_)
+ first_line_ = line;
+
rod_height_ += last_line_.padding_;
rod_height_ += line.extent_.length ();
spring_len_ += line.space_;
inverse_spring_k_ += line.inverse_hooke_;
+ first_line_ = line;
+
calc_force ();
}
Page_spacer::calc_subproblem (vsize page, vsize line)
{
bool last = line == lines_.size () - 1;
- Page_spacing space (breaker_->page_height (page + first_page_num_, last));
+ Page_spacing space (breaker_->page_height (page + first_page_num_, last),
+ breaker_->page_top_space ());
Page_spacing_node &cur = state_.at (line, page);
bool ragged = ragged_ || (ragged_last_ && last);
(stacking-dir . -1)
(padding . 0.5)
(vertical-skylines . ,ly:axis-group-interface::combine-skylines)
- (max-stretch . ,ly:align-interface::calc-max-stretch)
+ (max-stretch . 0)
(meta . ((class . Spanner)
(object-callbacks . ((Y-common . ,ly:axis-group-interface::calc-y-common)))
(interfaces . (align-interface