Make sure that each page is wider than the widest system.
--- /dev/null
+\version "2.15.40"
+
+\header {
+ texidoc = "The @var{ly:one-line-breaking} algorithm puts everything on one line."
+}
+
+\paper { page-breaking = #ly:one-line-breaking }
+
+\include "typography-demo.ly"
}
/*
- This is a somewhat unconventional page-breaking algorithm. Every
+ This is a somewhat unconventional page-breaking algorithm. Every
score will be put on a single page, whose width is enough
- to fit the entire score one one line. Line breaks and page breaks
- are ignored, as are the page dimensions in the paper block.
+ to fit the entire score one one line. Line breaks and page breaks
+ are ignored, and the paper-width setting in the paper block
+ will be modified to fit the music.
*/
SCM
One_line_page_breaking::solve ()
{
SCM all_pages = SCM_EOL;
+ Real max_width = 0;
for (vsize i = 0; i < system_specs_.size (); ++i)
- if (Paper_score *ps = system_specs_[i].pscore_)
- {
- vector<Grob*> cols = ps->root_system ()->used_columns ();
-
- // No indent, "infinite" line width, ragged.
- Column_x_positions pos = get_line_configuration (cols, numeric_limits<Real>::max (), 0, true);
- vector<Column_x_positions> positions;
- positions.push_back (pos);
-
- ps->root_system ()->break_into_pieces (positions);
- ps->root_system ()->do_break_substitution_and_fixup_refpoints ();
- Grob *system = ps->root_system ()->broken_intos_[0];
- Real width = system->extent (system, X_AXIS).length ();
- Real height = system->extent (system, Y_AXIS).length ();
-
- // HACK: probably shouldn't be modifying the paper_; better to modify the page
- // afterwards.
- book_->paper_->set_variable (ly_symbol2scm ("paper-width"), scm_from_double (width + 100));
- // TODO: figure out what the height should be.
- //book_->paper_->set_variable (ly_symbol2scm ("paper-height"), scm_from_double (height));
- vector<vsize> lines_per_page;
- lines_per_page.push_back (1);
- SCM systems = scm_list_1 (system->self_scm ());
- SCM pages = make_pages (lines_per_page, systems);
- all_pages = scm_cons (scm_car (pages), all_pages);
- }
+ {
+ if (Paper_score *ps = system_specs_[i].pscore_)
+ {
+ vector<Grob*> cols = ps->root_system ()->used_columns ();
+
+ // No indent, "infinite" line width, ragged.
+ Column_x_positions pos = get_line_configuration (cols, numeric_limits<Real>::max (), 0, true);
+ vector<Column_x_positions> positions;
+ positions.push_back (pos);
+
+ ps->root_system ()->break_into_pieces (positions);
+ ps->root_system ()->do_break_substitution_and_fixup_refpoints ();
+ Grob *system = ps->root_system ()->broken_intos_[0];
+
+ vector<vsize> lines_per_page;
+ lines_per_page.push_back (1);
+ SCM systems = scm_list_1 (system->self_scm ());
+ SCM pages = make_pages (lines_per_page, systems);
+
+ max_width = max (max_width, system->extent (system, X_AXIS).length ());
+ all_pages = scm_cons (scm_car (pages), all_pages);
+ }
+ else if (Prob *pb = system_specs_[i].prob_)
+ // Because we don't call Page_breaking::systems in this algorithm,
+ // we need to manually unprotect the titles.
+ pb->unprotect ();
+ }
+
+ // Alter paper-width so that it is large enough to fit every system.
+ // TODO: it might be nice to allow different pages to have different widths.
+ // This would need support in the backends (eg. framework-ps.scm).
+ Real right_margin = robust_scm2double (book_->paper_->c_variable ("right-margin"), 0.0);
+ Real left_margin = robust_scm2double (book_->paper_->c_variable ("left-margin"), 0.0);
+ Real width = max_width + right_margin + left_margin;
+ book_->paper_->set_variable (ly_symbol2scm ("paper-width"), scm_from_double (width));
return scm_reverse_x (all_pages, SCM_EOL);
}
LY_DEFINE (ly_one_line_breaking, "ly:one-line-breaking",
1, 0, 0, (SCM pb),
- "Put each score on a single line, and put each line on its own page.")
+ "Put each score on a single line, and put each line on its own"
+ " page. The paper-width setting will be modified so that"
+ " every page will be wider than the widest line.")
{
One_line_page_breaking b (unsmob_paper_book (pb));
return b.solve ();
// Create the page and draw it.
SCM page = make_page (page_num, last);
- SCM page_module = scm_c_resolve_module ("scm page");
- SCM page_stencil = scm_c_module_lookup (page_module, "page-stencil");
- page_stencil = scm_variable_ref (page_stencil);
Prob *p = unsmob_prob (page);
p->set_property ("lines", paper_systems);
foot = Page_layout_problem::add_footnotes_to_footer (footnotes, foot, book_);
p->set_property ("foot-stencil", foot.smobbed_copy ());
- scm_apply_1 (page_stencil, page, SCM_EOL);
return page;
}
label_page_table = SCM_EOL;
// Build a list of (systems configuration . footnote-count) triples.
- // Note that we lay out
- // the staves and find the configurations before drawing anything. Some
+ // Note that we lay out the staves and find the configurations,
+ // but we do not draw anything in this function. It is important
+ // that all staves are laid out vertically before any are drawn; some
// grobs (like tuplet brackets) look at their neighbours while drawing
- // themselves. If this happens before the neighbouring staves have
+ // themselves. If this happens before the neighbouring staves have
// been laid out, bad side-effects could happen (in particular,
// Align_interface::align_to_ideal_distances might be called).
SCM systems_configs_fncounts = SCM_EOL;
systems = scm_list_tail (systems, line_count);
}
- // Now it's safe to make the pages.
+ // TODO: previously, the following loop caused the systems to be
+ // drawn. Now that we no longer draw anything in Page_breaking,
+ // it is safe to merge these two loops.
int page_num = first_page_number + lines_per_page.size () - 1;
for (SCM s = systems_configs_fncounts; scm_is_pair (s); s = scm_cdr (s))
{
return ret;
}
-/* The page-turn-page-breaker needs to have a line-breaker between any two
- columns with non-NULL page-turn-permission.
-
- The optimal-breaker needs to have a line-breaker between any two columns
- with page-break-permission = 'force.
-
- By using a grob predicate, we can accommodate both of these uses.
-*/
void
Page_breaking::create_system_list ()
{
system_specs_.push_back (System_spec ());
}
+/* The page-turn-page-breaker needs to have a line-breaker between any two
+ columns with non-NULL page-turn-permission.
+
+ The optimal-breaker needs to have a line-breaker between any two columns
+ with page-break-permission = 'force.
+
+ By using a grob predicate, we can accommodate both of these uses.
+*/
void
Page_breaking::find_chunks_and_breaks (Break_predicate is_break, Prob_break_predicate prob_is_break)
{
{
SCM page_breaking = paper_->c_variable ("page-breaking");
pages_ = scm_apply_0 (page_breaking, scm_list_1 (self_scm ()));
+
+ // Create all the page stencils.
+ SCM page_module = scm_c_resolve_module ("scm page");
+ SCM page_stencil = scm_c_module_lookup (page_module, "page-stencil");
+ page_stencil = scm_variable_ref (page_stencil);
+ for (SCM pages = pages_; scm_is_pair (pages); pages = scm_cdr (pages))
+ scm_apply_1 (page_stencil, scm_car (pages), SCM_EOL);
+
+ // Perform any user-supplied post-processing.
SCM post_process = paper_->c_variable ("page-post-process");
if (ly_is_procedure (post_process))
scm_apply_2 (post_process, paper_->self_scm (), pages_, SCM_EOL);