]> git.donarmstrong.com Git - lilypond.git/blobdiff - scm/page-layout.scm
* stepmake/aclocal.m4 (STEPMAKE_PANGO_FT2): Define HAVE_PANGO16 too.
[lilypond.git] / scm / page-layout.scm
index ccfc71329a028ab96d11fbf885865504ee7c0eb6..08590f2f89d99865eecb08071f437d122d10cab7 100644 (file)
@@ -2,7 +2,7 @@
 ;;;;
 ;;;;  source file of the GNU LilyPond music typesetter
 ;;;;
-;;;; (c) 2004 Jan Nieuwenhuizen <janneke@gnu.org>
+;;;; (c) 2004--2005 Jan Nieuwenhuizen <janneke@gnu.org>
 ;;;;          Han-Wen Nienhuys <hanwen@cs.uu.nl>
 
 (use-modules (oop goops describe)
@@ -14,7 +14,7 @@
 (define-class <optimally-broken-page-node> ()
   (prev #:init-value '() #:accessor node-prev #:init-keyword #:prev)
   (page #:init-value 0 #:accessor node-page-number #:init-keyword #:pageno)
-  (force #:init-value 0 #:accessor node-force #:init-keyword #:force) 
+  (force #:init-value 0 #:accessor node-force #:init-keyword #:force)
   (penalty #:init-value 0 #:accessor node-penalty #:init-keyword #:penalty)
   (configuration #:init-value '() #:accessor node-configuration #:init-keyword #:configuration)
   (lines #:init-value 0 #:accessor node-lines #:init-keyword #:lines))
        " Penalty " (node-penalty node)
        "\n")))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(define-method (node-system-numbers (node <optimally-broken-page-node>))
+  (map ly:paper-system-number (node-lines node)))
 
-(define TAGLINE
-  (string-append "Engraved by LilyPond (version " (lilypond-version) ")"))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (define (page-headfoot layout scopes number sym sepsym dir last?)
   "Create a stencil including separating space."
             (not (ly:stencil-empty? head-stencil)))
        (set! head-stencil
              (ly:stencil-combine-at-edge
-              stencil Y  dir head-stencil
+              stencil Y dir head-stencil
               sep 0.0)))
 
     head-stencil))
 
 (define-public (default-page-music-height layout scopes number last?)
-  "Printable area for music and titles; matches default-page-make-stencil." 
+  "Printable area for music and titles; matches default-page-make-stencil."
   (let* ((h (- (ly:output-def-lookup layout 'vsize)
             (ly:output-def-lookup layout 'topmargin)
             (ly:output-def-lookup layout 'bottommargin)))
        (head (page-headfoot layout scopes number 'make-header 'headsep UP last?))
        (foot (page-headfoot layout scopes number 'make-footer 'footsep DOWN last?))
-       (available 
+       (available
        (- h (if (ly:stencil? head)
                 (interval-length (ly:stencil-extent head Y))
                 0)
           (if (ly:stencil? foot)
               (interval-length (ly:stencil-extent foot Y))
               0))))
-    
-                                       ;    (display (list "\n available" available head foot))
+
+    ;; (display (list "\n available" available head foot))
     available))
 
 (define-public (default-page-make-stencil
-                lines offsets layout scopes number last? )
-  "Construct a stencil representing the page from LINES.  "
-  (let* ((topmargin  (ly:output-def-lookup layout 'topmargin))
-       
+                lines offsets layout scopes number last?)
+  "Construct a stencil representing the page from LINES.
+
+ Offsets is a list of increasing numbers. They must be negated to
+create offsets.
+ "
+
+  (let* ((topmargin (ly:output-def-lookup layout 'topmargin))
+
        ;; TODO: naming vsize/hsize not analogous to TeX.
-       
-       (vsize (ly:output-def-lookup layout 'vsize))
-       (hsize (ly:output-def-lookup layout 'hsize))
-       
-       (lmargin (ly:output-def-lookup layout 'leftmargin))
-       (leftmargin (if lmargin
+
+        (vsize (ly:output-def-lookup layout 'vsize))
+        (hsize (ly:output-def-lookup layout 'hsize))
+
+        (system-separator-markup (ly:output-def-lookup layout 'systemSeparatorMarkup))
+        (system-separator-stencil (if (markup? system-separator-markup)
+                                      (interpret-markup layout
+                                                        (layout-extract-page-properties layout)
+                                                        system-separator-markup)
+                                      #f))
+        (lmargin (ly:output-def-lookup layout 'leftmargin))
+        (leftmargin (if lmargin
                       lmargin
                       (/ (- hsize
                             (ly:output-def-lookup layout 'linewidth)) 2)))
        (rightmargin (ly:output-def-lookup layout 'rightmargin))
        (bottom-edge (- vsize
                       (ly:output-def-lookup layout 'bottommargin)))
-       
+
        (head (page-headfoot layout scopes number 'make-header 'headsep UP last?))
        (foot (page-headfoot layout scopes number 'make-footer 'footsep DOWN last?))
 
                        (interval-length (ly:stencil-extent head Y))
                        0.0))
 
-       (line-stencils (map ly:paper-system-stencil lines))
        (height-proc (ly:output-def-lookup layout 'page-music-height))
 
        (page-stencil (ly:make-stencil '()
                                      (cons leftmargin hsize)
                                      (cons (- topmargin) 0)))
-       (was-title #t)
-       (add-system (lambda (stencil-position)
-                    (set! page-stencil
-                          (ly:stencil-add
-                           (ly:stencil-translate-axis
-                            (car stencil-position)
-                            (- 0
-                               head-height
-                               (cadr stencil-position)
-                               topmargin)
-                            Y)
-                           page-stencil)))))
+       (last-system #f)
+       (last-y 0.0)
+       (add-to-page (lambda (stencil y)
+                     (set! page-stencil
+                           (ly:stencil-add page-stencil
+                                           (ly:stencil-translate-axis stencil
+                                            (- 0 head-height y topmargin) Y)))))
+       (add-system
+       (lambda (stencil-position)
+         (let* ((system (car stencil-position))
+                (stencil (ly:paper-system-stencil system))
+                (y (cadr stencil-position))
+                (is-title (ly:paper-system-title?
+                           (car stencil-position))))
+           (add-to-page stencil y)
+           (if (and (ly:stencil? system-separator-stencil)
+                    last-system
+                    (not (ly:paper-system-title? system))
+                    (not (ly:paper-system-title? last-system)))
+               (add-to-page
+                system-separator-stencil
+                (average (- last-y
+                            (car (ly:paper-system-staff-extents last-system)))
+                         (- y
+                            (cdr (ly:paper-system-staff-extents system))))))
+           (set! last-system system)
+           (set! last-y y)))))
 
     (if #f
        (display (list
-                 "leftmargin" leftmargin "rightmargin" rightmargin)))
-    
-    (set! page-stencil (ly:stencil-combine-at-edge
-                       page-stencil Y DOWN head 0. 0.))
+                 "leftmargin " leftmargin "rightmargin " rightmargin
+                 )))
 
-    (map add-system (zip line-stencils offsets))
-    (if (ly:stencil? foot)
+    (set! page-stencil (ly:stencil-combine-at-edge
+                       page-stencil Y DOWN
+                       (if (and
+                            (ly:stencil? head)
+                            (not (ly:stencil-empty? head)))
+                           head
+                           (ly:make-stencil "" (cons 0 0) (cons 0 0)))
+                           0. 0.))
+
+    (map add-system (zip lines offsets))
+    (if (and (ly:stencil? foot)
+            (not (ly:stencil-empty? foot)))
        (set! page-stencil
              (ly:stencil-add
               page-stencil
 
     (ly:stencil-translate page-stencil (cons leftmargin 0))))
 
-
-
-
 ;;; optimal page breaking
 
 ;;; This is not optimal page breaking, this is optimal distribution of
 ;;; lines over pages; line breaks are a given.
 
-                                       ; TODO:
-                                       ;
-                                       ; - density scoring
-                                       ; - separate function for word-wrap style breaking?
-                                       ; - raggedbottom? raggedlastbottom? 
+;; TODO:
+;;
+;; - density scoring
+;; - separate function for word-wrap style breaking?
+;; - raggedbottom? raggedlastbottom?
 
 (define-public (ly:optimal-page-breaks
                lines paper-book)
@@ -166,28 +196,28 @@ of lines. "
       (if (procedure? p)
          (p paper scopes page-number last?)
          10000)))
-  
+
   (define (get-path node done)
     "Follow NODE.PREV, and return as an ascending list of pages. DONE
 is what have collected so far, and has ascending page numbers."
-    
+
     (if (is-a? node <optimally-broken-page-node>)
        (get-path (node-prev node) (cons node done))
        done))
 
   (define (combine-penalties force user best-paths)
-    (let* ((prev-force  (if (null? best-paths)
-                         0.0
-                         (node-force  (car best-paths))))
-        (prev-penalty (if (null? best-paths)
+    (let* ((prev-force (if (null? best-paths)
                           0.0
-                          (node-penalty (car best-paths))))
+                          (node-force (car best-paths))))
+          (prev-penalty (if (null? best-paths)
+                            0.0
+                            (node-penalty (car best-paths))))
         (inter-system-space (ly:output-def-lookup paper 'betweensystemspace))
         (force-equalization-factor 0.3)
         (relative-force (/ force inter-system-space))
         (abs-relative-force (abs relative-force)))
-      
-      
+
+
       (+ (* abs-relative-force (+ abs-relative-force 1))
         prev-penalty
         (* force-equalization-factor (/ (abs (- prev-force force)) inter-system-space))
@@ -195,21 +225,18 @@ is what have collected so far, and has ascending page numbers."
 
   (define (space-systems page-height lines ragged?)
     (let* ((inter-system-space
-         (ly:output-def-lookup paper 'betweensystemspace))
-        (system-vector (list->vector
-                        (append lines
-                                (if (= (length lines) 1)
-                                    '(#f)
-                                    '()))))
-
+           (ly:output-def-lookup paper 'betweensystemspace))
+          (system-vector (list->vector
+                          (append lines
+                                  (if (= (length lines) 1)
+                                      '(#f)
+                                      '()))))
         (staff-extents
          (list->vector
-          (append  (map
-                    ly:paper-system-staff-extents
-                    lines)
-                   (if (= (length lines) 1)
-                       '((0 .  0))
-                       '())) ))
+          (append (map ly:paper-system-staff-extents lines)
+                  (if (= (length lines) 1)
+                      '((0 . 0))
+                      '()))))
         (real-extents
          (list->vector
           (append
@@ -217,12 +244,12 @@ is what have collected so far, and has ascending page numbers."
             (lambda (sys) (ly:paper-system-extent sys Y)) lines)
            (if (= (length lines) 1)
                '((0 .  0))
-               '()) )))
+               '()))))
         (no-systems (vector-length real-extents))
         (topskip (interval-end (vector-ref real-extents 0)))
         (space-left (- page-height
                        (apply + (map interval-length (vector->list real-extents)))))
-        
+
         (space (- page-height
                   topskip
                   (-  (interval-start (vector-ref real-extents (1- no-systems))))))
@@ -232,7 +259,7 @@ is what have collected so far, and has ascending page numbers."
          (lambda (idx)
            (let* ((this-system-ext (vector-ref staff-extents idx))
                 (next-system-ext (vector-ref staff-extents (1+ idx)))
-                (fixed (max 0  (- (+ (interval-end next-system-ext)
+                (fixed (max 0 (- (+ (interval-end next-system-ext)
                                      fixed-dist)
                                   (interval-start this-system-ext))))
                 (title1? (and (vector-ref system-vector idx)
@@ -261,7 +288,7 @@ is what have collected so far, and has ascending page numbers."
                 (distance (max  (- (+ (interval-end next-system-ext)
                                       fixed-dist)
                                    (interval-start this-system-ext)
-                                   ) 0)) 
+                                   ) 0))
                 (entry (list idx (1+ idx) distance)))
              entry)))
         (rods (map calc-rod (iota (1- no-systems))))
@@ -275,9 +302,9 @@ is what have collected so far, and has ascending page numbers."
         (force (car result))
         (positions
          (map (lambda (y)
-                (+ y topskip)) 
+                (+ y topskip))
               (cdr  result))))
-      
+
       (if #f ;; debug.
          (begin
            (display (list "\n# systems: " no-systems
@@ -292,9 +319,9 @@ is what have collected so far, and has ascending page numbers."
                           "\nforce" force
                           "\nres" (cdr result)
                           "\npositions" positions "\n"))))
-      
+
       (cons force positions)))
-  
+
   (define (walk-paths done-lines best-paths current-lines  last? current-best)
     "Return the best optimal-page-break-node that contains
 CURRENT-LINES.  DONE-LINES.reversed ++ CURRENT-LINES is a consecutive
@@ -302,14 +329,14 @@ ascending range of lines, and BEST-PATHS contains the optimal breaks
 corresponding to DONE-LINES.
 
 CURRENT-BEST is the best result sofar, or #f."
-    
+
     (let* ((this-page-num (if (null? best-paths)
                               (ly:output-def-lookup paper 'firstpagenumber)
                               (1+ (node-page-number (car best-paths)))))
 
           (ragged-all? (eq? #t (ly:output-def-lookup paper 'raggedbottom)))
           (ragged-last? (eq? #t (ly:output-def-lookup paper 'raggedlastbottom)))
-          (ragged? (or ragged-all? 
+          (ragged? (or ragged-all?
                        (and ragged-last?
                             last?)))
            (page-height (page-height this-page-num last?))
@@ -334,22 +361,22 @@ CURRENT-BEST is the best result sofar, or #f."
                            force user-penalty
                           best-paths))
 
-          
+
            (better? (or
                      (not current-best)
                      (< total-penalty (node-penalty current-best))))
            (new-best (if better?
                         (make <optimally-broken-page-node>
-                          #:prev  (if (null? best-paths)
-                                      #f
-                                      (car best-paths))
+                          #:prev (if (null? best-paths)
+                                     #f
+                                     (car best-paths))
                           #:lines current-lines
                           #:pageno this-page-num
                           #:force force
                           #:configuration positions
                           #:penalty total-penalty)
                          current-best)))
-      
+
       (if #f ;; debug
           (display
            (list
@@ -367,14 +394,13 @@ CURRENT-BEST is the best result sofar, or #f."
                         (if (null? best-paths)
                             "start"
                             (node-lines (car best-paths))))))
-      
+
       (if (and (pair? done-lines)
                ;; if this page is too full, adding another line won't help
                satisfied-constraints)
           (walk-paths (cdr done-lines) (cdr best-paths)
                       (cons (car done-lines) current-lines)
                       last? new-best)
-         
          new-best)))
 
   (define (walk-lines done best-paths todo)
@@ -388,7 +414,7 @@ DONE."
               (last? (null? (cdr todo)))
               (next (walk-paths done best-paths (list this-line) last? #f)))
 
-                                       ;         (display "\n***************")
+         ;; (display "\n***************")
          (walk-lines (cons this-line done)
                      (cons next best-paths)
                      (cdr todo)))))
@@ -396,8 +422,29 @@ DONE."
   (define (line-number node)
     (ly:paper-system-number (car (node-lines node))))
 
+  (ly:message (_ "Calculating page breaks..."))
+
   (let* ((best-break-node (walk-lines '() '() lines))
-        (break-nodes (get-path best-break-node '())))
+        (break-nodes (get-path best-break-node '()))
+        (last-node (car (last-pair break-nodes))))
+
+    (define (node->page-stencil node)
+      (if (not (eq? node last-node))
+         (ly:progress "["))
+      (let ((stencil
+            ((ly:output-def-lookup paper 'page-make-stencil)
+             (node-lines node)
+             (node-configuration node)
+             paper
+             scopes
+             (node-page-number node)
+             (eq? node best-break-node))))
+       (if (not (eq? node last-node))
+           (begin
+             (ly:progress (number->string
+                           (car (last-pair (node-system-numbers node)))))
+             (ly:progress "]")))
+       stencil))
 
     (if #f; (ly:get-option 'verbose)
        (begin
@@ -407,17 +454,6 @@ DONE."
                   "\npenalties " (map node-penalty break-nodes)
                   "\nconfigs " (map node-configuration break-nodes))))
 
-    
-                                       ; create stencils.
-    
-    (map (lambda (node)
-          ((ly:output-def-lookup paper 'page-make-stencil)
-           (node-lines node)
-           (node-configuration node)
-           paper
-           scopes
-           (node-page-number node)
-           (eq? node best-break-node)))
-        break-nodes)))
-
-
+    (let ((stencils (map node->page-stencil break-nodes)))
+      (ly:progress "\n")
+      stencils)))