SVGHMI: Jump widget can now display as active or inactive, if corresponfing "active" and "inactive labeled elements are provided. svghmi
authorEdouard Tisserant
Fri, 27 Mar 2020 14:25:24 +0100
branchsvghmi
changeset 2903 881d0248b3ce
parent 2902 1fcb50af0335
child 2904 92d115d8828d
SVGHMI: Jump widget can now display as active or inactive, if corresponfing "active" and "inactive labeled elements are provided.
svghmi/detachable_pages.ysl2
svghmi/gen_index_xhtml.xslt
svghmi/svghmi.js
svghmi/widget_jump.ysl2
--- a/svghmi/detachable_pages.ysl2	Thu Mar 26 14:21:52 2020 +0100
+++ b/svghmi/detachable_pages.ysl2	Fri Mar 27 14:25:24 2020 +0100
@@ -131,11 +131,20 @@
     |         hmi_widgets["«@id»"]`if "position()!=last()" > ,`
     }
     |     ],
+    |     jumps: [
+    foreach "$parsed_widgets/widget[@id = $all_page_widgets/@id and @type='Jump']" {
+        const "_id","@id";
+        const "opts" call "jump_widget_activity" with "hmi_element", "$hmi_elements[@id=$_id]";
+        if "string-length($opts)>0"
+    |         hmi_widgets["«@id»"]`if "position()!=last()" > ,`
+    }
+    |     ],
     |     required_detachables: {
     foreach "$required_detachables" {
     |         "«@id»": detachable_elements["«@id»"]`if "position()!=last()" > ,`
     }
     |     }
+    /* TODO generate some code for init() instead */
     apply "$parsed_widgets/widget[@id = $all_page_widgets/@id]", mode="per_page_widget_template"{
         with "page_desc", "$desc";
     }
--- a/svghmi/gen_index_xhtml.xslt	Thu Mar 26 14:21:52 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt	Fri Mar 27 14:25:24 2020 +0100
@@ -404,6 +404,28 @@
     </xsl:for-each>
     <xsl:text>    ],
 </xsl:text>
+    <xsl:text>    jumps: [
+</xsl:text>
+    <xsl:for-each select="$parsed_widgets/widget[@id = $all_page_widgets/@id and @type='Jump']">
+      <xsl:variable name="_id" select="@id"/>
+      <xsl:variable name="opts">
+        <xsl:call-template name="jump_widget_activity">
+          <xsl:with-param name="hmi_element" select="$hmi_elements[@id=$_id]"/>
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:if test="string-length($opts)&gt;0">
+        <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:if>
+    </xsl:for-each>
+    <xsl:text>    ],
+</xsl:text>
     <xsl:text>    required_detachables: {
 </xsl:text>
     <xsl:for-each select="$required_detachables">
@@ -911,8 +933,25 @@
     <xsl:text>    },
 </xsl:text>
   </xsl:template>
+  <xsl:template name="jump_widget_activity">
+    <xsl:param name="hmi_element"/>
+    <xsl:call-template name="defs_by_labels">
+      <xsl:with-param name="hmi_element" select="$hmi_element"/>
+      <xsl:with-param name="labels">
+        <xsl:text>active inactive</xsl:text>
+      </xsl:with-param>
+      <xsl:with-param name="mandatory" select="'no'"/>
+    </xsl:call-template>
+  </xsl:template>
   <xsl:template mode="widget_defs" match="widget[@type='Jump']">
     <xsl:param name="hmi_element"/>
+    <xsl:variable name="opts">
+      <xsl:call-template name="jump_widget_activity">
+        <xsl:with-param name="hmi_element" select="$hmi_element"/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="have_opt" select="string-length($opts)&gt;0"/>
+    <xsl:value-of select="$opts"/>
     <xsl:text>    on_click: function(evt) {
 </xsl:text>
     <xsl:text>        const index = this.indexes.length &gt; 0 ? this.indexes[0] + this.offset : undefined;
@@ -923,12 +962,54 @@
 </xsl:text>
     <xsl:text>    },
 </xsl:text>
