SVGHMI: finished shift and capslock support n keypad widget. Added a helper in widgets_common to collect subelements likle active/inactive/disabled... svghmi
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Sat, 04 Apr 2020 22:32:54 +0200
branchsvghmi
changeset 2920 3ee337c8c769
parent 2919 c6e6051898f5
child 2921 2670f5c53caf
SVGHMI: finished shift and capslock support n keypad widget. Added a helper in widgets_common to collect subelements likle active/inactive/disabled...
svghmi/gen_index_xhtml.xslt
svghmi/svghmi.js
svghmi/widget_keypad.ysl2
svghmi/widgets_common.ysl2
tests/svghmi/svghmi_0@svghmi/svghmi.svg
--- a/svghmi/gen_index_xhtml.xslt	Sat Apr 04 17:47:16 2020 +0200
+++ b/svghmi/gen_index_xhtml.xslt	Sat Apr 04 22:32:54 2020 +0200
@@ -687,15 +687,16 @@
   <xsl:template name="defs_by_labels">
     <xsl:param name="labels" select="''"/>
     <xsl:param name="mandatory" select="'yes'"/>
+    <xsl:param name="subelements" select="/.."/>
     <xsl:param name="hmi_element"/>
     <xsl:variable name="widget_type" select="@type"/>
     <xsl:for-each select="str:split($labels)">
       <xsl:variable name="name" select="."/>
-      <xsl:variable name="elt_id" select="$result_svg_ns//*[@id = $hmi_element/@id]//*[@inkscape:label=$name][1]/@id"/>
+      <xsl:variable name="elt" select="$result_svg_ns//*[@id = $hmi_element/@id]//*[@inkscape:label=$name][1]"/>
       <xsl:choose>
-        <xsl:when test="not($elt_id)">
+        <xsl:when test="not($elt/@id)">
           <xsl:if test="$mandatory='yes'">
-            <xsl:message terminate="no">
+            <xsl:message terminate="yes">
               <xsl:value-of select="$widget_type"/>
               <xsl:text> widget must have a </xsl:text>
               <xsl:value-of select="$name"/>
