# HG changeset patch # User Edouard Tisserant <edouard.tisserant@gmail.com> # Date 1619993048 -7200 # Node ID b2b6bf45aa2d0363759903cabc908fda1ca2d3f4 # Parent f2bfb047d0e6c776ee06554c398ddfa7c4f6f77c SVGHMI: Add analyse_widget stylesheet and python code to execute it, in order to obtain widget signature independently of DnD SVG file generation. diff -r f2bfb047d0e6 -r b2b6bf45aa2d svghmi/Makefile --- a/svghmi/Makefile Sun May 02 23:43:57 2021 +0200 +++ b/svghmi/Makefile Mon May 03 00:04:08 2021 +0200 @@ -11,7 +11,7 @@ yml2path ?= $(abspath ../../yml2) -ysl2files := gen_index_xhtml.ysl2 gen_dnd_widget_svg.ysl2 +ysl2files := gen_index_xhtml.ysl2 gen_dnd_widget_svg.ysl2 analyse_widget.ysl2 ysl2includes := $(filter-out $(ysl2files), $(wildcard *.ysl2)) xsltfiles := $(patsubst %.ysl2, %.xslt, $(ysl2files)) diff -r f2bfb047d0e6 -r b2b6bf45aa2d svghmi/analyse_widget.xslt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svghmi/analyse_widget.xslt Mon May 03 00:04:08 2021 +0200 @@ -0,0 +1,153 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:str="http://exslt.org/strings" xmlns:func="http://exslt.org/functions" xmlns:svg="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.0" extension-element-prefixes="ns func exsl regexp str dyn" exclude-result-prefixes="ns func exsl regexp str dyn svg inkscape"> + <xsl:output method="xml"/> + <xsl:variable name="indexed_hmitree" select="/.."/> + <xsl:variable name="pathregex" select="'^([^\[,]+)(\[[^\]]+\])?([\d,]*)$'"/> + <xsl:template mode="parselabel" match="*"> + <xsl:variable name="label" select="@inkscape:label"/> + <xsl:variable name="id" select="@id"/> + <xsl:variable name="description" select="substring-after($label,'HMI:')"/> + <xsl:variable name="_args" select="substring-before($description,'@')"/> + <xsl:variable name="args"> + <xsl:choose> + <xsl:when test="$_args"> + <xsl:value-of select="$_args"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$description"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="_type" select="substring-before($args,':')"/> + <xsl:variable name="type"> + <xsl:choose> + <xsl:when test="$_type"> + <xsl:value-of select="$_type"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$args"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:if test="$type"> + <widget> + <xsl:attribute name="id"> + <xsl:value-of select="$id"/> + </xsl:attribute> + <xsl:attribute name="type"> + <xsl:value-of select="$type"/> + </xsl:attribute> + <xsl:for-each select="str:split(substring-after($args, ':'), ':')"> + <arg> + <xsl:attribute name="value"> + <xsl:value-of select="."/> + </xsl:attribute> + </arg> + </xsl:for-each> + <xsl:variable name="paths" select="substring-after($description,'@')"/> + <xsl:for-each select="str:split($paths, '@')"> + <xsl:if test="string-length(.) > 0"> + <path> + <xsl:variable name="path_match" select="regexp:match(.,$pathregex)"/> + <xsl:variable name="pathminmax" select="str:split($path_match[4],',')"/> + <xsl:variable name="path" select="$path_match[2]"/> + <xsl:variable name="path_accepts" select="$path_match[3]"/> + <xsl:variable name="pathminmaxcount" select="count($pathminmax)"/> + <xsl:attribute name="value"> + <xsl:value-of select="$path"/> + </xsl:attribute> + <xsl:if test="string-length($path_accepts)"> + <xsl:attribute name="accepts"> + <xsl:value-of select="$path_accepts"/> + </xsl:attribute> + </xsl:if> + <xsl:choose> + <xsl:when test="$pathminmaxcount = 2"> + <xsl:attribute name="min"> + <xsl:value-of select="$pathminmax[1]"/> + </xsl:attribute> + <xsl:attribute name="max"> + <xsl:value-of select="$pathminmax[2]"/> + </xsl:attribute> + </xsl:when> + <xsl:when test="$pathminmaxcount = 1 or $pathminmaxcount > 2"> + <xsl:message terminate="yes"> + <xsl:text>Widget id:</xsl:text> + <xsl:value-of select="$id"/> + <xsl:text> label:</xsl:text> + <xsl:value-of select="$label"/> + <xsl:text> has wrong syntax of path section </xsl:text> + <xsl:value-of select="$pathminmax"/> + </xsl:message> + </xsl:when> + </xsl:choose> + <xsl:if test="$indexed_hmitree"> + <xsl:choose> + <xsl:when test="regexp:test($path,'^\.[a-zA-Z0-9_]+$')"> + <xsl:attribute name="type"> + <xsl:text>PAGE_LOCAL</xsl:text> + </xsl:attribute> + </xsl:when> + <xsl:when test="regexp:test($path,'^[a-zA-Z0-9_]+$')"> + <xsl:attribute name="type"> + <xsl:text>HMI_LOCAL</xsl:text> + </xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:variable name="item" select="$indexed_hmitree/*[@hmipath = $path]"/> + <xsl:variable name="pathtype" select="local-name($item)"/> + <xsl:if test="$pathminmaxcount = 3 and not($pathtype = 'HMI_INT' or $pathtype = 'HMI_REAL')"> + <xsl:message terminate="yes"> + <xsl:text>Widget id:</xsl:text> + <xsl:value-of select="$id"/> + <xsl:text> label:</xsl:text> + <xsl:value-of select="$label"/> + <xsl:text> path section </xsl:text> + <xsl:value-of select="$pathminmax"/> + <xsl:text> use min and max on non mumeric value</xsl:text> + </xsl:message> + </xsl:if> + <xsl:if test="count($item) = 1"> + <xsl:attribute name="index"> + <xsl:value-of select="$item/@index"/> + </xsl:attribute> + <xsl:attribute name="type"> + <xsl:value-of select="$pathtype"/> + </xsl:attribute> + </xsl:if> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + </path> + </xsl:if> + </xsl:for-each> + </widget> + </xsl:if> + </xsl:template> + <xsl:template mode="genlabel" match="arg"> + <xsl:text>:</xsl:text> + <xsl:value-of select="@value"/> + </xsl:template> + <xsl:template mode="genlabel" match="path"> + <xsl:text>@</xsl:text> + <xsl:value-of select="@value"/> + <xsl:if test="string-length(@min)>0 or string-length(@max)>0"> + <xsl:text>,</xsl:text> + <xsl:value-of select="@min"/> + <xsl:text>,</xsl:text> + <xsl:value-of select="@max"/> + </xsl:if> + </xsl:template> + <xsl:template mode="genlabel" match="widget"> + <xsl:text>HMI:</xsl:text> + <xsl:value-of select="@type"/> + <xsl:apply-templates mode="genlabel" select="arg"/> + <xsl:apply-templates mode="genlabel" select="path"/> + </xsl:template> + <xsl:variable name="hmi_elements" select="//svg:*[starts-with(@inkscape:label, 'HMI:')]"/> + <xsl:template match="/"> + <widgets> + <xsl:apply-templates mode="parselabel" select="$hmi_elements"/> + </widgets> + </xsl:template> +</xsl:stylesheet> diff -r f2bfb047d0e6 -r b2b6bf45aa2d svghmi/analyse_widget.ysl2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svghmi/analyse_widget.ysl2 Mon May 03 00:04:08 2021 +0200 @@ -0,0 +1,20 @@ +include yslt_noindent.yml2 + +istylesheet + /* From Inkscape */ + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + + extension-element-prefixes="ns func exsl regexp str dyn" + exclude-result-prefixes="ns func exsl regexp str dyn svg inkscape" { + + const "indexed_hmitree", "/.."; // compatibility with parse_labels.ysl2 + include parse_labels.ysl2 + + const "hmi_elements", "//svg:*[starts-with(@inkscape:label, 'HMI:')]"; + + template "/" + widgets + apply "$hmi_elements", mode="parselabel"; + +} diff -r f2bfb047d0e6 -r b2b6bf45aa2d svghmi/ui.py --- a/svghmi/ui.py Sun May 02 23:43:57 2021 +0200 +++ b/svghmi/ui.py Mon May 03 00:04:08 2021 +0200 @@ -299,10 +299,54 @@ def GetSubHMITree(self, _context): return [self.hmitree_node.etree()] + def AnalyseWidget(self): + self.msg = "" + + try: + if self.selected_SVG is None: + raise Exception(_("No widget selected")) + + transform = XSLTransform( + os.path.join(ScriptDirectory, "analyse_widget.xslt"),[]) + + svgdom = etree.parse(self.selected_SVG) + + result = transform.transform(svgdom) + + for entry in transform.get_error_log(): + self.msg += "XSLT: " + entry.message + "\n" + + except Exception as e: + self.msg += str(e) + except XSLTApplyError as e: + self.msg += "Widget analysis error: " + e.message + else: + return result + + def UpdateUI(self, signature): + if signature is not None: + print(etree.tostring(signature, pretty_print=True)) + widgets = signature.getroot() + for widget in widgets: + widget_type = widget.get("type") + print(widget_type) + for path in widget: + path_value = path.get("value") + path_accepts = map( + str.strip, path.get("accepts", '')[1:-1].split(',')) + print(path_value, path_accepts) + + def ValidateWidget(self): self.msg = "" + signature = self.AnalyseWidget() + + self.UpdateUI(signature) + + return + if self.tempf is not None: os.unlink(self.tempf.name) self.tempf = None diff -r f2bfb047d0e6 -r b2b6bf45aa2d svghmi/widgetlib/modern_knob_1.svg --- a/svghmi/widgetlib/modern_knob_1.svg Sun May 02 23:43:57 2021 +0200 +++ b/svghmi/widgetlib/modern_knob_1.svg Mon May 03 00:04:08 2021 +0200 @@ -159,16 +159,16 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.35" - inkscape:cx="41.428571" - inkscape:cy="555.71429" + inkscape:zoom="1.979899" + inkscape:cx="208.80035" + inkscape:cy="841.9769" inkscape:document-units="mm" - inkscape:current-layer="svg2637" + inkscape:current-layer="g3058" showgrid="false" - inkscape:window-width="1414" - inkscape:window-height="840" - inkscape:window-x="1690" - inkscape:window-y="117" + inkscape:window-width="1623" + inkscape:window-height="1446" + inkscape:window-x="3346" + inkscape:window-y="244" inkscape:window-maximized="0" /> <metadata id="metadata2634"> @@ -178,7 +178,7 @@ <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> + <dc:title /> </cc:Work> </rdf:RDF> </metadata> @@ -206,7 +206,7 @@ <g style="fill:none;stroke-width:1.47405899" transform="matrix(0.53304115,0,0,0.53229017,1417.5153,1776.3135)" - inkscape:label="HMI:CircularBar@/CIRCULARBAR" + inkscape:label="HMI:CircularBar@value[HMI_REAL,HMI_INT]0,111@label[HMI_STRING]" id="g30664"> <text inkscape:label="value"