SVGHMI: Easier way to match HMI tree elements to paths. ForEach widget now looks for paths and indexes of all items, and enforce path to be consistent with ForEach items sub widgets
--- a/svghmi/detachable_pages.ysl2 Mon Mar 23 15:13:36 2020 +0100
+++ b/svghmi/detachable_pages.ysl2 Mon Mar 23 21:44:28 2020 +0100
@@ -91,13 +91,6 @@
const "_detachable_elements", "func:detachable_elements($hmi_pages)";
const "detachable_elements", "$_detachable_elements[not(ancestor::*/@id = $_detachable_elements/@id)]";
-def "func:is_descendant_path" {
- param "descend";
- param "ancest";
- result "string-length($ancest) > 0 and starts-with($descend,$ancest)";
-}
-
-
const "forEach_widgets_ids", "$parsed_widgets/widget[@type = 'ForEach']/@id";
const "forEach_widgets", "$hmi_elements[@id = $forEach_widgets_ids]";
const "in_forEach_widget_ids", "func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]/@id";
--- a/svghmi/gen_index_xhtml.xslt Mon Mar 23 15:13:36 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt Mon Mar 23 21:44:28 2020 +0100
@@ -74,49 +74,6 @@
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
- <func:function name="func:get_hmi_tree_elt">
- <xsl:param name="path"/>
- <xsl:param name="root" select="$hmitree"/>
- <xsl:message>
- <xsl:text>get_hmi_tree_elt </xsl:text>
- <xsl:value-of select="$path"/>
- </xsl:message>
- <xsl:if test="not(starts-with($path, '/'))">
- <xsl:message terminate="yes">
- <xsl:text>Given path "</xsl:text>
- <xsl:value-of select="$path"/>
- <xsl:text>" should start with a "/"</xsl:text>
- </xsl:message>
- </xsl:if>
- <xsl:variable name="stripped" select="substring($path, 2)"/>
- <xsl:variable name="token">
- <xsl:choose>
- <xsl:when test="contains($stripped, '/')">
- <xsl:value-of select="substring-before($stripped, '/')"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$stripped"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:choose>
- <xsl:when test="string-length($token) = 0">
- <func:result select="$root"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:variable name="rest" select="substring-after($stripped, $token)"/>
- <xsl:variable name="match" select="$root/*[@name = $token]"/>
- <xsl:choose>
- <xsl:when test="string-length($rest) > 0">
- <func:result select="func:get_hmi_tree_el($rest, $match)"/>
- </xsl:when>
- <xsl:otherwise>
- <func:result select="$match"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:otherwise>
- </xsl:choose>
- </func:function>
<xsl:template mode="parselabel" match="*">
<xsl:variable name="label" select="@inkscape:label"/>
<xsl:variable name="description" select="substring-after($label,'HMI:')"/>
@@ -185,6 +142,11 @@
<xsl:param name="id"/>
<func:result select="$parsed_widgets/widget[@id = $id]"/>
</func:function>
+ <func:function name="func:is_descendant_path">
+ <xsl:param name="descend"/>
+ <xsl:param name="ancest"/>
+ <func:result select="string-length($ancest) > 0 and starts-with($descend,$ancest)"/>
+ </func:function>
<xsl:template mode="testtree" match="*">
<xsl:param name="indent" select="''"/>
<xsl:value-of select="$indent"/>
@@ -362,11 +324,6 @@
</func:function>
<xsl:variable name="_detachable_elements" select="func:detachable_elements($hmi_pages)"/>
<xsl:variable name="detachable_elements" select="$_detachable_elements[not(ancestor::*/@id = $_detachable_elements/@id)]"/>
- <func:function name="func:is_descendant_path">
- <xsl:param name="descend"/>
- <xsl:param name="ancest"/>
- <func:result select="string-length($ancest) > 0 and starts-with($descend,$ancest)"/>
- </func:function>
<xsl:variable name="forEach_widgets_ids" select="$parsed_widgets/widget[@type = 'ForEach']/@id"/>
<xsl:variable name="forEach_widgets" select="$hmi_elements[@id = $forEach_widgets_ids]"/>
<xsl:variable name="in_forEach_widget_ids" select="func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]/@id"/>
@@ -746,21 +703,28 @@
<xsl:template mode="widget_defs" match="widget[@type='ForEach']">
<xsl:param name="hmi_element"/>
<xsl:variable name="widgets" select="func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]"/>
- <xsl:text> frequency: 2,
-</xsl:text>
- <xsl:text> dispatch: function(value) {
-</xsl:text>
- <xsl:text> // do something
-</xsl:text>
- <xsl:text> },
-</xsl:text>
+ <xsl:variable name="class" select="arg[1]/@value"/>
+ <xsl:variable name="base_path" select="path/@value"/>
+ <xsl:variable name="hmi_index_base" select="$indexed_hmitree/*[@hmipath = $base_path]"/>
+ <xsl:variable name="hmi_tree_base" select="$hmitree/descendant-or-self::*[@path = $hmi_index_base/@path]"/>
+ <xsl:variable name="hmi_tree_items" select="$hmi_tree_base/*[@class = $class]"/>
+ <xsl:variable name="hmi_index_items" select="$indexed_hmitree/*[@path = $hmi_tree_items/@path]"/>
+ <xsl:variable name="items_paths" select="$hmi_index_items/@hmipath"/>
<xsl:text> index_pool: [
</xsl:text>
+ <xsl:for-each select="$hmi_index_items">
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@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> buttons: [
</xsl:text>
- <xsl:variable name="class" select="arg[1]/@value"/>
<xsl:variable name="prefix" select="concat($class,':')"/>
<xsl:variable name="buttons_regex" select="concat('^',$prefix,'[+\-][0-9]+')"/>
<xsl:for-each select="$hmi_element/*[regexp:test(@inkscape:label, $buttons_regex)]">
@@ -787,19 +751,18 @@
</xsl:text>
<xsl:text> items: [
</xsl:text>
- <xsl:variable name="base_path" select="path/@value"/>
<xsl:variable name="items_regex" select="concat('^',$prefix,'[0-9]+')"/>
<xsl:variable name="unordered_items" select="$hmi_element//*[regexp:test(@inkscape:label, $items_regex)]"/>
<xsl:for-each select="$unordered_items">
<xsl:variable name="elt_label" select="concat($prefix, string(position()))"/>
<xsl:variable name="elt" select="$unordered_items[@inkscape:label = $elt_label]"/>
- <xsl:text> /* </xsl:text>
- <xsl:apply-templates mode="testtree" select="func:get_hmi_tree_elt($base_path)"/>
- <xsl:text> */
-</xsl:text>
- <xsl:text> [ /* </xsl:text>
+ <xsl:variable name="pos" select="position()"/>
+ <xsl:variable name="item_path" select="$items_paths[$pos]"/>
+ <xsl:text> [ /* item="</xsl:text>
<xsl:value-of select="$elt_label"/>
- <xsl:text> */
+ <xsl:text>" path="</xsl:text>
+ <xsl:value-of select="$item_path"/>
+ <xsl:text>" */
</xsl:text>
<xsl:if test="count($elt)=0">
<xsl:message terminate="yes">
@@ -810,6 +773,19 @@
</xsl:message>
</xsl:if>
<xsl:for-each select="func:refered_elements($elt)[@id = $hmi_elements/@id][not(@id = $elt/@id)]">
+ <xsl:if test="not(func:is_descendant_path(func:widget(@id)/path/@value, $item_path))">
+ <xsl:message terminate="yes">
+ <xsl:text>Widget id="</xsl:text>
+ <xsl:value-of select="@id"/>
+ <xsl:text>" label="</xsl:text>
+ <xsl:value-of select="@inkscape:label"/>
+ <xsl:text>" is having wrong path. Accroding to ForEach widget ancestor id="</xsl:text>
+ <xsl:value-of select="$hmi_element/@id"/>
+ <xsl:text>", path should be descendant of </xsl:text>
+ <xsl:value-of select="$item_path"/>
+ <xsl:text>.</xsl:text>
+ </xsl:message>
+ </xsl:if>
<xsl:text> hmi_widgets["</xsl:text>
<xsl:value-of select="@id"/>
<xsl:text>"]</xsl:text>
@@ -832,13 +808,13 @@
<xsl:template mode="widget_subscribe" match="widget[@type='ForEach']">
<xsl:text> sub: function(off){
</xsl:text>
- <xsl:text> subscribe.call(this,off);
+ <xsl:text> /*subscribe.call(this,off);*/
</xsl:text>
<xsl:text> },
</xsl:text>
<xsl:text> unsub: function(){
</xsl:text>
- <xsl:text> unsubscribe.call(this);
+ <xsl:text> /*unsubscribe.call(this);*/
</xsl:text>
<xsl:text> },
</xsl:text>
--- a/svghmi/hmi_tree.ysl2 Mon Mar 23 15:13:36 2020 +0100
+++ b/svghmi/hmi_tree.ysl2 Mon Mar 23 21:44:28 2020 +0100
@@ -52,36 +52,6 @@
}
}
-def "func:get_hmi_tree_elt" {
- param "path";
- param "root", "$hmitree";
- message > get_hmi_tree_elt «$path»
- if "not(starts-with($path, '/'))" error > Given path "«$path»" should start with a "/"
- const "stripped", "substring($path, 2)";
- const "token" choose {
- when "contains($stripped, '/')" value "substring-before($stripped, '/')";
- otherwise value "$stripped";
- }
-
- choose {
- when "string-length($token) = 0"{
- result "$root";
- }
- otherwise{
- const "rest", "substring-after($stripped, $token)";
- const "match", "$root/*[@name = $token]";
- choose {
- when "string-length($rest) > 0"{
- result "func:get_hmi_tree_el($rest, $match)";
- }
- otherwise{
- result "$match";
- }
- }
- }
- }
-}
-
// Parses:
// "HMI:WidgetType:param1:param2@path1@path2"
//
@@ -139,6 +109,14 @@
}
+def "func:is_descendant_path" {
+ param "descend";
+ param "ancest";
+ // TODO : use HMI tree to answer more accurately
+ result "string-length($ancest) > 0 and starts-with($descend,$ancest)";
+}
+
+
// Debug data
template "*", mode="testtree"{
param "indent", "''";
--- a/svghmi/widget_foreach.ysl2 Mon Mar 23 15:13:36 2020 +0100
+++ b/svghmi/widget_foreach.ysl2 Mon Mar 23 21:44:28 2020 +0100
@@ -2,14 +2,21 @@
template "widget[@type='ForEach']", mode="widget_defs" {
param "hmi_element";
const "widgets", "func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]";
- | frequency: 2,
- | dispatch: function(value) {
- | // do something
- | },
+
+ const "class","arg[1]/@value";
+
+ const "base_path","path/@value";
+ const "hmi_index_base", "$indexed_hmitree/*[@hmipath = $base_path]";
+ const "hmi_tree_base", "$hmitree/descendant-or-self::*[@path = $hmi_index_base/@path]";
+ const "hmi_tree_items", "$hmi_tree_base/*[@class = $class]";
+ const "hmi_index_items", "$indexed_hmitree/*[@path = $hmi_tree_items/@path]";
+ const "items_paths", "$hmi_index_items/@hmipath";
| index_pool: [
+ foreach "$hmi_index_items" {
+ | «@index»`if "position()!=last()" > ,`
+ }
| ],
| buttons: [
- const "class","arg[1]/@value";
const "prefix","concat($class,':')";
const "buttons_regex","concat('^',$prefix,'[+\-][0-9]+')";
foreach "$hmi_element/*[regexp:test(@inkscape:label, $buttons_regex)]" {
@@ -21,17 +28,18 @@
| },
| items: [
- const "base_path","path/@value";
const "items_regex","concat('^',$prefix,'[0-9]+')";
const "unordered_items","$hmi_element//*[regexp:test(@inkscape:label, $items_regex)]";
foreach "$unordered_items" {
const "elt_label","concat($prefix, string(position()))";
const "elt","$unordered_items[@inkscape:label = $elt_label]";
-
- | /* `apply "func:get_hmi_tree_elt($base_path)", mode="testtree";` */
- | [ /* «$elt_label» */
+ const "pos","position()";
+ const "item_path", "$items_paths[$pos]";
+ | [ /* item="«$elt_label»" path="«$item_path»" */
if "count($elt)=0" error > Missing item labeled «$elt_label» in ForEach widget «$hmi_element/@id»
foreach "func:refered_elements($elt)[@id = $hmi_elements/@id][not(@id = $elt/@id)]" {
+ if "not(func:is_descendant_path(func:widget(@id)/path/@value, $item_path))"
+ error > Widget id="«@id»" label="«@inkscape:label»" is having wrong path. Accroding to ForEach widget ancestor id="«$hmi_element/@id»", path should be descendant of «$item_path».
| hmi_widgets["«@id»"]`if "position()!=last()" > ,`
}
| ]`if "position()!=last()" > ,`
@@ -42,12 +50,12 @@
template "widget[@type='ForEach']", mode="widget_subscribe"{
// param "hmi_element";
| sub: function(off){
- | subscribe.call(this,off);
+ | /*subscribe.call(this,off);*/
/* TODO */
| },
| unsub: function(){
- | unsubscribe.call(this);
+ | /*unsubscribe.call(this);*/
/* TODO */
| },
}