[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [patch] \label, page references
From: |
Nicolas Sceaux |
Subject: |
Re: [patch] \label, page references |
Date: |
Sun, 27 May 2007 22:04:09 +0200 |
User-agent: |
Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (darwin) |
Han-wen,
Here is a new patch:
- the \label command can be used at top-level or inside music;
- for labels inside music: the paper_column_engraver handles
label-events and fills the labels property of the paper column;
- for top-level labels: Paper_book::get_system_specs() fill the labels
property of the previous prob or of the first column of the previous
paper_score;
- when systems are built, the labels of their columns are collected to
set the system labels property;
- in Page_breaking::make_pages(), a label->page-number table is built,
and stored in the labels_ slot of the paper-book object;
- the \page-ref markup command accesses the paper-book object by its
props argument, and then the label/page-number table using a
ly:paper-book-labels accessor. This evaluation of the stencil is
postponed to the layout output phase. A user-supplied gauge is used
in the mean time to estimate the stencil dimensions.
A MARKUP_HEAD_SCM0_MARKUP1_MARKUP2 token has been added to the parser
for this new markup command.
The regression test illustrates how this can be used for a table of
contents.
However, an major issue is remaining: only top-level markups can access
the paper-book instance, and thus the labels table. (With little effort,
page headers and footers could also do it). This means that \page-ref
won't work in a TextScript. I can't find a way to make that possible,
other than by modifying the paper instance. (Grobs can't access the
paper-book, do they?).
>> + else if (Prob * markup = unsmob_prob (scm_car (l)))
>> + labels = markup->get_property ("labels");
>> +
>
> This looks fishy; the type checking should be stricter, music is a prob too.
I haven't addressed this. Whatever the actual type of the prob that is
found here (this is in Page_breaking::make_pages), we would like to
collect the labels anyway, no? I've renamed the variable prob.
nicolas
diff --git a/input/regression/page-label.ly b/input/regression/page-label.ly
new file mode 100644
index 0000000..7adf975
--- /dev/null
+++ b/input/regression/page-label.ly
@@ -0,0 +1,32 @@
+\version "2.11.24"
+
+\header {
+ texidoc = "Page labels may be placed inside music or at top-level,
+and refered to in markups."
+}
+
+#(set-default-paper-size "a6")
+
+#(define-markup-command (toc-line layout props label text) (symbol? markup?)
+ (interpret-markup layout props
+ (markup #:fill-line (text #:page-ref label "8" "?"))))
+
+\score {
+ { c'1 c'1 \pageBreak
+ \mark "A" \label #'markA d'
+ \mark "B" \label #'markB d'2
+ \once \override Score . RehearsalMark #'break-visibility =
#begin-of-line-invisible
+ \mark "C" \label #'markC
+ }
+ \header { piece = "First score" }
+} \label #'firstScore
+\pageBreak
+\markup \column {
+ \large \fill-line { \null "Table of contents" \null }
+ \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"
+ \toc-line #'toc "Table of contents"
+} \label #'toc
diff --git a/lily/include/page-marker.hh b/lily/include/page-marker.hh
index a925a6c..69962e6 100644
--- a/lily/include/page-marker.hh
+++ b/lily/include/page-marker.hh
@@ -17,12 +17,17 @@ class Page_marker
SCM symbol_; /* either 'page-turn-permission or 'page-break-permission */
SCM permission_; /* 'force, 'allow, or '() */
+ SCM label_; /* bookmarking label (a symbol) */
public:
- Page_marker (SCM symbol, SCM permission);
+ Page_marker ();
+ void set_permission (SCM symbol, SCM permission);
+ void set_label (SCM label);
+
SCM permission_symbol ();
SCM permission_value ();
+ SCM label ();
};
DECLARE_UNSMOB (Page_marker, page_marker)
diff --git a/lily/include/paper-book.hh b/lily/include/paper-book.hh
index 4ea1927..25a4d6f 100644
--- a/lily/include/paper-book.hh
+++ b/lily/include/paper-book.hh
@@ -32,6 +32,7 @@ public:
SCM header_0_;
SCM scores_;
Output_def *paper_;
+ SCM labels_;
Paper_book ();
diff --git a/lily/include/paper-column-engraver.hh
b/lily/include/paper-column-engraver.hh
index 793d085..fbe51a5 100644
--- a/lily/include/paper-column-engraver.hh
+++ b/lily/include/paper-column-engraver.hh
@@ -31,6 +31,7 @@ protected:
virtual void finalize ();
DECLARE_TRANSLATOR_LISTENER (break);
+ DECLARE_TRANSLATOR_LISTENER (label);
DECLARE_ACKNOWLEDGER (item);
DECLARE_ACKNOWLEDGER (note_spacing);
@@ -38,6 +39,7 @@ protected:
System *system_;
vector<Stream_event*> break_events_;
+ vector<Stream_event*> label_events_;
int breaks_; // used for stat printing
Paper_column *command_column_;
Paper_column *musical_column_;
diff --git a/lily/lexer.ll b/lily/lexer.ll
index 66457f4..ec17fb3 100644
--- a/lily/lexer.ll
+++ b/lily/lexer.ll
@@ -536,6 +536,8 @@ BOM_UTF8 \357\273\277
return MARKUP_HEAD_SCM0_MARKUP1;
else if (tag == ly_symbol2scm
("scheme0-scheme1-markup2"))
return MARKUP_HEAD_SCM0_SCM1_MARKUP2;
+ else if (tag == ly_symbol2scm
("scheme0-markup1-markup2"))
+ return MARKUP_HEAD_SCM0_MARKUP1_MARKUP2;
else if (tag == ly_symbol2scm
("scheme0-scheme1-scheme2"))
return MARKUP_HEAD_SCM0_SCM1_SCM2;
else {
diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc
index 46a1eed..87aefc7 100644
--- a/lily/page-breaking.cc
+++ b/lily/page-breaking.cc
@@ -235,6 +235,7 @@ Page_breaking::make_pages (vector<vsize>
SCM book = book_->self_scm ();
int first_page_number = robust_scm2int (book_->paper_->c_variable
("first-page-number"), 1);
SCM ret = SCM_EOL;
+ SCM label_page_table = SCM_EOL;
for (vsize i = 0; i < lines_per_page.size (); i++)
{
@@ -246,10 +247,28 @@ Page_breaking::make_pages (vector<vsize>
SCM page = scm_apply_0 (make_page,
scm_list_n (book, lines, page_num, rag, last,
SCM_UNDEFINED));
+ /* collect labels */
+ for (SCM l = lines ; scm_is_pair (l) ; l = scm_cdr (l))
+ {
+ SCM labels = SCM_EOL;
+ if (Grob * line = unsmob_grob (scm_car (l)))
+ {
+ System *system = dynamic_cast<System*> (line);
+ labels = system->get_property ("labels");
+ }
+ else if (Prob *prob = unsmob_prob (scm_car (l)))
+ labels = prob->get_property ("labels");
+
+ for (SCM lbls = labels ; scm_is_pair (lbls) ; lbls = scm_cdr (lbls))
+ label_page_table = scm_cons (scm_cons (scm_car (lbls), page_num),
+ label_page_table);
+ }
+
scm_apply_1 (page_stencil, page, SCM_EOL);
ret = scm_cons (page, ret);
systems = scm_list_tail (systems, line_count);
}
+ book_->labels_ = label_page_table;
ret = scm_reverse (ret);
return ret;
}
diff --git a/lily/page-marker-scheme.cc b/lily/page-marker-scheme.cc
index 3278a7b..f2450be 100644
--- a/lily/page-marker-scheme.cc
+++ b/lily/page-marker-scheme.cc
@@ -8,12 +8,24 @@
#include "page-marker.hh"
-LY_DEFINE (ly_make_page_marker, "ly:make-page-marker",
+LY_DEFINE (ly_make_page_permission_marker, "ly:make-page-permission-marker",
2, 0, 0,
(SCM symbol, SCM permission),
"Return page marker with page breaking and turning permissions.")
{
LY_ASSERT_TYPE (ly_is_symbol, symbol, 1);
- Page_marker *page_marker = new Page_marker (symbol, permission);
+ Page_marker *page_marker = new Page_marker ();
+ page_marker->set_permission (symbol, permission);
+ return page_marker->unprotect ();
+}
+
+LY_DEFINE (ly_make_page_label_marker, "ly:make-page-label-marker",
+ 1, 0, 0,
+ (SCM label),
+ "Return page marker with label.")
+{
+ LY_ASSERT_TYPE (ly_is_symbol, label, 1);
+ Page_marker *page_marker = new Page_marker ();
+ page_marker->set_label (label);
return page_marker->unprotect ();
}
diff --git a/lily/page-marker.cc b/lily/page-marker.cc
index dd43c35..11b1999 100644
--- a/lily/page-marker.cc
+++ b/lily/page-marker.cc
@@ -9,10 +9,11 @@
#include "page-marker.hh"
#include "ly-smobs.icc"
-Page_marker::Page_marker (SCM symbol, SCM permission)
+Page_marker::Page_marker ()
{
- symbol_ = symbol;
- permission_ = permission;
+ symbol_ = SCM_EOL;
+ permission_ = SCM_EOL;
+ label_ = SCM_EOL;
smobify_self ();
}
@@ -30,6 +31,7 @@ Page_marker::mark_smob (SCM smob)
Page_marker *pm = (Page_marker *) SCM_CELL_WORD_1 (smob);
scm_gc_mark (pm->symbol_);
scm_gc_mark (pm->permission_);
+ scm_gc_mark (pm->label_);
return SCM_EOL;
}
@@ -53,3 +55,24 @@ Page_marker::permission_value ()
{
return permission_;
}
+
+SCM
+Page_marker::label ()
+{
+ return label_;
+}
+
+void
+Page_marker::set_permission (SCM symbol, SCM permission)
+{
+ symbol_ = symbol;
+ permission_ = permission;
+}
+
+void
+Page_marker::set_label (SCM label)
+{
+ label_ = label;
+}
+
+
diff --git a/lily/paper-book-scheme.cc b/lily/paper-book-scheme.cc
index 94bb17f..f366d88 100644
--- a/lily/paper-book-scheme.cc
+++ b/lily/paper-book-scheme.cc
@@ -56,3 +56,11 @@ LY_DEFINE (ly_paper_book_paper, "ly:pape
Paper_book *pbook = unsmob_paper_book (pb);
return pbook->paper_->self_scm ();
}
+
+LY_DEFINE (ly_paper_book_labels, "ly:paper-book-labels",
+ 1, 0, 0, (SCM pb),
+ "Return the labels - page numbers table of book PB.")
+{
+ LY_ASSERT_SMOB (Paper_book, pb, 1);
+ return unsmob_paper_book (pb)->labels_;
+}
diff --git a/lily/paper-book.cc b/lily/paper-book.cc
index 95be368..df51cf0 100644
--- a/lily/paper-book.cc
+++ b/lily/paper-book.cc
@@ -29,6 +29,7 @@ Paper_book::Paper_book ()
scores_ = SCM_EOL;
performances_ = SCM_EOL;
systems_ = SCM_BOOL_F;
+ labels_ = SCM_EOL;
paper_ = 0;
smobify_self ();
@@ -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->labels_);
return b->systems_;
}
@@ -270,6 +272,24 @@ set_system_penalty (SCM sys, SCM header)
}
}
+void
+set_label (SCM sys, SCM label)
+{
+ if (Paper_score *ps = dynamic_cast<Paper_score*> (unsmob_music_output (sys)))
+ {
+ vector<Grob*> cols = ps->get_columns ();
+ if (cols.size ())
+ {
+ Paper_column *col = dynamic_cast<Paper_column*> (cols[0]);
+ col->set_property ("labels", scm_cons (label, col->get_property
("labels")));
+ Paper_column *col_right = col->find_prebroken_piece (RIGHT);
+ col_right->set_property ("labels", scm_cons (label,
col_right->get_property ("labels")));
+ }
+ }
+ else if (Prob *pb = unsmob_prob (sys))
+ pb->set_property ("labels", scm_cons (label, pb->get_property ("labels")));
+}
+
SCM
Paper_book::get_score_title (SCM header)
{
@@ -310,8 +330,9 @@ Paper_book::get_system_specs ()
}
SCM page_properties
- = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"),
- paper_->self_scm ());
+ = scm_cons (scm_list_1 (scm_cons (ly_symbol2scm ("paper-book"), self_scm
())),
+ scm_call_1 (ly_lily_module_constant
("layout-extract-page-properties"),
+ paper_->self_scm ()));
SCM header = SCM_EOL;
for (SCM s = scm_reverse (scores_); scm_is_pair (s); s = scm_cdr (s))
@@ -324,11 +345,22 @@ Paper_book::get_system_specs ()
}
else if (Page_marker *page_marker = unsmob_page_marker (scm_car (s)))
{
- /* a page marker: set previous element page break or turn permission
*/
- if (scm_is_pair (system_specs))
- set_page_permission (scm_car (system_specs),
- page_marker->permission_symbol (),
- page_marker->permission_value ());
+ /* page markers are used to set page breaking/turning permission,
+ or to place bookmarking labels */
+ if (scm_is_symbol (page_marker->permission_symbol ()))
+ {
+ /* set previous element page break or turn permission */
+ if (scm_is_pair (system_specs))
+ set_page_permission (scm_car (system_specs),
+ page_marker->permission_symbol (),
+ page_marker->permission_value ());
+ }
+ if (scm_is_symbol (page_marker->label ()))
+ {
+ /* set previous element label */
+ if (scm_is_pair (system_specs))
+ set_label (scm_car (system_specs), page_marker->label ());
+ }
}
else if (Music_output *mop = unsmob_music_output (scm_car (s)))
{
diff --git a/lily/paper-column-engraver.cc b/lily/paper-column-engraver.cc
index d583bc5..6dbafb5 100644
--- a/lily/paper-column-engraver.cc
+++ b/lily/paper-column-engraver.cc
@@ -116,6 +116,13 @@ Paper_column_engraver::listen_break (Str
break_events_.push_back (ev);
}
+IMPLEMENT_TRANSLATOR_LISTENER (Paper_column_engraver, label);
+void
+Paper_column_engraver::listen_label (Stream_event *ev)
+{
+ label_events_.push_back (ev);
+}
+
void
Paper_column_engraver::process_music ()
{
@@ -150,6 +157,13 @@ Paper_column_engraver::process_music ()
command_column_->set_property (perm_str.c_str (), perm);
}
+ for (vsize i = 0 ; i < label_events_.size () ; i ++)
+ {
+ SCM label = label_events_[i]->get_property ("label");
+ SCM labels = command_column_->get_property ("labels");
+ command_column_->set_property ("labels", scm_cons (label, labels));
+ }
+
bool start_of_measure = (last_moment_.main_part_ != now_mom ().main_part_
&& !measure_position (context ()).main_part_);
diff --git a/lily/parser.yy b/lily/parser.yy
index f901a6d..18668de 100644
--- a/lily/parser.yy
+++ b/lily/parser.yy
@@ -279,6 +279,7 @@ If we give names, Bison complains.
%token <scm> MARKUP_HEAD_SCM0_MARKUP1
%token <scm> MARKUP_HEAD_SCM0_SCM1
%token <scm> MARKUP_HEAD_SCM0_SCM1_MARKUP2
+%token <scm> MARKUP_HEAD_SCM0_MARKUP1_MARKUP2
%token <scm> MARKUP_HEAD_SCM0_SCM1_SCM2
%token <scm> MARKUP_IDENTIFIER
%token <scm> MUSIC_FUNCTION
@@ -2293,6 +2294,9 @@ simple_markup:
| MARKUP_HEAD_SCM0_SCM1 embedded_scm embedded_scm {
$$ = scm_list_3 ($1, $2, $3);
}
+ | MARKUP_HEAD_SCM0_MARKUP1_MARKUP2 embedded_scm markup markup {
+ $$ = scm_list_4 ($1, $2, $3, $4);
+ }
| MARKUP_HEAD_EMPTY {
$$ = scm_list_1 ($1);
}
diff --git a/lily/stencil-interpret.cc b/lily/stencil-interpret.cc
index f6deee0..8afc330 100644
--- a/lily/stencil-interpret.cc
+++ b/lily/stencil-interpret.cc
@@ -21,6 +21,11 @@ interpret_stencil_expression (SCM expr,
SCM head = scm_car (expr);
+ if (head == ly_symbol2scm ("delay-stencil-evaluation"))
+ {
+ interpret_stencil_expression (scm_force (scm_cadr (expr)), func,
func_arg, o);
+ return;
+ }
if (head == ly_symbol2scm ("translate-stencil"))
{
o += ly_scm2offset (scm_cadr (expr));
diff --git a/lily/system.cc b/lily/system.cc
index e700615..ef0e067 100644
--- a/lily/system.cc
+++ b/lily/system.cc
@@ -227,11 +227,17 @@ System::break_into_pieces (vector<Column
system->set_bound (LEFT, c[0]);
system->set_bound (RIGHT, c.back ());
+ SCM system_labels = SCM_EOL;
for (vsize j = 0; j < c.size (); j++)
{
c[j]->translate_axis (breaking[i].config_[j], X_AXIS);
dynamic_cast<Paper_column *> (c[j])->system_ = system;
+ /* collect the column labels */
+ SCM col_labels = c[j]->get_property ("labels");
+ if (scm_is_pair (col_labels))
+ system_labels = scm_append (scm_list_2 (col_labels, system_labels));
}
+ system->set_property ("labels", system_labels);
set_loose_columns (system, &breaking[i]);
broken_intos_.push_back (system);
diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly
index 8360dcb..ea28ba4 100644
--- a/ly/music-functions-init.ly
+++ b/ly/music-functions-init.ly
@@ -298,7 +298,15 @@ killCues =
(if (string? (ly:music-property mus 'quoted-music-name))
(ly:music-property mus 'element)
mus)) music))
-
+
+label =
+#(define-music-function (parser location label) (symbol?)
+ (_i "Place a bookmarking label, either at top-level or inside music.")
+ (make-music 'EventChord
+ 'page-marker #t
+ 'label label
+ 'elements (list (make-music 'LabelEvent
+ 'label label))))
makeClusters =
#(define-music-function
diff --git a/scm/define-event-classes.scm b/scm/define-event-classes.scm
index 2bda1a2..f5d7b79 100644
--- a/scm/define-event-classes.scm
+++ b/scm/define-event-classes.scm
@@ -16,7 +16,7 @@
OneTimeStep Finish))
(music-event . (annotate-output-event
arpeggio-event breathing-event extender-event span-event
- rhythmic-event dynamic-event break-event percent-event
+ rhythmic-event dynamic-event break-event label-event percent-event
key-change-event string-number-event stroke-finger-event tie-event
part-combine-event
beam-forbid-event script-event
tremolo-event bend-after-event fingering-event glissando-event
@@ -86,7 +86,7 @@
;; All leaf event classes that no translator listens to
;; directly. Avoids printing a warning.
(define unlistened-music-event-classes
- '(harmonic-event line-break-event page-break-event page-turn-event
+ '(harmonic-event line-break-event page-break-event page-turn-event
label-event
solo-one-event solo-two-event skip-event unisono-event))
;; produce neater representation of music event tree.
diff --git a/scm/define-markup-commands.scm b/scm/define-markup-commands.scm
index 8a0853e..8198cbc 100644
--- a/scm/define-markup-commands.scm
+++ b/scm/define-markup-commands.scm
@@ -1463,8 +1463,31 @@ that."
(m (interpret-markup layout props arg)))
(bracketify-stencil m Y th (* 2.5 th) th)))
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; size indications arrow
+;; Delayed markup evaluation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(define-builtin-markup-command (page-ref layout props label gauge default)
+ (symbol? markup? markup?)
+ "Reference to a page number. @var{label} is the label set on the referenced
+page (using the @code{\\label} command), @var{gauge} a markup used to estimate
+the maximum width of the page number, and @var{default} the value to display
+when @var{label} is not found."
+ (let* ((gauge-stencil (interpret-markup layout props gauge))
+ (x-ext (ly:stencil-extent gauge-stencil X))
+ (y-ext (ly:stencil-extent gauge-stencil Y)))
+ (ly:make-stencil
+ `(delay-stencil-evaluation
+ ,(delay (ly:stencil-expr
+ (let* ((paper-book (chain-assoc-get 'paper-book props #f))
+ (table (and paper-book (ly:paper-book-labels
paper-book)))
+ (label-page (and (list? table) (assoc label table)))
+ (page-number (and label-page (cdr label-page)))
+ (page-markup (if page-number (format "~a" page-number)
default))
+ (page-stencil (interpret-markup layout props
page-markup))
+ (gap (- (interval-length x-ext)
+ (interval-length (ly:stencil-extent page-stencil
X)))))
+ (interpret-markup layout props
+ (markup #:concat (#:hspace gap
page-markup)))))))
+ x-ext
+ y-ext)))
diff --git a/scm/define-music-types.scm b/scm/define-music-types.scm
index 03ac6f8..c6a83c4 100644
--- a/scm/define-music-types.scm
+++ b/scm/define-music-types.scm
@@ -238,6 +238,9 @@ Syntax: @code{\\key } @var{name} @var{sc
(to-relative-callback . ,(lambda (x p) p))
(types . (general-music key-change-event event))
))
+ (LabelEvent
+ . ((description . "Place a bookmarking label")
+ (types . (general-music label-event event))))
(LaissezVibrerEvent
. ((description . "Don't damp this chord.
diff --git a/scm/define-stencil-commands.scm b/scm/define-stencil-commands.scm
index 9b0b942..6a027b6 100644
--- a/scm/define-stencil-commands.scm
+++ b/scm/define-stencil-commands.scm
@@ -37,6 +37,8 @@
no-origin
placebox
unknown
+
+ delay-stencil-evaluation
))
;; TODO:
diff --git a/scm/lily-library.scm b/scm/lily-library.scm
index 7a1141d..5435533 100644
--- a/scm/lily-library.scm
+++ b/scm/lily-library.scm
@@ -70,17 +70,21 @@
value
#f)))
(cond ((music-property 'page-marker)
- ;; a page marker: set page break/turn permissions
- (for-each (lambda (symbol)
- (let ((permission (music-property symbol)))
- (if (symbol? permission)
- (score-handler
- (ly:make-page-marker symbol
- (if (eqv? 'forbid permission)
- '()
- permission))))))
- (list 'line-break-permission 'page-break-permission
- 'page-turn-permission)))
+ ;; a page marker: set page break/turn permissions or label
+ (begin
+ (let ((label (music-property 'label)))
+ (if (symbol? label)
+ (score-handler (ly:make-page-label-marker label))))
+ (for-each (lambda (symbol)
+ (let ((permission (music-property symbol)))
+ (if (symbol? permission)
+ (score-handler
+ (ly:make-page-permission-marker symbol
+ (if (eqv? 'forbid
permission)
+ '()
+
permission))))))
+ (list 'line-break-permission 'page-break-permission
+ 'page-turn-permission))))
((not (music-property 'void))
;; a regular music expression: make a score with this music
;; void music is discarded