SVGHMI: Added parsing of min and max value that can be given as @path,min,max in widget description svghmi
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Thu, 24 Dec 2020 16:56:19 +0100
branchsvghmi
changeset 3097 a098b2dd9dff
parent 3096 fc5a0b1ece10
child 3098 5823b73b132f
SVGHMI: Added parsing of min and max value that can be given as @path,min,max in widget description
svghmi/gen_index_xhtml.xslt
svghmi/hmi_tree.ysl2
tests/svghmi/svghmi_0@svghmi/svghmi.svg
--- a/svghmi/gen_index_xhtml.xslt	Tue Dec 22 14:57:59 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt	Thu Dec 24 16:56:19 2020 +0100
@@ -55,7 +55,27 @@
       <xsl:text>
 </xsl:text>
     </xsl:for-each>
-    <xsl:text>]
+    <xsl:text>];
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>var hmitree_paths = [
+</xsl:text>
+    <xsl:for-each select="$indexed_hmitree/*">
+      <xsl:text>    /* </xsl:text>
+      <xsl:value-of select="@index"/>
+      <xsl:text> </xsl:text>
+      <xsl:value-of select="substring(local-name(), 5)"/>
+      <xsl:text> */ "</xsl:text>
+      <xsl:value-of select="@hmipath"/>
+      <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>
@@ -122,6 +142,7 @@
   </xsl:template>
   <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">
@@ -148,7 +169,7 @@
     <xsl:if test="$type">
       <widget>
         <xsl:attribute name="id">
-          <xsl:value-of select="@id"/>
+          <xsl:value-of select="$id"/>
         </xsl:attribute>
         <xsl:attribute name="type">
           <xsl:value-of select="$type"/>
@@ -164,33 +185,65 @@
         <xsl:for-each select="str:split($paths, '@')">
           <xsl:if test="string-length(.) &gt; 0">
             <path>
+              <xsl:variable name="pathminmax" select="str:split(.,',')"/>
+              <xsl:variable name="path" select="$pathminmax[1]"/>
+              <xsl:variable name="pathminmaxcount" select="count($pathminmax)"/>
               <xsl:attribute name="value">
-                <xsl:value-of select="."/>
+                <xsl:value-of select="$path"/>
               </xsl:attribute>
-              <xsl:variable name="path" select="."/>
-              <xsl:variable name="item" select="$indexed_hmitree/*[@hmipath = $path]"/>
               <xsl:choose>
-                <xsl:when test="count($item) = 1">
-                  <xsl:attribute name="index">
-                    <xsl:value-of select="$item/@index"/>
+                <xsl:when test="$pathminmaxcount = 3">
+                  <xsl:attribute name="min">
+                    <xsl:value-of select="$pathminmax[2]"/>
                   </xsl:attribute>
+                  <xsl:attribute name="max">
+                    <xsl:value-of select="$pathminmax[3]"/>
+                  </xsl:attribute>
+                </xsl:when>
+                <xsl:when test="$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:choose>
+                <xsl:when test="regexp:test($path,'^\.[a-zA-Z0-9_]+')">
                   <xsl:attribute name="type">
-                    <xsl:value-of select="local-name($item)"/>
+                    <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: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:choose>
+                  <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>
             </path>
@@ -1223,6 +1276,8 @@
 </xsl:text>
     <xsl:text>        if(typeof(index) == "string"){
 </xsl:text>
+    <xsl:text>            /* XXX return index as path */
+</xsl:text>
     <xsl:text>            index = page_local_index(index, this.container_id);
 </xsl:text>
     <xsl:text>        } else {
@@ -1233,19 +1288,27 @@
 </xsl:text>
     <xsl:text>            }
 </xsl:text>
+    <xsl:text>            /* XXX check for hmi_paths and return path */
+</xsl:text>
     <xsl:text>        }
 </xsl:text>
     <xsl:text>        return index;
 </xsl:text>
     <xsl:text>    }
 </xsl:text>
+    <xsl:text>
+</xsl:text>
     <xsl:text>    change_hmi_value(index, opstr) {
 </xsl:text>
     <xsl:text>        let realindex = this.get_variable_index(index);
 </xsl:text>
     <xsl:text>        if(realindex == undefined) return undefined;
 </xsl:text>
-    <xsl:text>        return change_hmi_value(realindex, opstr);
+    <xsl:text>        let old_val = cache[realindex];
+</xsl:text>
+    <xsl:text>        let new_val = eval_operation_string(old_val, opstr);
+</xsl:text>
+    <xsl:text>        return apply_hmi_value(realindex, new_val);
 </xsl:text>
     <xsl:text>    }
 </xsl:text>
@@ -3995,7 +4058,7 @@
 </xsl:text>
     <xsl:text>         on_op_click(opstr) {
 </xsl:text>
-    <xsl:text>             let new_val = this.change_hmi_value(0, opstr);
+    <xsl:text>             this.change_hmi_value(0, opstr);
 </xsl:text>
     <xsl:text>         }
 </xsl:text>
