/*
This file is part of LilyPond, the GNU music typesetter.
- Copyright (C) 2009--2011 Joe Neeman <joeneeman@gmail.com>
+ Copyright (C) 2009--2012 Joe Neeman <joeneeman@gmail.com>
LilyPond is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Returns the number of footntoes associated with a given line.
*/
-vsize
-Page_layout_problem::get_footnote_count (SCM lines)
+vector<Grob *>
+Page_layout_problem::get_footnote_grobs (SCM lines)
{
- vsize fn_count = 0;
+ vector<Grob *> footnotes;
for (SCM s = lines; scm_is_pair (s); s = scm_cdr (s))
{
if (Grob *g = unsmob_grob (scm_car (s)))
programming_error ("got a grob for footnotes that wasn't a System");
continue;
}
- fn_count += sys->num_footnotes ();
+ extract_grob_set (sys, "footnotes-after-line-breaking", footnote_grobs);
+ footnotes.insert (footnotes.end (), footnote_grobs.begin (), footnote_grobs.end ());
}
else if (Prob *p = unsmob_prob (scm_car (s)))
{
if (stencils == SCM_EOL)
continue;
for (SCM st = stencils; scm_is_pair (st); st = scm_cdr (st))
- fn_count++;
+ footnotes.push_back (0);
}
}
- return fn_count;
+ return footnotes;
+}
+
+vsize
+Page_layout_problem::get_footnote_count (SCM lines)
+{
+ vector<Grob *> notes = get_footnote_grobs (lines);
+ return notes.size ();
}
SCM
Real padding = robust_scm2double (paper->c_variable ("footnote-padding"), 0.0);
Real number_raise = robust_scm2double (paper->c_variable ("footnote-number-raise"), 0.0);
- vsize fn_count = get_footnote_count (lines);
+ vector<Grob *> fn_grobs = get_footnote_grobs (lines);
+ vsize fn_count = fn_grobs.size ();
// now, make the footnote stencils with the numbering function
SCM numbers = SCM_EOL;
vector<Stencil *> footnote_number_stencils; // Holds translated versions of the stencilized numbering markups.
for (vsize i = 0; i < fn_count; i++)
{
+ if (fn_grobs[i])
+ {
+ SCM assertion_function = fn_grobs[i]->get_property ("numbering-assertion-function");
+ if (ly_is_procedure (assertion_function))
+ (void) scm_call_1 (assertion_function, scm_from_int (counter));
+ }
SCM markup = scm_call_1 (numbering_function, scm_from_int (counter));
Stencil *s = unsmob_stencil (Text_interface::interpret_markup (layout, props, markup));
if (!s)
}
Stencil mol;
Stencil in_note_mol;
- for (vsize i = 0; i < sys->footnote_grobs ()->size (); i++)
+ extract_grob_set (sys, "footnotes-after-line-breaking", footnote_grobs);
+ for (vsize i = 0; i < footnote_grobs.size (); i++)
{
- Grob *footnote = sys->footnote_grobs ()->at (i);
+ Grob *footnote = footnote_grobs[i];
SCM footnote_markup = footnote->get_property ("footnote-text");
if (Spanner *orig = dynamic_cast<Spanner *>(footnote))
if (orig->is_broken ())
if (orig->is_broken ())
for (vsize i = 0; i < orig->broken_intos_.size (); i++)
do_numbering = do_numbering
- || to_boolean (orig->broken_intos_[i]->get_property ("automatically-numbered"));
+ || to_boolean (orig->broken_intos_[i]->get_property ("automatically-numbered"));
}
if (do_numbering)
{
: bottom_skyline_ (DOWN)
{
Prob *page = unsmob_prob (page_scm);
+ bottom_loose_baseline_ = 0;
header_height_ = 0;
footer_height_ = 0;
header_padding_ = 0;
footer_padding_ = 0;
page_height_ = 100;
+ force_ = 0;
if (page)
{
Skyline *sky = in_note_direction_ == UP ? &up_skyline : &down_skyline;
sky->set_minimum_height (sky->max_height ()
+ in_note_direction_
- * (in_note_padding_
- + in_note_stencil->extent (Y_AXIS).length ()));
+ * (in_note_padding_
+ + in_note_stencil->extent (Y_AXIS).length ()));
}
/*
*/
Real minimum_distance = up_skyline.distance (bottom_skyline_,
robust_scm2double (sys->get_property ("skyline-horizontal-padding"),
- 0))
+ 0))
+ padding;
Spring spring_copy = spring;
{
if (is_spaceable (elts[i]))
{
- // We don't add a spring for the first staff, since
- // we are only adding springs _between_ staves here.
if (!found_spaceable_staff)
{
+ // Ensure space for any loose lines above this system
+ if (i > 0)
+ springs_.back ().ensure_min_distance (bottom_loose_baseline_
+ - minimum_offsets_with_min_dist[i]
+ + padding);
found_spaceable_staff = true;
last_spaceable_staff = i;
+ // We don't add a spring for the first staff, since
+ // we are only adding springs _between_ staves here.
continue;
}
}
}
+ bottom_loose_baseline_ = found_spaceable_staff
+ ? ( minimum_offsets_with_min_dist[last_spaceable_staff]
+ - minimum_offsets_with_min_dist.back ())
+ : 0;
+
// Corner case: there was only one staff, and it wasn't spaceable.
// Mark it spaceable, because we do not allow non-spaceable staves
// to be at the top or bottom of a system.
elements_.push_back (Element (prob, padding));
}
+/**
+ For ragged-last pages, we usually want to stretch the page so that it
+ is not much more compressed than the previous page. Here, if ragged is
+ true and you pass a value of fixed_force that !isinf, then I will try
+ to space this page using the given force. If it does not fit, I will
+ resort to just filling the page (non-raggedly).
+*/
void
-Page_layout_problem::solve_rod_spring_problem (bool ragged)
+Page_layout_problem::solve_rod_spring_problem (bool ragged, Real fixed_force)
{
Simple_spacer spacer;
for (vsize i = 0; i < springs_.size (); ++i)
spacer.add_spring (springs_[i]);
- spacer.solve (page_height_, ragged);
+ if (ragged && !isinf (fixed_force))
+ {
+ // We need to tell the spacer it isn't ragged. Otherwise, it will
+ // refuse to stretch.
+ spacer.solve (page_height_, false);
+
+ if (spacer.configuration_length (fixed_force) <= page_height_)
+ spacer.set_force (fixed_force);
+ }
+ else
+ spacer.solve (page_height_, ragged);
+
solution_ = spacer.spring_positions ();
+ force_ = spacer.force ();
if (!spacer.fits ())
{
}
}
+Real
+Page_layout_problem::force () const
+{
+ return force_;
+}
+
// The solution_ vector stores the position of every live VerticalAxisGroup
// and every title. From that information,
// 1) within each system, stretch the staves so they land at the right position
if (staff_idx)
loose_line_min_distances.push_back (min_offsets[staff_idx - 1] - min_offsets[staff_idx]);
else
- loose_line_min_distances.push_back (elements_[i].padding - min_offsets[staff_idx]);
+ {
+ // A null line to break any staff-affinity from the previous system
+ loose_line_min_distances.push_back (0.0);
+ loose_lines.push_back (0);
+ loose_line_min_distances.push_back (elements_[i].padding - min_offsets[0]);
+ }
loose_lines.push_back (staff);
distribute_loose_lines (loose_lines, loose_line_min_distances,
// this is the first line in a system
Real min_dist = 0;
if (loose_lines.back ())
- // distance to the final line in the preceding system,
- // including 'system-system-spacing 'padding
- min_dist = (Axis_group_interface::minimum_distance (loose_lines.back (),
- staff,
- Y_AXIS)
- + elements_[i].padding);
+ {
+ // distance to the final line in the preceding system,
+ // including 'system-system-spacing 'padding
+ min_dist = (Axis_group_interface::minimum_distance (loose_lines.back (),
+ staff, Y_AXIS)
+ + elements_[i].padding);
+ // A null line to break any staff-affinity for the previous system
+ loose_line_min_distances.push_back (0.0);
+ loose_lines.push_back (0);
+ }
else if (!last_title_extent.is_empty ())
// distance to the preceding title,
// including 'markup-system-spacing 'padding
vector<Real> solution = spacer.spring_positions ();
for (vsize i = 1; i + 1 < solution.size (); ++i)
- {
- Real system_offset = scm_to_double (loose_lines[i]->get_property ("system-Y-offset"));
- loose_lines[i]->translate_axis (first_translation - solution[i] - system_offset, Y_AXIS);
- }
+ if (loose_lines[i])
+ {
+ Real system_offset = scm_to_double (loose_lines[i]->get_property ("system-Y-offset"));
+ loose_lines[i]->translate_axis (first_translation - solution[i] - system_offset, Y_AXIS);
+ }
+}
+
+SCM
+Page_layout_problem::fixed_force_solution (Real force)
+{
+ solve_rod_spring_problem (true, force);
+ return find_system_offsets ();
}
SCM
Page_layout_problem::solution (bool ragged)
{
- solve_rod_spring_problem (ragged);
+ solve_rod_spring_problem (ragged, -infinity_f);
return find_system_offsets ();
}