--- /dev/null
+\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" "?"))))
+
+\markup \huge \fill-line { \null "Title Page" \null }
+
+\pageBreak
+
+\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"
+} \label #'toc
+
+\pageBreak
+
+\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" }
+} \label #'firstScore
\ No newline at end of file
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)
virtual void finalize ();
DECLARE_TRANSLATOR_LISTENER (break);
+ DECLARE_TRANSLATOR_LISTENER (label);
DECLARE_ACKNOWLEDGER (item);
DECLARE_ACKNOWLEDGER (note_spacing);
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_;
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 {
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++)
{
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_->paper_->set_variable (ly_symbol2scm ("label-page-table"), label_page_table);
ret = scm_reverse (ret);
return ret;
}
#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 ();
}
#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 ();
}
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;
}
{
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;
+}
+
+
}
}
+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)
{
}
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)))
{
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 ()
{
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_);
first_ = false;
break_events_.clear ();
-
+ label_events_.clear ();
SCM mpos = get_property ("measurePosition");
SCM barnum = get_property ("internalBarNumber");
%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
| 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);
}
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));
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);
(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
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
;; 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.
(m (interpret-markup layout props arg)))
(bracketify-stencil m Y th (* 2.5 th) th)))
\f
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; 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* ((table (ly:output-def-lookup layout 'label-page-table))
+ (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)))
(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.
no-origin
placebox
unknown
+
+ delay-stencil-evaluation
))
;; TODO:
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