# HG changeset patch # User Edouard Tisserant # Date 1589189580 -7200 # Node ID c0ea5015e46f1ec26e300e71a81318373b3f0b96 # Parent 64e603b84aa30b967d12de0a1d6de1ea5764b867# Parent 6b01738308bba1c78e71e54752b41c120c30b79c merge diff -r 6b01738308bb -r c0ea5015e46f svghmi/detachable_pages.ysl2 --- a/svghmi/detachable_pages.ysl2 Mon May 11 11:10:38 2020 +0200 +++ b/svghmi/detachable_pages.ysl2 Mon May 11 11:33:00 2020 +0200 @@ -131,7 +131,7 @@ ancestor-or-self::*[@id = $detachable_elements/@id]"""; | "«$desc/arg[1]/@value»": { - | widget: hmi_widgets["«@id»"], + //| widget: hmi_widgets["«@id»"], | bbox: [«$p/@x», «$p/@y», «$p/@w», «$p/@h»], if "$desc/path/@value" { if "count($desc/path/@index)=0" diff -r 6b01738308bb -r c0ea5015e46f svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Mon May 11 11:10:38 2020 +0200 +++ b/svghmi/gen_index_xhtml.xslt Mon May 11 11:33:00 2020 +0200 @@ -1,6 +1,6 @@ - - + + @@ -19,6 +19,14 @@ + + + /* + + */ + + + var hmi_hash = [ ]; @@ -51,6 +59,8 @@ + + @@ -215,6 +225,14 @@ + + + /* + + */ + + + Raw HMI tree @@ -229,10 +247,20 @@ + + + + + /* + + */ + + + ID, x, y, w, h @@ -249,6 +277,8 @@ + + @@ -322,10 +352,20 @@ + /* + + */ + + + + + var default_page = " "; + + @@ -387,6 +427,14 @@ + /* + + */ + + + + + var detachable_elements = { @@ -405,6 +453,8 @@ } + + @@ -422,10 +472,6 @@ ": { - widget: hmi_widgets[" - - "], - bbox: [ , @@ -531,17 +577,35 @@ + /* + + */ + + + + + var page_desc = { } + + + /* + + */ + + + + + DETACHABLES: @@ -558,6 +622,8 @@ + + @@ -672,17 +738,35 @@ + + + /* + + */ + + + let id = document.getElementById.bind(document); var svg_root = id(" "); + + + /* + + */ + + + + + Unlinked : @@ -690,99 +774,222 @@ - - + + + + + + + " + + " + + , + + + + + + + + + Widget + + id=" + + " : No match for path " + + " in HMI tree + + + + + + , + + + + + " - ": { - - type: " + ": new - ", - - args: [ - - - " - - " - - , - - - - - ], - - offset: 0, - - indexes: [ - - - - - - Widget - - id=" - - " : No match for path " - - " in HMI tree - - - - - - /* - - */ - - , - - - - - - - ], - - element: id(" + Widget (" - "), + ",[ + + ],[ + + ],{ - - - - } + }) , + + + + + + + + + + + + + + + + + + + + + + + + /* + + */ + + + + class Widget { + + constructor(elt_id,args,indexes,members){ + + this.element = id(elt_id); + + this.args = args; + + this.indexes = indexes; + + this.offset = 0; + + Object.keys(members).forEach(prop => this[prop]=members[prop]); + + } + + unsub(){ + + /* remove subsribers */ + + for(let index of this.indexes){ + + let idx = index + this.offset; + + subscribers[idx].delete(this); + + } + + this.offset = 0; + + } + + + + sub(new_offset=0){ + + /* set the offset because relative */ + + this.offset = new_offset; + + /* add this's subsribers */ + + for(let index of this.indexes){ + + subscribers[index + new_offset].add(this); + + } + + need_cache_apply.push(this); + + } + + + + 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); + + } + + } + + + + } + + + + + + + + + /* + + */ + + + + + + + + + + class + + Widget extends Widget{ + + /* empty class, as + + widget didn't provide any */ + + } + + + + + + + /* + + */ + + + var hmi_widgets = { - + } - - - sub: subscribe, - - unsub: unsubscribe, - - apply_cache: widget_apply_cache, - - - + + + @@ -1658,125 +1865,114 @@ item_offset: 0, - on_click: foreach_onclick, - - - - sub: foreach_subscribe, - - unsub: foreach_unsubscribe, - - apply_cache: foreach_apply_cache, - - - - - function foreach_unsubscribe(){ - - for(let item of this.items){ - - for(let widget of item) { - - unsubscribe.call(widget); + + + class ForEachWidget extends Widget{ + + unsub(){ + + for(let item of this.items){ + + for(let widget of item) { + + widget.unsub(); + + } } + this.offset = 0; + } - this.offset = 0; + + + 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) { + + todo(widget).call(widget, new_offset + item_index_offset); + + } + + } + + } + + + + sub(new_offset=0){ + + this.foreach_widgets_do(new_offset, w=>w.sub); + + } + + + + apply_cache() { + + this.foreach_widgets_do(this.offset, w=>w.apply_cache); + + } + + + + on_click(opstr, evt) { + + let new_item_offset = eval(String(this.item_offset)+opstr); + + if(new_item_offset + this.items.length > this.index_pool.length) { + + if(this.item_offset + this.items.length == this.index_pool.length) + + new_item_offset = 0; + + else + + new_item_offset = this.index_pool.length - this.items.length; + + } else if(new_item_offset < 0) { + + if(this.item_offset == 0) + + new_item_offset = this.index_pool.length - this.items.length; + + else + + new_item_offset = 0; + + } + + this.item_offset = new_item_offset; + + this.unsub(); + + this.sub(this.offset); + + update_subscriptions(); + + need_cache_apply.push(this); + + jumps_need_update = true; + + requestHMIAnimation(); + + } } - - - 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) { - - todo.call(widget, new_offset + item_index_offset); - - } - - } - - } - - - - function foreach_subscribe(new_offset=0){ - - foreach_widgets_do.call(this, new_offset, subscribe); - - } - - - - 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) { - - if(this.item_offset + this.items.length == this.index_pool.length) - - new_item_offset = 0; - - else - - new_item_offset = this.index_pool.length - this.items.length; - - } else if(new_item_offset < 0) { - - if(this.item_offset == 0) - - new_item_offset = this.index_pool.length - this.items.length; - - else - - new_item_offset = 0; - - } - - 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); - - jumps_need_update = true; - - requestHMIAnimation(); - - } - - - @@ -2003,45 +2199,22 @@ this.inactive_elt_style = this.inactive_elt.getAttribute("style"); - - this.disabled_elt_style = this.disabled_elt.getAttribute("style"); - - - }, - - - - - - - - - - - - - - - - - sub: subscribe, - - unsub: unsubscribe, - - apply_cache: widget_apply_cache, + this.disabled_elt_style = this.disabled_elt.getAttribute("style"); - sub: function(){}, - - unsub: function(){}, - - apply_cache: function(){}, + this.sub = function(){}; + + this.unsub = function(){}; + + this.apply_cache = function(){}; + }, + @@ -2083,6 +2256,14 @@ + + + /* + + */ + + + var jumps_need_update = false; var jump_history = [[default_page, undefined]]; @@ -2099,11 +2280,21 @@ + + + /* + + */ + + + + + var keypads = { @@ -2124,6 +2315,8 @@ } + + @@ -2453,15 +2646,10 @@ Made with SVGHMI. https://beremiz.org - - - - : - - - - - + + + + @@ -3152,74 +3340,6 @@ - function* chain(a,b){ - - yield* a; - - yield* b; - - }; - - - - function unsubscribe(){ - - /* remove subsribers */ - - for(let index of this.indexes){ - - let idx = index + this.offset; - - subscribers[idx].delete(this); - - } - - this.offset = 0; - - } - - - - function subscribe(new_offset=0){ - - /* set the offset because relative */ - - this.offset = new_offset; - - /* add this's subsribers */ - - for(let index of this.indexes){ - - subscribers[index + new_offset].add(this); - - } - - need_cache_apply.push(this); - - } - - - - 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 switch_visible_page(page_name) { diff -r 6b01738308bb -r c0ea5015e46f svghmi/gen_index_xhtml.ysl2 --- a/svghmi/gen_index_xhtml.ysl2 Mon May 11 11:10:38 2020 +0200 +++ b/svghmi/gen_index_xhtml.ysl2 Mon May 11 11:33:00 2020 +0200 @@ -7,7 +7,11 @@ decl emit(*name) alias - { *name; template *name { + | + | /* «local-name()» */ + | content; + | } }; @@ -56,12 +60,7 @@ comment > Made with SVGHMI. https://beremiz.org // all debug output from included definitions, as comments - foreach "document('')/*/debug:*" { - comment { - | «local-name()» : - apply "."; - } - } + comment apply "document('')/*/debug:*"; html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg" diff -r 6b01738308bb -r c0ea5015e46f svghmi/svghmi.js --- a/svghmi/svghmi.js Mon May 11 11:10:38 2020 +0200 +++ b/svghmi/svghmi.js Mon May 11 11:33:00 2020 +0200 @@ -325,40 +325,6 @@ return true; }; -function* chain(a,b){ - yield* a; - yield* b; -}; - -function unsubscribe(){ - /* remove subsribers */ - for(let index of this.indexes){ - let idx = index + this.offset; - subscribers[idx].delete(this); - } - this.offset = 0; -} - -function subscribe(new_offset=0){ - /* set the offset because relative */ - this.offset = new_offset; - /* add this's subsribers */ - for(let index of this.indexes){ - subscribers[index + new_offset].add(this); - } - need_cache_apply.push(this); -} - -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 switch_visible_page(page_name) { let old_desc = page_desc[current_visible_page]; diff -r 6b01738308bb -r c0ea5015e46f svghmi/widget_foreach.ysl2 --- a/svghmi/widget_foreach.ysl2 Mon May 11 11:10:38 2020 +0200 +++ b/svghmi/widget_foreach.ysl2 Mon May 11 11:33:00 2020 +0200 @@ -45,69 +45,62 @@ | ] | }, | item_offset: 0, - | on_click: foreach_onclick, } -template "widget[@type='ForEach']", mode="widget_subscribe"{ - // param "hmi_element"; - | sub: foreach_subscribe, - | unsub: foreach_unsubscribe, - | apply_cache: foreach_apply_cache, -} +template "widget[@type='ForEach']", mode="widget_class" +|| +class ForEachWidget extends Widget{ + unsub(){ + for(let item of this.items){ + for(let widget of item) { + widget.unsub(); + } + } + this.offset = 0; + } -emit "definitions:foreach" -|| -function foreach_unsubscribe(){ - for(let item of this.items){ - for(let widget of item) { - unsubscribe.call(widget); + 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) { + todo(widget).call(widget, new_offset + item_index_offset); + } } } - 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) { - todo.call(widget, new_offset + item_index_offset); + sub(new_offset=0){ + this.foreach_widgets_do(new_offset, w=>w.sub); + } + + apply_cache() { + this.foreach_widgets_do(this.offset, w=>w.apply_cache); + } + + on_click(opstr, evt) { + let new_item_offset = eval(String(this.item_offset)+opstr); + if(new_item_offset + this.items.length > this.index_pool.length) { + if(this.item_offset + this.items.length == this.index_pool.length) + new_item_offset = 0; + else + new_item_offset = this.index_pool.length - this.items.length; + } else if(new_item_offset < 0) { + if(this.item_offset == 0) + new_item_offset = this.index_pool.length - this.items.length; + else + new_item_offset = 0; } + this.item_offset = new_item_offset; + this.unsub(); + this.sub(this.offset); + update_subscriptions(); + need_cache_apply.push(this); + jumps_need_update = true; + requestHMIAnimation(); } } +|| -function foreach_subscribe(new_offset=0){ - foreach_widgets_do.call(this, new_offset, subscribe); -} - -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) { - if(this.item_offset + this.items.length == this.index_pool.length) - new_item_offset = 0; - else - new_item_offset = this.index_pool.length - this.items.length; - } else if(new_item_offset < 0) { - if(this.item_offset == 0) - new_item_offset = this.index_pool.length - this.items.length; - else - new_item_offset = 0; - } - 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); - jumps_need_update = true; - requestHMIAnimation(); -} - -|| diff -r 6b01738308bb -r c0ea5015e46f svghmi/widget_jump.ysl2 --- a/svghmi/widget_jump.ysl2 Mon May 11 11:10:38 2020 +0200 +++ b/svghmi/widget_jump.ysl2 Mon May 11 11:33:00 2020 +0200 @@ -81,33 +81,19 @@ | this.active_elt_style = this.active_elt.getAttribute("style"); | this.inactive_elt_style = this.inactive_elt.getAttribute("style"); } - if "$have_disability" { + choose { + when "$have_disability" { | this.disabled_elt_style = this.disabled_elt.getAttribute("style"); + } + otherwise { + | this.sub = function(){}; + | this.unsub = function(){}; + | this.apply_cache = function(){}; + } } | }, } -// default : normal subscribing -template "widget[@type='Jump']", mode="widget_subscribe" { - param "hmi_element"; - const "activity" call "jump_widget_activity" with "hmi_element", "$hmi_element"; - const "have_activity","string-length($activity)>0"; - const "disability" call "jump_widget_disability" with "hmi_element", "$hmi_element"; - const "have_disability","$have_activity and string-length($disability)>0"; - choose { - when "$have_disability" { - | sub: subscribe, - | unsub: unsubscribe, - | apply_cache: widget_apply_cache, - } - otherwise { - | sub: function(){}, - | unsub: function(){}, - | apply_cache: function(){}, - } - } -} - template "widget[@type='Jump']", mode="per_page_widget_template"{ param "page_desc"; /* check that given path is compatible with page's reference path */ diff -r 6b01738308bb -r c0ea5015e46f svghmi/widgets_common.ysl2 --- a/svghmi/widgets_common.ysl2 Mon May 11 11:10:38 2020 +0200 +++ b/svghmi/widgets_common.ysl2 Mon May 11 11:33:00 2020 +0200 @@ -21,49 +21,111 @@ } }; -template "svg:*", mode="hmi_elements" { +template "svg:*", mode="hmi_widgets" { const "widget", "func:widget(@id)"; const "eltid","@id"; - | "«@id»": { - | type: "«$widget/@type»", - | args: [ - foreach "$widget/arg" - | "«@value»"`if "position()!=last()" > ,` - | ], - | offset: 0, - | indexes: [ - foreach "$widget/path" { + const "args" foreach "$widget/arg" > "«@value»"`if "position()!=last()" > ,` + const "indexes" foreach "$widget/path" { choose { when "not(@index)" { warning > Widget «$widget/@type» id="«$eltid»" : No match for path "«@value»" in HMI tree } otherwise { - | «@index» /* «@value» */ `if "position()!=last()" > ,` + > «@index»`if "position()!=last()" > ,` } } } - | ], - | element: id("«@id»"), + + | "«@id»": new «$widget/@type»Widget ("«@id»",[«$args»],[«$indexes»],{ apply "$widget", mode="widget_defs" with "hmi_element","."; - apply "$widget", mode="widget_subscribe" with "hmi_element","."; - | }`if "position()!=last()" > ,` + | })`if "position()!=last()" > ,` } +def "func:unique_types" { + param "elts_with_type"; + choose { + when "count($elts_with_type) > 1" { + const "prior_results","func:unique_types($elts_with_type[position()!=last()])"; + choose { + when "$elts_with_type[last()][@type = $prior_results/@type]"{ + // type already in + result "$prior_results"; + } + otherwise { + result "$prior_results | $elts_with_type[last()]"; + } + } + } + otherwise { + result "$elts_with_type"; + } + } +} + +emit "preamble:widget-base-class" { + || + class Widget { + constructor(elt_id,args,indexes,members){ + this.element = id(elt_id); + this.args = args; + this.indexes = indexes; + this.offset = 0; + Object.keys(members).forEach(prop => this[prop]=members[prop]); + } + unsub(){ + /* remove subsribers */ + for(let index of this.indexes){ + let idx = index + this.offset; + subscribers[idx].delete(this); + } + this.offset = 0; + } + + sub(new_offset=0){ + /* set the offset because relative */ + this.offset = new_offset; + /* add this's subsribers */ + for(let index of this.indexes){ + subscribers[index + new_offset].add(this); + } + need_cache_apply.push(this); + } + + 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); + } + } + + } + || +} + +emit "preamble:hmi-classes" { + const "used_widget_types", "func:unique_types($parsed_widgets/widget)"; + apply "$used_widget_types", mode="widget_class"; +} + +template "widget", mode="widget_class" +|| +class «@type»Widget extends Widget{ + /* empty class, as «@type» widget didn't provide any */ +} +|| + +const "excluded_types", "str:split('Page Lang List')"; +const "excluded_ids","$parsed_widgets/widget[not(@type = $excluded_types)]/@id"; + emit "preamble:hmi-elements" { | var hmi_widgets = { - apply "$hmi_elements", mode="hmi_elements"; + apply "$hmi_elements[@id = $excluded_ids]", mode="hmi_widgets"; | } } -// default : normal subscribing -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"; - function "defs_by_labels" { param "labels","''"; param "mandatory","'yes'";