Deutsches Lilypond Forum (Archiv)

Allgemein => Fragen zu Funktionen => Thema gestartet von: Manuela am Freitag, 11. November 2016, 18:01

Titel: formatAdditionalVerses - Spaltenbreite festlegen möglich?
Beitrag von: Manuela am Freitag, 11. November 2016, 18:01
Hallo Harm,

es tun sich immer wieder neue Fragen auf  ;)
Zum Beispiel wenn ich von einem Lied verschiedene Textversionen aufschreibe und dazwischen Anmerkungen mache, so werden die Spaltenbreiten jedesmal neu festgelegt, sodass die Strophen nicht vertikal ausgerichtet sind. Anhand des Screenshots ist zu erkennen, was ich meine.

Hier der Code dazu:

\version "2.19.42"

#(define-markup-list-command (paragraph layout props args) (markup-list?)
   #:properties ((x-shift 2))
   (interpret-markup-list layout props
     (make-justified-lines-markup-list (cons (make-hspace-markup x-shift) args))))
#(define (numbering-start lst strt)
   "Returns a list of custom formated markups for numbers, relying on the length
of @var{lst}, starting with number 2"
   (if (eq? strt 0)
       (map
        (lambda (i)
          #{ \markup \concat \paragraph { " " } #})
        (iota (length lst)))
       (map
        (lambda (i)
          #{ \markup \concat \paragraph { \bold #(format #f "~2d. " i) } #})
        (iota (length lst) strt 1))))
formatAdditionalVerses =
#(define-scheme-function (center-overshoot number-start columns lst)
   ((boolean? #t) index? index? markup-list?)
   (let* ((numberings (numbering-start lst number-start))
          (new-list
           (map
            (lambda (x y)
              #{
                \markup
                \override #'(baseline-skip . 3)
                \line {
                  \paragraph {
                    \overlay {
                      \right-align \transparent "222"
                      \right-align \number $x
                    }
                  }
                  $y
                }
              #})
            numberings
            lst))
          (lst-lngth (length lst))
          (table-lst
           (if (and (odd? lst-lngth)
                    (= (remainder lst-lngth columns) 1)
                    center-overshoot)
               (drop-right new-list 1)
               new-list))
          (odd-tail
           (if (and (odd? lst-lngth)
                    (= (remainder lst-lngth columns) 1)
                    center-overshoot)
               (take-right new-list 1)
               #f))
          (columns-format-list (make-list columns LEFT))
          (args-list
           #{ \markuplist {
             \override #'(font-size . -1)
             \table #columns-format-list #table-lst
           } #})
          (args-list-rev
           (append
            args-list
            (if odd-tail
                #{
                  \markuplist \override #'(font-size . -1)
                  %% hier nix ändern, das sind die Nummerierungen!!
                  \column-lines { \fill-line { \line { #odd-tail } } }
                #}
                '()))))
     args-list-rev))

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% _If_ all verses have the same amount of lines one could do:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#(define (equal-sized-splited-list lst n rl)
   "Split @var{lst} in equal sized parts of length @var{n}.
If @var{lst} is finally not empty add the remaining rest."
   (cond ((null? lst) (reverse rl))
     ((< (length lst) n) (reverse (cons lst rl)))
     (else
      (equal-sized-splited-list (drop lst n) n (cons (take lst n) rl)))))

columns-markup-list =
#(define-scheme-function (lines-per-verse ls)(index? markup-list?)
   "Returns a markup-list.  Each markup is done from a subset of @var{ls} under
control of @var{lines-per-verse}.  The markups are custom-formated using
@code{\\column-lines}, @code{\\column} and a hard-coded @code{baseline-skip} of
value 3"
   (let ((splitted-ls (equal-sized-splited-list ls lines-per-verse '())))
     (map
      (lambda (l)
        #{ \markup \override #'(baseline-skip . 3)
           \column \column-lines $l #})
      splitted-ls) ))

\markuplist {

  \wordwrap-lines \bold { Kölner Gesangbuch 1722: }
  \override #'(padding . 1)
  \override #'(x-shift . 2)
  \override #'(baseline-skip . 4)
  \formatAdditionalVerses
  %% additional verses starts with this numbering
  #1
  %% amount of columns
  #2
  \columns-markup-list #4
  \markuplist {
    "O komm, o komm, Emanuel,"
    "Mach frei Dein armes Israel!"
    "In hartem Elend liegt es hier,"
    "In Tränen seufzt es auf zu Dir."

    "O komm, o komm, Du Himmelskind,"
    "Das aller Welt das Heil gewinnt."
    "Dein Israel seufzt tief in Schuld,"
    "O bring ihm Deines Vaters Huld."

  }
  \override #'(baseline-skip . 4)
  \formatAdditionalVerses
  %% additional verses starts with this numbering
  #0
  %% amount of columns
  #2
  \columns-markup-list #2
  \markuplist {
    \line {
      \number \fontsize #-3 "1-6 "
      "Bald kommt dein Heil: Emanuel."
    }
    \line {
      \with-color #white \number \fontsize #-3 "1-6 "
      "Frohlock und jauchze Israel."
    }
  }

  \wordwrap-lines \bold { C. B. Verspoell 1810: }
  \override #'(padding . 1)
  \override #'(x-shift . 2)
  \override #'(baseline-skip . 4)
  \formatAdditionalVerses
  %% additional verses starts with this numbering
  #1
  %% amount of columns
  #2
  \columns-markup-list #4
  \markuplist {
    "O komm, o komm, Immanuel!"
    "Mach frei Dein armes Israel."
    "In Angst und Elend liegen wir,"
    "und flehn voll Sehnsucht auf zu dir."

    "O komm, du wahres Licht der Welt,"
    "das unsre Finsternis erhellt."
    "Wir irren hier in Trug und Wahn,"
    "o führ uns auf des Lichtes Bahn."

  }
  \override #'(baseline-skip . 4)
  \formatAdditionalVerses
  %% additional verses starts with this numbering
  #0
  %% amount of columns
  #2
  \columns-markup-list #2
  \markuplist {
    \line {
      \number \fontsize #-3 "1-4 "
      "Freu dich, freu dich, o Israel!"
    }
    \line {
      \with-color #white \number \fontsize #-3 "1-4 "
      "Bald kommt, bald kommt Immanuel."
    }
  }

}
Titel: Re: formatAdditionalVerses - Spaltenbreite festlegen möglich?
Beitrag von: harm6 am Samstag, 12. November 2016, 00:17
Hallo Manuela,

hier eine Teillösung.
\table kriegt ein neues property: minimum-x-length
sowie overrides dafür an entsprechenden Stellen.
Aber die Zusatzverse, die nur rechts stehen sind so nicht gut anzugleichen, bin aber momentan zu müde, um tiefer einzusteigen. Vielleicht morgen, aber keine Garantie ...

\version "2.19.49"
#(define-markup-list-command (table layout props column-align lst)
  (number-list? markup-list?)
  #:properties ((padding 0)
                (minimum-x-length 0)
                (baseline-skip))
  "@cindex creating a table.

Returns a table.

@var{column-align} specifies how each column is aligned, possible values are
-1, 0, 1.  The number of elements in @var{column-align} determines how many
columns will be printed.
The entries to print are given by @var{lst}, a markup-list.  If needed, the last
row is filled up with @code{point-stencil}s.
Overriding @code{padding} may be used to increase columns horizontal distance.
Overriding @code{baseline-skip} to increase rows vertical distance.
@lilypond[verbatim,quote]
\\markuplist {
  \\override #'(padding . 2)
  \\table
    #'(0 1 0 -1)
    {
      \\underline { center-aligned right-aligned center-aligned left-aligned }
      one \number 1 thousandth \number 0.001
      eleven \number 11 hundredth \number 0.01
      twenty \number 20 tenth \number 0.1
      thousand \number 1000 one \number 1.0
    }
}
@end lilypond
"

  (define (split-lst initial-lst lngth result-lst)
    ;; split a list into a list of sublists of length lngth
    ;; eg. (split-lst '(1 2 3 4 5 6) 2 '())
    ;; -> ((1 2) (3 4) (5 6))
    (cond ((not (integer? (/ (length initial-lst) lngth)))
           (ly:warning
            "Can't split list of length ~a into ~a parts, returning empty list"
            (length initial-lst) lngth)
           '())
          ((null? initial-lst)
            (reverse result-lst))
          (else
            (split-lst
              (drop initial-lst lngth)
              lngth
              (cons (take initial-lst lngth) result-lst)))))

  (define (dists-list init padding lst)
    ;; Returns a list, where each element of `lst' is
    ;; added to the sum of the previous elements of `lst' plus padding.
    ;; `init' will be the first element of the resulting list. The addition
    ;; starts with the values of `init', `padding' and `(car lst)'.
    ;; eg. (dists-list 0.01 0.1 '(1 2 3 4)))
    ;; -> (0.01 1.11 3.21 6.31 10.41)
    (if (or (not (number? init))
            (not (number? padding))
            (not (number-list? lst)))
        (begin
          (ly:warning
            "not fitting argument for `dists-list', return empty lst ")
          '())
        (reverse
          (fold (lambda (elem rl) (cons (+ elem padding (car rl)) rl))
                (list init)
                lst))))

  (let* (;; get the number of columns
         (columns (length column-align))
         (init-stils (interpret-markup-list layout props lst))
         ;; If the given markup-list is the result of a markup-list call, their
         ;; length may not be easily predictable, thus we add point-stencils
         ;; to fill last row of the table.
         (rem (remainder (length init-stils) columns))
         (filled-stils
           (if (zero? rem)
               init-stils
               (append init-stils (make-list (- columns rem) point-stencil))))
         ;; get the stencils in sublists of length `columns'
         (stils
           (split-lst filled-stils columns '()))
         ;; procedure to return stencil-length
         ;; If it is nan, return 0
         (lengths-proc
           (lambda (m)
             (let ((lngth (interval-length (ly:stencil-extent m X))))
               (if (nan? lngth) 0 lngth))))
         ;; get the max width of each column in a list
         (columns-max-x-lengths
           (map
             (lambda (x)
               (apply max minimum-x-length
                      (map
                        lengths-proc
                        (map (lambda (l) (list-ref l x)) stils))))
             (iota columns)))
         ;; create a list of (basic) distances, which each column should
         ;; moved, using `dists-list'. Some padding may be added.
         (dist-sequence
           (dists-list 0 padding columns-max-x-lengths))
         ;; Get all stencils of a row, moved accurately to build columns.
         ;; If the items of a column are aligned other than left, we need to
         ;; move them to avoid collisions:
         ;; center aligned: move all items half the width of the widest item
         ;; right aligned: move all items the full width of the widest item.
         ;; Added to the default-offset calculated in `dist-sequence'.
         ;; `stencils-for-row-proc' needs four arguments:
         ;;    stil    - a stencil
         ;;    dist    - a numerical value as basic offset in X direction
         ;;    column  - a numerical value for the column we're in
         ;;    x-align - a numerical value how current column should be
         ;;              aligned, where (-1, 0, 1) means (LEFT, CENTER, RIGHT)
         (stencils-for-row-proc
           (lambda (stil dist column x-align)
             (ly:stencil-translate-axis
               (ly:stencil-aligned-to stil X x-align)
               (cond ((member x-align '(0 1))
                      (let* (;; get the stuff for relevant column
                             (stuff-for-column
                               (map
                                 (lambda (s) (list-ref s column))
                                 stils))
                             ;; get length of every column-item
                             (lengths-for-column
                               (map lengths-proc stuff-for-column))
                             (widest
                               (apply max 0 lengths-for-column)))
                        (+ dist (/ widest (if (= x-align 0) 2 1)))))
                     (else dist))
               X)))
         ;; get a list of rows using `ly:stencil-add' on a list of stencils
         (rows
           (map
             (lambda (stil-list)
               (apply ly:stencil-add
                 (map
                   ;; the procedure creating the stencils:
                   stencils-for-row-proc
                   ;; the procedure's args:
                   stil-list
                   dist-sequence
                   (iota columns)
                   column-align)))
             stils))) (write-me "columns-max-x-lengths " column-align)
   (space-lines baseline-skip rows)))

   
\version "2.19.42"

#(define-markup-list-command (paragraph layout props args) (markup-list?)
   #:properties ((x-shift 2))
   (interpret-markup-list layout props
     (make-justified-lines-markup-list (cons (make-hspace-markup x-shift) args))))
#(define (numbering-start lst strt)
   "Returns a list of custom formated markups for numbers, relying on the length
of @var{lst}, starting with number 2"
   (if (eq? strt 0)
       (map
        (lambda (i)
          #{ \markup \concat \paragraph { " " } #})
        (iota (length lst)))
       (map
        (lambda (i)
          #{ \markup \concat \paragraph { \bold #(format #f "~2d. " i) } #})
        (iota (length lst) strt 1))))
formatAdditionalVerses =
#(define-scheme-function (center-overshoot number-start columns lst)
   ((boolean? #t) index? index? markup-list?)
   (let* ((numberings (numbering-start lst number-start))
          (new-list
           (map
            (lambda (x y)
              #{
                \markup
                \override #'(baseline-skip . 3)
                \line {
                  \paragraph {
                    \overlay {
                      \right-align \transparent "222"
                      \right-align \number $x
                    }
                  }
                  $y
                }
              #})
            numberings
            lst))
          (lst-lngth (length lst))
          (table-lst
           (if (and (odd? lst-lngth)
                    (= (remainder lst-lngth columns) 1)
                    center-overshoot)
               (drop-right new-list 1)
               new-list))
          (odd-tail
           (if (and (odd? lst-lngth)
                    (= (remainder lst-lngth columns) 1)
                    center-overshoot)
               (take-right new-list 1)
               #f))
          (columns-format-list (make-list columns LEFT))
          (args-list
           #{ \markuplist {
             \override #'(font-size . -1)
             \table #columns-format-list #table-lst
           } #})
          (args-list-rev
           (append
            args-list
            (if odd-tail
                #{
                  \markuplist \override #'(font-size . -1)
                  %% hier nix ändern, das sind die Nummerierungen!!
                  \column-lines { \fill-line { \line { #odd-tail } } }
                #}
                '()))))
     args-list-rev))

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% _If_ all verses have the same amount of lines one could do:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#(define (equal-sized-splited-list lst n rl)
   "Split @var{lst} in equal sized parts of length @var{n}.
If @var{lst} is finally not empty add the remaining rest."
   (cond ((null? lst) (reverse rl))
     ((< (length lst) n) (reverse (cons lst rl)))
     (else
      (equal-sized-splited-list (drop lst n) n (cons (take lst n) rl)))))

columns-markup-list =
#(define-scheme-function (lines-per-verse ls)(index? markup-list?)
   "Returns a markup-list.  Each markup is done from a subset of @var{ls} under
control of @var{lines-per-verse}.  The markups are custom-formated using
@code{\\column-lines}, @code{\\column} and a hard-coded @code{baseline-skip} of
value 3"
   (let ((splitted-ls (equal-sized-splited-list ls lines-per-verse '())))
     (map
      (lambda (l)
        #{ \markup \override #'(baseline-skip . 3)
           \column \column-lines $l #})
      splitted-ls) ))

\markuplist {

  \wordwrap-lines \bold { Kölner Gesangbuch 1722: }
  \override #'(padding . 1)
  \override #'(x-shift . 2)
  \override #'(baseline-skip . 4)
  \override #'(minimum-x-length . 40)
  \formatAdditionalVerses
  %% additional verses starts with this numbering
  #1
  %% amount of columns
  #2
  \columns-markup-list #4
  \markuplist {
    "O komm, o komm, Emanuel,"
    "Mach frei Dein armes Israel!"
    "In hartem Elend liegt es hier,"
    "In Tränen seufzt es auf zu Dir."

    "O komm, o komm, Du Himmelskind,"
    "Das aller Welt das Heil gewinnt."
    "Dein Israel seufzt tief in Schuld,"
    "O bring ihm Deines Vaters Huld."

  }
  \override #'(baseline-skip . 4)
  \formatAdditionalVerses
  %% additional verses starts with this numbering
  #0
  %% amount of columns
  #2
  \columns-markup-list #2
  \markuplist {
    \line {
      \number \fontsize #-3 "1-6"
      "Bald kommt dein Heil: Emanuel."
    }
    \line {
      \with-color #white \number \fontsize #-3 "1-6 "
      "Frohlock und jauchze Israel."
    }
  }

  \wordwrap-lines \bold { C. B. Verspoell 1810: }
  \override #'(padding . 1)
  \override #'(x-shift . 2)
  \override #'(baseline-skip . 4)
  \override #'(minimum-x-length . 40)
  \formatAdditionalVerses
  %% additional verses starts with this numbering
  #1
  %% amount of columns
  #2
  \columns-markup-list #4
  \markuplist {
    "O komm, o komm, Immanuel!"
    "Mach frei Dein armes Israel."
    "In Angst und Elend liegen wir,"
    "und flehn voll Sehnsucht auf zu dir."

    "O komm, du wahres Licht der Welt,"
    "das unsre Finsternis erhellt."
    "Wir irren hier in Trug und Wahn,"
    "o führ uns auf des Lichtes Bahn."

  }
  \override #'(baseline-skip . 4)
  \formatAdditionalVerses
  %% additional verses starts with this numbering
  #0
  %% amount of columns
  #2
  \columns-markup-list #2
  \markuplist {
    \line {
      \number \fontsize #-3 "1-4 "
      "Freu dich, freu dich, o Israel!"
    }
    \line {
      \with-color #white \number \fontsize #-3 "1-4 "
      "Bald kommt, bald kommt Immanuel."
    }
  }

}


Gruß,
  Harm
Titel: Re: formatAdditionalVerses - Spaltenbreite festlegen möglich?
Beitrag von: Manuela am Samstag, 12. November 2016, 08:47

Aber die Zusatzverse, die nur rechts stehen sind so nicht gut anzugleichen, bin aber momentan zu müde, um tiefer einzusteigen. Vielleicht morgen, aber keine Garantie ...


Danke Harm  :)
Die Zusatzverse sollten eigentlich in der Mitte stehen, das kriege ich auch anders hin, brauchst dir darüber keinen Kopf zu machen  ;)