svghmi/inline_svg.ysl2
author Edouard Tisserant <edouard.tisserant@gmail.com>
Fri, 20 Mar 2020 10:46:15 +0100
branchsvghmi
changeset 2891 8927ae8326b2
parent 2878 bec552270ad1
child 2904 92d115d8828d
permissions -rw-r--r--
SVGHMI: add widget_foreach.ysl2
// inline_svg.ysl2
//
// Produce Inline SVG element of resulting XHTML page.

// Identity template :
//  - copy every attributes 
//  - copy every sub-elements
template "@* | node()", mode="inline_svg" {
  // use real xsl:copy instead copy-of alias from yslt.yml2
  if "not(@id = $discardable_elements/@id)"
      xsl:copy apply "@* | node()", mode="inline_svg";
}

// replaces inkscape's height and width hints. forces fit
template "svg:svg/@width", mode="inline_svg";
template "svg:svg/@height", mode="inline_svg";
svgtmpl "svg:svg", mode="inline_svg" svg {
    attrib "preserveAspectRatio" > none
    attrib "height" > 100vh
    attrib "width" > 100vw
    apply "@* | node()", mode="inline_svg";
}
// ensure that coordinate in CSV file generated by inkscape are in default reference frame
template "svg:svg[@viewBox!=concat('0 0 ', @width, ' ', @height)]", mode="inline_svg" {
    error > ViewBox settings other than X=0, Y=0 and Scale=1 are not supported
}
// ensure that coordinate in CSV file generated by inkscape match svg default unit
template "sodipodi:namedview[@units!='px' or @inkscape:document-units!='px']", mode="inline_svg" {
    error > All units must be set to "px" in Inkscape's document properties
}


//////////////// Clone Unlinking

// svg:use (inkscape's clones) inside a widgets are
// replaced by real elements they refer in order to :
//  - allow finding "needle" element in "meter" widget,
//    even if "needle" is in a group refered by a svg use.
//  - if "needle" is visible through a svg:use for
//    each instance of the widget, then needle would show
//    the same position in all instances
//
// For now, clone unlinkink applies to descendants of all widget except HMI:Page
// TODO: narrow application of clone unlinking to active elements,
//       while keeping static decoration cloned
const "to_unlink", "$hmi_elements[not(@id = $hmi_pages)]//svg:use";
svgtmpl "svg:use", mode="inline_svg"
{
    choose {
        when "@id = $to_unlink/@id"
            call "unlink_clone";
        otherwise
            xsl:copy apply "@* | node()", mode="inline_svg";
    }
}

// to unlink a clone, an group containing a copy of target element is created
// that way, style and transforms can be preserved
const "_excluded_use_attrs" {
    name > href
    name > width
    name > height
    name > x
    name > y
}
const "excluded_use_attrs","exsl:node-set($_excluded_use_attrs)";

svgfunc "unlink_clone"{
    g{
        // include non excluded attributes
        foreach "@*[not(local-name() = $excluded_use_attrs/name)]"
            attrib "{name()}" > «.»

        const "targetid","substring-after(@xlink:href,'#')";
        apply "//svg:*[@id = $targetid]", mode="unlink_clone"{
            with "seed","@id";
        }
    }
}

// clone unlinking is really similar to deep-copy
// all nodes are sytematically copied
svgtmpl "@id", mode="unlink_clone" {
    param "seed";
    attrib "id" > «$seed»_«.»
}

svgtmpl "@*", mode="unlink_clone" xsl:copy;

// copying widgets would have unwanted effect
// instead widget is refered through a svg:use.
svgtmpl "svg:*", mode="unlink_clone" {
    param "seed";
    choose {
        // node recursive copy ends when finding a widget
        when "@id = $hmi_elements/@id" {
            // place a clone instead of copying
            use{
                attrib "xlink:href" > «concat('#',@id)»
            }
        }
        otherwise {
            xsl:copy apply "@* | node()", mode="unlink_clone" {
                with "seed","$seed";
            }
        }
    }
}

/*const "mark" > =HMI=\n*/

const "result_svg" apply "/", mode="inline_svg";
const "result_svg_ns", "exsl:node-set($result_svg)";

function "debug_unlink" {
    foreach "$to_unlink"{
        | «@id»
    }
}
!debug_output_calls.append("debug_unlink")