edouard@2884: // widgets_common.ysl2 edouard@2884: Edouard@2808: in xsl decl labels(*ptr, name="defs_by_labels") alias call-template { Edouard@2808: with "hmi_element", "$hmi_element"; Edouard@2810: with "labels"{text *ptr}; edouard@2937: content; Edouard@2808: }; Edouard@2808: edouard@2937: decl optional_labels(*ptr) alias - { edouard@2937: /* TODO add some per label xslt variable to check if exist */ edouard@2937: labels(*ptr){ edouard@2937: with "mandatory","'no'"; edouard@2937: content; edouard@2937: } Edouard@2836: }; Edouard@2836: edouard@2937: decl activable_labels(*ptr) alias - { edouard@2937: optional_labels(*ptr) { edouard@2937: with "subelements","'active inactive'"; edouard@2937: content; edouard@2937: } edouard@2920: }; edouard@2920: edouard@2955: template "svg:*", mode="hmi_widgets" { edouard@2886: const "widget", "func:widget(@id)"; Edouard@2881: const "eltid","@id"; edouard@2950: const "args" foreach "$widget/arg" > "«@value»"`if "position()!=last()" > ,` edouard@2950: const "indexes" foreach "$widget/path" { Edouard@2881: choose { Edouard@2881: when "not(@index)" { edouard@3017: choose { edouard@3017: when "not(@type)" edouard@3017: error > Widget «$widget/@type» id="«$eltid»" : No match for path "«@value»" in HMI tree edouard@3017: when "@type = 'PAGE_LOCAL'" Edouard@3022: > "«substring(@value, 1)»"`if "position()!=last()" > ,` edouard@3017: when "@type = 'HMI_LOCAL'" edouard@3017: > hmi_local_index("«@value»")`if "position()!=last()" > ,` edouard@3017: } Edouard@2881: } Edouard@2881: otherwise { edouard@2950: > «@index»`if "position()!=last()" > ,` Edouard@2792: } Edouard@2792: } Edouard@2792: } edouard@2950: edouard@2950: | "«@id»": new «$widget/@type»Widget ("«@id»",[«$args»],[«$indexes»],{ Edouard@2881: apply "$widget", mode="widget_defs" with "hmi_element","."; edouard@2949: | })`if "position()!=last()" > ,` edouard@2949: } edouard@2948: edouard@2948: def "func:unique_types" { edouard@2948: param "elts_with_type"; edouard@2948: choose { edouard@2948: when "count($elts_with_type) > 1" { edouard@2948: const "prior_results","func:unique_types($elts_with_type[position()!=last()])"; edouard@2948: choose { edouard@2948: when "$elts_with_type[last()][@type = $prior_results/@type]"{ edouard@2948: // type already in edouard@2948: result "$prior_results"; edouard@2948: } edouard@2948: otherwise { edouard@2948: result "$prior_results | $elts_with_type[last()]"; edouard@2948: } edouard@2948: } edouard@2948: } edouard@2948: otherwise { edouard@2948: result "$elts_with_type"; edouard@2948: } edouard@2948: } edouard@2948: } edouard@2948: edouard@3017: emit "preamble:local-variable-indexes" { edouard@3017: || edouard@3017: let hmi_locals = {}; edouard@3017: var last_remote_index = hmitree_types.length - 1; edouard@3017: var next_available_index = hmitree_types.length; edouard@3017: Edouard@3022: var cache = hmitree_types.map(_ignored => undefined); Edouard@3022: edouard@3017: function page_local_index(varname, pagename){ edouard@3017: let pagevars = hmi_locals[pagename]; Edouard@3022: let new_index; edouard@3017: if(pagevars == undefined){ Edouard@3022: new_index = next_available_index++; Edouard@3022: hmi_locals[pagename] = {[varname]:new_index} edouard@3017: } else { edouard@3017: let result = pagevars[varname]; Edouard@3022: if(result != undefined) { Edouard@3022: return result; Edouard@3022: } Edouard@3022: Edouard@3022: new_index = next_available_index++; Edouard@3022: pagevars[varname] = new_index; Edouard@3022: } Edouard@3022: cache[new_index] = ""; Edouard@3022: return new_index; edouard@3017: } edouard@3017: edouard@3017: function hmi_local_index(varname){ edouard@3017: return page_local_index(varname, "HMI_LOCAL"); edouard@3017: } edouard@3017: || edouard@3017: } edouard@3017: edouard@2949: emit "preamble:widget-base-class" { edouard@3017: || edouard@2949: class Widget { edouard@2963: offset = 0; edouard@2963: frequency = 10; /* FIXME arbitrary default max freq. Obtain from config ? */ Edouard@2980: unsubscribable = false; edouard@2950: constructor(elt_id,args,indexes,members){ edouard@2958: this.element_id = elt_id; edouard@2950: this.element = id(elt_id); edouard@2950: this.args = args; edouard@2950: this.indexes = indexes; edouard@2949: Object.keys(members).forEach(prop => this[prop]=members[prop]); edouard@2949: } edouard@2958: edouard@2951: unsub(){ edouard@2951: /* remove subsribers */ edouard@3005: if(!this.unsubscribable) edouard@3005: for(let i = 0; i < this.indexes.length; i++) { edouard@3005: let index = this.indexes[i]; edouard@3005: if(this.relativeness[i]) edouard@3005: index += this.offset; Edouard@3022: subscribers(index).delete(this); edouard@3005: } edouard@2951: this.offset = 0; edouard@3005: this.relativeness = undefined; edouard@3005: } edouard@3005: edouard@3017: sub(new_offset=0, relativeness, container_id){ edouard@2951: this.offset = new_offset; edouard@3005: this.relativeness = relativeness; edouard@3017: this.container_id = container_id ; edouard@2951: /* add this's subsribers */ edouard@3005: if(!this.unsubscribable) edouard@3005: for(let i = 0; i < this.indexes.length; i++) { edouard@3017: let index = this.get_variable_index(i); Edouard@3022: subscribers(index).add(this); edouard@3005: } edouard@2951: need_cache_apply.push(this); edouard@2951: } edouard@2951: edouard@2951: apply_cache() { edouard@3017: if(!this.unsubscribable) for(let i = 0; i < this.indexes.length; i++) { edouard@2951: /* dispatch current cache in newly opened page widgets */ edouard@3017: let realindex = this.get_variable_index(i); edouard@2951: let cached_val = cache[realindex]; edouard@2951: if(cached_val != undefined) edouard@3006: this.new_hmi_value(realindex, cached_val, cached_val); edouard@2951: } edouard@2951: } edouard@2951: edouard@3017: get_variable_index(varnum) { edouard@3017: let index = this.indexes[varnum]; edouard@3017: if(typeof(index) == "string"){ edouard@3017: index = page_local_index(index, this.container_id); edouard@3017: } else { edouard@3017: if(this.relativeness[varnum]){ edouard@3017: index += this.offset; edouard@3017: } edouard@3017: } edouard@3017: return index; edouard@3001: } edouard@3004: change_hmi_value(index,opstr) { edouard@3017: return change_hmi_value(this.get_variable_index(index), opstr); edouard@3004: } edouard@3004: edouard@3004: apply_hmi_value(index, new_val) { edouard@3017: return apply_hmi_value(this.get_variable_index(0), new_val); edouard@3004: } edouard@3006: edouard@3006: new_hmi_value(index, value, oldval) { edouard@3006: try { edouard@3006: // TODO avoid searching, store index at sub() edouard@3006: for(let i = 0; i < this.indexes.length; i++) { edouard@3017: let refindex = this.get_variable_index(i); edouard@3006: edouard@3006: if(index == refindex) { edouard@3006: let d = this.dispatch; edouard@3006: if(typeof(d) == "function"){ edouard@3006: d.call(this, value, oldval, i); edouard@3006: } edouard@3006: else if(typeof(d) == "object"){ edouard@3006: d[i].call(this, value, oldval); edouard@3006: } edouard@3006: /* else dispatch_0, ..., dispatch_n ? */ edouard@3006: /*else { edouard@3006: throw new Error("Dunno how to dispatch to widget at index = " + index); edouard@3006: }*/ edouard@3006: break; edouard@3006: } edouard@3006: } edouard@3006: } catch(err) { edouard@3006: console.log(err); edouard@3006: } edouard@3006: } edouard@2949: } edouard@2949: || edouard@2949: } edouard@2949: edouard@3007: emit "declarations:hmi-classes" { edouard@2948: const "used_widget_types", "func:unique_types($parsed_widgets/widget)"; edouard@2948: apply "$used_widget_types", mode="widget_class"; Edouard@2881: } Edouard@2810: edouard@2949: template "widget", mode="widget_class" edouard@2949: || edouard@2949: class «@type»Widget extends Widget{ edouard@2949: /* empty class, as «@type» widget didn't provide any */ edouard@2949: } edouard@2949: || edouard@2949: edouard@2997: const "excluded_types", "str:split('Page Lang')"; edouard@2955: const "excluded_ids","$parsed_widgets/widget[not(@type = $excluded_types)]/@id"; edouard@2955: edouard@3007: emit "declarations:hmi-elements" { edouard@2941: | var hmi_widgets = { edouard@2955: apply "$hmi_elements[@id = $excluded_ids]", mode="hmi_widgets"; edouard@2941: | } edouard@2941: } edouard@2941: Edouard@2881: function "defs_by_labels" { Edouard@2881: param "labels","''"; Edouard@2881: param "mandatory","'yes'"; edouard@2920: param "subelements","/.."; Edouard@2881: param "hmi_element"; Edouard@2881: const "widget_type","@type"; Edouard@2881: foreach "str:split($labels)" { Edouard@2881: const "name","."; edouard@2920: const "elt","$result_svg_ns//*[@id = $hmi_element/@id]//*[@inkscape:label=$name][1]"; Edouard@2881: choose { edouard@2920: when "not($elt/@id)" { Edouard@2881: if "$mandatory='yes'" { edouard@2920: error > «$widget_type» widget must have a «$name» element Edouard@2834: } Edouard@2881: // otherwise produce nothing Edouard@2797: } Edouard@2881: otherwise { edouard@2920: | «$name»_elt: id("«$elt/@id»"), edouard@2920: if "$subelements" { edouard@2920: | «$name»_sub: { edouard@2920: foreach "str:split($subelements)" { edouard@2920: const "subname","."; edouard@2920: const "subelt","$elt/*[@inkscape:label=$subname][1]"; edouard@2920: choose { edouard@2920: when "not($subelt/@id)" { edouard@2920: if "$mandatory='yes'" { edouard@2920: error > «$widget_type» widget must have a «$name»/«$subname» element edouard@2920: } edouard@2920: | /* missing «$name»/«$subname» element */ edouard@2920: } edouard@2920: otherwise { edouard@2920: | "«$subname»": id("«$subelt/@id»")`if "position()!=last()" > ,` edouard@2920: } edouard@2920: } edouard@2920: } edouard@2920: | }, edouard@2920: } Edouard@2836: } Edouard@2808: } Edouard@2808: } Edouard@2881: } Edouard@2808: edouard@2883: def "func:escape_quotes" { edouard@2883: param "txt"; edouard@2883: // have to use a python string to enter escaped quote edouard@2883: const "frst", !"substring-before($txt,'\"')"!; edouard@2883: const "frstln", "string-length($frst)"; edouard@2883: choose { edouard@2883: when "$frstln > 0 and string-length($txt) > $frstln" { edouard@2883: result !"concat($frst,'\\\"',func:escape_quotes(substring-after($txt,'\"')))"!; edouard@2883: } edouard@2883: otherwise { edouard@2883: result "$txt"; edouard@2883: } edouard@2883: } edouard@2883: } edouard@2883: