lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: SVG export - how might you add classes for all graphical objects?


From: Carl Sorensen
Subject: Re: SVG export - how might you add classes for all graphical objects?
Date: Tue, 29 Jun 2021 19:45:27 +0000
User-agent: Microsoft-MacOutlook/10.10.1b.201012


On 6/29/21, 11:33 AM, "lilypond-user on behalf of Aaron Hill" 
<lilypond-user-bounces+carl.d.sorensen=gmail.com@gnu.org on behalf of 
lilypond@hillvisions.com> wrote:

    On 2021-06-29 9:43 am, Jean Abou Samra wrote:
    > However, this problem can be solved by writing
    > an engraver (those are the powerful tools that
    > \applyOutput uses under the hood).
    > 
    > \version "2.22.0"
    > 
    > \layout {
    >   \context {
    >     \Score
    >     \consists
    >       #(lambda (context)
    >          (make-engraver
    >            (acknowledgers
    >              ((grob-interface engraver grob source-engraver)
    >                 (set! (ly:grob-property grob 'output-attributes)
    >                       `((class . ,(grob::name grob))))))))
    >   }
    > }
    > 
    > <<
    >   { c d e f }
    >   \\
    >   { g a b c' }
    >>> 
    
    NOTE: You might want this engraver to *append* to the class attribute, 
    so you can still specify classes on an individual basis:

Great idea, and nice implementation, Aaron!
    
    %%%%
    \version "2.22.0"
    
    SvgAddClassName =
    #(lambda (ctxt)
       (define (add-class-name grob)
        (let* ((attribs (ly:grob-property grob 'output-attributes '()))
               (class (ly:assoc-get 'class attribs '()))
               (name (grob::name grob)))
         (set! class (if (null? class) name (format #f "~a ~a" class name)))
         (set! attribs (assoc-set! attribs 'class class))
         (ly:grob-set-property! grob 'output-attributes attribs)))
       (make-engraver
        (acknowledgers
         ((grob-interface engraver grob source)
          (add-class-name grob)))))
    
    \layout { \context { \Score \consists \SvgAddClassName } }
    
    { \tweak output-attributes #'((class . foo)) b'4 }
    %%%%
    
When I learned Scheme 36 years ago from the CS guys at MIT, they really frowned 
on using set! (side-effects of code were avoided as much as possible).

So I rewrote the code using only the necessary set! functions

%%%%
\version "2.20.0"

SvgAddClassName =
#(lambda (ctxt)
   (define (add-class-name grob)
    (let* ((attribs (ly:grob-property grob 'output-attributes '()))
           (class (ly:assoc-get 'class attribs '()))
           (name (grob::name grob))
           (grob-class-name (if (null? class)
                                name
                                (format #f "~a ~a" class name))))
     (ly:grob-set-property! grob 'output-attributes (assoc-set! attribs 'class 
grob-class-name))))
   (make-engraver
    (acknowledgers
     ((grob-interface engraver grob source)
      (add-class-name grob)))))

\layout { \context { \Score \consists \SvgAddClassName } }

{ \tweak output-attributes #'((class . foo)) b'4 }
%%%%

I believe that the logical implications of side-effects are not very concerning 
when local variables are set!, so there's probably very little or no downside 
to the set!s in Aaron's code.  In fact, it's possible that Aaron's code will 
use less heap space by re-using class instead of adding a new variable 
grob-class-name.  But I can't help myself; I want to avoid the grief  Sussman 
would give me over two unneeded set! calls.....

Carl




reply via email to

[Prev in Thread] Current Thread [Next in Thread]