# HG changeset patch # User Edouard Tisserant # Date 1585139764 -3600 # Node ID bf8a39cc65e4cc9cf344b367a0eb5efb134d0483 # Parent 99c5335ed59fc48c74492782ddadff189a70a6dd SVGHMI: Generalize applying cache to widgets, be it from page or ForEach widgets. Now ForEach widget buttons work as expected. diff -r 99c5335ed59f -r bf8a39cc65e4 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Tue Mar 24 23:07:54 2020 +0100 +++ b/svghmi/gen_index_xhtml.xslt Wed Mar 25 13:36:04 2020 +0100 @@ -635,6 +635,8 @@ </xsl:text> <xsl:text> unsub: unsubscribe, </xsl:text> + <xsl:text> apply_cache: widget_apply_cache, +</xsl:text> </xsl:template> <xsl:template mode="widget_subscribe" match="widget[@type='Page']"/> <xsl:template name="defs_by_labels"> @@ -798,27 +800,17 @@ </xsl:text> <xsl:text> }, </xsl:text> - <xsl:text> on_click: function(opstr, evt) { -</xsl:text> - <xsl:text> console.log(opstr); -</xsl:text> - <xsl:text> }, -</xsl:text> <xsl:text> item_offset: 0, </xsl:text> + <xsl:text> on_click: foreach_onclick, +</xsl:text> </xsl:template> <xsl:template mode="widget_subscribe" match="widget[@type='ForEach']"> - <xsl:text> sub: function(off){ -</xsl:text> - <xsl:text> foreach_subscribe.call(this,off); -</xsl:text> - <xsl:text> }, -</xsl:text> - <xsl:text> unsub: function(){ -</xsl:text> - <xsl:text> foreach_unsubscribe.call(this); -</xsl:text> - <xsl:text> }, + <xsl:text> sub: foreach_subscribe, +</xsl:text> + <xsl:text> unsub: foreach_unsubscribe, +</xsl:text> + <xsl:text> apply_cache: foreach_apply_cache, </xsl:text> </xsl:template> <xsl:template mode="widget_defs" match="widget[@type='Input']"> @@ -1149,6 +1141,8 @@ </xsl:text> <xsl:text>var updates = {}; </xsl:text> + <xsl:text>var need_cache_apply = []; +</xsl:text> <xsl:text> </xsl:text> <xsl:text>function dispatch_value_to_widget(widget, index, value, oldval) { @@ -1319,11 +1313,13 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text> if(current_subscribed_page_index != current_visible_page_index){ -</xsl:text> - <xsl:text> apply_cache(); -</xsl:text> - <xsl:text> } + <xsl:text> while(widget = need_cache_apply.pop()){ +</xsl:text> + <xsl:text> widget.apply_cache(); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> </xsl:text> <xsl:text> apply_updates(); </xsl:text> @@ -1659,10 +1655,6 @@ </xsl:text> <xsl:text>var current_subscribed_page; </xsl:text> - <xsl:text>var current_visible_page_index; -</xsl:text> - <xsl:text>var current_subscribed_page_index; -</xsl:text> <xsl:text> </xsl:text> <xsl:text>function prepare_svg() { @@ -1747,6 +1739,8 @@ </xsl:text> <xsl:text> } </xsl:text> + <xsl:text> need_cache_apply.push(this); +</xsl:text> <xsl:text>} </xsl:text> <xsl:text> @@ -1763,138 +1757,210 @@ </xsl:text> <xsl:text> } </xsl:text> + <xsl:text> this.offset = 0; +</xsl:text> <xsl:text>} </xsl:text> <xsl:text> </xsl:text> + <xsl:text>function foreach_widgets_do(new_offset, todo){ +</xsl:text> + <xsl:text> this.offset = new_offset; +</xsl:text> + <xsl:text> for(let i = 0; i < this.items.length; i++) { +</xsl:text> + <xsl:text> let item = this.items[i]; +</xsl:text> + <xsl:text> let orig_item_index = this.index_pool[i]; +</xsl:text> + <xsl:text> let item_index = this.index_pool[i+this.item_offset]; +</xsl:text> + <xsl:text> let item_index_offset = item_index - orig_item_index; +</xsl:text> + <xsl:text> for(let widget of item) { +</xsl:text> + <xsl:text> todo.call(widget, new_offset + item_index_offset); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> <xsl:text>function foreach_subscribe(new_offset=0){ </xsl:text> - <xsl:text> for(let i = 0; i < this.items.length; i++) { -</xsl:text> - <xsl:text> let item = this.items[i]; -</xsl:text> - <xsl:text> let orig_item_index = this.index_pool[i]; -</xsl:text> - <xsl:text> let item_index = this.index_pool[i+this.item_offset]; -</xsl:text> - <xsl:text> let item_index_offset = item_index - orig_item_index; -</xsl:text> - <xsl:text> for(let widget of item) { -</xsl:text> - <xsl:text> subscribe.call(widget,new_offset + item_index_offset); + <xsl:text> foreach_widgets_do.call(this, new_offset, subscribe); +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function widget_apply_cache() { +</xsl:text> + <xsl:text> for(let index of this.indexes){ +</xsl:text> + <xsl:text> /* dispatch current cache in newly opened page widgets */ +</xsl:text> + <xsl:text> let realindex = index+this.offset; +</xsl:text> + <xsl:text> let cached_val = cache[realindex]; +</xsl:text> + <xsl:text> if(cached_val != undefined) +</xsl:text> + <xsl:text> dispatch_value_to_widget(this, realindex, cached_val, cached_val); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function foreach_apply_cache() { +</xsl:text> + <xsl:text> foreach_widgets_do.call(this, this.offset, widget_apply_cache); +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function foreach_onclick(opstr, evt) { +</xsl:text> + <xsl:text> new_item_offset = eval(String(this.item_offset)+opstr) +</xsl:text> + <xsl:text> if(new_item_offset + this.items.length > this.index_pool.length) { +</xsl:text> + <xsl:text> new_item_offset = 0; +</xsl:text> + <xsl:text> } else if(new_item_offset < 0) { +</xsl:text> + <xsl:text> new_item_offset = this.index_pool.length - this.items.length; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> this.item_offset = new_item_offset; +</xsl:text> + <xsl:text> off = this.offset; +</xsl:text> + <xsl:text> foreach_unsubscribe.call(this); +</xsl:text> + <xsl:text> foreach_subscribe.call(this,off); +</xsl:text> + <xsl:text> update_subscriptions(); +</xsl:text> + <xsl:text> need_cache_apply.push(this); +</xsl:text> + <xsl:text> requestHMIAnimation(); +</xsl:text> + <xsl:text> console.log(opstr, new_item_offset); +</xsl:text> + <xsl:text>} +</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> 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; +</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=>w.unsub()); +</xsl:text> + <xsl:text> old_desc.relative_widgets.map(w=>w.unsub()); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> new_desc.absolute_widgets.map(w=>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=>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> +</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)){ +</xsl:text> + <xsl:text> let [element, parent] = old_desc.required_detachables[eltid]; +</xsl:text> + <xsl:text> parent.removeChild(element); +</xsl:text> + <xsl:text> } </xsl:text> <xsl:text> } </xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text>} -</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> 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; -</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=>w.unsub()); -</xsl:text> - <xsl:text> old_desc.relative_widgets.map(w=>w.unsub()); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> new_desc.absolute_widgets.map(w=>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=>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_subscribed_page_index = page_index; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> requestHMIAnimation(); -</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)){ -</xsl:text> - <xsl:text> let [element, parent] = old_desc.required_detachables[eltid]; -</xsl:text> - <xsl:text> parent.removeChild(element); + <xsl:text> for(let eltid in new_desc.required_detachables){ +</xsl:text> + <xsl:text> if(!(eltid in old_desc.required_detachables)){ +</xsl:text> + <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; +</xsl:text> + <xsl:text> parent.appendChild(element); </xsl:text> <xsl:text> } </xsl:text> <xsl:text> } </xsl:text> + <xsl:text> }else{ +</xsl:text> <xsl:text> for(let eltid in new_desc.required_detachables){ </xsl:text> - <xsl:text> if(!(eltid in old_desc.required_detachables)){ -</xsl:text> - <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; -</xsl:text> - <xsl:text> parent.appendChild(element); -</xsl:text> - <xsl:text> } + <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; +</xsl:text> + <xsl:text> parent.appendChild(element); </xsl:text> <xsl:text> } </xsl:text> - <xsl:text> }else{ -</xsl:text> - <xsl:text> for(let eltid in new_desc.required_detachables){ -</xsl:text> - <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; -</xsl:text> - <xsl:text> parent.appendChild(element); -</xsl:text> - <xsl:text> } -</xsl:text> <xsl:text> } </xsl:text> <xsl:text> @@ -1905,38 +1971,6 @@ </xsl:text> <xsl:text>}; </xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function apply_cache() { -</xsl:text> - <xsl:text> let new_desc = page_desc[current_visible_page]; -</xsl:text> - <xsl:text> for(let widget of chain(new_desc.absolute_widgets,new_desc.relative_widgets)){ -</xsl:text> - <xsl:text> for(let index of widget.indexes){ -</xsl:text> - <xsl:text> /* dispatch current cache in newly opened page widgets */ -</xsl:text> - <xsl:text> let realindex = index+widget.offset; -</xsl:text> - <xsl:text> let cached_val = cache[realindex]; -</xsl:text> - <xsl:text> if(cached_val != undefined) -</xsl:text> - <xsl:text> dispatch_value_to_widget(widget, realindex, cached_val, cached_val); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> current_visible_page_index = current_subscribed_page_index; -</xsl:text> - <xsl:text>} -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> -</xsl:text> <xsl:text> </xsl:text> <xsl:text>// Once connection established diff -r 99c5335ed59f -r bf8a39cc65e4 svghmi/svghmi.js --- a/svghmi/svghmi.js Tue Mar 24 23:07:54 2020 +0100 +++ b/svghmi/svghmi.js Wed Mar 25 13:36:04 2020 +0100 @@ -2,6 +2,7 @@ var cache = hmitree_types.map(_ignored => undefined); var updates = {}; +var need_cache_apply = []; function dispatch_value_to_widget(widget, index, value, oldval) { try { @@ -87,9 +88,10 @@ switch_visible_page(current_subscribed_page); } - if(current_subscribed_page_index != current_visible_page_index){ - apply_cache(); - } + while(widget = need_cache_apply.pop()){ + widget.apply_cache(); + } + apply_updates(); requestAnimationFrameID = null; } @@ -257,8 +259,6 @@ var current_visible_page; var current_subscribed_page; -var current_visible_page_index; -var current_subscribed_page_index; function prepare_svg() { for(let eltid in detachable_elements){ @@ -301,6 +301,7 @@ for(let index of this.indexes){ subscribers[index + new_offset].add(this); } + need_cache_apply.push(this); } function foreach_unsubscribe(){ @@ -309,18 +310,55 @@ unsubscribe.call(widget); } } -} - -function foreach_subscribe(new_offset=0){ + this.offset = 0; +} + +function foreach_widgets_do(new_offset, todo){ + this.offset = new_offset; for(let i = 0; i < this.items.length; i++) { let item = this.items[i]; let orig_item_index = this.index_pool[i]; let item_index = this.index_pool[i+this.item_offset]; let item_index_offset = item_index - orig_item_index; for(let widget of item) { - subscribe.call(widget,new_offset + item_index_offset); - } - } + todo.call(widget, new_offset + item_index_offset); + } + } +} + +function foreach_subscribe(new_offset=0){ + foreach_widgets_do.call(this, new_offset, subscribe); +} + +function widget_apply_cache() { + for(let index of this.indexes){ + /* dispatch current cache in newly opened page widgets */ + let realindex = index+this.offset; + let cached_val = cache[realindex]; + if(cached_val != undefined) + dispatch_value_to_widget(this, realindex, cached_val, cached_val); + } +} + +function foreach_apply_cache() { + foreach_widgets_do.call(this, this.offset, widget_apply_cache); +} + +function foreach_onclick(opstr, evt) { + new_item_offset = eval(String(this.item_offset)+opstr) + if(new_item_offset + this.items.length > this.index_pool.length) { + new_item_offset = 0; + } else if(new_item_offset < 0) { + new_item_offset = this.index_pool.length - this.items.length; + } + this.item_offset = new_item_offset; + off = this.offset; + foreach_unsubscribe.call(this); + foreach_subscribe.call(this,off); + update_subscriptions(); + need_cache_apply.push(this); + requestHMIAnimation(); + console.log(opstr, new_item_offset); } function switch_subscribed_page(page_name, page_index) { @@ -347,7 +385,6 @@ update_subscriptions(); current_subscribed_page = page_name; - current_subscribed_page_index = page_index; requestHMIAnimation(); } @@ -380,22 +417,6 @@ svg_root.setAttribute('viewBox',new_desc.bbox.join(" ")); current_visible_page = page_name; }; - -function apply_cache() { - let new_desc = page_desc[current_visible_page]; - for(let widget of chain(new_desc.absolute_widgets,new_desc.relative_widgets)){ - for(let index of widget.indexes){ - /* dispatch current cache in newly opened page widgets */ - let realindex = index+widget.offset; - let cached_val = cache[realindex]; - if(cached_val != undefined) - dispatch_value_to_widget(widget, realindex, cached_val, cached_val); - } - } - current_visible_page_index = current_subscribed_page_index; -} - - // Once connection established ws.onopen = function (evt) { diff -r 99c5335ed59f -r bf8a39cc65e4 svghmi/widget_foreach.ysl2 --- a/svghmi/widget_foreach.ysl2 Tue Mar 24 23:07:54 2020 +0100 +++ b/svghmi/widget_foreach.ysl2 Wed Mar 25 13:36:04 2020 +0100 @@ -44,19 +44,14 @@ } | ] | }, - | on_click: function(opstr, evt) { - | console.log(opstr); - | }, | item_offset: 0, + | on_click: foreach_onclick, } template "widget[@type='ForEach']", mode="widget_subscribe"{ // param "hmi_element"; - | sub: function(off){ - | foreach_subscribe.call(this,off); - | }, + | sub: foreach_subscribe, + | unsub: foreach_unsubscribe, + | apply_cache: foreach_apply_cache, +} - | unsub: function(){ - | foreach_unsubscribe.call(this); - | }, -} diff -r 99c5335ed59f -r bf8a39cc65e4 svghmi/widgets_common.ysl2 --- a/svghmi/widgets_common.ysl2 Tue Mar 24 23:07:54 2020 +0100 +++ b/svghmi/widgets_common.ysl2 Wed Mar 25 13:36:04 2020 +0100 @@ -43,6 +43,7 @@ template "widget", mode="widget_subscribe" { | sub: subscribe, | unsub: unsubscribe, + | apply_cache: widget_apply_cache, } // page aren't subscribers template "widget[@type='Page']", mode="widget_subscribe";