2005-09-27 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ * lily/book.cc (process): bugfix: flip ?: cases.
+
+ * Documentation/user/changing-defaults.itely (Difficult tweaks):
+ add outputProperty.
+
+ * ly/music-functions-init.ly: add outputProperty music function.
+
+ * scm/paper.scm (set-paper-dimension-variables): add pagetopspace
+
+ * scm/page-layout.scm (ly:optimal-page-breaks): read next-space
+ and next-padding.
+ (optimal-page-breaks): rename from ly:optimal-page-breaks.
+
+ * lily/paper-system-scheme.cc (LY_DEFINE): new function.
+
+ * lily/paper-system.cc (internal_get_property): new function.
+
+ * Documentation/user/global.itely (Vertical spacing): refer to page-spacing.ly
+
+ * scm/page-layout.scm (ly:optimal-page-breaks): add support for
+ pagetopspace
+
+ * input/regression/page-spacing.ly: new file.
+
+ * input/regression/page-top-space.ly: new file.
+
* lily/spacing-spanner.cc: cmath -> math.h
* lily/paper-system.cc (read_left_bound): new function. Read
any context of type @var{type}, regardless of its given name.
This variant is used with music expressions that can be interpreted at
-several levels. For example, the @code{\applyoutput} command (see
+several levels. For example, the @code{\applyOutput} command (see
@ref{Running a function on all layout objects}). Without an explicit
@code{\context}, it is usually applied to @context{Voice}
@example
-\applyoutput #@var{function} % apply to Voice
+\applyOutput #@var{function} % apply to Voice
@end example
To have it interpreted at the @context{Score} or @context{Staff} level use
these forms
@example
-\context Score \applyoutput #@var{function}
-\context Staff \applyoutput #@var{function}
+\context Score \applyOutput #@var{function}
+\context Staff \applyOutput #@var{function}
@end example
@node Difficult tweaks
@subsection Difficult tweaks
-There are two classes of difficult adjustments. First, when there are
+There are a few classes of difficult adjustments.
+
+@itemize @bullet
+First, when there are
several of the same objects at one point, and you want to adjust only
-one. For example, if you want to change only one note head in a chord.
+one.
+
+For example, if you want to change only one note head in a chord.
-In this case, the @code{\applyoutput} function must be used. The
+In this case, the @code{\applyOutput} function must be used. The
next example defines a Scheme function @code{set-position-font-size}
that sets the @code{font-size} property, but only
on objects that have @internalsref{note-head-interface} and are at the
\relative {
c
- \applyoutput #(set-position-font-size -2 4)
+ \applyOutput #(set-position-font-size -2 4)
<c e g>
}
@end lilypond
A similar technique can be used for accidentals. In that case, the
function should check for @code{accidental-interface}.
+@item
Another difficult adjustment is the appearance of spanner objects,
such as slur and tie. Initially, only one of these objects is created,
and they can be adjusted with the normal mechanism. However, in some
is one. For example, if using this with @code{Slur},
@code{Slur::after_line_breaking} should also be called.
+
+@item Some objects cannot be changed with @code{\override} for
+technical reasons. Examples of those are @code{NonMusicalPaperColumn}
+and @code{PaperColumn}. They can be changed with the
+@code{\outputProperty} function, which works similar to @code{\once
+\override}, but uses a different syntax,
+
+@example
+\outputProperty
+#"Score.NonMusicalPaperColumn" % Grob name
+#'line-break-system-details % Property name
+#'((next-padding . 20)) % Value
+@end example
+
+@end itemize
@item footsep
Distance between the bottom-most music system and the page footer.
+@cindex @code{pagetopspace}
+Distance from the top of the printable area to the center of the first
+staff. This only works for staves which are vertically small. Big staves
+are set with the top of their bounding box aligned to the top of the
+printable area.
+
@cindex @code{raggedbottom}
@item raggedbottom
If set to true, systems will not be spread across the page.
@end example
+@c let's wait for a some comments before writing more.
+
+The vertical spacing on a page can also be changed for each system individually.
+Some examples are found in the example file
+@inputfileref{input/regression/,page-spacing.ly}.
+
+
@seealso
Internals: Vertical alignment of staves is handled by the
specifying the vertical extent are described in connection with
the @internalsref{Axis_group_engraver}.
+Example files: @inputfileref{input/regression/,page-spacing.ly}.
+
+
@refbugs
@code{minimumVerticalExtent} is syntactic sugar for setting
@code{forced-distance} cannot be changed per system.
-
@node Horizontal spacing
@subsection Horizontal Spacing
-The spacing engine translates differences in durations into
-stretchable distances (``springs'') of differring lengths. Longer
-durations get more space, shorter durations get less. The shortest
-durations get a fixed amount of space (which is controlled by
-@code{shortest-duration-space} in the @internalsref{SpacingSpanner} object).
-The longer the duration, the more space it gets: doubling a
+The spacing engine translates differences in durations into stretchable
+distances (``springs'') of differring lengths. Longer durations get
+more space, shorter durations get less. The shortest durations get a
+fixed amount of space (which is controlled by
+@code{shortest-duration-space} in the @internalsref{SpacingSpanner}
+object). The longer the duration, the more space it gets: doubling a
duration adds a fixed amount (this amount is controlled by
@code{spacing-increment}) of space to the note.
<d f g>
\once \override NoteHead #'style = #'cross
<d f g>
- \applyoutput #mc-squared
+ \applyOutput #mc-squared
<d f g>
<<
{ d8[ es-( fis^^ g] fis2-) }
- \repeat unfold 5 { \applyoutput #mc-squared s8 }
+ \repeat unfold 5 { \applyOutput #mc-squared s8 }
>>
}
@end lilypond
@cindex calling code on layout objects
-@cindex @code{\applyoutput}
+@cindex @code{\applyOutput}
-The most versatile way of tuning an object is @code{\applyoutput}. Its
+The most versatile way of tuning an object is @code{\applyOutput}. Its
syntax is
@example
-\applyoutput @var{proc}
+\applyOutput @var{proc}
@end example
@noindent
@itemize @bullet
@item the layout object itself,
@item the context where the layout object was created, and
-@item the context where @code{\applyoutput} is processed.
+@item the context where @code{\applyOutput} is processed.
@end itemize
@internalsref{NoteHead} event, and for a @internalsref{Stem} object,
this is a @internalsref{NoteHead} object.
-Here is a function to use for @code{\applyoutput}; it blanks
+Here is a function to use for @code{\applyOutput}; it blanks
note-heads on the center-line:
@example
--- /dev/null
+
+\header {
+
+ texidoc = "By setting properties in NonMusicalPaperColumn, vertical
+spacing of page layout can be adjusted.
+
+For technical reasons, @code{outputProperty} has to be used for
+setting properties on individual object. @code{\override} may still be
+used for global overrides.
+
+"
+
+}
+
+\version "2.7.10"
+
+#(set-global-staff-size 11)
+
+\book {
+ \score {
+ \relative c'' \new StaffGroup <<
+ \new Voice {
+ c1\break
+
+ \outputProperty
+ #"Score.NonMusicalPaperColumn"
+ #'line-break-system-details
+ #'((Y-extent . (-30 . 10)))
+ c^"This system has big extents (property Y-extent)"\break
+
+ c\break
+ \outputProperty
+ #"Score.NonMusicalPaperColumn"
+ #'line-break-system-details
+ #'((next-padding . 20))
+
+ c^"This system is followed by padding, ie unstretchable space. (property next-padding)" \break
+ \outputProperty
+ #"Score.NonMusicalPaperColumn"
+ #'line-break-system-details
+ #'((next-space . 20))
+ c^"This system is followed by stretchable space (property next-space)"\break
+ c\break
+ c\break
+ \outputProperty
+ #"Score.NonMusicalPaperColumn" #'line-break-system-details
+ #'((bottom-space . 25.0))
+ c^"This system has 25 staff space to the bottom of the page. (property bottom-space)"\break
+
+
+ }
+ { c1 c c c c c c c }
+ >>
+ }
+ \paper {
+ raggedlastbottom = ##f
+ betweensystemspace = 1.0
+ }
+}
--- /dev/null
+\header {
+
+ texidoc = "By setting @code{pagetopspace,} the Y position of the
+first system can be forced to be uniform."
+
+}
+\version "2.7.11"
+
+\book {
+ \score {
+
+ \relative {
+ c1\break\pageBreak
+ c1\break\pageBreak
+ c1
+ \break\pageBreak
+ \override TextScript #'padding = #20
+ c1^"bla"
+ }
+ }
+
+ \paper {
+ pagetopspace = 3 \cm
+ }
+}
+
if (score->error_found_)
return 0;
- Output_def *paper = paper_ ? default_paper : paper_;
+ Output_def *paper = paper_ ? paper_ : default_paper;
if (!paper)
return 0;
DECLARE_SMOBS (Paper_system,);
Stencil stencil_;
bool is_title_;
-
+ SCM details_;
public:
Interval staff_refpoints_;
Real break_before_penalty_;
void read_left_bound (Item*);
Stencil to_stencil () const;
SCM stencils () const;
+ SCM internal_get_property (SCM sym) const;
bool is_title () const;
Real break_before_penalty () const;
Interval staff_refpoints () const;
"should use a whole rest or a breve rest to represent 1 measure ",
/* create */ "MultiMeasureRest MultiMeasureRestNumber MultiMeasureRestText",
/* accept */ "multi-measure-rest-event multi-measure-text-event",
- /* read */ "currentBarNumber restNumberThreshold breakableSeparationItem currentCommandColumn measurePosition measureLength",
+ /* read */
+ "currentBarNumber "
+ "restNumberThreshold "
+ "breakableSeparationItem "
+ "currentCommandColumn "
+ "measurePosition "
+ "measureLength",
/* write */ "");
return ly_interval2scm (ps->staff_refpoints ());
}
+
+
+LY_DEFINE (ly_paper_system_property, "ly:paper-system-property",
+ 2, 1, 0, (SCM system, SCM sym, SCM dfault),
+ "Return the value for @var{sym}. Properties may be set by "
+ "setting the @code{line-break-system-details} property of "
+ "NonMusicalPaperColumn. If the property is not found, "
+ "return @var{dfault}, "
+ "or @code{'()} if undefined.")
+{
+ Paper_system *ps = unsmob_paper_system (system);
+ SCM_ASSERT_TYPE (ps, system, SCM_ARG1, __FUNCTION__, "paper-system");
+ if (dfault == SCM_UNDEFINED)
+ dfault = SCM_EOL;
+
+ SCM retval = ps->internal_get_property (sym);
+ if (retval == SCM_EOL)
+ return dfault;
+ else
+ return retval;
+}
+
+
Paper_system::mark_smob (SCM smob)
{
Paper_system *system = (Paper_system *) SCM_CELL_WORD_1 (smob);
+ scm_gc_mark (system->details_);
return system->stencil_.expr ();
}
break_before_penalty_
= robust_scm2double (left->get_property ("page-penalty"), 0.0);
- SCM details
+ details_
= left->get_property ("line-break-system-details");
SCM yext
- = scm_assoc (ly_symbol2scm ("Y-extent"), details);
+ = scm_assq (ly_symbol2scm ("Y-extent"), details_);
SCM staff_ext
- = scm_assoc (ly_symbol2scm ("refpoint-Y-extent"), details);
+ = scm_assq (ly_symbol2scm ("refpoint-Y-extent"), details_);
if (scm_is_pair (yext)
&& is_number_pair (scm_cdr (yext)))
}
}
+SCM
+Paper_system::internal_get_property (SCM sym) const
+{
+ SCM handle = scm_assq (sym, details_);
+ if (scm_is_pair (handle))
+ return scm_cdr (handle);
+ else
+ return SCM_EOL;
+}
+
+/*
+ todo: move to Paper_system property.
+ */
Interval
Paper_system::staff_refpoints () const
{
/* create */ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
/* accept */ "pedal-event",
/* read */ "currentCommandColumn "
- "pedalSostenutoStrings pedalSustainStrings "
- "pedalUnaCordaStrings pedalSostenutoStyle "
- "pedalSustainStyle pedalUnaCordaStyle",
+ "pedalSostenutoStrings "
+ "pedalSustainStrings "
+ "pedalUnaCordaStrings "
+ "pedalSostenutoStyle "
+ "pedalSustainStyle "
+ "pedalUnaCordaStyle",
/* write */ "");
void
Separating_line_group_engraver::process_music ()
{
-
if (!sep_span_)
{
sep_span_ = make_spanner ("SeparatingGroupSpanner", SCM_EOL);
ADD_ACKNOWLEDGER (Separating_line_group_engraver, item);
ADD_TRANSLATOR (Separating_line_group_engraver,
/* doc */ "Generates objects for computing spacing parameters.",
- /* create */ "SeparationItem SeparatingGroupSpanner StaffSpacing",
+
+ /* create */
+ "SeparationItem "
+ "SeparatingGroupSpanner "
+ "StaffSpacing",
/* accept */ "",
/* read */ "createSpacing",
/* write */ "breakableSeparationItem");
/* create */ "SpacingSpanner",
/* accept */ "",
- /* read */ "currentMusicalColumn currentCommandColumn proportionalNotationDuration",
+ /* read */
+ "currentMusicalColumn "
+ "currentCommandColumn "
+ "proportionalNotationDuration",
+
/* write */ "");
'procedure proc))
outputProperty =
-#(def-music-function (parser location name prop value)
- (symbol? symbol? scheme?)
+#(def-music-function (parser location name property value)
+ (string? symbol? scheme?)
- "Set @var{prop} to @var{value} in all grobs named @var{name} "
+ "Set @var{property} to @var{value} in all grobs named @var{name}.
+The @var{name} argument is a string of the form @code{\"Context.GrobName\"}
+or @code{\"GrobName\"}"
- (make-music 'ApplyOutputEvent
- 'origin location
- 'procedure
- (lambda (grob orig-context context)
- (if (equal?
- (cdr (assoc 'name (ly:grob-property grob 'meta)))
- name)
- (set! (ly:grob-property grob prop) value)
- ))))
+ (let*
+ ((name-components (string-split name #\.))
+ (context-name 'Bottom)
+ (grob-name #f))
+
+ (if (> 2 (length name-components))
+ (set! grob-name (string->symbol (car name-components)))
+ (begin
+ (set! grob-name (string->symbol (list-ref name-components 1)))
+ (set! context-name (string->symbol (list-ref name-components 0)))))
+
+ (context-spec-music
+ (make-music 'ApplyOutputEvent
+ 'origin location
+ 'procedure
+ (lambda (grob orig-context context)
+ (if (equal?
+ (cdr (assoc 'name (ly:grob-property grob 'meta)))
+ grob-name)
+ (set! (ly:grob-property grob property) value)
+ )))
+
+ context-name)))
breathe =
#(def-music-function (parser location) ()
%% staves themselves.
%%
betweensystemspace = #(* 20 mm)
-
+
+
%%
%% fixed space between systems.
%%
beforetitlespace = 10 \mm
betweentitlespace = 2 \mm
+
+ %%
+ %% Small staves are aligned so they come out on the same place on
+ %% across different pages.
+ %%
+ pagetopspace = #(* 12 mm)
+
+
raggedbottom = ##f
%%
(baseline-skip . 3)
(word-space . 0.6)))
- #(define page-breaking ly:optimal-page-breaks)
+ #(define page-breaking optimal-page-breaks)
#(define page-music-height default-page-music-height )
#(define page-make-stencil default-page-make-stencil )
;; - separate function for word-wrap style breaking?
;; - raggedbottom? raggedlastbottom?
-(define-public (ly:optimal-page-breaks
- lines paper-book)
+(define-public (optimal-page-breaks lines paper-book)
"Return pages as a list starting with 1st page. Each page is a list
of lines. "
user)))
(define (space-systems page-height lines ragged?)
- (let* ((inter-system-space
+ (let* ((global-inter-system-space
(ly:output-def-lookup paper 'betweensystemspace))
+ (top-space
+ (ly:output-def-lookup paper 'pagetopspace))
+ (global-fixed-dist (ly:output-def-lookup paper 'betweensystempadding))
+
(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))
- '()))))
- (real-extents
- (list->vector
- (append
- (map
- (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))))))
-
- (fixed-dist (ly:output-def-lookup paper 'betweensystempadding))
- (calc-spring
- (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-dist)
- (interval-start this-system-ext))))
- (title1? (and (vector-ref system-vector idx)
- (ly:paper-system-title? (vector-ref system-vector idx))))
- (title2? (and
- (vector-ref system-vector (1+ idx))
- (ly:paper-system-title? (vector-ref system-vector (1+ idx)))))
- (ideal (+
- (cond
- ((and title2? title1?)
- (ly:output-def-lookup paper 'betweentitlespace))
- (title1?
- (ly:output-def-lookup paper 'aftertitlespace))
- (title2?
- (ly:output-def-lookup paper 'beforetitlespace))
- (else inter-system-space))
- fixed))
- (hooke (/ 1 (- ideal fixed))))
- (list ideal hooke))))
-
- (springs (map calc-spring (iota (1- no-systems))))
- (calc-rod
- (lambda (idx)
- (let* ((this-system-ext (vector-ref real-extents idx))
- (next-system-ext (vector-ref real-extents (1+ idx)))
- (distance (max (- (+ (interval-end next-system-ext)
- fixed-dist)
- (interval-start this-system-ext)
- ) 0))
- (entry (list idx (1+ idx) distance)))
- entry)))
- (rods (map calc-rod (iota (1- no-systems))))
-
- ;; we don't set ragged based on amount space left.
- ;; raggedbottomlast = ##T is much more predictable
- (result (ly:solve-spring-rod-problem
- springs rods space
- ragged?))
-
- (force (car result))
- (positions
- (map (lambda (y)
- (+ y topskip))
- (cdr result))))
+ (staff-extents
+ (list->vector
+ (append (map ly:paper-system-staff-extents lines)
+ (if (= (length lines) 1)
+ '((0 . 0))
+ '()))))
+
+ (real-extents
+ (list->vector
+ (append
+ (map
+ (lambda (sys) (ly:paper-system-extent sys Y)) lines)
+ (if (= (length lines) 1)
+ '((0 . 0))
+ '()))))
+
+ (system-count (vector-length real-extents))
+ (topskip (max
+ (+
+ top-space
+ (interval-end (vector-ref staff-extents 0)))
+ (interval-end (vector-ref real-extents 0))
+ ))
+ (last-system (vector-ref system-vector (1- system-count)))
+ (bottom-space (if (ly:paper-system? last-system)
+ (ly:paper-system-property last-system 'bottom-space 0.0)
+ 0.0))
+ (space-left (- page-height
+ bottom-space
+ (apply + (map interval-length
+ (vector->list real-extents)))))
+
+ (space (- page-height
+ topskip
+ bottom-space
+ (- (interval-start
+ (vector-ref real-extents (1- system-count))))))
+
+ (calc-spring
+ (lambda (idx)
+ (let* (
+ (upper-system (vector-ref system-vector idx))
+ (between-space (ly:paper-system-property upper-system 'next-space
+ global-inter-system-space))
+ (fixed-dist (ly:paper-system-property upper-system 'next-padding
+ global-fixed-dist))
+
+ (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-dist)
+ (interval-start this-system-ext))))
+ (title1? (and (vector-ref system-vector idx)
+ (ly:paper-system-title? (vector-ref system-vector idx))))
+ (title2? (and
+ (vector-ref system-vector (1+ idx))
+ (ly:paper-system-title? (vector-ref system-vector (1+ idx)))))
+ (ideal (+
+ (cond
+ ((and title2? title1?)
+ (ly:output-def-lookup paper 'betweentitlespace))
+ (title1?
+ (ly:output-def-lookup paper 'aftertitlespace))
+ (title2?
+ (ly:output-def-lookup paper 'beforetitlespace))
+ (else between-space))
+ fixed))
+ (hooke (/ 1 (- ideal fixed))))
+ (list ideal hooke))))
+
+ (springs (map calc-spring (iota (1- system-count))))
+ (calc-rod
+ (lambda (idx)
+ (let* (
+ (upper-system (vector-ref system-vector idx))
+ (fixed-dist (ly:paper-system-property upper-system 'next-padding
+ global-fixed-dist))
+ (this-system-ext (vector-ref real-extents idx))
+ (next-system-ext (vector-ref real-extents (1+ idx)))
+
+ (distance (max (- (+ (interval-end next-system-ext)
+ fixed-dist)
+ (interval-start this-system-ext)
+ ) 0))
+ (entry (list idx (1+ idx) distance)))
+ entry)))
+ (rods (map calc-rod (iota (1- system-count))))
+
+ ;; we don't set ragged based on amount space left.
+ ;; raggedbottomlast = ##T is much more predictable
+ (result (ly:solve-spring-rod-problem
+ springs rods space
+ ragged?))
+
+ (force (car result))
+ (positions
+ (map (lambda (y)
+ (+ y topskip))
+ (cdr result))))
(if #f ;; debug.
(begin
- (display (list "\n# systems: " no-systems
+ (display (list "\n# systems: " system-count
"\nreal-ext" real-extents "\nstaff-ext" staff-extents
"\ninterscore" inter-system-space
"\nspace-letf" space-left
(define-public (set-paper-dimension-variables mod)
(module-define! mod 'dimension-variables
'(pt mm cm in staffheight staff-space
+ pagetopspace
betweensystemspace betweensystempadding
linewidth indent hsize vsize horizontalshift
staffspace linethickness ledgerlinethickness