Guide, node Updating translation committishes.
@end ignore
-@c \version "2.17.18"
+@c \version "2.17.19"
@c Translators: Till Paala
"It has two lines."
}
}
- \vspace #0.1 % adds vertical spacing between verses
+ \combine \null \vspace #0.1 % adds vertical spacing between verses
\line { \bold "3."
\column {
"This is verse three."
"It has two lines."
}
}
- \vspace #0.1 % adds vertical spacing between verses
+ \combine \null \vspace #0.1 % adds vertical spacing between verses
\line { \bold "5."
\column {
"This is verse five."
Guide, node Updating translation committishes..
@end ignore
-@c \version "2.17.18"
+@c \version "2.17.19"
@node Música vocal
@section Música vocal
"It has two lines."
}
}
- \vspace #0.1 % adds vertical spacing between verses
+ \combine \null \vspace #0.1 % adds vertical spacing between verses
\line { \bold "3."
\column {
"This is verse three."
"It has two lines."
}
}
- \vspace #0.1 % adds vertical spacing between verses
+ \combine \null \vspace #0.1 % adds vertical spacing between verses
\line { \bold "5."
\column {
"This is verse five."
Guide, node Updating translation committishes..
@end ignore
-@c \version "2.17.18"
+@c \version "2.17.19"
@c Translators: Valentin Villenave, Jean-Charles Malahieude
@c Translation checkers: Jean-Jacques Gerbaud
"Je me suis fait sécher..."
}
}
- \vspace #0.1 % ajout d'espace vertical entre les couplets
+ \combine \null \vspace #0.1 % ajout d'espace vertical entre les couplets
\line { \bold "3."
\column {
"Chante, rossignol, chante,"
"Sans l'avoir mérité..."
}
}
- \vspace #0.1 % ajout d'espace vertical entre les couplets
+ \combine \null \vspace #0.1 % ajout d'espace vertical entre les couplets
\line { \bold "5."
\column {
"Je voudrais que la rose"
Guide, node Updating translation committishes..
@end ignore
-@c \version "2.17.18"
+@c \version "2.17.19"
@c Translators: Yoshiki Sawada
@c Translation status: post-GDP
"It has two lines."
}
}
- \vspace #0.1 % 次の歌詞との間に垂直方向のスペースを入れます
+ \combine \null \vspace #0.1 % 次の歌詞との間に垂直方向のスペースを入れます
\line { \bold "3."
\column {
"This is verse three."
"It has two lines."
}
}
- \vspace #0.1 % 次の歌詞との間に垂直方向のスペースを入れます
+ \combine \null \vspace #0.1 % 次の歌詞との間に垂直方向のスペースを入れます
\line { \bold "5."
\column {
"This is verse five."
Guide, node Updating translation committishes..
@end ignore
-@c \version "2.17.18"
+@c \version "2.17.19"
@node Vocal music
@section Vocal music
"It has two lines."
}
}
- \vspace #0.1 % adds vertical spacing between verses
+ \combine \null \vspace #0.1 % adds vertical spacing between verses
\line { \bold "3."
\column {
"This is verse three."
"It has two lines."
}
}
- \vspace #0.1 % adds vertical spacing between verses
+ \combine \null \vspace #0.1 % adds vertical spacing between verses
\line { \bold "5."
\column {
"This is verse five."
%% and then run scripts/auxiliar/makelsr.py
%%
%% This file is in the public domain.
-\version "2.17.15"
+\version "2.17.19"
\header {
lsrtags = "paper-and-layout, staff-notation, syntax-and-expressions"
\header {
title = \markup
\column {
- \vspace #1
+ \combine \null \vspace #1
"Exercise: Improve the given choral"
" "
}
\markup \override #'(fret-diagram-details . ((finger-code . below-string))) {
\myFretDiagram
- \hspace #4
\override #'(size . 1.5) \myFretDiagram
- \hspace #8
\override #'(size . 3) \myFretDiagram
}
-\version "2.17.12"
+\version "2.17.19"
\header {
texidoc = "@code{\\note-by-number} and @code{\\note} support
\markup {
\column {
- \vspace #1
+ \combine \null \vspace #1
\underline "Note-head-styles:"
\override #'(baseline-skip . 6)
\show-note-styles #styles-list
\markup {
\column {
- \vspace #1
+ \combine \null \vspace #1
\underline "Modern-straight-flag:"
\override #'(flag-style . modern-straight-flag)
\show-note-styles #'(default)
\markup {
\column {
- \vspace #1
+ \combine \null \vspace #1
\underline "Old-straight-flag:"
\override #'(flag-style . old-straight-flag)
\show-note-styles #'(default)
-\version "2.17.9"
+\version "2.17.19"
\header {
texidoc = "The rest markup function works for a variety of style, dot and
semipetrucci
kievan)))))
-\markup \column { \bold "Simple Rests" \vspace #0.1 }
+\markup \column { \bold "Simple Rests" \combine \null \vspace #0.1 }
\showSimpleRest #"."
-\markup \column { \vspace #0.1 \bold "MultiMeasureRests" \vspace #0.1 }
+\markup \column { \combine \null \vspace #0.1 \bold "MultiMeasureRests" \combine \null \vspace #0.1 }
\showMultiMeasureRests
-\version "2.16.0"
+\version "2.17.19"
\header {
texidoc = "
A list of special character ASCII aliases can be easily included.
\italic \justify {
№2 – &OE;dipe…
}
- \vspace #0.5
+ \combine \null \vspace #0.5
\bold "Lyric example:"
}
\new Lyrics \lyricmode {
ragged-last-bottom = ##f
oddHeaderMarkup = \markup {
- \override #'(baseline-skip . 1)
+ \override #'(baseline-skip . 2.5)
\center-column {
\box \fill-line { \teeny " " " " }
\on-the-fly #first-page "first-page-header-text"
evenHeaderMarkup = \oddHeaderMarkup
oddFooterMarkup = \markup \fill-line {
- \override #'(baseline-skip . 0.5)
+ \override #'(baseline-skip . 1)
\center-column {
\on-the-fly #first-page "first-page-footer-text"
\on-the-fly #last-page "last-page-footer-text"
Box::translate (Offset o)
{
for (Axis i = X_AXIS; i < NO_AXES; incr (i))
- interval_a_[i] += o[i];
+ if (!is_empty (i))
+ interval_a_[i] += o[i];
}
void
bool
Box::is_empty () const
{
- return interval_a_[X_AXIS].is_empty ()
- || interval_a_[Y_AXIS].is_empty ();
+ return is_empty (X_AXIS) && is_empty (Y_AXIS);
+}
+
+bool
+Box::is_empty (Axis a) const
+{
+ Interval empty;
+ empty.set_empty ();
+ return interval_a_[a][LEFT] == empty[LEFT]
+ && interval_a_[a][RIGHT] == empty[RIGHT];
}
Box::Box (Interval ix, Interval iy)
last_column_ = 0;
force_ = 0;
Stencil *st = unsmob_stencil (pb->get_property ("stencil"));
- Interval stencil_extent = st->is_empty () ? Interval (0, 0)
+ Interval stencil_extent = st->is_empty (Y_AXIS) ? Interval (0, 0)
: st->extent (Y_AXIS);
shape_ = Line_shape (stencil_extent, stencil_extent); // pretend it goes all the way across
tallness_ = 0;
for (int i = scm_to_int (c); i--;)
{
- d.translate_axis (2 * dw, X_AXIS);
mol.add_at_edge (X_AXIS, RIGHT, d, dw);
}
}
Interval &operator [] (Axis a);
Real area () const;
bool is_empty () const;
+ bool is_empty (Axis a) const;
Offset center () const;
Set dimensions to empty, or to (Interval (0, 0), Interval (0, 0) */
void set_empty (bool);
void add_at_edge (Axis a, Direction d, const Stencil &m, Real padding);
+ void stack (Axis a, Direction d, const Stencil &m, Real padding, Real mindist);
void add_stencil (Stencil const &m);
void translate (Offset);
Stencil translated (Offset) const;
Interval extent (Axis) const;
Box extent_box () const;
bool is_empty () const;
+ bool is_empty (Axis) const;
Stencil in_color (Real r, Real g, Real b) const;
static SCM skylines_from_stencil (SCM, Real, Axis);
};
sky_ = sky;
for (vsize i = 0; i < boxes.size (); i++)
- if (!boxes[i].is_empty ())
+ if (!boxes[i].is_empty (X_AXIS)
+ && !boxes[i].is_empty (Y_AXIS))
buildings.push_front (Building (boxes[i], horizon_axis, sky));
buildings_ = internal_build_skyline (&buildings);
Skyline::Skyline (Box const &b, Axis horizon_axis, Direction sky)
{
sky_ = sky;
- Building front (b, horizon_axis, sky);
- single_skyline (front, &buildings_);
- normalize ();
+ if (!b.is_empty (X_AXIS) && !b.is_empty (Y_AXIS))
+ {
+ Building front (b, horizon_axis, sky);
+ single_skyline (front, &buildings_);
+ normalize ();
+ }
}
void
}
/* do the same filtering as in Skyline (vector<Box> const&, etc.) */
- if (b.is_empty ())
+ if (b.is_empty (X_AXIS) || b.is_empty (Y_AXIS))
return;
my_bld.splice (my_bld.begin (), buildings_);
}
LY_DEFINE (ly_stencil_empty_p, "ly:stencil-empty?",
- 1, 0, 0, (SCM stil),
- "Return whether @var{stil} is empty.")
+ 1, 1, 0, (SCM stil, SCM axis),
+ "Return whether @var{stil} is empty. If an optional"
+ " @var{axis} is supplied, the emptiness check is"
+ " restricted to that axis.")
{
Stencil *s = unsmob_stencil (stil);
LY_ASSERT_SMOB (Stencil, stil, 1);
- return scm_from_bool (s->is_empty ());
+ if (SCM_UNBNDP (axis))
+ return scm_from_bool (s->is_empty ());
+ LY_ASSERT_TYPE (is_axis, axis, 2);
+ return scm_from_bool (s->is_empty (Axis (scm_to_int (axis))));
}
LY_DEFINE (ly_stencil_combine_at_edge, "ly:stencil-combine-at-edge",
return result.smobbed_copy ();
}
+LY_DEFINE (ly_stencil_stack, "ly:stencil-stack",
+ 4, 2, 0, (SCM first, SCM axis, SCM direction,
+ SCM second,
+ SCM padding,
+ SCM mindist),
+ "Construct a stencil by stacking @var{second} next to @var{first}."
+ " @var{axis} can be 0 (x-axis) or@tie{}1 (y-axis)."
+ " @var{direction} can be -1 (left or down) or@tie{}1 (right or"
+ " up). The stencils are juxtaposed with @var{padding} as extra"
+ " space. @var{first} and @var{second} may also be @code{'()} or"
+ " @code{#f}. As opposed to @code{ly:stencil-combine-at-edge},"
+ " metrics are suited for successively accumulating lines of"
+ " stencils. Also, @var{second} stencil is drawn last.\n\n"
+ "If @var{mindist} is specified, reference points are placed"
+ " apart at least by this distance. If either of the stencils"
+ " is spacing, @var{padding} and @var{mindist} do not apply.")
+{
+ Stencil *s1 = unsmob_stencil (first);
+ Stencil *s2 = unsmob_stencil (second);
+ Stencil result;
+
+ SCM_ASSERT_TYPE (s1 || first == SCM_BOOL_F || first == SCM_EOL,
+ first, SCM_ARG1, __FUNCTION__, "Stencil, #f or ()");
+ SCM_ASSERT_TYPE (s2 || second == SCM_BOOL_F || second == SCM_EOL,
+ second, SCM_ARG4, __FUNCTION__, "Stencil, #f or ()");
+ LY_ASSERT_TYPE (is_axis, axis, 2);
+ LY_ASSERT_TYPE (is_direction, direction, 3);
+
+ Real p = 0.0;
+ if (padding != SCM_UNDEFINED)
+ {
+ LY_ASSERT_TYPE (scm_is_number, padding, 5);
+ p = scm_to_double (padding);
+ }
+ Real d = -infinity_f;
+ if (!SCM_UNBNDP (mindist))
+ {
+ LY_ASSERT_TYPE (scm_is_number, mindist, 6);
+ d = scm_to_double (mindist);
+ }
+
+ if (s1)
+ result = *s1;
+
+ if (s2)
+ result.stack (Axis (scm_to_int (axis)),
+ Direction (scm_to_int (direction)), *s2, p, d);
+
+ return result.smobbed_copy ();
+}
+
LY_DEFINE (ly_stencil_add, "ly:stencil-add",
0, 0, 1, (SCM args),
"Combine stencils. Takes any number of arguments.")
"@item\n"
"The vertical and horizontal extents of the object, given as"
" pairs. If an extent is unspecified (or if you use"
- " @code{(1000 . -1000)} as its value), it is taken to be empty.\n"
+ " @code{empty-interval} as its value), it is taken to be empty.\n"
"@end enumerate\n")
{
SCM_ASSERT_TYPE (!scm_is_pair (expr)
bool
Stencil::is_empty () const
-/* If only one of X- or Y-extent is empty; such a stencil can be useful
- * for backspacing, as with \hspace #-2, so we do not consider it empty.
- */
{
return (expr_ == SCM_EOL
- || (dim_[X_AXIS].is_empty ()
- && dim_[Y_AXIS].is_empty ()));
+ || dim_.is_empty ());
+}
+
+bool
+Stencil::is_empty (Axis a) const
+{
+ return dim_.is_empty (a);
}
SCM
incr (a);
}
- expr_ = scm_list_n (ly_symbol2scm ("translate-stencil"),
- ly_offset2scm (o),
- expr_, SCM_UNDEFINED);
+ if (!scm_is_null (expr_))
+ expr_ = scm_list_n (ly_symbol2scm ("translate-stencil"),
+ ly_offset2scm (o),
+ expr_, SCM_UNDEFINED);
if (!is_empty ())
dim_.translate (o);
}
Stencil::add_stencil (Stencil const &s)
{
SCM cs = ly_symbol2scm ("combine-stencil");
- if (scm_is_pair (expr_)
+ if (scm_is_null (expr_))
+ expr_ = s.expr_;
+ else if (scm_is_null (s.expr_))
+ ;
+ else if (scm_is_pair (expr_)
&& scm_is_eq (cs, scm_car (expr_)))
{
if (scm_is_pair (s.expr_)
void
Stencil::align_to (Axis a, Real x)
{
- if (is_empty ())
+ if (is_empty (a))
return;
Interval i (extent (a));
}
/* See scheme Function. */
+
+// Any stencil that is empty in the orthogonal axis is spacing.
+// Spacing is not subjected to the max (0) rule and can thus be
+// negative.
+
void
Stencil::add_at_edge (Axis a, Direction d, Stencil const &s, Real padding)
{
- Interval my_extent = dim_[a];
- Interval i (s.extent (a));
- Real his_extent;
- if (i.is_empty ())
+ // Material that is empty in the axis of reference has only limited
+ // usefulness for combining. We still retain as much information as
+ // available since there may be uses like setting page links or
+ // background color or watermarks, and off-axis extents.
+
+ if (is_empty (a))
{
- programming_error ("Stencil::add_at_edge: adding empty stencil.");
- his_extent = 0.0;
+ add_stencil (s);
+ return;
}
- else
- his_extent = i[-d];
- Real offset = (my_extent.is_empty () ? 0.0 : my_extent[d] - his_extent)
- + d * padding;
+ Interval first_extent = extent (a);
+
+ if (s.is_empty (a))
+ {
+ Stencil toadd (s);
+ // translation does not affect axis-empty extent box.
+ toadd.translate_axis (first_extent[d], a);
+ add_stencil (toadd);
+ return;
+ }
+
+ Interval next_extent = s.extent (a);
+
+ bool first_is_spacing = is_empty (other_axis (a));
+ bool next_is_spacing = s.is_empty (other_axis (a));
+
+ Real offset = first_extent[d] - next_extent[-d];
+
+ if (!(first_is_spacing || next_is_spacing))
+ {
+ offset += d * padding;
+ }
Stencil toadd (s);
toadd.translate_axis (offset, a);
add_stencil (toadd);
}
+// Stencil::stack is mainly used for assembling lines or columns
+// of stencils. For the most common case of adding at the right, the
+// reference point of the added stencil is usually placed at the right
+// edge of the current one, unless the added stencil has a negative
+// left extent in which case its left edge is placed at the right edge
+// of the current one.
+//
+// Spacing is special in that it is applied without padding. Spacing
+// at the right edge shifts the right edge accordingly.
+//
+// For spacing at the left edge, there are several approaches. In
+// order to get to predictable behavior, we want to have at least a
+// continuous approach. An obvious idea is to do a "translate" by the
+// appropriate amount. Doing that while retaining the nominal left
+// edge seems like the most straightforward way.
+
+void
+Stencil::stack (Axis a, Direction d, Stencil const &s, Real padding, Real mindist)
+{
+ // Material that is empty in the axis of reference can't be sensibly
+ // stacked. We just revert to add_at_edge behavior then.
+
+ if (is_empty (a))
+ {
+ Stencil toadd (s);
+ toadd.add_stencil (*this);
+ expr_ = toadd.expr ();
+ dim_ = toadd.extent_box ();
+ return;
+ }
+
+ Interval first_extent = extent (a);
+
+ if (s.is_empty (a))
+ {
+ Stencil toadd (s);
+ toadd.translate_axis (first_extent[d], a);
+ toadd.add_stencil (*this);
+ expr_ = toadd.expr ();
+ dim_ = toadd.extent_box ();
+ return;
+ }
+
+ Interval next_extent = s.extent (a);
+
+ // It is somewhat tedious to special-case all spacing, but it turns
+ // out that not doing so makes it astonishingly hard to make the
+ // code do the correct thing.
+
+ // If first is spacing, we translate second accordingly without
+ // letting this affect its backward edge.
+ if (is_empty (other_axis (a)))
+ {
+ Stencil toadd (s);
+ Real offset = d * first_extent.delta ();
+ toadd.translate_axis (offset, a);
+ toadd.add_stencil (*this);
+ expr_ = toadd.expr ();
+ dim_ = toadd.extent_box ();
+ dim_[a][-d] = next_extent[-d];
+ dim_[a][d] = next_extent[d] + offset;
+ return;
+ }
+
+ // If next is spacing, similar action:
+ if (s.is_empty (other_axis (a)))
+ {
+ Stencil toadd (s);
+ Real offset = first_extent [d];
+ toadd.translate_axis (offset, a);
+ toadd.add_stencil (*this);
+ expr_ = toadd.expr ();
+ dim_ = toadd.extent_box ();
+ dim_[a][-d] = first_extent[-d];
+ dim_[a][d] = first_extent[d] + d * next_extent.delta ();
+ return;
+ }
+
+
+ Real offset = first_extent[d];
+
+ // If the added stencil has a backwardly protruding edge, we make
+ // room for it when combining.
+
+ if (d * next_extent [-d] < 0)
+ offset -= next_extent [-d];
+
+ offset += d * padding;
+
+ if (offset * d < mindist)
+ offset = d * mindist;
+
+ Stencil toadd (s);
+ toadd.translate_axis (offset, a);
+ toadd.add_stencil (*this);
+ expr_ = toadd.expr ();
+ dim_ = toadd.extent_box ();
+ dim_[a][-d] = first_extent [-d];
+ dim_[a][d] = next_extent [d] + offset;
+}
+
+
Stencil
Stencil::in_color (Real r, Real g, Real b) const
{
\paper {
tocTitleMarkup = \markup \huge \column {
\fill-line { \null "Table of Contents" \null }
- \hspace #1
+ \null
}
tocItemMarkup = \markup \fill-line {
\fromproperty #'toc:text \fromproperty #'toc:page
str = re.sub ('cueClefOctavationStyle', 'cueClefTranspositionStyle', str)
return str
+@rule((2, 17, 19), r"\column { \vspace #2 } -> \column { \combine \null \vspace #2 }")
+def conv(str):
+ def vspace_replace(m):
+
+# vspace now always adds space and does not, for example, change the
+# impact of either baselineskip or descenders on the line above.
+#
+# We can't simulate the old behavior in a simpler manner. A command
+# of its own is not really warranted since this behavior combines
+# badly enough with other spacing considerations (like baselineskip
+# and descenders) as to make it not all that useful. So this
+# conversion rule is here more for compatibility's sake rather than
+# preserving desirable behavior.
+
+ str = re.sub (r"(\\\\?)vspace(\s)", r"\1combine \1null \1vspace\2", m.group(0))
+ return str
+
+ str = re.sub (r"\\(?:left-|right-|center-|)column\s*\{" + brace_matcher (20) + r"\}",
+ vspace_replace, str)
+ return str
+
# Guidelines to write rules (please keep this at the end of this file)
#
# - keep at most one rule per version; if several conversions should be done,
(make-line-markup (list empty-markup))
(conditional-kern-before
(alteration->text-accidental-markup alteration)
- (= alteration FLAT) 0.2)))
+ (= alteration FLAT) 0.094725)))
(define (accidental->markup-italian alteration)
"Return accidental markup for ALTERATION, for use after an italian chord root name."
(make-hspace-markup 0.2)
(make-line-markup
(list
- (make-hspace-markup (if (= alteration FLAT) 0.7 0.5))
+ (make-hspace-markup (if (= alteration FLAT) 0.57285385 0.5))
(make-raise-markup 0.7 (alteration->text-accidental-markup alteration))
(make-hspace-markup (if (= alteration SHARP) 0.2 0.1))
))))
;; utility functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(define-public empty-stencil (ly:make-stencil '() '(1 . -1) '(1 . -1)))
+(define-public empty-stencil (ly:make-stencil '()
+ empty-interval empty-interval))
(define-public point-stencil (ly:make-stencil "" '(0 . 0) '(0 . 0)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-markup-command (hspace layout props amount)
(number?)
#:category align
- #:properties ((word-space))
"
@cindex creating horizontal spaces in text
three
}
@end lilypond"
- (let ((corrected-space (- amount word-space)))
- (ly:make-stencil "" (cons 0 corrected-space) '(0 . 0))))
+ (ly:make-stencil "" (cons 0 amount) empty-interval))
(define-markup-command (vspace layout props amount)
(number?)
}
@end lilypond"
(let ((amount (* amount 3.0)))
- (ly:make-stencil "" (cons 0 0) (cons 0 amount))))
+ (ly:make-stencil "" empty-interval (cons 0 amount))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(let ((stencils (interpret-markup-list layout props args)))
(if (= text-direction LEFT)
(set! stencils (reverse stencils)))
- (stack-stencil-line
- word-space
- (remove ly:stencil-empty? stencils))))
+ (stack-stencil-line word-space stencils)))
(define-markup-command (concat layout props args)
(markup-list?)
;; justify only stretches lines.
(* 0.7 base-space)
base-space))
+ (define (stencil-space stencil line-start)
+ (if (ly:stencil-empty? stencil X)
+ 0
+ (cdr (ly:stencil-extent
+ (ly:stencil-stack (if line-start
+ empty-stencil
+ point-stencil)
+ X RIGHT stencil)
+ X))))
(define (take-list width space stencils
accumulator accumulated-width)
"Return (head-list . tail) pair, with head-list fitting into width"
(if (null? stencils)
(cons accumulator stencils)
(let* ((first (car stencils))
- (first-wid (cdr (ly:stencil-extent (car stencils) X)))
- (newwid (+ space first-wid accumulated-width)))
+ (first-wid (stencil-space first (null? accumulator)))
+ (newwid (+ (if (or (ly:stencil-empty? first Y)
+ (ly:stencil-empty? first X))
+ 0 space)
+ first-wid accumulated-width)))
(if (or (null? accumulator)
(< newwid width))
(take-list width space
'() 0.0))
(line-stencils (car line-break))
(space-left (- line-width
- (apply + (map (lambda (x) (cdr (ly:stencil-extent x X)))
- line-stencils))))
+ (stencil-space
+ (stack-stencil-line 0 line-stencils)
+ #t)))
+ (line-words (count (lambda (s) (not (or (ly:stencil-empty? s Y)
+ (ly:stencil-empty? s X))))
+ line-stencils))
(line-word-space (cond ((not justify) space)
;; don't stretch last line of paragraph.
;; hmmm . bug - will overstretch the last line in some case.
((null? (cdr line-break))
base-space)
- ((null? line-stencils) 0.0)
- ((null? (cdr line-stencils)) 0.0)
- (else (/ space-left (1- (length line-stencils))))))
- (line (stack-stencil-line line-word-space
+ ((< line-words 2) space)
+ (else (/ space-left (1- line-words)))))
+ (line (stack-stencil-line line-word-space
(if (= text-dir RIGHT)
(reverse line-stencils)
line-stencils))))
(word-space)
(text-direction RIGHT))
"Internal markup list command used to define @code{\\justify} and @code{\\wordwrap}."
- (wordwrap-stencils (remove ly:stencil-empty?
- (interpret-markup-list layout props args))
+ (wordwrap-stencils (interpret-markup-list layout props args)
justify
word-space
(or line-width
para-strings))
(para-lines (map (lambda (words)
(let* ((stencils
- (remove ly:stencil-empty?
- (map (lambda (x)
- (interpret-markup layout props x))
- words))))
+ (map (lambda (x)
+ (interpret-markup layout props x))
+ words)))
(wordwrap-stencils stencils
justify word-space
line-width text-direction)))
}
@end lilypond"
(let ((arg-stencils (interpret-markup-list layout props args)))
- (stack-lines -1 0.0 baseline-skip
- (remove ly:stencil-empty? arg-stencils))))
+ (stack-lines -1 0.0 baseline-skip arg-stencils)))
(define-markup-command (dir-column layout props args)
(markup-list?)
(cons (acons key val (car chain)) (cdr chain)))
(define-public (stack-stencil-line space stencils)
- "Adjoin a list of STENCILS along the X axis, leaving SPACE between the
- end of each stencil and the reference point of the following stencil."
- (if (and (pair? stencils)
- (ly:stencil? (car stencils)))
-
- (if (and (pair? (cdr stencils))
- (ly:stencil? (cadr stencils)))
- (let* ((tail (stack-stencil-line space (cdr stencils)))
- (head (car stencils))
- (xoff (+ space (interval-end (ly:stencil-extent head X)))))
- (ly:stencil-add head
- (ly:stencil-translate-axis tail xoff X)))
- (car stencils))
- (ly:make-stencil '() '(0 . 0) '(0 . 0))))
-
+ "Adjoin a list of @var{stencils} along the X axis, leaving
+@var{space} between the end of each stencil and the beginning of the
+following stencil. Stencils with empty Y extent are not given
+@var{space} before them and don't avoid overlapping other stencils."
+ (stack-stencils X RIGHT space (filter ly:stencil? stencils)))
;;; convert a full markup object to an approximate pure string representation
ly:stencil-combine-at-edge
ly:stencil-expr
ly:stencil-extent
+ ly:stencil-stack
ly:stencil-translate
ly:stencil-translate-axis
ly:stencil?
(define-public (stack-stencils axis dir padding stils)
"Stack stencils @var{stils} in direction @var{axis}, @var{dir}, using
@var{padding}."
- (cond
- ((null? stils) empty-stencil)
- ((null? (cdr stils)) (car stils))
- (else (ly:stencil-combine-at-edge
- (car stils) axis dir (stack-stencils axis dir padding (cdr stils))
- padding))))
-
-(define-public (stack-stencils-padding-list axis dir padding stils)
+ (reduce
+ (lambda (next front)
+ (ly:stencil-stack front axis dir next padding))
+ empty-stencil
+ stils))
+
+(define-public (stack-stencils-padding-list axis dir paddings stils)
"Stack stencils @var{stils} in direction @var{axis}, @var{dir}, using
-a list of @var{padding}."
- (cond
- ((null? stils) empty-stencil)
- ((null? (cdr stils)) (car stils))
- (else (ly:stencil-combine-at-edge
- (car stils)
- axis dir
- (stack-stencils-padding-list axis dir (cdr padding) (cdr stils))
- (car padding)))))
+a list of @var{paddings}."
+ (if (null? stils)
+ empty-stencil
+ (fold
+ (lambda (next padding front)
+ (ly:stencil-stack front axis dir next padding))
+ (car stils)
+ (cdr stils)
+ paddings)))
(define-public (centered-stencil stencil)
"Center stencil @var{stencil} in both the X and Y directions."
(define-public (stack-lines dir padding baseline stils)
"Stack vertically with a baseline skip."
- (define result empty-stencil)
- (define last-y #f)
- (do
- ((last-stencil #f (car p))
- (p stils (cdr p)))
-
- ((null? p))
-
- (if (number? last-y)
- (begin
- (let* ((dy (max (+ (* dir (interval-bound (ly:stencil-extent last-stencil Y) dir))
- padding
- (* (- dir) (interval-bound (ly:stencil-extent (car p) Y) (- dir))))
- baseline))
- (y (+ last-y (* dir dy))))
-
-
-
- (set! result
- (ly:stencil-add result (ly:stencil-translate-axis (car p) y Y)))
- (set! last-y y)))
- (begin
- (set! last-y 0)
- (set! result (car p)))))
-
- result)
-
+ (reduce-right
+ (lambda (next back) (ly:stencil-stack next Y dir back padding baseline))
+ empty-stencil
+ (map
+ (lambda (s)
+ ;; X-empty stencils may add vertical space. A stencil that is
+ ;; merely Y-empty counts as horizontal spacing. Since we want
+ ;; those to register as lines of their own (is this a good
+ ;; idea?), we make them a separately visible line.
+ (if (and (ly:stencil-empty? s Y)
+ (not (ly:stencil-empty? s X)))
+ (ly:make-stencil (ly:stencil-expr s) (ly:stencil-extent s X) '(0 . 0))
+ s))
+ stils)))
(define-public (bracketify-stencil stil axis thick protrusion padding)
"Add brackets around @var{stil}, producing a new stencil."
(set! stil
(ly:stencil-combine-at-edge stil (other-axis axis) 1 rb padding))
(set! stil
- (ly:stencil-combine-at-edge lb (other-axis axis) 1 stil padding))
+ (ly:stencil-combine-at-edge stil (other-axis axis) -1 lb padding))
stil))
(define (make-parenthesis-stencil
y-extent half-thickness (- width) angularity))
(rp (make-parenthesis-stencil
y-extent half-thickness width angularity)))
- (set! stencil (ly:stencil-combine-at-edge lp X RIGHT stencil padding))
+ (set! stencil (ly:stencil-combine-at-edge stencil X LEFT lp padding))
(set! stencil (ly:stencil-combine-at-edge stencil X RIGHT rp padding))
stencil))
(if (markup? markup)
(interpret-markup layout props markup)
- (ly:make-stencil '() '(1 . -1) '(1 . -1)))))
+ empty-stencil)))