@@ -707,9 +708,53 @@
           <xsl:text>    </xsl:text>
           <xsl:value-of select="$name"/>
           <xsl:text>_elt: id("</xsl:text>
-          <xsl:value-of select="$elt_id"/>
+          <xsl:value-of select="$elt/@id"/>
           <xsl:text>"),
 </xsl:text>
+          <xsl:if test="$subelements">
+            <xsl:text>    </xsl:text>
+            <xsl:value-of select="$name"/>
+            <xsl:text>_sub: {
+</xsl:text>
+            <xsl:for-each select="str:split($subelements)">
+              <xsl:variable name="subname" select="."/>
+              <xsl:variable name="subelt" select="$elt/*[@inkscape:label=$subname][1]"/>
+              <xsl:choose>
+                <xsl:when test="not($subelt/@id)">
+                  <xsl:if test="$mandatory='yes'">
+                    <xsl:message terminate="yes">
+                      <xsl:value-of select="$widget_type"/>
+                      <xsl:text> widget must have a </xsl:text>
+                      <xsl:value-of select="$name"/>
+                      <xsl:text>/</xsl:text>
+                      <xsl:value-of select="$subname"/>
+                      <xsl:text> element</xsl:text>
+                    </xsl:message>
+                  </xsl:if>
+                  <xsl:text>        /* missing </xsl:text>
+                  <xsl:value-of select="$name"/>
+                  <xsl:text>/</xsl:text>
+                  <xsl:value-of select="$subname"/>
+                  <xsl:text> element */
+</xsl:text>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:text>        "</xsl:text>
+                  <xsl:value-of select="$subname"/>
+                  <xsl:text>": id("</xsl:text>
+                  <xsl:value-of select="$subelt/@id"/>
+                  <xsl:text>")</xsl:text>
+                  <xsl:if test="position()!=last()">
+                    <xsl:text>,</xsl:text>
+                  </xsl:if>
+                  <xsl:text>
+</xsl:text>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:for-each>
+            <xsl:text>    },
+</xsl:text>
+          </xsl:if>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:for-each>
@@ -1197,10 +1242,18 @@
     <xsl:call-template name="defs_by_labels">
       <xsl:with-param name="hmi_element" select="$hmi_element"/>
       <xsl:with-param name="labels">
-        <xsl:text>Sign CapsLock Shift Space</xsl:text>
+        <xsl:text>Sign Space NumDot</xsl:text>
       </xsl:with-param>
       <xsl:with-param name="mandatory" select="'no'"/>
     </xsl:call-template>
+    <xsl:call-template name="defs_by_labels">
+      <xsl:with-param name="hmi_element" select="$hmi_element"/>
+      <xsl:with-param name="labels">
+        <xsl:text>CapsLock Shift</xsl:text>
+      </xsl:with-param>
+      <xsl:with-param name="mandatory" select="'no'"/>
+      <xsl:with-param name="subelements" select="'active inactive'"/>
+    </xsl:call-template>
     <xsl:text>    init: function() {
 </xsl:text>
     <xsl:for-each select="$hmi_element/*[@inkscape:label = 'Keys']/*">
@@ -1213,7 +1266,7 @@
       <xsl:text>')");
 </xsl:text>
     </xsl:for-each>
-    <xsl:for-each select="str:split('Esc Enter BackSpace Sign Space CapsLock Shift')">
+    <xsl:for-each select="str:split('Esc Enter BackSpace Sign Space NumDot CapsLock Shift')">
       <xsl:text>        if(this.</xsl:text>
       <xsl:value-of select="."/>
       <xsl:text>_elt)
@@ -1241,16 +1294,12 @@
 </xsl:text>
     <xsl:text>        this.update();
 </xsl:text>
-    <xsl:text>        console.log(symbols);
-</xsl:text>
     <xsl:text>    },
 </xsl:text>
     <xsl:text>    on_Esc_click: function() {
 </xsl:text>
     <xsl:text>        end_modal.call(this);
 </xsl:text>
-    <xsl:text>        console.log("Esc");
-</xsl:text>
     <xsl:text>    },
 </xsl:text>
     <xsl:text>    on_Enter_click: function() {
@@ -1261,8 +1310,6 @@
 </xsl:text>
     <xsl:text>        callback_obj.edit_callback(this.editstr);
 </xsl:text>
-    <xsl:text>        console.log("Enter");
-</xsl:text>
     <xsl:text>    },
 </xsl:text>
     <xsl:text>    on_BackSpace_click: function() {
@@ -1271,8 +1318,6 @@
 </xsl:text>
     <xsl:text>        this.update();
 </xsl:text>
-    <xsl:text>        console.log("BackSpace");
-</xsl:text>
     <xsl:text>    },
 </xsl:text>
     <xsl:text>    on_Sign_click: function() {
@@ -1285,35 +1330,53 @@
 </xsl:text>
     <xsl:text>            this.editstr = "-" + this.editstr;
 </xsl:text>
-    <xsl:text>        console.log("Sign");
+    <xsl:text>        this.update();
 </xsl:text>
     <xsl:text>    },
 </xsl:text>
+    <xsl:text>    on_NumDot_click: function() {
+</xsl:text>
+    <xsl:text>        if(this.editstr.indexOf(".") == "-1"){
+</xsl:text>
+    <xsl:text>            this.editstr += ".";
+</xsl:text>
+    <xsl:text>            this.update();
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    },
+</xsl:text>
     <xsl:text>    on_Space_click: function() {
 </xsl:text>
     <xsl:text>        this.editstr += " ";
 </xsl:text>
-    <xsl:text>        console.log("Space");
+    <xsl:text>        this.update();
 </xsl:text>
     <xsl:text>    },
 </xsl:text>
     <xsl:text>    caps: false,
 </xsl:text>
+    <xsl:text>    _caps: undefined,
+</xsl:text>
     <xsl:text>    on_CapsLock_click: function() {
 </xsl:text>
     <xsl:text>        this.caps = !this.caps;
 </xsl:text>
-    <xsl:text>        console.log("CapsLock");
+    <xsl:text>        this.update();
 </xsl:text>
     <xsl:text>    },
 </xsl:text>
     <xsl:text>    shift: false,
 </xsl:text>
+    <xsl:text>    _shift: undefined,
+</xsl:text>
     <xsl:text>    on_Shift_click: function() {
 </xsl:text>
-    <xsl:text>        this.shift = true;
-</xsl:text>
-    <xsl:text>        console.log("Shift");
+    <xsl:text>        this.shift = !this.shift;
+</xsl:text>
+    <xsl:text>        this.caps = false;
+</xsl:text>
+    <xsl:text>        this.update();
 </xsl:text>
     <xsl:text>    },
 </xsl:text>
@@ -1326,6 +1389,8 @@
 </xsl:text>
     <xsl:text>    editstr: "",
 </xsl:text>
+    <xsl:text>    _editstr: undefined,
+</xsl:text>
     <xsl:text>    result_callback_obj: undefined,
 </xsl:text>
     <xsl:text>    start_edit: function(info, valuetype, callback_obj, initial) {
@@ -1348,9 +1413,29 @@
 </xsl:text>
     <xsl:text>    update: function() {
 </xsl:text>
-    <xsl:text>        /* TODO Swith shift and capslock active/inactive elements */
-</xsl:text>
-    <xsl:text>        this.Value_elt.textContent = this.editstr;
+    <xsl:text>        if(this.editstr != this._editstr){
+</xsl:text>
+    <xsl:text>            this._editstr = this.editstr;
+</xsl:text>
+    <xsl:text>            this.Value_elt.textContent = this.editstr;
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        if(this.shift != this._shift){
+</xsl:text>
+    <xsl:text>            this._shift = this.shift;
+</xsl:text>
+    <xsl:text>            (this.shift?widget_active_activable:widget_inactive_activable)(this.Shift_sub);
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        if(this.caps != this._caps){
+</xsl:text>
+    <xsl:text>            this._caps = this.caps;
+</xsl:text>
+    <xsl:text>            (this.caps?widget_active_activable:widget_inactive_activable)(this.CapsLock_sub);
+</xsl:text>
+    <xsl:text>        }
 </xsl:text>
     <xsl:text>    },
 </xsl:text>
@@ -2605,5 +2690,39 @@
 </xsl:text>
     <xsl:text>};
 </xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>function widget_active_activable(eltsub) {
+</xsl:text>
+    <xsl:text>    if(eltsub.inactive_style === undefined)
+</xsl:text>
+    <xsl:text>        eltsub.inactive_style = eltsub.inactive.getAttribute("style");
+</xsl:text>
+    <xsl:text>    eltsub.inactive.setAttribute("style", "display:none");
+</xsl:text>
+    <xsl:text>    if(eltsub.active_style !== undefined)
+</xsl:text>
+    <xsl:text>            eltsub.active.setAttribute("style", eltsub.active_style);
+</xsl:text>
+    <xsl:text>    console.log("active", eltsub);
+</xsl:text>
+    <xsl:text>};
+</xsl:text>
+    <xsl:text>function widget_inactive_activable(eltsub) {
+</xsl:text>
+    <xsl:text>    if(eltsub.active_style === undefined)
+</xsl:text>
+    <xsl:text>        eltsub.active_style = eltsub.active.getAttribute("style");
+</xsl:text>
+    <xsl:text>    eltsub.active.setAttribute("style", "display:none");
+</xsl:text>
+    <xsl:text>    if(eltsub.inactive_style !== undefined)
+</xsl:text>
+    <xsl:text>            eltsub.inactive.setAttribute("style", eltsub.inactive_style);
+</xsl:text>
+    <xsl:text>    console.log("inactive", eltsub);
+</xsl:text>
+    <xsl:text>};
+</xsl:text>
   </xsl:template>
 </xsl:stylesheet>
--- a/svghmi/svghmi.js	Sat Apr 04 17:47:16 2020 +0200
+++ b/svghmi/svghmi.js	Sat Apr 04 22:32:54 2020 +0200
@@ -505,3 +505,20 @@
 
     current_modal = undefined;
 };
+
+function widget_active_activable(eltsub) {
+    if(eltsub.inactive_style === undefined)
+        eltsub.inactive_style = eltsub.inactive.getAttribute("style");
+    eltsub.inactive.setAttribute("style", "display:none");
+    if(eltsub.active_style !== undefined)
+            eltsub.active.setAttribute("style", eltsub.active_style);
+    console.log("active", eltsub);
+};
+function widget_inactive_activable(eltsub) {
+    if(eltsub.active_style === undefined)
+        eltsub.active_style = eltsub.active.getAttribute("style");
+    eltsub.active.setAttribute("style", "display:none");
+    if(eltsub.inactive_style !== undefined)
+            eltsub.inactive.setAttribute("style", eltsub.inactive_style);
+    console.log("inactive", eltsub);
+};
--- a/svghmi/widget_keypad.ysl2	Sat Apr 04 17:47:16 2020 +0200
+++ b/svghmi/widget_keypad.ysl2	Sat Apr 04 22:32:54 2020 +0200
@@ -3,12 +3,13 @@
 template "widget[@type='Keypad']", mode="widget_defs" {
     param "hmi_element";
     labels("Esc Enter BackSpace Keys Info Value");
-    optional_labels("Sign CapsLock Shift Space");
+    optional_labels("Sign Space NumDot");
+    activable_labels("CapsLock Shift");
     |     init: function() {
     foreach "$hmi_element/*[@inkscape:label = 'Keys']/*" {
     |         id("«@id»").setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_key_click('«func:escape_quotes(@inkscape:label)»')");
     }
-    foreach "str:split('Esc Enter BackSpace Sign Space CapsLock Shift')" {
+    foreach "str:split('Esc Enter BackSpace Sign Space NumDot CapsLock Shift')" {
     |         if(this.«.»_elt)
     |             this.«.»_elt.setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_«.»_click()");
     }
@@ -19,51 +20,53 @@
     |         this.editstr += syms[this.shift?syms.length-1:0];
     |         this.shift = false;
     |         this.update();
-    |         console.log(symbols);
     |     },
     |     on_Esc_click: function() {
     |         end_modal.call(this);
-    |         console.log("Esc");
     |     },
     |     on_Enter_click: function() {
     |         end_modal.call(this);
     |         callback_obj = this.result_callback_obj;
     |         callback_obj.edit_callback(this.editstr);
-    |         console.log("Enter");
     |     },
     |     on_BackSpace_click: function() {
     |         this.editstr = this.editstr.slice(0,this.editstr.length-1);
     |         this.update();
-    |         console.log("BackSpace");
     |     },
     |     on_Sign_click: function() {
     |         if(this.editstr[0] == "-")
     |             this.editstr = this.editstr.slice(1,this.editstr.length);
     |         else
     |             this.editstr = "-" + this.editstr;
-    |         console.log("Sign");
+    |         this.update();
+    |     },
+    |     on_NumDot_click: function() {
+    |         if(this.editstr.indexOf(".") == "-1"){
+    |             this.editstr += ".";
+    |             this.update();
+    |         }
     |     },
     |     on_Space_click: function() {
     |         this.editstr += " ";
     |         this.update();
-    |         console.log("Space");
     |     },
     |     caps: false,
+    |     _caps: undefined,
     |     on_CapsLock_click: function() {
     |         this.caps = !this.caps;
     |         this.update();
-    |         console.log("CapsLock");
     |     },
     |     shift: false,
+    |     _shift: undefined,
     |     on_Shift_click: function() {
-    |         this.shift = true;
+    |         this.shift = !this.shift;
     |         this.caps = false;
     |         this.update();
-    |         console.log("Shift");
     |     },
     const "g", "$geometry[@Id = $hmi_element/@id]"; 
     |     coordinates: [«$g/@x», «$g/@y»],
     |     editstr: "",
+    |     _editstr: undefined,
     |     result_callback_obj: undefined,
     |     start_edit: function(info, valuetype, callback_obj, initial) {
     |         show_modal.call(this);
@@ -75,7 +78,17 @@
     |         this.update();
     |     },
     |     update: function() {
-    |         /* TODO Swith shift and capslock active/inactive elements */
-    |         this.Value_elt.textContent = this.editstr;
+    |         if(this.editstr != this._editstr){
+    |             this._editstr = this.editstr;
+    |             this.Value_elt.textContent = this.editstr;
+    |         }
+    |         if(this.shift != this._shift){
+    |             this._shift = this.shift;
+    |             (this.shift?widget_active_activable:widget_inactive_activable)(this.Shift_sub);
+    |         }
+    |         if(this.caps != this._caps){
+    |             this._caps = this.caps;
+    |             (this.caps?widget_active_activable:widget_inactive_activable)(this.CapsLock_sub);
+    |         }
     |     },
 }
--- a/svghmi/widgets_common.ysl2	Sat Apr 04 17:47:16 2020 +0200
+++ b/svghmi/widgets_common.ysl2	Sat Apr 04 22:32:54 2020 +0200
@@ -11,6 +11,13 @@
     with "mandatory","'no'";
 };
 
+in xsl decl activable_labels(*ptr, name="defs_by_labels") alias call-template {
+    with "hmi_element", "$hmi_element";
+    with "labels"{text *ptr};
+    with "mandatory","'no'";
+    with "subelements","'active inactive'";
+};
+
 template "svg:*", mode="hmi_elements" {
     const "widget", "func:widget(@id)";
     const "eltid","@id";
@@ -51,21 +58,40 @@
 function "defs_by_labels" {
     param "labels","''";
     param "mandatory","'yes'";
+    param "subelements","/..";
     param "hmi_element";
     const "widget_type","@type";
     foreach "str:split($labels)" {
         const "name",".";
-        const "elt_id","$result_svg_ns//*[@id = $hmi_element/@id]//*[@inkscape:label=$name][1]/@id";
+        const "elt","$result_svg_ns//*[@id = $hmi_element/@id]//*[@inkscape:label=$name][1]";
         choose {
-            when "not($elt_id)" {
+            when "not($elt/@id)" {
                 if "$mandatory='yes'" {
-                    // TODO FIXME error > «$widget_type» widget must have a «$name» element
-                    warning > «$widget_type» widget must have a «$name» element
+                    error > «$widget_type» widget must have a «$name» element
                 }
                 // otherwise produce nothing
             }
             otherwise {
-                |     «$name»_elt: id("«$elt_id»"),
+                |     «$name»_elt: id("«$elt/@id»"),
+                if "$subelements" {
+                |     «$name»_sub: {
+                    foreach "str:split($subelements)" {
+                        const "subname",".";
+                        const "subelt","$elt/*[@inkscape:label=$subname][1]";
+                        choose {
+                            when "not($subelt/@id)" {
+                                if "$mandatory='yes'" {
+                                    error > «$widget_type» widget must have a «$name»/«$subname» element
+                                }
+                |         /* missing «$name»/«$subname» element */
+                            }
+                            otherwise {
+                |         "«$subname»": id("«$subelt/@id»")`if "position()!=last()" > ,`
+                            }
+                        }
+                    }
+                |     },
+                }
             }
         }
     }
--- a/tests/svghmi/svghmi_0@svghmi/svghmi.svg	Sat Apr 04 17:47:16 2020 +0200
+++ b/tests/svghmi/svghmi_0@svghmi/svghmi.svg	Sat Apr 04 22:32:54 2020 +0200
@@ -1529,22 +1529,6 @@
            x="636.4165"
            transform="scale(1.0007154,0.99928514)">0</text>
       </g>
-      <g
-         style="stroke-width:0.13585199"
-         id="g4942"
-         inkscape:label=".">
-        <path
-           inkscape:connector-curvature="0"
-           d="m 697,197 h 20 c 2,0 3,1 3,2 v 19 c 0,1 -1,2 -3,2 h -20 c -1,0 -3,-1 -3,-2 v -19 c 0,-1 2,-2 3,-2 z"
-           id="path181"
-           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.10074359;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
-        <text
-           style="font-weight:normal;font-size:6.96602964px;font-family:Arial;fill:#2b2828;stroke-width:0.10514989"
-           id="text771"
-           y="204.54802"
-           x="696.7464"
-           transform="scale(1.0007154,0.99928514)">.</text>
-      </g>
     </g>
     <g
        id="g3113"
@@ -1608,6 +1592,23 @@
          x="252.9579"
          y="12.333653"
          style="stroke-width:0.30784383px">information</tspan></text>
+    <g
+       transform="matrix(1.6700128,0,0,1.6700128,-826.83854,-145.60856)"
+       style="fill-rule:evenodd;stroke-width:0.13585199"
+       id="g4942"
+       inkscape:label="NumDot">
+      <path
+         inkscape:connector-curvature="0"
+         d="m 697,197 h 20 c 2,0 3,1 3,2 v 19 c 0,1 -1,2 -3,2 h -20 c -1,0 -3,-1 -3,-2 v -19 c 0,-1 2,-2 3,-2 z"
+         id="path181"
+         style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.10074359;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <text
+         style="font-weight:normal;font-size:6.96602964px;font-family:Arial;fill:#2b2828;stroke-width:0.10514989"
+         id="text771"
+         y="204.54802"
+         x="696.7464"
+         transform="scale(1.0007154,0.99928514)">.</text>
+    </g>
   </g>
   <g
      transform="matrix(3.3549332,0,0,3.14525,-181.87457,1556.0198)"