+    <xsl:if test="$have_opt">
+      <xsl:text>    notify_page_change: function(page_name, index){
+</xsl:text>
+      <xsl:text>        const ref_index = this.indexes.length &gt; 0 ? this.indexes[0] + this.offset : undefined;
+</xsl:text>
+      <xsl:text>        const ref_name = this.args[0];
+</xsl:text>
+      <xsl:text>        if((ref_name == undefined || ref_name == page_name) &amp;&amp; index == ref_index) {
+</xsl:text>
+      <xsl:text>             console.log("active", ref_name, ref_index, page_name, index);
+</xsl:text>
+      <xsl:text>             /* show active */ 
+</xsl:text>
+      <xsl:text>             this.active_elt.setAttribute("style", this.active_elt_style);
+</xsl:text>
+      <xsl:text>             /* hide inactive */ 
+</xsl:text>
+      <xsl:text>             this.inactive_elt.setAttribute("style", "display:none");
+</xsl:text>
+      <xsl:text>        } else {
+</xsl:text>
+      <xsl:text>             console.log("inactive",ref_name, ref_index,  page_name, index);
+</xsl:text>
+      <xsl:text>             /* show inactive */ 
+</xsl:text>
+      <xsl:text>             this.inactive_elt.setAttribute("style", this.inactive_elt_style);
+</xsl:text>
+      <xsl:text>             /* hide active */ 
+</xsl:text>
+      <xsl:text>             this.active_elt.setAttribute("style", "display:none");
+</xsl:text>
+      <xsl:text>        }
+</xsl:text>
+      <xsl:text>    },
+</xsl:text>
+    </xsl:if>
     <xsl:text>    init: function() {
 </xsl:text>
     <xsl:text>        this.element.setAttribute("onclick", "hmi_widgets['</xsl:text>
     <xsl:value-of select="$hmi_element/@id"/>
     <xsl:text>'].on_click(evt)");
 </xsl:text>
+    <xsl:if test="$have_opt">
+      <xsl:text>        this.active_elt_style = this.active_elt.getAttribute("style");
+</xsl:text>
+      <xsl:text>        this.inactive_elt_style = this.inactive_elt.getAttribute("style");
+</xsl:text>
+    </xsl:if>
     <xsl:text>    },
 </xsl:text>
   </xsl:template>
@@ -1224,6 +1305,8 @@
 </xsl:text>
     <xsl:text>var need_cache_apply = []; 
 </xsl:text>
+    <xsl:text>var jumps_need_update = false;
+</xsl:text>
     <xsl:text>var jump_history = [[default_page, undefined]];
 </xsl:text>
     <xsl:text>
@@ -1404,6 +1487,10 @@
 </xsl:text>
     <xsl:text>
 </xsl:text>
+    <xsl:text>    if(jumps_need_update) update_jumps();
+</xsl:text>
+    <xsl:text>
+</xsl:text>
     <xsl:text>    apply_updates();
 </xsl:text>
     <xsl:text>    requestAnimationFrameID = null;
@@ -1738,6 +1825,8 @@
 </xsl:text>
     <xsl:text>var current_subscribed_page;
 </xsl:text>
+    <xsl:text>var current_page_index;
+</xsl:text>
     <xsl:text>
 </xsl:text>
     <xsl:text>function prepare_svg() {
@@ -1774,7 +1863,71 @@
 </xsl:text>
     <xsl:text>
 </xsl:text>
-    <xsl:text>    return switch_subscribed_page(page_name, page_index);
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    let old_desc = page_desc[current_subscribed_page];
+</xsl:text>
+    <xsl:text>    let new_desc = page_desc[page_name];
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    if(new_desc == undefined){
+</xsl:text>
+    <xsl:text>        /* TODO LOG ERROR */
+</xsl:text>
+    <xsl:text>        return false;
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    if(page_index == undefined){
+</xsl:text>
+    <xsl:text>        page_index = new_desc.page_index;
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    if(old_desc){
+</xsl:text>
+    <xsl:text>        old_desc.absolute_widgets.map(w=&gt;w.unsub());
+</xsl:text>
+    <xsl:text>        old_desc.relative_widgets.map(w=&gt;w.unsub());
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>    new_desc.absolute_widgets.map(w=&gt;w.sub());
+</xsl:text>
+    <xsl:text>    var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index;
+</xsl:text>
+    <xsl:text>    new_desc.relative_widgets.map(w=&gt;w.sub(new_offset));
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    update_subscriptions();
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    current_subscribed_page = page_name;
+</xsl:text>
+    <xsl:text>    current_page_index = page_index;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    jumps_need_update = true;
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    requestHMIAnimation();
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    jump_history.push([page_name, page_index]);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    return true;
 </xsl:text>
     <xsl:text>};
 </xsl:text>
@@ -1946,6 +2099,8 @@
 </xsl:text>
     <xsl:text>    need_cache_apply.push(this);
 </xsl:text>
+    <xsl:text>    jumps_need_update = true;
+</xsl:text>
     <xsl:text>    requestHMIAnimation();
 </xsl:text>
     <xsl:text>    console.log(opstr, new_item_offset);
@@ -1954,82 +2109,20 @@
 </xsl:text>
     <xsl:text>
 </xsl:text>
-    <xsl:text>function switch_subscribed_page(page_name, page_index) {
-</xsl:text>
-    <xsl:text>    let old_desc = page_desc[current_subscribed_page];
+    <xsl:text>
+</xsl:text>
+    <xsl:text>function switch_visible_page(page_name) {
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    let old_desc = page_desc[current_visible_page];
 </xsl:text>
     <xsl:text>    let new_desc = page_desc[page_name];
 </xsl:text>
     <xsl:text>
 </xsl:text>
-    <xsl:text>    if(new_desc == undefined){
-</xsl:text>
-    <xsl:text>        /* TODO LOG ERROR */
-</xsl:text>
-    <xsl:text>        return false;
-</xsl:text>
-    <xsl:text>    }
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    if(page_index == undefined){
-</xsl:text>
-    <xsl:text>        page_index = new_desc.page_index;
-</xsl:text>
-    <xsl:text>    }
-</xsl:text>
-    <xsl:text>
-</xsl:text>
     <xsl:text>    if(old_desc){
 </xsl:text>
-    <xsl:text>        old_desc.absolute_widgets.map(w=&gt;w.unsub());
-</xsl:text>
-    <xsl:text>        old_desc.relative_widgets.map(w=&gt;w.unsub());
-</xsl:text>
-    <xsl:text>    }
-</xsl:text>
-    <xsl:text>    new_desc.absolute_widgets.map(w=&gt;w.sub());
-</xsl:text>
-    <xsl:text>    var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index;
-</xsl:text>
-    <xsl:text>    new_desc.relative_widgets.map(w=&gt;w.sub(new_offset));
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    update_subscriptions();
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    current_subscribed_page = page_name;
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    requestHMIAnimation();
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    jump_history.push([page_name, page_index]);
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    return true;
-</xsl:text>
-    <xsl:text>}
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>function switch_visible_page(page_name) {
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    let old_desc = page_desc[current_visible_page];
-</xsl:text>
-    <xsl:text>    let new_desc = page_desc[page_name];
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    if(old_desc){
-</xsl:text>
     <xsl:text>        for(let eltid in old_desc.required_detachables){
 </xsl:text>
     <xsl:text>            if(!(eltid in new_desc.required_detachables)){
@@ -2076,6 +2169,18 @@
 </xsl:text>
     <xsl:text>
 </xsl:text>
+    <xsl:text>function update_jumps() {
+</xsl:text>
+    <xsl:text>    page_desc[current_visible_page].jumps.map(w=&gt;w.notify_page_change(current_visible_page,current_page_index));
+</xsl:text>
+    <xsl:text>    jumps_need_update = false;
+</xsl:text>
+    <xsl:text>};
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>
+</xsl:text>
     <xsl:text>// Once connection established
 </xsl:text>
     <xsl:text>ws.onopen = function (evt) {
--- a/svghmi/svghmi.js	Thu Mar 26 14:21:52 2020 +0100
+++ b/svghmi/svghmi.js	Fri Mar 27 14:25:24 2020 +0100
@@ -3,6 +3,7 @@
 var cache = hmitree_types.map(_ignored => undefined);
 var updates = {};
 var need_cache_apply = []; 
+var jumps_need_update = false;
 var jump_history = [[default_page, undefined]];
 
 function dispatch_value_to_widget(widget, index, value, oldval) {
@@ -93,6 +94,8 @@
         widget.apply_cache();
     }
 
+    if(jumps_need_update) update_jumps();
+
     apply_updates();
     requestAnimationFrameID = null;
 }
@@ -260,6 +263,7 @@
 
 var current_visible_page;
 var current_subscribed_page;
+var current_page_index;
 
 function prepare_svg() {
     for(let eltid in detachable_elements){
@@ -278,7 +282,39 @@
     if(page_name == undefined)
         page_name = current_subscribed_page;
 
-    return switch_subscribed_page(page_name, page_index);
+
+    let old_desc = page_desc[current_subscribed_page];
+    let new_desc = page_desc[page_name];
+
+    if(new_desc == undefined){
+        /* TODO LOG ERROR */
+        return false;
+    }
+
+    if(page_index == undefined){
+        page_index = new_desc.page_index;
+    }
+
+    if(old_desc){
+        old_desc.absolute_widgets.map(w=>w.unsub());
+        old_desc.relative_widgets.map(w=>w.unsub());
+    }
+    new_desc.absolute_widgets.map(w=>w.sub());
+    var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index;
+    new_desc.relative_widgets.map(w=>w.sub(new_offset));
+
+    update_subscriptions();
+
+    current_subscribed_page = page_name;
+    current_page_index = page_index;
+
+    jumps_need_update = true;
+
+    requestHMIAnimation();
+
+    jump_history.push([page_name, page_index]);
+
+    return true;
 };
 
 function* chain(a,b){
@@ -364,41 +400,11 @@
     foreach_subscribe.call(this,off);
     update_subscriptions();
     need_cache_apply.push(this);
+    jumps_need_update = true;
     requestHMIAnimation();
     console.log(opstr, new_item_offset);
 }
 
-function switch_subscribed_page(page_name, page_index) {
-    let old_desc = page_desc[current_subscribed_page];
-    let new_desc = page_desc[page_name];
-
-    if(new_desc == undefined){
-        /* TODO LOG ERROR */
-        return false;
-    }
-
-    if(page_index == undefined){
-        page_index = new_desc.page_index;
-    }
-
-    if(old_desc){
-        old_desc.absolute_widgets.map(w=>w.unsub());
-        old_desc.relative_widgets.map(w=>w.unsub());
-    }
-    new_desc.absolute_widgets.map(w=>w.sub());
-    var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index;
-    new_desc.relative_widgets.map(w=>w.sub(new_offset));
-
-    update_subscriptions();
-
-    current_subscribed_page = page_name;
-
-    requestHMIAnimation();
-
-    jump_history.push([page_name, page_index]);
-
-    return true;
-}
 
 function switch_visible_page(page_name) {
 
@@ -429,6 +435,12 @@
     current_visible_page = page_name;
 };
 
+function update_jumps() {
+    page_desc[current_visible_page].jumps.map(w=>w.notify_page_change(current_visible_page,current_page_index));
+    jumps_need_update = false;
+};
+
+
 // Once connection established
 ws.onopen = function (evt) {
     init_widgets();
--- a/svghmi/widget_jump.ysl2	Thu Mar 26 14:21:52 2020 +0100
+++ b/svghmi/widget_jump.ysl2	Fri Mar 27 14:25:24 2020 +0100
@@ -1,13 +1,39 @@
 // widget_jump.ysl2
 
+function "jump_widget_activity" {
+    param "hmi_element";
+        optional_labels("active inactive");
+}
+
 template "widget[@type='Jump']", mode="widget_defs" {
     param "hmi_element";
-
+    const "opts" call "jump_widget_activity" with "hmi_element", "$hmi_element";
+    const "have_opt","string-length($opts)>0";
+    value "$opts";
     |     on_click: function(evt) {
     |         const index = this.indexes.length > 0 ? this.indexes[0] + this.offset : undefined;
     |         const name = this.args[0];
     |         switch_page(name, index);
     |     },
+    if "$have_opt" {
+    |     notify_page_change: function(page_name, index){
+    |         const ref_index = this.indexes.length > 0 ? this.indexes[0] + this.offset : undefined;
+    |         const ref_name = this.args[0];
+    |         if((ref_name == undefined || ref_name == page_name) && index == ref_index) {
+    |              console.log("active", ref_name, ref_index, page_name, index);
+    |              /* show active */ 
+    |              this.active_elt.setAttribute("style", this.active_elt_style);
+    |              /* hide inactive */ 
+    |              this.inactive_elt.setAttribute("style", "display:none");
+    |         } else {
+    |              console.log("inactive",ref_name, ref_index,  page_name, index);
+    |              /* show inactive */ 
+    |              this.inactive_elt.setAttribute("style", this.inactive_elt_style);
+    |              /* hide active */ 
+    |              this.active_elt.setAttribute("style", "display:none");
+    |         }
+    |     },
+    }
     |     init: function() {
     /* registering event this way does not "click" through svg:use 
     |     this.element.onclick = evt => switch_page(this.args[0]);
@@ -15,6 +41,10 @@
     TODO : generalize mouse event handling by global event capture + getElementsAtPoint()
     */
     |         this.element.setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_click(evt)");
+    if "$have_opt" {
+    |         this.active_elt_style = this.active_elt.getAttribute("style");
+    |         this.inactive_elt_style = this.inactive_elt.getAttribute("style");
+    }
     |     },
 }