From: Nicolas Sceaux Date: Sat, 23 Aug 2008 16:34:30 +0000 (+0200) Subject: Book parts: nestable book parts X-Git-Tag: release/2.11.65-1~51^2~2^2~22 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=dbefd4b8d0249c6a739d09118f3e0a71001c1c52;p=lilypond.git Book parts: nestable book parts - Book and Paper_book instances respectively are nestable: children book or paper_book are added to the bookparts_ slot; - the paper_ slot of a child Book (or Book_paper) is created empty, and has its parent set to the paper object of the parent Book (or Paper_book), so that default paper properties are got from the higher level paper object, and child objects only store part-wide overrides. This way, we ensure that fonts are loaded in the higher level paper object, so that the output framework can get all the loaded fonts from the top level book; - a Paper_book::top_paper() method is added to access the higher level paper object, to access properties that are book-wide, for instance the table used to store labels and page numbers; - in the parser, \bookpart blocks are introduced, which can be used at toplevel, or inside a \book block. It can contain the same things as \book blocks (except \bookpart blocks, though that would be possible). The associated handlers are added. --- diff --git a/input/regression/bookparts.ly b/input/regression/bookparts.ly new file mode 100644 index 0000000000..da5300f02f --- /dev/null +++ b/input/regression/bookparts.ly @@ -0,0 +1,39 @@ +\version "2.11.55" + +\header { + texidoc = "A book can be split into several parts with different paper settings, +using @code{\\bookpart}. + +Fonts are loaded into the top-level paper. +Page labels are also collected into the top-level paper." +} + +#(set-default-paper-size "a6") + +#(define-markup-command (roman-page-number layout props) () + (let ((page-number (chain-assoc-get 'page:page-number props))) + (interpret-markup layout props (format #f "~@r" page-number)))) + +\book { + \tocItem \markup "First part" + \header { title = "Book with several parts" } + \markup { First part } + \markup { with default paper settings. } + + \bookpart { + \paper { + left-margin = 20\mm + right-margin = 20\mm + line-width = 65\mm + evenHeaderMarkup = \markup \fill-line { \roman-page-number "SECOND PART" \null } + oddHeaderMarkup = \markup \fill-line { \null "SECOND PART" \roman-page-number } + } + \tocItem \markup "Second part" + \markup \justify { Second part, with different margins and page header. } + { c' } + } + + \tocItem \markup "Third part" + \markup { Third part } + \markuplines \table-of-contents +} diff --git a/lily/book-scheme.cc b/lily/book-scheme.cc index e00f1ded49..58a0565061 100644 --- a/lily/book-scheme.cc +++ b/lily/book-scheme.cc @@ -34,6 +34,18 @@ LY_DEFINE (ly_make_book, "ly:make-book", return x; } +LY_DEFINE (ly_make_book_part, "ly:make-book-part", + 1, 0, 0, (SCM scores), + "Make a @code{\\bookpart} containing @code{\\scores}.") +{ + Book *book = new Book; + book->scores_ = scm_append (scm_list_2 (scores, book->scores_)); + + SCM x = book->self_scm (); + book->unprotect (); + return x; +} + LY_DEFINE (ly_book_process, "ly:book-process", 4, 0, 0, (SCM book_smob, SCM default_paper, @@ -96,3 +108,13 @@ LY_DEFINE (ly_book_add_score_x, "ly:book-add-score!", book->add_score (score); return SCM_UNSPECIFIED; } + +LY_DEFINE (ly_book_add_bookpart_x, "ly:book-add-bookpart!", + 2, 0, 0, (SCM book_smob, SCM book_part), + "Add @var{book_part} to @var{book-smob} book part list.") +{ + LY_ASSERT_SMOB (Book, book_smob, 1); + Book *book = unsmob_book (book_smob); + book->add_bookpart (book_part); + return SCM_UNSPECIFIED; +} diff --git a/lily/book.cc b/lily/book.cc index 335507601d..700405f314 100644 --- a/lily/book.cc +++ b/lily/book.cc @@ -29,6 +29,7 @@ Book::Book () paper_ = 0; header_ = SCM_EOL; scores_ = SCM_EOL; + bookparts_ = SCM_EOL; input_location_ = SCM_EOL; smobify_self (); @@ -40,6 +41,7 @@ Book::Book (Book const &s) paper_ = 0; header_ = SCM_EOL; scores_ = SCM_EOL; + bookparts_ = SCM_EOL; input_location_ = SCM_EOL; smobify_self (); @@ -64,6 +66,16 @@ Book::Book (Book const &s) t = SCM_CDRLOC (*t); newscore->unprotect (); } + + t = &bookparts_; + for (SCM p = s.bookparts_; scm_is_pair (p); p = scm_cdr (p)) + { + Book *newpart = unsmob_book (scm_car (p))->clone (); + + *t = scm_cons (newpart->self_scm (), SCM_EOL); + t = SCM_CDRLOC (*t); + newpart->unprotect (); + } } Input * @@ -87,6 +99,7 @@ Book::mark_smob (SCM s) if (book->paper_) scm_gc_mark (book->paper_->self_scm ()); scm_gc_mark (book->scores_); + scm_gc_mark (book->bookparts_); scm_gc_mark (book->input_location_); return book->header_; @@ -105,62 +118,145 @@ Book::add_score (SCM s) scores_ = scm_cons (s, scores_); } +void +Book::set_parent (Book *parent) +{ + if (!paper_) + { + paper_ = new Output_def (); + paper_->unprotect (); + } + paper_->parent_ = parent->paper_; -/* Concatenate all score outputs into a Paper_book - */ -Paper_book * -Book::process (Output_def *default_paper, - Output_def *default_layout) + if (header_ == SCM_EOL) + { + header_ = ly_make_anonymous_module (false); + if (ly_is_module (parent->header_)) + ly_module_copy (header_, parent->header_); + } +} + +void +Book::add_bookpart () +{ + if (scm_is_pair (scores_)) + { + /* If scores have been added to this book, add them to a child + * book part */ + Book *part = new Book; + part->set_parent (this); + part->scores_ = scores_; + bookparts_ = scm_cons (part->self_scm (), bookparts_); + part->unprotect (); + scores_ = SCM_EOL; + } +} + +void +Book::add_bookpart (SCM b) +{ + add_bookpart (); + Book *part = unsmob_book (b); + part->set_parent (this); + bookparts_ = scm_cons (b, bookparts_); +} + +bool +Book::error_found () { for (SCM s = scores_; scm_is_pair (s); s = scm_cdr (s)) if (Score *score = unsmob_score (scm_car (s))) if (score->error_found_) - return 0; + return true; + + for (SCM part = bookparts_; scm_is_pair (part); part = scm_cdr (part)) + if (Book *bookpart = unsmob_book (scm_car (part))) + if (bookpart->error_found ()) + return true; + return false; +} + +Paper_book * +Book::process (Output_def *default_paper, + Output_def *default_layout) +{ + return process (default_paper, default_layout, 0); +} + +/* Concatenate all score or book part outputs into a Paper_book + */ +Paper_book * +Book::process (Output_def *default_paper, + Output_def *default_layout, + Output_def *parent_paper) +{ Output_def *paper = paper_ ? paper_ : default_paper; + + /* If top book, recursively check score errors */ + if (!parent_paper && error_found ()) + return 0; + if (!paper) return 0; - + Paper_book *paper_book = new Paper_book (); Real scale = scm_to_double (paper->c_variable ("output-scale")); Output_def *scaled_bookdef = scale_output_def (paper, scale); - paper_book->paper_ = scaled_bookdef; - scaled_bookdef->unprotect (); - + if (parent_paper) + paper_book->paper_->parent_ = parent_paper; paper_book->header_ = header_; - /* Render in order of parsing. */ - for (SCM s = scm_reverse (scores_); scm_is_pair (s); s = scm_cdr (s)) + if (scm_is_pair (bookparts_)) { - if (Score *score = unsmob_score (scm_car (s))) - { - SCM outputs = score - ->book_rendering (paper_book->paper_, default_layout); - - while (scm_is_pair (outputs)) - { - Music_output *output = unsmob_music_output (scm_car (outputs)); - - if (Performance *perf = dynamic_cast (output)) - paper_book->add_performance (perf->self_scm ()); - else if (Paper_score *pscore = dynamic_cast (output)) - { - if (ly_is_module (score->get_header ())) - paper_book->add_score (score->get_header ()); - paper_book->add_score (pscore->self_scm ()); - } - - outputs = scm_cdr (outputs); - } - } - else if (Text_interface::is_markup_list (scm_car (s)) - || unsmob_page_marker (scm_car (s))) - paper_book->add_score (scm_car (s)); - else - assert (0); + /* Process children book parts */ + add_bookpart (); + for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p)) + { + if (Book *book = unsmob_book (scm_car (p))) + { + Paper_book *paper_book_part = book + ->process (paper, default_layout, paper_book->paper_); + if (paper_book_part) + paper_book->add_bookpart (paper_book_part->self_scm ()); + } + } + } + else + { + /* Process scores */ + /* Render in order of parsing. */ + for (SCM s = scm_reverse (scores_); scm_is_pair (s); s = scm_cdr (s)) + { + if (Score *score = unsmob_score (scm_car (s))) + { + SCM outputs = score + ->book_rendering (paper_book->paper_, default_layout); + + while (scm_is_pair (outputs)) + { + Music_output *output = unsmob_music_output (scm_car (outputs)); + + if (Performance *perf = dynamic_cast (output)) + paper_book->add_performance (perf->self_scm ()); + else if (Paper_score *pscore = dynamic_cast (output)) + { + if (ly_is_module (score->get_header ())) + paper_book->add_score (score->get_header ()); + paper_book->add_score (pscore->self_scm ()); + } + + outputs = scm_cdr (outputs); + } + } + else if (Text_interface::is_markup_list (scm_car (s)) + || unsmob_page_marker (scm_car (s))) + paper_book->add_score (scm_car (s)); + else + assert (0); + } } return paper_book; } - diff --git a/lily/include/book.hh b/lily/include/book.hh index cf47843238..d92bcc72a2 100644 --- a/lily/include/book.hh +++ b/lily/include/book.hh @@ -24,6 +24,7 @@ public: SCM header_; Output_def *paper_; SCM scores_; + SCM bookparts_; SCM input_location_; Book (Book const &); @@ -31,8 +32,15 @@ public: VIRTUAL_COPY_CONSTRUCTOR(Book, Book); Book (); void add_score (SCM); + void add_bookpart (); + void add_bookpart (SCM); + void set_parent (Book *parent); + bool error_found (); Paper_book *process (Output_def *def_paper, Output_def *def_layout); + Paper_book *process (Output_def *default_paper, + Output_def *default_layout, + Output_def *parent_paper); void set_keys (); }; diff --git a/lily/include/paper-book.hh b/lily/include/paper-book.hh index 4ea1927946..74829492ed 100644 --- a/lily/include/paper-book.hh +++ b/lily/include/paper-book.hh @@ -31,11 +31,15 @@ public: SCM header_; SCM header_0_; SCM scores_; + SCM bookparts_; Output_def *paper_; Paper_book (); + Output_def *top_paper (); + void add_score (SCM); + void add_bookpart (SCM); void add_performance (SCM); SCM performances () const; @@ -47,7 +51,12 @@ public: Stencil book_title (); Stencil score_title (SCM); + void classic_output_aux (SCM output); void classic_output (SCM output_channel); + int output_aux (SCM output_channel, + int first_page_number, + bool is_first, + bool is_last); void output (SCM output_channel); }; diff --git a/lily/lily-lexer.cc b/lily/lily-lexer.cc index 7b77d58922..374eed4ec8 100644 --- a/lily/lily-lexer.cc +++ b/lily/lily-lexer.cc @@ -31,6 +31,7 @@ static Keyword_ent the_key_tab[] {"alias", ALIAS}, {"alternative", ALTERNATIVE}, {"book", BOOK}, + {"bookpart", BOOKPART}, {"change", CHANGE}, {"chordmode", CHORDMODE}, {"chords", CHORDS}, diff --git a/lily/minimal-page-breaking.cc b/lily/minimal-page-breaking.cc index 870340f83d..0826e18190 100644 --- a/lily/minimal-page-breaking.cc +++ b/lily/minimal-page-breaking.cc @@ -40,7 +40,7 @@ Minimal_page_breaking::solve () break_into_pieces (0, end, current_configuration (0)); message (_ ("Computing page breaks...")); - vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1); + vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("part-first-page-number"), 1); Page_spacing_result res = pack_systems_on_least_pages (0, first_page_num); SCM lines = systems (); return make_pages (res.systems_per_page_, lines); diff --git a/lily/optimal-page-breaking.cc b/lily/optimal-page-breaking.cc index 3c26c9abe0..9d395a1b50 100644 --- a/lily/optimal-page-breaking.cc +++ b/lily/optimal-page-breaking.cc @@ -38,7 +38,7 @@ Optimal_page_breaking::solve () { vsize end = last_break_position (); vsize max_sys_count = max_system_count (0, end); - vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1); + vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("part-first-page-number"), 1); SCM forced_page_count = book_->paper_->c_variable ("page-count"); set_to_ideal_line_configuration (0, end); diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc index 1ae769e82d..a0aeddd43d 100644 --- a/lily/page-breaking.cc +++ b/lily/page-breaking.cc @@ -253,14 +253,17 @@ Page_breaking::make_pages (vector lines_per_page, SCM systems) SCM book = book_->self_scm (); int first_page_number - = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1); + = robust_scm2int (book_->paper_->c_variable ("part-first-page-number"), 1); + bool last_part = ly_scm2bool (book_->paper_->c_variable ("part-is-last")); SCM ret = SCM_EOL; - SCM label_page_table = SCM_EOL; + SCM label_page_table = book_->top_paper ()->c_variable ("label-page-table"); + if (label_page_table == SCM_UNDEFINED) + label_page_table = SCM_EOL; for (vsize i = 0; i < lines_per_page.size (); i++) { SCM page_num = scm_from_int (i + first_page_number); - SCM last = scm_from_bool (i == lines_per_page.size () - 1); + SCM last = scm_from_bool (last_part && (i == lines_per_page.size () - 1)); SCM rag = scm_from_bool (ragged () || (to_boolean (last) && ragged_last ())); SCM line_count = scm_from_int (lines_per_page[i]); @@ -290,7 +293,7 @@ Page_breaking::make_pages (vector lines_per_page, SCM systems) ret = scm_cons (page, ret); systems = scm_list_tail (systems, line_count); } - book_->paper_->set_variable (ly_symbol2scm ("label-page-table"), label_page_table); + book_->top_paper ()->set_variable (ly_symbol2scm ("label-page-table"), label_page_table); ret = scm_reverse (ret); return ret; } diff --git a/lily/page-turn-page-breaking.cc b/lily/page-turn-page-breaking.cc index 75e1a3bbf2..d2e501cb65 100644 --- a/lily/page-turn-page-breaking.cc +++ b/lily/page-turn-page-breaking.cc @@ -122,7 +122,7 @@ Page_turn_page_breaking::calc_subproblem (vsize ending_breakpoint) if (start > 0 && best.demerits_ < state_[start-1].demerits_) continue; - int p_num = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1); + int p_num = robust_scm2int (book_->paper_->c_variable ("part-first-page-number"), 1); if (start > 0) { /* except possibly for the first page, enforce the fact that first_page_number_ @@ -260,7 +260,7 @@ Page_turn_page_breaking::make_pages (vector const &soln, SCM systems /* this should only actually modify first-page-number if auto-first-page-number was true. */ - book_->paper_->set_variable (ly_symbol2scm ("first-page-number"), + book_->paper_->set_variable (ly_symbol2scm ("part-first-page-number"), scm_from_int (soln[0].first_page_number_)); return Page_breaking::make_pages (lines_per_page, systems); } diff --git a/lily/paper-book.cc b/lily/paper-book.cc index 020c2e7b21..43e2012043 100644 --- a/lily/paper-book.cc +++ b/lily/paper-book.cc @@ -27,6 +27,7 @@ Paper_book::Paper_book () header_0_ = SCM_EOL; pages_ = SCM_BOOL_F; scores_ = SCM_EOL; + bookparts_ = SCM_EOL; performances_ = SCM_EOL; systems_ = SCM_BOOL_F; @@ -53,6 +54,7 @@ Paper_book::mark_smob (SCM smob) scm_gc_mark (b->pages_); scm_gc_mark (b->performances_); scm_gc_mark (b->scores_); + scm_gc_mark (b->bookparts_); return b->systems_; } @@ -65,6 +67,15 @@ Paper_book::print_smob (SCM smob, SCM port, scm_print_state*) return 1; } +Output_def * +Paper_book::top_paper () +{ + Output_def *paper = paper_; + while (paper->parent_) + paper = paper->parent_; + return paper; +} + SCM dump_fields () { @@ -82,14 +93,23 @@ Paper_book::add_score (SCM s) scores_ = scm_cons (s, scores_); } +void +Paper_book::add_bookpart (SCM p) +{ + bookparts_ = scm_cons (p, bookparts_); +} + void Paper_book::add_performance (SCM s) { performances_ = scm_cons (s, performances_); } -void -Paper_book::output (SCM output_channel) +int +Paper_book::output_aux (SCM output_channel, + int first_page_number, + bool is_first, + bool is_last) { if (scm_is_pair (performances_)) { @@ -98,11 +118,44 @@ Paper_book::output (SCM output_channel) scm_call_2 (proc, performances (), output_channel); } - if (scores_ == SCM_EOL) - return; + if (scm_is_pair (bookparts_)) + { + bool is_first_part = is_first; + int page_number = first_page_number; + for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p)) + if (Paper_book *pbookpart = unsmob_paper_book (scm_car (p))) + { + bool is_last_part = (is_last && !scm_is_pair (scm_cdr (p))); + page_number += pbookpart->output_aux (output_channel, + page_number, + is_first_part, + is_last_part); + is_first_part = false; + } + return page_number; + } + else + { + if (scores_ == SCM_EOL) + return 0; + paper_->set_variable (ly_symbol2scm ("part-first-page-number"), + scm_long2num (first_page_number)); + paper_->set_variable (ly_symbol2scm ("part-is-first"), + ly_bool2scm (is_first)); + paper_->set_variable (ly_symbol2scm ("part-is-last"), + ly_bool2scm (is_last)); + /* Generate all stencils to trigger font loads. */ + return scm_ilength (pages ()); + } +} - /* Generate all stencils to trigger font loads. */ - pages (); +void +Paper_book::output (SCM output_channel) +{ + output_aux (output_channel, + robust_scm2int (paper_->c_variable ("first-page-number"), 1), + true, + true); SCM scopes = SCM_EOL; if (ly_is_module (header_)) @@ -137,7 +190,7 @@ Paper_book::output (SCM output_channel) } void -Paper_book::classic_output (SCM output) +Paper_book::classic_output_aux (SCM output) { if (scm_is_pair (performances_)) { @@ -148,6 +201,12 @@ Paper_book::classic_output (SCM output) /* Generate all stencils to trigger font loads. */ systems (); +} + +void +Paper_book::classic_output (SCM output) +{ + classic_output_aux (output); SCM scopes = SCM_EOL; if (ly_is_module (header_)) @@ -322,15 +381,18 @@ Paper_book::get_system_specs () { SCM system_specs = SCM_EOL; - Stencil title = book_title (); - if (!title.is_empty ()) + if (ly_scm2bool (paper_->c_variable ("part-is-first"))) { - SCM props = paper_->lookup_variable (ly_symbol2scm ("book-title-properties")); - Prob *ps = make_paper_system (props); - paper_system_set_stencil (ps, title); - - system_specs = scm_cons (ps->self_scm (), system_specs); - ps->unprotect (); + Stencil title = book_title (); + if (!title.is_empty ()) + { + SCM props = paper_->lookup_variable (ly_symbol2scm ("book-title-properties")); + Prob *ps = make_paper_system (props); + paper_system_set_stencil (ps, title); + + system_specs = scm_cons (ps->self_scm (), system_specs); + ps->unprotect (); + } } SCM page_properties @@ -448,46 +510,54 @@ Paper_book::systems () return systems_; systems_ = SCM_EOL; - SCM specs = get_system_specs (); - for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s)) + if (scm_is_pair (bookparts_)) { - if (Paper_score *pscore = dynamic_cast (unsmob_music_output (scm_car (s)))) - { - SCM system_list = scm_vector_to_list (pscore->get_paper_systems ()); - system_list = scm_reverse (system_list); - systems_ = scm_append (scm_list_2 (system_list, systems_)); - } - else - { - systems_ = scm_cons (scm_car (s), systems_); - } + for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p)) + if (Paper_book *pbookpart = unsmob_paper_book (scm_car (p))) + systems_ = scm_append_x (scm_list_2 (systems_, pbookpart->systems ())); } - - systems_ = scm_reverse (systems_); - - /* backwards compatibility for the old page breaker */ - int i = 0; - Prob *last = 0; - for (SCM s = systems_; scm_is_pair (s); s = scm_cdr (s)) + else { - Prob *ps = unsmob_prob (scm_car (s)); - ps->set_property ("number", scm_from_int (++i)); - - if (last - && to_boolean (last->get_property ("is-title")) - && !scm_is_number (ps->get_property ("penalty"))) - ps->set_property ("penalty", scm_from_int (10000)); - last = ps; - - if (scm_is_pair (scm_cdr (s))) - { - SCM perm = ps->get_property ("page-break-permission"); - Prob *next = unsmob_prob (scm_cadr (s)); - if (perm == SCM_EOL) - next->set_property ("penalty", scm_from_int (10001)); - else if (perm == ly_symbol2scm ("force")) - next->set_property ("penalty", scm_from_int (-10001)); - } + SCM specs = get_system_specs (); + for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s)) + { + if (Paper_score *pscore = dynamic_cast (unsmob_music_output (scm_car (s)))) + { + SCM system_list = scm_vector_to_list (pscore->get_paper_systems ()); + system_list = scm_reverse (system_list); + systems_ = scm_append (scm_list_2 (system_list, systems_)); + } + else + { + systems_ = scm_cons (scm_car (s), systems_); + } + } + systems_ = scm_reverse (systems_); + + /* backwards compatibility for the old page breaker */ + int i = 0; + Prob *last = 0; + for (SCM s = systems_; scm_is_pair (s); s = scm_cdr (s)) + { + Prob *ps = unsmob_prob (scm_car (s)); + ps->set_property ("number", scm_from_int (++i)); + + if (last + && to_boolean (last->get_property ("is-title")) + && !scm_is_number (ps->get_property ("penalty"))) + ps->set_property ("penalty", scm_from_int (10000)); + last = ps; + + if (scm_is_pair (scm_cdr (s))) + { + SCM perm = ps->get_property ("page-break-permission"); + Prob *next = unsmob_prob (scm_cadr (s)); + if (perm == SCM_EOL) + next->set_property ("penalty", scm_from_int (10001)); + else if (perm == ly_symbol2scm ("force")) + next->set_property ("penalty", scm_from_int (-10001)); + } + } } return systems_; @@ -500,22 +570,29 @@ Paper_book::pages () return pages_; pages_ = SCM_EOL; - SCM proc = paper_->c_variable ("page-breaking-wrapper"); - pages_ = scm_apply_0 (proc, scm_list_1 (self_scm ())); - - /* set systems_ from the pages */ - if (systems_ == SCM_BOOL_F) + if (scm_is_pair (bookparts_)) { - systems_ = SCM_EOL; - for (SCM p = pages_; scm_is_pair (p); p = scm_cdr (p)) - { - Prob *page = unsmob_prob (scm_car (p)); - SCM systems = page->get_property ("lines"); - - systems_ = scm_append (scm_list_2 (systems_, systems)); - } + for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p)) + if (Paper_book *pbookpart = unsmob_paper_book (scm_car (p))) + pages_ = scm_append_x (scm_list_2 (pages_, pbookpart->pages ())); + } + else + { + SCM proc = paper_->c_variable ("page-breaking-wrapper"); + pages_ = scm_apply_0 (proc, scm_list_1 (self_scm ())); + + /* set systems_ from the pages */ + if (systems_ == SCM_BOOL_F) + { + systems_ = SCM_EOL; + for (SCM p = pages_; scm_is_pair (p); p = scm_cdr (p)) + { + Prob *page = unsmob_prob (scm_car (p)); + SCM systems = page->get_property ("lines"); + systems_ = scm_append (scm_list_2 (systems_, systems)); + } + } } - return pages_; } diff --git a/lily/parser.yy b/lily/parser.yy index be4e7e26e5..213f3ec539 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -159,6 +159,7 @@ void set_music_properties (Music *p, SCM a); %token ALIAS "\\alias" %token ALTERNATIVE "\\alternative" %token BOOK "\\book" +%token BOOKPART "\\bookpart" %token CHANGE "\\change" %token CHORDMODE "\\chordmode" %token CHORDS "\\chords" @@ -306,6 +307,8 @@ If we give names, Bison complains. %type book_block %type book_body +%type bookpart_block +%type bookpart_body %type bare_unsigned %type figured_bass_alteration @@ -474,6 +477,12 @@ toplevel_expression: scm_call_2 (proc, PARSER->self_scm (), book->self_scm ()); book->unprotect (); } + | bookpart_block { + Book *bookpart = $1; + SCM proc = PARSER->lexer_->lookup_identifier ("toplevel-bookpart-handler"); + scm_call_2 (proc, PARSER->self_scm (), bookpart->self_scm ()); + bookpart->unprotect (); + } | score_block { Score *score = $1; @@ -565,6 +574,10 @@ identifier_init: $$ = $1->self_scm (); $1->unprotect (); } + | bookpart_block { + $$ = $1->self_scm (); + $1->unprotect (); + } | output_def { $$ = $1->self_scm (); $1->unprotect (); @@ -664,6 +677,12 @@ book_body: $$->paper_ = $2; $2->unprotect (); } + | book_body bookpart_block { + Book *bookpart = $2; + SCM proc = PARSER->lexer_->lookup_identifier ("book-bookpart-handler"); + scm_call_2 (proc, $$->self_scm (), bookpart->self_scm ()); + bookpart->unprotect (); + } | book_body score_block { Score *score = $2; SCM proc = PARSER->lexer_->lookup_identifier ("book-score-handler"); @@ -689,12 +708,64 @@ book_body: | book_body error { $$->paper_ = 0; $$->scores_ = SCM_EOL; + $$->bookparts_ = SCM_EOL; } | book_body object_id_setting { $$->user_key_ = ly_scm2string ($2); } ; +bookpart_block: + BOOKPART '{' bookpart_body '}' { + $$ = $3; + } + ; + +bookpart_body: + { + $$ = new Book; + $$->origin ()->set_spot (@$); + } + | BOOK_IDENTIFIER { + $$ = unsmob_book ($1); + $$->protect (); + $$->origin ()->set_spot (@$); + } + | bookpart_body paper_block { + $$->paper_ = $2; + $2->unprotect (); + } + | bookpart_body score_block { + Score *score = $2; + SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-score-handler"); + scm_call_2 (proc, $$->self_scm (), score->self_scm ()); + score->unprotect (); + } + | bookpart_body composite_music { + Music *music = unsmob_music ($2); + SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-music-handler"); + scm_call_3 (proc, PARSER->self_scm (), $$->self_scm (), music->self_scm ()); + } + | bookpart_body full_markup { + SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-text-handler"); + scm_call_2 (proc, $$->self_scm (), scm_list_1 ($2)); + } + | bookpart_body full_markup_list { + SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-text-handler"); + scm_call_2 (proc, $$->self_scm (), $2); + } + | bookpart_body lilypond_header { + $$->header_ = $2; + } + | bookpart_body error { + $$->paper_ = 0; + $$->scores_ = SCM_EOL; + } + | bookpart_body object_id_setting { + $$->user_key_ = ly_scm2string ($2); + } + ; + score_block: SCORE '{' score_body '}' { $$ = $3; diff --git a/ly/declarations-init.ly b/ly/declarations-init.ly index 88fdfe1c03..70498e717c 100644 --- a/ly/declarations-init.ly +++ b/ly/declarations-init.ly @@ -111,13 +111,18 @@ setDefaultDurationToQuarter = { c4 } #(define musicQuotes (make-hash-table 29)) #(define toplevel-book-handler print-book-with-defaults) +#(define toplevel-bookpart-handler collect-bookpart-for-book) #(define toplevel-music-handler collect-music-for-book) #(define toplevel-score-handler collect-scores-for-book) #(define toplevel-text-handler collect-scores-for-book) +#(define book-bookpart-handler ly:book-add-bookpart!) #(define book-music-handler collect-book-music-for-book) #(define book-score-handler ly:book-add-score!) #(define book-text-handler ly:book-add-score!) +#(define bookpart-score-handler ly:book-add-score!) +#(define bookpart-text-handler ly:book-add-score!) +#(define bookpart-music-handler collect-book-music-for-book) \include "predefined-fretboards-init.ly" diff --git a/ly/init.ly b/ly/init.ly index a4bd1c3a39..5a2103e83c 100644 --- a/ly/init.ly +++ b/ly/init.ly @@ -10,7 +10,8 @@ #(ly:set-option 'old-relative #f) -#(define toplevel-scores '()) +#(define toplevel-scores (list)) +#(define toplevel-bookparts (list)) #(define output-count 0) #(define $defaultheader #f) #(define version-seen #f) @@ -35,13 +36,26 @@ (version-not-seen-message input-file-name)) #(ly:set-option 'protected-scheme-parsing #f) -#(if (or (pair? toplevel-scores) output-empty-score-list) - ((if (defined? 'default-toplevel-book-handler) - default-toplevel-book-handler - toplevel-book-handler) - parser - (apply ly:make-book $defaultpaper $defaultheader toplevel-scores))) +#(let ((book-handler (if (defined? 'default-toplevel-book-handler) + default-toplevel-book-handler + toplevel-book-handler))) + (cond ((pair? toplevel-bookparts) + (let ((book (ly:make-book $defaultpaper $defaultheader))) + (map (lambda (part) + (ly:book-add-bookpart! book part)) + (reverse! toplevel-bookparts)) + (set! toplevel-bookparts (list)) + ;; if scores have been defined after the last explicit \bookpart: + (if (pair? toplevel-scores) + (map (lambda (score) + (ly:book-add-score! book score)) + (reverse! toplevel-scores))) + (set! toplevel-scores (list)) + (book-handler parser book))) + ((or (pair? toplevel-scores) output-empty-score-list) + (book-handler parser (apply ly:make-book $defaultpaper + $defaultheader toplevel-scores))))) #(if (eq? expect-error (ly:parser-has-error? parser)) (ly:parser-clear-error parser) diff --git a/scm/lily-library.scm b/scm/lily-library.scm index f772d0527e..553d6c7dc4 100644 --- a/scm/lily-library.scm +++ b/scm/lily-library.scm @@ -56,8 +56,22 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; parser <-> output hooks. - +(define-public (collect-bookpart-for-book parser book-part) + "Toplevel book-part handler" + (define (add-bookpart book-part) + (ly:parser-define! + parser 'toplevel-bookparts + (cons book-part (ly:parser-lookup parser 'toplevel-bookparts)))) + ;; If toplevel scores have been found before this \bookpart, + ;; add them first to a dedicated bookpart + (if (pair? (ly:parser-lookup parser 'toplevel-scores)) + (begin + (add-bookpart (ly:make-book-part + (ly:parser-lookup parser 'toplevel-scores))) + (ly:parser-define! parser 'toplevel-scores (list)))) + (add-bookpart book-part)) + (define-public (collect-scores-for-book parser score) (ly:parser-define! parser 'toplevel-scores