Attached to this post there's the improved version (fixed indentation and lines' max length). Note too that this version includes a function that prevents opening the default menu with the right mouse button.
Can someone fix the scheme code indentation? After that, can we add this on the snippets repository? On Sun, Dec 15, 2019 at 8:04 AM Werner LEMBERG <w...@gnu.org> wrote: > > > At this point, here's the complete all-in-one .ly template. [...] > > It would be nice if you could format this to avoid line lengths longer > than 80 characters. As the non-HTML part of your e-mail shows, the > code becomes very hard to read otherwise. > > > Werner >
\version "2.19.45" JSSVGSlurTuner = #(define-void-function (body) (string?) (let* ((mod (resolve-module '(scm framework-svg))) (svg-end (module-ref mod 'svg-end #f))) (if (procedure? svg-end) (module-define! mod 'svg-end (lambda () (string-join (list "<script type=\"text/javascript\"><![CDATA[" body "]]></script>" (svg-end)) "\n")))))) JSSVGSlurTunerScript = #" rootNode = document.querySelector('svg') pixelsX = rootNode.getAttribute('width').replace('mm', '') * 96 / 25.4 pixelsY = rootNode.getAttribute('height').replace('mm', '') * 96 / 25.4 scaleX = rootNode.getAttribute('viewBox').split(' ')[2] / pixelsX scaleY = rootNode.getAttribute('viewBox').split(' ')[3] / pixelsY var slurId = 0 var currCp = null function setCpsOnPath(path, x1, y1, x2, y2, x3, y3, x4, y4) { path.setAttribute('d', 'M ' + x1 + ',' + y1 + ' ' + 'C ' + x2 + ',' + y2 + ' ' + x3 + ',' + y3 + ' ' + x4 + ',' + y4) } function initSlur(node) { //already initialized if (node.hasAttribute('id')) return cpsCounter = 1 lineCounter = 1 for (n1 = node.firstChild; n1 !== null; n1 = n1.nextSibling) { if (n1.nodeName == 'g') { for (n2 = n1.firstChild; n2 !== null; n2 = n2.nextSibling) { if (n2.nodeName == 'circle') { if (!node.hasAttribute('cp' + cpsCounter + 'x')) { //TODO Ugly parsering, replace with a proper and safer one transf = n2.getAttribute('transform') node.setAttribute('cp' + cpsCounter + 'x', transf.replace('translate(', '').split(',')[0]) node.setAttribute('cp' + cpsCounter + 'y', transf.split(',')[1].trim().replace(')', '')) n2.setAttribute('id', slurId + '_cp_' + cpsCounter) n2.setAttribute('onmousedown', 'selectCp(this)') } cpsCounter++ } if (n2.nodeName == 'line') { n2.setAttribute('id', slurId + '_line_' + lineCounter) lineCounter++ } } } //remove 'transform' attribute and set abs coords if (n1.nodeName == 'path') { if (n1.hasAttribute('transform')) n1.removeAttribute('transform') setCpsOnPath(n1, node.getAttribute('cp1x'), node.getAttribute('cp1y'), node.getAttribute('cp2x'), node.getAttribute('cp2y'), node.getAttribute('cp3x'), node.getAttribute('cp3y'), node.getAttribute('cp4x'), node.getAttribute('cp4y')) n1.setAttribute('id', slurId + '_path') n1.setAttribute('fill', 'none') } } node.setAttribute('id', slurId) coords = document.createElementNS('http://www.w3.org/2000/svg', 'text') coords.setAttribute('transform', 'translate('+ node.getAttribute('cp1x') + ',' + node.getAttribute('cp1y') + ')') coords.setAttribute('font-size', '2') coords.setAttribute('class', 'lilySlurCoords') coords.setAttribute('id', slurId + '_coords') node.appendChild(coords) slurId++ } function selectCp(cp) { if (!cp.hasAttribute('id')) return if (!detectLeftButton(event)) { event.preventDefault() showCoords(cp.getAttribute('id').split('_')[0]) return } cp.setAttribute('color', 'cyan') currCp = cp } function unselectCp() { if (currCp) currCp.setAttribute('color', 'rgb(255, 127, 0)') currCp = null } function moveCp() { if (!currCp) return translateCoordsStr = event.pageX * scaleX + ',' + event.pageY * scaleY currCp.setAttribute('transform', 'translate(' + translateCoordsStr + ')') //get the associated path assocSlurId = currCp.getAttribute('id').split('_')[0] path = document.getElementById(assocSlurId + '_path') xs = [] ys = [] for (i = 0; i < 4; i++) { cpElem = document.getElementById(assocSlurId + '_cp_' + (i + 1)) transf = cpElem.getAttribute('transform') xs[i] = transf.replace('translate(', '') xs[i] = xs[i].split(',')[0] ys[i] = transf.split(',')[1].trim().replace(')', '') } for (i = 0; i < 3; i++) { currLine = document.getElementById(assocSlurId + '_line_' + (i + 1)) currLine.setAttribute('transform', 'translate(' + xs[i] + ',' + ys[i] + ')') currLine.setAttribute('x2', xs[i + 1] - xs[i]) currLine.setAttribute('y2', ys[i + 1] - ys[i]) } setCpsOnPath(path, xs[0], ys[0], xs[1], ys[1], xs[2], ys[2], xs[3], ys[3]) } function showCoords(assocSlurId) { coordsToDisplay = '\\\\shape #\\'(' assocSlur = document.getElementById(assocSlurId) for (q = 0; q < 4; q++) { newCp = document.getElementById(assocSlurId + '_cp_' + (q + 1)) xsOrig = assocSlur.getAttribute('cp' + (q + 1) + 'x') xsNew = newCp.getAttribute('transform') xsNew = xsNew.replace('translate(', '').split(',')[0] ysOrig = assocSlur.getAttribute('cp' + (q + 1) + 'y') ysNew = newCp.getAttribute('transform').split(',')[1] ysNew = ysNew.trim().replace(')', '') diffX = (xsNew - xsOrig).toFixed(3) diffY = (ysOrig - ysNew).toFixed(3) coordsToDisplay += '(' + (+diffX) + ' . ' + (+diffY) + ') ' } coordsToDisplay = coordsToDisplay.substring(0, coordsToDisplay.length - 1) coordsToDisplay += ') ' + assocSlur.getAttribute('slurtype') alert(coordsToDisplay) } function detectLeftButton(evt) { evt = evt || window.event if ('buttons' in evt) { return evt.buttons == 1 } var button = evt.which || evt.button return button == 1 } window.oncontextmenu = function (evt) { evt.preventDefault() } var as = document.querySelectorAll('a') //Remove all 'a' tags for (var i = 0; i < as.length; i++) { as[i].replaceWith(...as[i].childNodes) } slurs = document.querySelectorAll('svg .lilySlur') for (i = 0; i < slurs.length; i++) { initSlur(slurs[i]) } document.addEventListener('mouseup', unselectCp) document.addEventListener('mousemove', moveCp) " addJSSVGSlurTuner = \JSSVGSlurTuner \JSSVGSlurTunerScript addControlPoints = #(grob-transformer 'stencil (lambda (grob orig) (define (draw-control-point pt) #{ \markup \translate $pt \with-color #'(1 .7 .7) \draw-circle #0.6 #0 ##t #}) (define (draw-control-segment pt1 pt2) (let ((delta (cons (- (car pt2) (car pt1)) (- (cdr pt2) (cdr pt1))))) #{ \markup \translate $pt1 \with-color #'(1 .5 0) \draw-line $delta #})) (let* ((pts (ly:grob-property grob 'control-points)) (dots (map (lambda (pt) (grob-interpret-markup grob (draw-control-point pt))) pts)) (lines (map (lambda (pt1 pt2) (grob-interpret-markup grob (draw-control-segment pt1 pt2))) pts (cdr pts)))) (ly:stencil-add (apply ly:stencil-add lines) (apply ly:stencil-add dots) orig)))) showControlPoints = { \override PhrasingSlur.stencil = #addControlPoints \override PhrasingSlur.output-attributes = #'((class . "lilySlur")(slurtype . "PhrasingSlur")) \override Slur.stencil = #addControlPoints \override Slur.output-attributes = #'((class . "lilySlur")(slurtype . "Slur")) \override Tie.stencil = #addControlPoints \override Tie.output-attributes = #'((class . "lilySlur")(slurtype . "Tie")) } %% How it works: %% %% 1) Produce SVG output file(s) ( compile with -dbackend=svg ) %% 2) Open the SVG file(s) with any viewer (it works with Firefox and Chrome browsers too) %% 3) Modify slurs/ties with the mouse by moving their control points %% 4) Right click on one of the control points of a modified slur/tie, %% and copy and paste the expression generated by the script to the .ly file, just before the corresponding slur/tie. Recompile. \score { { \showControlPoints g4_\( a' b'2~ | b'2( e''8 d'') c'4\) } } \addJSSVGSlurTuner