# HG changeset patch # User Edouard Tisserant # Date 1661940969 -7200 # Node ID 375626e60b63c9dadebc75dc2a91fa5f216d1da8 # Parent 30f7eade322feadb55675419eea57353a3e0f11d SVGHMI: rework Jump widget to cope with Enable Expressions. Relative jumps are not disabled implicitely anymore when pointed HMI_NODE is 0. Also, "activable()" implementation was enhanced to make it optional. diff -r 30f7eade322f -r 375626e60b63 svghmi/parse_labels.ysl2 --- a/svghmi/parse_labels.ysl2 Tue Aug 23 12:19:44 2022 +0200 +++ b/svghmi/parse_labels.ysl2 Wed Aug 31 12:16:09 2022 +0200 @@ -70,11 +70,7 @@ } attrib "freq" > «$freq» } - foreach "str:split(substring-after($args, ':'), ':')" { - arg { - attrib "value" > «.» - } - } + // find "#" + JS expr at the end const "tail", "substring-after($declaration,'@')"; const "taillen","string-length($tail)"; @@ -90,6 +86,12 @@ attrib "enable_expr" value "$enable_expr"; } + foreach "str:split(substring-after($args, ':'), ':')" { + arg { + attrib "value" > «.» + } + } + // for stricter syntax checking, this should make error // if $paths contains "@@" or ends with "@" (empty paths) diff -r 30f7eade322f -r 375626e60b63 svghmi/widget_jump.ysl2 --- a/svghmi/widget_jump.ysl2 Tue Aug 23 12:19:44 2022 +0200 +++ b/svghmi/widget_jump.ysl2 Wed Aug 31 12:16:09 2022 +0200 @@ -3,17 +3,38 @@ widget_desc("Jump") { longdesc || - Jump widget brings focus to a different page. Mandatory single argument + Jump widget brings focus to a different page. Mandatory first argument gives name of the page. - Optional single path is used as new reference when jumping to a relative - page, it must point to a HMI_NODE. + If first path is pointint to HMI_NODE variable is used as new reference + when jumping to a relative page. + Additional arguments are unordered options: + + - Absolute: force page jump to be not relative even if first path is of type HMI_NODE + + - name=value: Notify jump by setting variable with path having same name assigned + "active"+"inactive" labeled elements can be provided and reflect current page being shown. - "disabled" labeled element, if provided, is shown instead of "active" or - "inactive" widget when pointed HMI_NODE is null. + Exemples: + + Relative jump: + + HMI:Jump:RelativePage@/PUMP9 + HMI:Jump:RelativePage@/PUMP9@role=.userrole#role=="admin" + + Absolute jump: + + HMI:Jump:AbsolutePage + HMI:Jump:AbsolutePage@role=.userrole#role=="admin" + + Forced absolute jump: + + HMI:Jump:AbsolutePage:Absolute@/PUMP9 + HMI:Jump:AbsolutePage:Absolute:notify=1@notify=/PUMP9 + || shortdesc > Jump to given page @@ -27,34 +48,15 @@ || activable = false; active = false; - disabled = false; frequency = 2; update_activity() { - if(this.active) { - /* show active */ - this.active_elt.style.display = ""; - /* hide inactive */ - this.inactive_elt.style.display = "none"; - } else { - /* show inactive */ - this.inactive_elt.style.display = ""; - /* hide active */ - this.active_elt.style.display = "none"; - } + this.set_activation_state(this.active); } update_disability() { - if(this.disabled) { - /* show disabled */ - this.disabled_elt.style.display = ""; - /* hide inactive */ - this.inactive_elt.style.display = "none"; - /* hide active */ - this.active_elt.style.display = "none"; - } else { - /* hide disabled */ - this.disabled_elt.style.display = "none"; + this.animate_enable(); + if(this.enable_state) { this.update_activity(); } } @@ -66,8 +68,8 @@ /* TODO: in order to allow jumps to page selected through for exemple a dropdown, support path pointing to local variable whom value would be an HMI_TREE index and then jump to a relative page not hard-coded in advance */ - if(!that.disabled) { - const index = that.indexes.length > 0 ? that.indexes[0] + that.offset : undefined; + if(that.enable_state) { + const index = (that.is_relative && that.indexes.length > 0) ? that.indexes[0] + that.offset : undefined; fading_page_switch(name, index); } } @@ -82,43 +84,43 @@ } } - dispatch(value) { - this.disabled = !Number(value); - - // TODO : use RequestAnimate and animate() - + animate() { this.update_state(); } || } +def "func:is_relative_jump" { + param "widget"; + result "$widget/path and $widget/path[1]/@type='HMI_NODE' and not($widget/arg[position()>1 and @value = 'Absolute'])"; +} + widget_defs("Jump") { - // TODO: ensure both active and inactive are provided - const "activity" optional_labels("active inactive"); - const "have_activity","string-length($activity)>0"; - value "$activity"; + optional_activable(); - const "disability" optional_labels("disabled"); - const "have_disability","$have_activity and string-length($disability)>0"; - value "$disability"; + const "jump_disability","$has_activity and $has_disability"; | init: function() { | this.element.onclick = this.make_on_click(); - if "$have_activity" { + if "$has_activity" { | this.activable = true; } - if "not($have_disability)" { - | this.unsubscribable = true; - } > this.update_state = choose { - when "$have_disability" { + when "$jump_disability" { > this.update_disability } - when "$have_activity" { + when "$has_activity" { > this.update_activity } - otherwise > null + otherwise > function(){} + } + > ;\n + + > this.is_relative = + choose{ + when "func:is_relative_jump(.)" > true + otherwise > false } > ;\n | }, @@ -127,9 +129,11 @@ widget_page("Jump"){ param "page_desc"; - /* check that given path is compatible with page's reference path */ - if "path" { - /* TODO: suport local variable containing an HMI_TREE index to jump to a relative page */ + /* jump is considered relative jump if first path points to HMI_NODE + but a jump can be forced Absolute by adding a "Absolute" argument */ + if "func:is_relative_jump(.)" { + /* if relative check that given path is compatible with page's reference path */ + /* when no page name provided, check for same page */ const "target_page_name" choose { when "arg" value "arg[1]/@value"; @@ -142,9 +146,12 @@ if "not(func:same_class_paths($target_page_path, path[1]/@value))" error > Jump id="«@id»" to page "«$target_page_name»" with incompatible path "«path[1]/@value» (must be same class as "«$target_page_path»") + } } + + /* TODO: move to detachable pages ysl2 */ emit "cssdefs:jump" || diff -r 30f7eade322f -r 375626e60b63 svghmi/widgets_common.ysl2 --- a/svghmi/widgets_common.ysl2 Tue Aug 23 12:19:44 2022 +0200 +++ b/svghmi/widgets_common.ysl2 Wed Aug 31 12:16:09 2022 +0200 @@ -21,13 +21,24 @@ } }; +decl _activable(*level) alias - { + | activable_sub:{ + const "activity" labels("/active /inactive") { + with "mandatory"{text *level}; + content; + } + value "$activity"; + const "has_activity","string-length($activity)>0"; + | }, +}; + decl activable() alias - { - | activable_sub:{ - warning_labels("/active /inactive") { - content; - } - | } -}; + _activable("warn") +}; +decl optional_activable() alias - { + _activable("no") +}; + decl activable_labels(*ptr) alias - { optional_labels(*ptr) { with "subelements","'active inactive'"; @@ -48,6 +59,10 @@ in xsl decl widget_defs(%name, match="widget[@type='%name']", mode="widget_defs") alias template { param "hmi_element"; + // all widget potentially has a "disabled" labeled element + const "disability" optional_labels("disabled"); + value "$disability"; + const "has_disability","string-length($disability)>0"; content; }; @@ -256,6 +271,10 @@ [this.indexes, this.variables_options] = (variables.length>0) ? zip(...variables) : [[],[]]; this.indexes_length = this.indexes.length; this.enable_expr = enable_expr; + this.enable_state = true; + this.enable_displayed_state = true; + this.enabled_elts = []; + Object.keys(members).forEach(prop => this[prop]=members[prop]); this.lastapply = this.indexes.map(() => undefined); this.inhibit = this.indexes.map(() => undefined); @@ -301,14 +320,11 @@ } if(this.enable_expr){ - this.disabled_elt = null; - this.enabled_elts = []; this.enable_state = false; this.enable_displayed_state = false; for(let child of Array.from(this.element.children)){ - if(child.getAttribute("inkscape:label")=="disabled"){ - this.disabled_elt = child; - }else{ + let label = child.getAttribute("inkscape:label"); + if(label!="disabled"){ this.enabled_elts.push(child); this.element.removeChild(child); } @@ -318,26 +334,25 @@ unsub(){ /* remove subsribers */ - if(!this.unsubscribable) - for(let i = 0; i < this.indexes_length; i++) { - /* flush updates pending because of inhibition */ - let inhibition = this.inhibit[i]; - if(inhibition != undefined){ - clearTimeout(inhibition); - this.lastapply[i] = undefined; - this.uninhibit(i); - } - let deafened = this.deafen[i]; - if(deafened != undefined){ - clearTimeout(deafened); - this.lastdispatch[i] = undefined; - this.undeafen(i); - } - let index = this.indexes[i]; - if(this.relativeness[i]) - index += this.offset; - subscribers(index).delete(this); - } + for(let i = 0; i < this.indexes_length; i++) { + /* flush updates pending because of inhibition */ + let inhibition = this.inhibit[i]; + if(inhibition != undefined){ + clearTimeout(inhibition); + this.lastapply[i] = undefined; + this.uninhibit(i); + } + let deafened = this.deafen[i]; + if(deafened != undefined){ + clearTimeout(deafened); + this.lastdispatch[i] = undefined; + this.undeafen(i); + } + let index = this.indexes[i]; + if(this.relativeness[i]) + index += this.offset; + subscribers(index).delete(this); + } this.offset = 0; this.relativeness = undefined; } @@ -347,17 +362,16 @@ this.relativeness = relativeness; this.container_id = container_id ; /* add this's subsribers */ - if(!this.unsubscribable) - for(let i = 0; i < this.indexes_length; i++) { - let index = this.get_variable_index(i); - if(index == undefined) continue; - subscribers(index).add(this); - } + for(let i = 0; i < this.indexes_length; i++) { + let index = this.get_variable_index(i); + if(index == undefined) continue; + subscribers(index).add(this); + } need_cache_apply.push(this); } apply_cache() { - if(!this.unsubscribable) for(let index in this.indexes){ + for(let index in this.indexes){ /* dispatch current cache in newly opened page widgets */ let realindex = this.get_variable_index(index); if(realindex == undefined) continue; diff -r 30f7eade322f -r 375626e60b63 tests/projects/svghmi/plc.xml --- a/tests/projects/svghmi/plc.xml Tue Aug 23 12:19:44 2022 +0200 +++ b/tests/projects/svghmi/plc.xml Wed Aug 31 12:16:09 2022 +0200 @@ -1,7 +1,7 @@ - + @@ -575,64 +575,6 @@ - - - - - - Sloth - - - - - - - - - - - Pressure - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100 - @@ -688,7 +630,7 @@ - TargetPressure + Pressure diff -r 30f7eade322f -r 375626e60b63 tests/projects/svghmi/svghmi_0@svghmi/confnode.xml --- a/tests/projects/svghmi/svghmi_0@svghmi/confnode.xml Tue Aug 23 12:19:44 2022 +0200 +++ b/tests/projects/svghmi/svghmi_0@svghmi/confnode.xml Wed Aug 31 12:16:09 2022 +0200 @@ -1,2 +1,2 @@ - + diff -r 30f7eade322f -r 375626e60b63 tests/projects/svghmi/svghmi_0@svghmi/svghmi.svg --- a/tests/projects/svghmi/svghmi_0@svghmi/svghmi.svg Tue Aug 23 12:19:44 2022 +0200 +++ b/tests/projects/svghmi/svghmi_0@svghmi/svghmi.svg Wed Aug 31 12:16:09 2022 +0200 @@ -133,12 +133,12 @@ inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:document-units="px" - inkscape:current-layer="hmi0" + inkscape:current-layer="g1450-4-9" showgrid="false" units="px" - inkscape:zoom="0.14174805" - inkscape:cx="-1530.0784" - inkscape:cy="-1404.9832" + inkscape:zoom="1.1339844" + inkscape:cx="1880.7924" + inkscape:cy="528.36862" inkscape:window-width="1600" inkscape:window-height="836" inkscape:window-x="0" @@ -3240,7 +3240,7 @@ inkscape:label="PUMP:1"> + Disabled + Inactive - - Pump + id="tspan1460-3-6">Active + + + 8888 + + + 8888 + + + 8888 + x="1093.7899" + y="657.59668" + style="text-align:center;text-anchor:middle;fill:#434343;fill-opacity:1;stroke-width:0.99999994px;" + id="tspan1460-3-5-9">Disabled - - - - + id="g1067-1" + inkscape:label="inactive" + style="display:inline"> + Inactive + id="rect1069-6" + style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:#ff6600;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> + Active + + + + + 8888 + + + + Disabled + Inactive - Pump - 8888 - - - - - - + inkscape:label="active" + id="g1071-7" + style="display:inline"> + Active + + + + + 8888 + + + + Disabled + id="g1067-12" + inkscape:label="inactive" + style="display:inline"> + Inactive + id="g1071-78" + style="display:inline"> - - Pump - 8888 - - - - - - - - - - - - - - - - Pump - 8888 + id="tspan1460-3-6-0">Active