# HG changeset patch # User Edouard Tisserant # Date 1585315524 -3600 # Node ID 881d0248b3ce19200a93be4191cf91632829dd43 # Parent 1fcb50af0335c7953672b4282f1c497be0c7f09d SVGHMI: Jump widget can now display as active or inactive, if corresponfing "active" and "inactive labeled elements are provided. diff -r 1fcb50af0335 -r 881d0248b3ce svghmi/detachable_pages.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"; } diff -r 1fcb50af0335 -r 881d0248b3ce svghmi/gen_index_xhtml.xslt --- 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)>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)>0"/> + <xsl:value-of select="$opts"/> <xsl:text> on_click: function(evt) { </xsl:text> <xsl:text> const index = this.indexes.length > 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 > 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) && 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=>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_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=>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> 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=>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) { diff -r 1fcb50af0335 -r 881d0248b3ce svghmi/svghmi.js --- 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(); diff -r 1fcb50af0335 -r 881d0248b3ce svghmi/widget_jump.ysl2 --- 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"); + } | }, }