From 7c24df07725a38d5643efe86b23c26dec71058fa Mon Sep 17 00:00:00 2001 From: Nicolas Sceaux Date: Sun, 17 Jun 2007 13:19:27 +0200 Subject: [PATCH] Automatic table of contents: - markups used for building the table of contents (its title, the text/page-number lines) are defined as \paper variables, like the titling markups; - A music function is defined to place a label and push a (label paper-markup-variable text-markup) element to a list of toc items; - a \table-of-contents markup list command reads this toc items list to generate the table of contents. --- Documentation/user/non-music.itely | 171 +++++++++++++++++++++-------- input/regression/page-label.ly | 58 +++++----- input/regression/toc.ly | 29 +++++ ly/declarations-init.ly | 1 + ly/toc-init.ly | 59 ++++++++++ scm/define-markup-commands.scm | 2 +- 6 files changed, 244 insertions(+), 76 deletions(-) create mode 100644 input/regression/toc.ly create mode 100644 ly/toc-init.ly diff --git a/Documentation/user/non-music.itely b/Documentation/user/non-music.itely index 2ee1f37f3b..536780c36f 100644 --- a/Documentation/user/non-music.itely +++ b/Documentation/user/non-music.itely @@ -482,6 +482,7 @@ some pieces include a lot more information. * Creating titles:: * Custom titles:: * Reference to page numbers:: +* Table of contents:: @end menu @@ -742,26 +743,30 @@ command, either at top-level or inside music. This label can then be refered to in a markup, to get the number of the page where the marked point is placed, using the @code{\page-ref} markup command. -@verbatim -\label #'firstScore -\score { - { - c'1 - \mark A \label #'markA - c' +@lilypond[verbatim,line-width=11.0\cm] +\header { tagline = ##f } +\book { + \label #'firstScore + \score { + { + c'1 + \pageBreak \mark A \label #'markA + c' + } } -} -\markup { The first score is on page \page-ref #'firstScore "0" "?" } -\markup { Mark A is on page \page-ref #'markA "0" "?" } -@end verbatim + \markup { The first score begins on page \page-ref #'firstScore "0" "?" } + \markup { Mark A is on page \page-ref #'markA "0" "?" } +} +@end lilypond The @code{\page-ref} markup command takes three arguments: @enumerate -@item the label, a scheme symbol, eg. #'firstScore +@item the label, a scheme symbol, eg. @code{#'firstScore}; @item a markup that will be used as a gauge to estimate the dimensions -of the markup -@item a markup that will be used if the label is not known +of the markup; +@item a markup that will be used in place of the page number if the label +is not known; @end enumerate The reason why a gauge is needed is that, at the time markups are @@ -772,53 +777,125 @@ the markup have to be known before, so a gauge is used to decide these dimensions. If the book has between 10 and 99 pages, it may be "00", ie. a two digit number. -@code{\label} and @code{\page-ref} can be used to build a table of contents: - -@verbatim -#(set-default-paper-size "a6") +@refcommands -#(define-markup-command (toc-line layout props label text) (symbol? markup?) - (interpret-markup layout props - (markup #:fill-line (text #:page-ref label "8" "?")))) +@funindex \label +@code{\label} +@funindex \page-ref +@code{\page-ref} -\markup \column { - \large \fill-line { \null "Table of contents" \null } - \hspace #1 - \toc-line #'toc "Table of contents" - \toc-line #'scoreI "First Score" - \toc-line #'markA \line { \hspace #3 Mark A } - \toc-line #'scoreII "Second Score" -} \label #'toc +@node Table of contents +@subsection Table of contents +A table of contents is included using the @code{\markuplines \table-of-contents} +command. The elements which should appear in the table of contents are +entered with the @code{\tocItem} command, which may be used either at +top-level, or inside a music expression. +@verbatim +\markuplines \table-of-contents \pageBreak +\tocItem \markup "First score" +\score { + { + c' % ... + \tocItem \markup "Some particular point in the first score" + d' % ... + } +} + +\tocItem \markup "Second score" \score { - { - c'1 \break - \mark A \label #'markA - c'1 + { + e' % ... } - \header { piece = "First score" } -} \label #'scoreI +} +@end verbatim -\pageBreak +The markups which are used to format the table of contents are defined +in the @code{\paper} block. The default ones are @code{tocTitleMarkup}, +for formatting the title of the table, and @code{tocItemMarkup}, for +formatting the toc elements, composed of the element title and page +number. These variables may be changed by the user: -\score { - { d' } - \header { piece = "Second score" } -} \label #'scoreII +@verbatim +\paper { + %% Translate the toc title into French: + tocTitleMarkup = \markup \huge \column { + \fill-line { \null "Table des matières" \null } + \hspace #1 + } + %% use larfer font size + tocItemMarkup = \markup \large \fill-line { + \fromproperty #'toc:text \fromproperty #'toc:page + } +} @end verbatim -In this example, a @code{\toc-line} markup command is defined to build -the table of content items. As this example has less than 10 pages, the -gauge used by @code{\page-ref} has a single digit. +Note how the toc element text and page number are refered to in +the @code{tocItemMarkup} definition. + +New commands and markups may also be defined to build more elaborated +table of contents: +@itemize @bullet +@item first, define a new markup variable in the @code{\paper} block +@item then, define a music function which aims at adding a toc element +using this markup paper variable. +@end itemize + +In the following example, a new style is defined for entering act names +in the table of contents of an opera: + +@verbatim +\paper { + tocActMarkup = \markup \large \column { + \hspace #1 + \fill-line { \null \italic \fromproperty #'toc:text \null } + \hspace #1 + } +} + +tocAct = +#(define-music-function (parser location text) (markup?) + (add-toc-item! 'tocActMarkup text)) +@end verbatim + +@lilypond[line-width=11.0\cm] +\header { tagline = ##f } +\paper { + tocActMarkup = \markup \large \column { + \hspace #1 + \fill-line { \null \italic \fromproperty #'toc:text \null } + \hspace #1 + } +} + +tocAct = +#(define-music-function (parser location text) (markup?) + (add-toc-item! 'tocActMarkup text)) + +\book { + \markuplines \table-of-contents + \tocAct \markup { Atto Primo } + \tocItem \markup { Coro. Viva il nostro Alcide } + \tocItem \markup { Cesare. Presti omai l'Egizzia terra } + \tocAct \markup { Atto Secondo } + \tocItem \markup { Sinfonia } + \tocItem \markup { Cleopatra. V'adoro, pupille, saette d'Amore } + \markup \null +} +@end lilypond + +@seealso + +Init files: @file{ly/@/toc@/-init@/.ly}. @refcommands -@funindex \label -@code{\label} -@funindex \page-ref -@code{\page-ref} +@funindex \table-of-contents +@code{\table-of-contents} +@funindex \tocItem +@code{\tocItem} @node MIDI output @section MIDI output diff --git a/input/regression/page-label.ly b/input/regression/page-label.ly index 6f1e5c8e88..cb023872dc 100644 --- a/input/regression/page-label.ly +++ b/input/regression/page-label.ly @@ -11,34 +11,36 @@ and refered to in markups." (interpret-markup layout props (markup #:fill-line (text #:page-ref label "8" "?")))) -\markup \huge \fill-line { \null "Title Page" \null } - -\pageBreak - -\label #'toc -\markup \column { - \large \fill-line { \null "Table of contents" \null } - \toc-line #'toc "Table of contents" - \toc-line #'firstScore "First Score" - \toc-line #'markA "Mark A" - \toc-line #'markB "Mark B" - \toc-line #'markC "Mark C" - \toc-line #'unknown "Unknown label" -} +\book { + \markup \huge \fill-line { \null "Title Page" \null } + + \pageBreak + + \label #'toc + \markup \column { + \large \fill-line { \null "Table of contents" \null } + \toc-line #'toc "Table of contents" + \toc-line #'firstScore "First Score" + \toc-line #'markA "Mark A" + \toc-line #'markB "Mark B" + \toc-line #'markC "Mark C" + \toc-line #'unknown "Unknown label" + } -\pageBreak - -\label #'firstScore -\score { - { c'2 c' - \mark \markup { A (page \concat { \page-ref #'markA "0" "?" ) }} \label #'markA - c' c' - \pageBreak - \mark "B" \label #'markB - d' d' - d' d' - \once \override Score . RehearsalMark #'break-visibility = #begin-of-line-invisible - \mark "C" \label #'markC + \pageBreak + + \label #'firstScore + \score { + { c'2 c' + \mark \markup { A (page \concat { \page-ref #'markA "0" "?" ) }} \label #'markA + c' c' + \pageBreak + \mark "B" \label #'markB + d' d' + d' d' + \once \override Score . RehearsalMark #'break-visibility = #begin-of-line-invisible + \mark "C" \label #'markC + } + \header { piece = "First score" } } - \header { piece = "First score" } } \ No newline at end of file diff --git a/input/regression/toc.ly b/input/regression/toc.ly new file mode 100644 index 0000000000..e6164ea602 --- /dev/null +++ b/input/regression/toc.ly @@ -0,0 +1,29 @@ +\version "2.11.26" + +\header { + texidoc = "A table of contents is included using +@code{\\markuplines \\table-of-contents}. The toc items are added with +the @code{\\tocItem} command." +} + +#(set-default-paper-size "a6") + +\book { + \markuplines \table-of-contents + \pageBreak + + \tocItem \markup "The first score" + \score { + { + c'1 \pageBreak + \mark "A" \tocItem \markup "Mark A" + d' + } + } + \pageBreak + \tocItem \markup "The second score" + \score { + { e' } + \header { piece = "Second score" } + } +} \ No newline at end of file diff --git a/ly/declarations-init.ly b/ly/declarations-init.ly index 364068c043..b8c36e4f33 100644 --- a/ly/declarations-init.ly +++ b/ly/declarations-init.ly @@ -10,6 +10,7 @@ maxima = #(ly:make-duration -3 0) \include "markup-init.ly" \include "music-functions-init.ly" +\include "toc-init.ly" %% default note names are dutch \include "nederlands.ly" diff --git a/ly/toc-init.ly b/ly/toc-init.ly new file mode 100644 index 0000000000..334c983d0b --- /dev/null +++ b/ly/toc-init.ly @@ -0,0 +1,59 @@ +\version "2.11.26" + +%% defined later, in a closure +#(define-public (add-toc-item! markup-symbol text) + #f) +#(define-public (toc-items) + #f) + +#(let ((toc-item-list (list))) + (set! add-toc-item! + (lambda (markup-symbol text) + (let ((label (gensym "toc"))) + (set! toc-item-list + (cons (list label markup-symbol text) + toc-item-list)) + (make-music 'EventChord + 'page-marker #t + 'page-label label + 'elements (list (make-music 'LabelEvent + 'page-label label)))))) + (set! toc-items (lambda () + (reverse toc-item-list)))) + +\paper { + tocTitleMarkup = \markup \huge \column { + \fill-line { \null "Table of Contents" \null } + \hspace #1 + } + tocItemMarkup = \markup \fill-line { + \fromproperty #'toc:text \fromproperty #'toc:page + } +} + +#(define-markup-list-command (table-of-contents layout props) () + "Outputs the table of contents, using the paper variable +@code{tocTitleMarkup} for its title, then the list of lines +built using the @code{tocItem} music function +Usage: @code{\\markuplines \\table-of-contents}" + (cons (interpret-markup layout props + (ly:output-def-lookup layout 'tocTitleMarkup)) + (space-lines (chain-assoc-get 'baseline-skip props) + (map (lambda (toc-item) + (let ((label (car toc-item)) + (toc-markup (cadr toc-item)) + (text (caddr toc-item))) + (interpret-markup + layout + (cons (list (cons 'toc:page + (markup #:page-ref label "XXX" "?")) + (cons 'toc:text text)) + props) + (ly:output-def-lookup layout toc-markup)))) + (toc-items))))) + +tocItem = +#(define-music-function (parser location text) (markup?) + "Add a line to the table of content, using the @code{tocItemMarkup} paper +variable markup" + (add-toc-item! 'tocItemMarkup text)) diff --git a/scm/define-markup-commands.scm b/scm/define-markup-commands.scm index 956bd817bf..5405aff312 100644 --- a/scm/define-markup-commands.scm +++ b/scm/define-markup-commands.scm @@ -1493,7 +1493,7 @@ when @var{label} is not found." ;; Markup list commands ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define (space-lines baseline-skip lines) +(define-public (space-lines baseline-skip lines) (map (lambda (line) (stack-lines DOWN 0.0 (/ baseline-skip 2.0) (list (ly:make-stencil "" (cons 0 0) (cons 0 0)) -- 2.39.2