@@ -6827,71 +6890,83 @@
 </xsl:text>
           <xsl:text>
 </xsl:text>
+          <xsl:text>function eval_operation_string(old_val, opstr) {
+</xsl:text>
+          <xsl:text>    let op = opstr[0];
+</xsl:text>
+          <xsl:text>    let given_val;
+</xsl:text>
+          <xsl:text>    if(opstr.length &lt; 2) 
+</xsl:text>
+          <xsl:text>        return undefined;
+</xsl:text>
+          <xsl:text>    if(opstr[1] in quotes){
+</xsl:text>
+          <xsl:text>        if(opstr.length &lt; 3) 
+</xsl:text>
+          <xsl:text>            return undefined;
+</xsl:text>
+          <xsl:text>        if(opstr[opstr.length-1] == opstr[1]){
+</xsl:text>
+          <xsl:text>            given_val = opstr.slice(2,opstr.length-1);
+</xsl:text>
+          <xsl:text>        }
+</xsl:text>
+          <xsl:text>    } else {
+</xsl:text>
+          <xsl:text>        given_val = Number(opstr.slice(1));
+</xsl:text>
+          <xsl:text>    }
+</xsl:text>
+          <xsl:text>    let new_val;
+</xsl:text>
+          <xsl:text>    switch(op){
+</xsl:text>
+          <xsl:text>      case "=":
+</xsl:text>
+          <xsl:text>        new_val = given_val;
+</xsl:text>
+          <xsl:text>        break;
+</xsl:text>
+          <xsl:text>      case "+":
+</xsl:text>
+          <xsl:text>        new_val = old_val + given_val;
+</xsl:text>
+          <xsl:text>        break;
+</xsl:text>
+          <xsl:text>      case "-":
+</xsl:text>
+          <xsl:text>        new_val = old_val - given_val;
+</xsl:text>
+          <xsl:text>        break;
+</xsl:text>
+          <xsl:text>      case "*":
+</xsl:text>
+          <xsl:text>        new_val = old_val * given_val;
+</xsl:text>
+          <xsl:text>        break;
+</xsl:text>
+          <xsl:text>      case "/":
+</xsl:text>
+          <xsl:text>        new_val = old_val / given_val;
+</xsl:text>
+          <xsl:text>        break;
+</xsl:text>
+          <xsl:text>    }
+</xsl:text>
+          <xsl:text>    return new_val;
+</xsl:text>
+          <xsl:text>}
+</xsl:text>
+          <xsl:text>
+</xsl:text>
+          <xsl:text>/*
+</xsl:text>
           <xsl:text>function change_hmi_value(index, opstr) {
 </xsl:text>
-          <xsl:text>    let op = opstr[0];
-</xsl:text>
-          <xsl:text>    let given_val;
-</xsl:text>
-          <xsl:text>    if(opstr.length &lt; 2) 
-</xsl:text>
-          <xsl:text>        return undefined; // TODO raise
-</xsl:text>
-          <xsl:text>    if(opstr[1] in quotes){
-</xsl:text>
-          <xsl:text>        if(opstr.length &lt; 3) 
-</xsl:text>
-          <xsl:text>            return undefined; // TODO raise
-</xsl:text>
-          <xsl:text>        if(opstr[opstr.length-1] == opstr[1]){
-</xsl:text>
-          <xsl:text>            given_val = opstr.slice(2,opstr.length-1);
-</xsl:text>
-          <xsl:text>        }
-</xsl:text>
-          <xsl:text>    } else {
-</xsl:text>
-          <xsl:text>        given_val = Number(opstr.slice(1));
-</xsl:text>
-          <xsl:text>    }
-</xsl:text>
           <xsl:text>    let old_val = cache[index];
 </xsl:text>
-          <xsl:text>    let new_val;
-</xsl:text>
-          <xsl:text>    switch(op){
-</xsl:text>
-          <xsl:text>      case "=":
-</xsl:text>
-          <xsl:text>        new_val = given_val;
-</xsl:text>
-          <xsl:text>        break;
-</xsl:text>
-          <xsl:text>      case "+":
-</xsl:text>
-          <xsl:text>        new_val = old_val + given_val;
-</xsl:text>
-          <xsl:text>        break;
-</xsl:text>
-          <xsl:text>      case "-":
-</xsl:text>
-          <xsl:text>        new_val = old_val - given_val;
-</xsl:text>
-          <xsl:text>        break;
-</xsl:text>
-          <xsl:text>      case "*":
-</xsl:text>
-          <xsl:text>        new_val = old_val * given_val;
-</xsl:text>
-          <xsl:text>        break;
-</xsl:text>
-          <xsl:text>      case "/":
-</xsl:text>
-          <xsl:text>        new_val = old_val / given_val;
-</xsl:text>
-          <xsl:text>        break;
-</xsl:text>
-          <xsl:text>    }
+          <xsl:text>    let new_val = eval_operation_string(old_val, opstr);
 </xsl:text>
           <xsl:text>    if(new_val != undefined &amp;&amp; old_val != new_val)
 </xsl:text>
@@ -6903,6 +6978,8 @@
 </xsl:text>
           <xsl:text>}
 </xsl:text>
+          <xsl:text>*/
+</xsl:text>
           <xsl:text>
 </xsl:text>
           <xsl:text>var current_visible_page;
