lilypond-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Proposal: page breaking protocol


From: Nicolas Sceaux
Subject: Proposal: page breaking protocol
Date: Fri, 28 Jul 2006 16:59:59 +0200
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (darwin)

Hi,

Today, the page breaking function (optimal-page-breaks) does the page
breaking + computes the page stencils + calls the page post process
function. This means that every alternate page breaking function has to
do the same. I propose to define an umbrella function, which will call
the actual page breaking function (as chosen by the user in the \paper
block), and then will do the other common processings (stencil
computation and post processes, eg. annotations).

This new function could also be the place to introduce new page breaking
facilities. It is possible today to force page breaks inside a piece, or
before its title, but adding a page break between markups, or simply
before a piece that does not have a title, requires some unsatisfactory
hacks.

The page breaking wrapper function could split the system list every
time some property is seen. Then, it would call the actual page breaking
function on each chunk of system list.

Benefits:
 - introduce page breaks between pieces or markups
 - some pages inside the book can be ragged-bottom, which is nice to
 separate chapters or acts of an opera for instance.

I've implemented such a beast for my scores, it seems to work nicely.

newPage = 
#(define-music-function (parser location) ()
  #{ 
    \overrideProperty #"Score.NonMusicalPaperColumn"
      #'line-break-system-details #'((void . #t) (break-before . #t))
    c'
  #})

newChapter = 
#(define-music-function (parser location) ()
  #{
    \overrideProperty #"Score.NonMusicalPaperColumn"
      #'line-break-system-details
      #'((void . #t) (break-before . #t) (ragged-bottom-before . #t))
    c'
  #})

The 'void property indicates that this system should not be printed
(it's just a layout marker). The break-before property says that a page
break should occur here, and the ragged-bottom-before property that the
previous page should be ragged-bottom.

Then, \newPage and \newChapter are used at the toplevel, between markups
or scores. (The names suck, but \pageBreak already exists, I'd welcome
better names).

The wrapper function would look like that:

(define-public (page-break-wrapper book-lines paper-book)
  "Computes the book pages from `book-lines':
 - look for page break requests in book-lines
 - call the page breaking function on each chunk of lines
 - computes page stencils
 - call the page post process function
 - finally, return the page list.
The page breaking and post process functions are the
page-breaking-function and page-post-process-function defined in the
\\paper block, respectively."
  (ly:message (_ "Calculating page breaks... "))
  (let* ((layout (ly:paper-book-paper paper-book))
         (break-pages (ly:output-def-lookup
                       layout 'page-breaking-function)))
    (define (page-break-aux lines current-lines previous-pages 
current-page-number)
      (if (null? lines)
          (reverse! (if (null? current-lines)
                        previous-pages
                        (append! (break-pages (reverse! current-lines)
                                              paper-book
                                              current-page-number
                                              #t
                                              (eq? #t (ly:output-def-lookup
                                                       layout
                                                       'ragged-last-bottom)))
                                 previous-pages)))
          (let ((line (first lines)))
            (if (eq? #t (ly:prob-property line 'break-before #f))
                ;; a page break is requested here
                (let* ((last-line (null? (cdr lines)))
                       (ragged-last (or (eq? #t (ly:prob-property
                                                 line 'ragged-bottom-before))
                                        (and last-line
                                             (eq? #t (ly:output-def-lookup
                                                      layout
                                                      'ragged-last-bottom)))))
                       (new-pages (break-pages (reverse! current-lines)
                                               paper-book
                                               current-page-number
                                               last-line
                                               ragged-last))
                       (new-page-number (+ current-page-number
                                           (length new-pages))))
                  (format #t "~%Page break requested, ~a pages before"
                          (length new-pages))
                  (page-break-aux (if (eq? #t (ly:prob-property line 'void #f))
                                      (cdr lines)
                                      lines)
                                  (list)
                                  (append! new-pages previous-pages)
                                  new-page-number))
                ;; add the line to the current line list
                (page-break-aux (cdr lines)
                                (cons line current-lines)
                                previous-pages
                                current-page-number)))))
    (let ((book-pages (page-break-aux book-lines
                                      (list)
                                      (list)
                                      (ly:output-def-lookup
                                       layout 'first-page-number))))
      (for-each page-stencil book-pages)
      ((ly:output-def-lookup layout 'page-post-process-function)
       layout book-pages)
      book-pages)))

The signature of page breaking functions changes:

* page-breaking-function (lines paper-book first-page-number last-lines
ragged-last) [function]
Return a list of pages containing the `lines'. Positions of lines on
pages are set in the 'configuration page property.
If `lines' is empty, return an empty page.
- first-page-number: the number of the first page.
- last-lines: #t if there are no other lines, #f otherwise (in order to
know the last computed page is also the last page of the book)
- ragged-last: if #t, the last computed page should be ragged-bottom.


Would this be useful?

nicolas




reply via email to

[Prev in Thread] Current Thread [Next in Thread]