# HG changeset patch # User Edouard Tisserant # Date 1570788194 -7200 # Node ID c5ba1e77f05499b354c005de95c047686fe27d65 # Parent c7a22ce8c1569a2a965d767ba2cdb68cd13c24e6 SVGHMI: added a widgets description object, accessed by id. Added frequency to widgets, as separate template to allow future customization. Excluded non svg elements (i.e inkscape Sets) with HMI: labels from widgets. diff -r c7a22ce8c156 -r c5ba1e77f054 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Thu Oct 10 10:03:47 2019 +0200 +++ b/svghmi/gen_index_xhtml.xslt Fri Oct 11 12:03:14 2019 +0200 @@ -3,7 +3,7 @@ <xsl:output method="xml" cdata-section-elements="script"/> <xsl:variable name="geometry" select="ns:GetSVGGeometry()"/> <xsl:variable name="hmitree" select="ns:GetHMITree()"/> - <xsl:variable name="hmi_elements" select="//*[starts-with(@inkscape:label, 'HMI:')]"/> + <xsl:variable name="hmi_elements" select="//svg:*[starts-with(@inkscape:label, 'HMI:')]"/> <xsl:variable name="hmi_geometry" select="$geometry[@Id = $hmi_elements/@id]"/> <xsl:variable name="hmi_pages" select="$hmi_elements[func:parselabel(@inkscape:label)/widget/@type = 'Page']"/> <xsl:variable name="default_page"> @@ -179,27 +179,30 @@ <func:result select="exsl:node-set($ast)"/> </func:function> <xsl:template name="scripts"> - <xsl:text>var hmi_index = { -</xsl:text> - <xsl:variable name="svg" select="/"/> - <xsl:for-each select="$indexed_hmitree/*"> - <xsl:value-of select="@index"/> + <xsl:text>var hmi_hash = [</xsl:text> + <xsl:value-of select="$hmitree/@hash"/> + <xsl:text>]; +</xsl:text> + <xsl:text>var hmi_widgets = { +</xsl:text> + <xsl:for-each select="$hmi_elements"> + <xsl:variable name="widget" select="func:parselabel(@inkscape:label)/widget"/> + <xsl:value-of select="@id"/> <xsl:text>: { </xsl:text> - <xsl:text> name: "</xsl:text> - <xsl:value-of select="@name"/> + <xsl:text> type: "</xsl:text> + <xsl:value-of select="$widget/@type"/> <xsl:text>", </xsl:text> - <xsl:text> hmipath: "</xsl:text> - <xsl:value-of select="@hmipath"/> - <xsl:text>" -</xsl:text> - <xsl:text> ids: [ -</xsl:text> - <xsl:variable name="hmipath" select="@hmipath"/> - <xsl:for-each select="$svg//*[substring-after(@inkscape:label,'@') = $hmipath]"> + <xsl:text> frequency: </xsl:text> + <xsl:apply-templates mode="refresh_frequency" select="$widget"/> + <xsl:text>, +</xsl:text> + <xsl:text> args: [ +</xsl:text> + <xsl:for-each select="$widget/arg"> <xsl:text> "</xsl:text> - <xsl:value-of select="@id"/> + <xsl:value-of select="@value"/> <xsl:text>"</xsl:text> <xsl:if test="position()!=last()"> <xsl:text>,</xsl:text> @@ -207,6 +210,28 @@ <xsl:text> </xsl:text> </xsl:for-each> + <xsl:text> ], +</xsl:text> + <xsl:text> paths: [ +</xsl:text> + <xsl:for-each select="$widget/path"> + <xsl:variable name="hmipath" select="@value"/> + <xsl:variable name="hmitree_match" select="$indexed_hmitree/*[@hmipath = $hmipath]"/> + <xsl:if test="count($hmitree_match) = 0"> + <xsl:message terminate="yes"> + <xsl:text>No match for HMI </xsl:text> + <xsl:value-of select="$hmipath"/> + <xsl:text>;</xsl:text> + </xsl:message> + </xsl:if> + <xsl:text> </xsl:text> + <xsl:value-of select="$hmitree_match/@index"/> + <xsl:if test="position()!=last()"> + <xsl:text>,</xsl:text> + </xsl:if> + <xsl:text> +</xsl:text> + </xsl:for-each> <xsl:text> ] </xsl:text> <xsl:text>}</xsl:text> @@ -220,10 +245,54 @@ </xsl:text> <xsl:text> </xsl:text> + <xsl:text>var hmi_index = [ +</xsl:text> + <xsl:variable name="svg" select="/"/> + <xsl:for-each select="$indexed_hmitree/*"> + <xsl:text>{ /* </xsl:text> + <xsl:value-of select="@index"/> + <xsl:text> </xsl:text> + <xsl:value-of select="@hmipath"/> + <xsl:text> */ +</xsl:text> + <xsl:text> type: "</xsl:text> + <xsl:value-of select="local-name()"/> + <xsl:text>", +</xsl:text> + <xsl:text> ids: [ +</xsl:text> + <xsl:variable name="hmipath" select="@hmipath"/> + <xsl:for-each select="$svg//*[substring-after(@inkscape:label,'@') = $hmipath]"> + <xsl:text> hmi_widgets["</xsl:text> + <xsl:value-of select="@id"/> + <xsl:text>"]</xsl:text> + <xsl:if test="position()!=last()"> + <xsl:text>,</xsl:text> + </xsl:if> + <xsl:text> +</xsl:text> + </xsl:for-each> + <xsl:text> ] +</xsl:text> + <xsl:text>}</xsl:text> + <xsl:if test="position()!=last()"> + <xsl:text>,</xsl:text> + </xsl:if> + <xsl:text> +</xsl:text> + </xsl:for-each> + <xsl:text>] +</xsl:text> + <xsl:text> +</xsl:text> <xsl:text>var page_desc = { </xsl:text> <xsl:for-each select="$hmi_pages"> <xsl:variable name="desc" select="func:parselabel(@inkscape:label)/widget"/> + <xsl:variable name="page" select="."/> + <xsl:variable name="p" select="$hmi_geometry[@Id = $page/@id]"/> + <xsl:variable name="page_ids" select="$hmi_geometry[@Id != $page/@id and @x >= $p/@x and @y >= $p/@y and @x+@w <= $p/@x+$p/@w and @y+@h <= $p/@y+$p/@h]/@Id"/> + <xsl:variable name="page_elements" select="$hmi_elements[@id = $page_ids]"/> <xsl:text> "</xsl:text> <xsl:value-of select="$desc/arg[1]/@value"/> <xsl:text>": { @@ -234,11 +303,9 @@ </xsl:text> <xsl:text> widgets: [ </xsl:text> - <xsl:variable name="page" select="."/> - <xsl:variable name="p" select="$hmi_geometry[@Id = $page/@id]"/> - <xsl:for-each select="$hmi_geometry[@Id != $page/@id and @x >= $p/@x and @y >= $p/@y and @x+@w <= $p/@x+$p/@w and @y+@h <= $p/@y+$p/@h]"> + <xsl:for-each select="$page_ids"> <xsl:text> "</xsl:text> - <xsl:value-of select="@Id"/> + <xsl:value-of select="."/> <xsl:text>"</xsl:text> <xsl:if test="position()!=last()"> <xsl:text>,</xsl:text> @@ -248,6 +315,30 @@ </xsl:for-each> <xsl:text> ] </xsl:text> + <xsl:text> subscriptions: [ +</xsl:text> + <xsl:for-each select="$page_elements"> + <xsl:variable name="hmipaths" select="func:parselabel(@inkscape:label)/widget/path/@value"/> + <xsl:variable name="notlast" select="position()!=last()"/> + <xsl:for-each select="$hmipaths"> + <xsl:variable name="hmipath" select="."/> + <xsl:text> </xsl:text> + <xsl:value-of select="$indexed_hmitree/*[@hmipath = $hmipath]/@index"/> + <xsl:if test="$notlast or position()!=last()"> + <xsl:text>,</xsl:text> + </xsl:if> + <xsl:text> +</xsl:text> + </xsl:for-each> + </xsl:for-each> + <xsl:text> ] +</xsl:text> + <xsl:text> }</xsl:text> + <xsl:if test="position()!=last()"> + <xsl:text>,</xsl:text> + </xsl:if> + <xsl:text> +</xsl:text> </xsl:for-each> <xsl:text>} </xsl:text> @@ -321,13 +412,11 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text> -</xsl:text> <xsl:text> // subscription state as needed by widget now </xsl:text> <xsl:text> // expected {index:[widgets]}; </xsl:text> - <xsl:text> var subscribers = {}; + <xsl:text> var subscribers = new Map(); </xsl:text> <xsl:text> </xsl:text> @@ -337,24 +426,30 @@ </xsl:text> <xsl:text> let delta = []; </xsl:text> - <xsl:text> Object.keys(subscribers).forEach(index => { -</xsl:text> - <xsl:text> + <xsl:text> for(let [index, widgets] in subscribers.entries()){ +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> // periods are in ms </xsl:text> <xsl:text> let previous_period = subscriptions.get(index); </xsl:text> - <xsl:text> delete subscriptions[index]; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> let new_period = Math.min(...widgets.map(widget => widget.period)); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> if(previous_period != new_period) + <xsl:text> +</xsl:text> + <xsl:text> let new_period = Math.min(...widgets.map(widget => 1000/widget.frequency)); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> if(previous_period != new_period) { +</xsl:text> + <xsl:text> subscriptions.set(index, new_period); </xsl:text> <xsl:text> delta.push({index: index, period: new_period}); </xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> <xsl:text> }) </xsl:text> <xsl:text> return result; @@ -373,8 +468,28 @@ </xsl:text> <xsl:text> </xsl:text> + <xsl:text> var current_page = default_page; +</xsl:text> + <xsl:text> +</xsl:text> <xsl:text> function switch_page(page_name) { </xsl:text> + <xsl:text> let new_desc = page_desc[page_name]; +</xsl:text> + <xsl:text> let old_desc = page_desc[page_name]; +</xsl:text> + <xsl:text> /* TODO hide / show widgets */ +</xsl:text> + <xsl:text> /* TODO move viewport */ +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> /* Update subscribers */ +</xsl:text> + <xsl:text> /* Update subscriptions */ +</xsl:text> + <xsl:text> +</xsl:text> <xsl:text> </xsl:text> <xsl:text> }; @@ -456,4 +571,16 @@ </xsl:with-param> </xsl:apply-templates> </xsl:template> + <xsl:template mode="refresh_frequency" match="widget"> + <xsl:text>10</xsl:text> + </xsl:template> + <xsl:template mode="refresh_frequency" match="widget[@type='Meter']"> + <xsl:text>10</xsl:text> + </xsl:template> + <xsl:template mode="refresh_frequency" match="widget[@type='Display']"> + <xsl:text>5</xsl:text> + </xsl:template> + <xsl:template mode="refresh_frequency" match="widget[@type='Input']"> + <xsl:text>5</xsl:text> + </xsl:template> </xsl:stylesheet> diff -r c7a22ce8c156 -r c5ba1e77f054 svghmi/gen_index_xhtml.ysl2 --- a/svghmi/gen_index_xhtml.ysl2 Thu Oct 10 10:03:47 2019 +0200 +++ b/svghmi/gen_index_xhtml.ysl2 Fri Oct 11 12:03:14 2019 +0200 @@ -24,7 +24,7 @@ const "geometry", "ns:GetSVGGeometry()"; const "hmitree", "ns:GetHMITree()"; - const "hmi_elements", "//*[starts-with(@inkscape:label, 'HMI:')]"; + const "hmi_elements", "//svg:*[starts-with(@inkscape:label, 'HMI:')]"; const "hmi_geometry", "$geometry[@Id = $hmi_elements/@id]"; const "hmi_pages", "$hmi_elements[func:parselabel(@inkscape:label)/widget/@type = 'Page']"; @@ -163,7 +163,8 @@ function "scripts" { - /* TODO : paste hmitree hash stored in hmi tree root node */ + /* paste hmitree hash stored in hmi tree root node */ + | var hmi_hash = [«$hmitree/@hash»]; /* TODO re-enable || @@ -183,45 +184,74 @@ || */ - /*TODO add : - - pages content - + with ref to elt ? - - widgets parameters - */ - - | var hmi_index = { + | var hmi_widgets = { + foreach "$hmi_elements" { + const "widget", "func:parselabel(@inkscape:label)/widget"; + | «@id»: { + | type: "«$widget/@type»", + | frequency: `apply "$widget", mode="refresh_frequency"`, + | args: [ + foreach "$widget/arg" + | "«@value»"`if "position()!=last()" > ,` + | ], + | paths: [ + foreach "$widget/path" { + const "hmipath","@value"; + const "hmitree_match","$indexed_hmitree/*[@hmipath = $hmipath]"; + if "count($hmitree_match) = 0" + error > No match for HMI «$hmipath»; + | «$hmitree_match/@index»`if "position()!=last()" > ,` + } + | ] + | }`if "position()!=last()" > ,` + } + | } + | + | var hmi_index = [ const "svg","/"; /* foreach loses document root */ foreach "$indexed_hmitree/*" { - | «@index»: { - | name: "«@name»", - | hmipath: "«@hmipath»" + | { /* «@index» «@hmipath» */ + | type: "«local-name()»", | ids: [ const "hmipath","@hmipath"; foreach "$svg//*[substring-after(@inkscape:label,'@') = $hmipath]" { - | "«@id»"`if "position()!=last()" > ,` + | hmi_widgets["«@id»"]`if "position()!=last()" > ,` } | ] | }`if "position()!=last()" > ,` } - | } + | ] | | var page_desc = { foreach "$hmi_pages" { const "desc", "func:parselabel(@inkscape:label)/widget"; + const "page", "."; + const "p", "$hmi_geometry[@Id = $page/@id]"; + const "page_ids","""$hmi_geometry[@Id != $page/@id and + @x >= $p/@x and @y >= $p/@y and + @x+@w <= $p/@x+$p/@w and @y+@h <= $p/@y+$p/@h]/@Id"""; + const "page_elements", "$hmi_elements[@id = $page_ids]"; | "«$desc/arg[1]/@value»": { | id: "«@id»", | widgets: [ - const "page", "."; - const "p", "$hmi_geometry[@Id = $page/@id]"; - foreach """$hmi_geometry[@Id != $page/@id and - @x >= $p/@x and @y >= $p/@y and - @x+@w <= $p/@x+$p/@w and @y+@h <= $p/@y+$p/@h]""" { - | "«@Id»"`if "position()!=last()" > ,` + foreach "$page_ids" { + | "«.»"`if "position()!=last()" > ,` } | ] + | subscriptions: [ + foreach "$page_elements" { + const "hmipaths", "func:parselabel(@inkscape:label)/widget/path/@value"; + const "notlast", "position()!=last()"; + foreach "$hmipaths" { + const "hmipath","."; + | «$indexed_hmitree/*[@hmipath = $hmipath]/@index»`if "$notlast or position()!=last()" > ,` + } + } + | ] + | }`if "position()!=last()" > ,` } | } @@ -291,4 +321,9 @@ with "indent" value "concat($indent,'>')" }; } + + template "widget", mode="refresh_frequency" > 10 + template "widget[@type='Meter']", mode="refresh_frequency" > 10 + template "widget[@type='Display']", mode="refresh_frequency" > 5 + template "widget[@type='Input']", mode="refresh_frequency" > 5 }