--- a/svghmi/hmi_tree.ysl2	Tue Dec 22 14:57:59 2020 +0100
+++ b/svghmi/hmi_tree.ysl2	Thu Dec 24 16:56:19 2020 +0100
@@ -24,7 +24,7 @@
     foreach "$indexed_hmitree/*" 
     |     /* «@index»  «@hmipath» */ "«substring(local-name(), 5)»"`if "position()!=last()" > ,`
 
-    | ]
+    | ];
     |
 }
 
@@ -67,19 +67,20 @@
 }
 
 //  Parses:
-//  "HMI:WidgetType:param1:param2@path1@path2"
+//  "HMI:WidgetType:param1:param2@path1,path1min,path1max@path2"
 //
 //  Into:
 //  widget type="WidgetType" id="blah456" {
 //      arg value="param1";
 //      arg value="param2";
-//      path value=".path1" index=".path1" type="PAGE_LOCAL";
+//      path value=".path1" index=".path1" min="path1min" max="path1max" type="PAGE_LOCAL";
 //      path value="/path1" index="348" type="HMI_INT";
 //      path value="path4" index="path4" type="HMI_LOCAL";
 //  }
 //
 template "*", mode="parselabel" {
     const "label","@inkscape:label";
+    const "id","@id";
     const "description", "substring-after($label,'HMI:')";
 
     const "_args", "substring-before($description,'@')";
@@ -95,7 +96,7 @@
     }
 
     if "$type" widget {
-        attrib "id" > «@id»
+        attrib "id" > «$id»
         attrib "type" > «$type»
         foreach "str:split(substring-after($args, ':'), ':')" {
             arg {
@@ -105,22 +106,35 @@
         const "paths", "substring-after($description,'@')";
         foreach "str:split($paths, '@')" {
             if "string-length(.) > 0" path {
-                attrib "value" > «.»
-                const "path", ".";
-                const "item", "$indexed_hmitree/*[@hmipath = $path]";
+                const "pathminmax", "str:split(.,',')";
+                const "path", "$pathminmax[1]";
+                const "pathminmaxcount", "count($pathminmax)";
+                attrib "value" > «$path»
                 choose {
-                    when "count($item) = 1" {
-                        attrib "index" > «$item/@index»
-                        attrib "type" > «local-name($item)»
+                    when "$pathminmaxcount = 3" {
+                        attrib "min" > «$pathminmax[2]»
+                        attrib "max" > «$pathminmax[3]»
+                    }
+                    when "$pathminmaxcount = 2" {
+                        error > Widget id:«$id» label:«$label» has wrong syntax of path section «$pathminmax»
+                    }
+                }
+                choose {
+                    when "regexp:test($path,'^\.[a-zA-Z0-9_]+')" {
+                        attrib "type" > PAGE_LOCAL
+                    }
+                    when "regexp:test($path,'^[a-zA-Z0-9_]+')" {
+                        attrib "type" > HMI_LOCAL
                     }
                     otherwise {
-                        choose {
-                            when "regexp:test($path,'^\.[a-zA-Z0-9_]+')" {
-                                attrib "type" > PAGE_LOCAL
-                            }
-                            when "regexp:test($path,'^[a-zA-Z0-9_]+')" {
-                                attrib "type" > HMI_LOCAL
-                            }
+                        const "item", "$indexed_hmitree/*[@hmipath = $path]";
+                        const "pathtype", "local-name($item)";
+                        if "$pathminmaxcount = 3 and not($pathtype = 'HMI_INT' or $pathtype = 'HMI_REAL')" {
+                            error > Widget id:«$id» label:«$label» path section «$pathminmax» use min and max on non mumeric value
+                        }
+                        if "count($item) = 1" {
+                            attrib "index" > «$item/@index»
+                            attrib "type" > «$pathtype»
                         }
                     }
                 }
--- a/tests/svghmi/svghmi_0@svghmi/svghmi.svg	Tue Dec 22 14:57:59 2020 +0100
+++ b/tests/svghmi/svghmi_0@svghmi/svghmi.svg	Thu Dec 24 16:56:19 2020 +0100
@@ -304,7 +304,7 @@
   </g>
   <g
      id="g84"
-     inkscape:label="HMI:Input@/TARGETPRESSURE"
+     inkscape:label="HMI:Input@/TARGETPRESSURE,0,100"
      transform="matrix(0.35865594,0,0,0.35865594,22.072155,63.074421)">
     <text
        inkscape:label="value"