beremiz

Button fix if no active or inactive state,
svghmi
2020-10-01, usveticic
9ec338a99a18
Button fix if no active or inactive state,
Widget animate changed to use anitmateTransform and added option to change rotation
Widget circular slider fixed so it is working on got and reprogramed so it similar to normal slider
Widget slider added support for changing size still need some changes to work properly
Added slider to svghmi test project
Changed svg in svhgmi_v2 project
// widgets_common.ysl2
in xsl decl labels(*ptr, name="defs_by_labels") alias call-template {
with "hmi_element", "$hmi_element";
with "labels"{text *ptr};
content;
};
decl optional_labels(*ptr) alias - {
/* TODO add some per label xslt variable to check if exist */
labels(*ptr){
with "mandatory","'no'";
content;
}
};
decl activable_labels(*ptr) alias - {
optional_labels(*ptr) {
with "subelements","'active inactive'";
content;
}
};
template "svg:*", mode="hmi_widgets" {
const "widget", "func:widget(@id)";
const "eltid","@id";
const "args" foreach "$widget/arg" > "«func:escape_quotes(@value)»"`if "position()!=last()" > ,`
const "indexes" foreach "$widget/path" {
choose {
when "not(@index)" {
choose {
when "not(@type)" {
warning > Widget «$widget/@type» id="«$eltid»" : No match for path "«@value»" in HMI tree
> undefined`if "position()!=last()" > ,`
}
when "@type = 'PAGE_LOCAL'"
> "«@value»"`if "position()!=last()" > ,`
when "@type = 'HMI_LOCAL'"
> hmi_local_index("«@value»")`if "position()!=last()" > ,`
}
}
otherwise {
> «@index»`if "position()!=last()" > ,`
}
}
}
| "«@id»": new «$widget/@type»Widget ("«@id»",[«$args»],[«$indexes»],{
apply "$widget", mode="widget_defs" with "hmi_element",".";
| })`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:local-variable-indexes" {
||
let hmi_locals = {};
var last_remote_index = hmitree_types.length - 1;
var next_available_index = hmitree_types.length;
const local_defaults = {
||
foreach "$parsed_widgets/widget[@type = 'VarInit']"{
if "count(path) != 1" error > VarInit «@id» must have only one variable given.
if "path/@type != 'PAGE_LOCAL' and path/@type != 'HMI_LOCAL'" error > VarInit «@id» only applies to HMI variable.
| "«path/@value»":«arg[1]/@value»`if "position()!=last()" > ,`
}
||
};
var cache = hmitree_types.map(_ignored => undefined);
function page_local_index(varname, pagename){
let pagevars = hmi_locals[pagename];
let new_index;
if(pagevars == undefined){
new_index = next_available_index++;
hmi_locals[pagename] = {[varname]:new_index}
} else {
let result = pagevars[varname];
if(result != undefined) {
return result;
}
new_index = next_available_index++;
pagevars[varname] = new_index;
}
let defaultval = local_defaults[varname];
if(defaultval != undefined)
cache[new_index] = defaultval;
return new_index;
}
function hmi_local_index(varname){
return page_local_index(varname, "HMI_LOCAL");
}
||
}
emit "preamble:widget-base-class" {
||
var pending_widget_animates = [];
class Widget {
offset = 0;
frequency = 10; /* FIXME arbitrary default max freq. Obtain from config ? */
unsubscribable = false;
pending_animate = false;
constructor(elt_id,args,indexes,members){
this.element_id = elt_id;
this.element = id(elt_id);
this.args = args;
this.indexes = indexes;
Object.keys(members).forEach(prop => this[prop]=members[prop]);
}
unsub(){
/* remove subsribers */
if(!this.unsubscribable)
for(let i = 0; i < this.indexes.length; i++) {
let index = this.indexes[i];
if(this.relativeness[i])
index += this.offset;
subscribers(index).delete(this);
}
this.offset = 0;
this.relativeness = undefined;
}
sub(new_offset=0, relativeness, container_id){
this.offset = new_offset;
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);
}
need_cache_apply.push(this);
}
apply_cache() {
if(!this.unsubscribable) 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;
let cached_val = cache[realindex];
if(cached_val != undefined)
this._dispatch(cached_val, cached_val, index);
}
}
get_variable_index(varnum) {
let index = this.indexes[varnum];
if(typeof(index) == "string"){
index = page_local_index(index, this.container_id);
} else {
if(this.relativeness[varnum]){
index += this.offset;
}
}
return index;
}
change_hmi_value(index, opstr) {
let realindex = this.get_variable_index(index);
if(realindex == undefined) return undefined;
return change_hmi_value(realindex, opstr);
}
apply_hmi_value(index, new_val) {
let realindex = this.get_variable_index(index);
if(realindex == undefined) return undefined;
return apply_hmi_value(realindex, new_val);
}
new_hmi_value(index, value, oldval) {
// TODO avoid searching, store index at sub()
for(let i = 0; i < this.indexes.length; i++) {
let refindex = this.get_variable_index(i);
if(refindex == undefined) continue;
if(index == refindex) {
this._dispatch(value, oldval, i);
break;
}
}
}
_dispatch(value, oldval, varnum) {
let dispatch = this.dispatch;
if(dispatch != undefined){
try {
dispatch.call(this, value, oldval, varnum);
} catch(err) {
console.log(err);
}
}
}
_animate(){
this.animate();
this.pending_animate = false;
}
request_animate(){
if(!this.pending_animate){
pending_widget_animates.push(this);
this.pending_animate = true;
requestHMIAnimation();
}
}
}
||
}
emit "declarations: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 VarInit')";
const "included_ids","$parsed_widgets/widget[not(@type = $excluded_types)]/@id";
emit "declarations:hmi-elements" {
| var hmi_widgets = {
apply "$hmi_elements[@id = $included_ids]", mode="hmi_widgets";
| }
}
function "defs_by_labels" {
param "labels","''";
param "mandatory","'yes'";
param "subelements","/..";
param "hmi_element";
const "widget_type","@type";
foreach "str:split($labels)" {
const "name",".";
const "elt","$result_svg_ns//*[@id = $hmi_element/@id]//*[@inkscape:label=$name][1]";
choose {
when "not($elt/@id)" {
if "$mandatory='yes'" {
error > «$widget_type» widget must have a «$name» element
}
// otherwise produce nothing
}
otherwise {
| «$name»_elt: id("«$elt/@id»"),
if "$subelements" {
| «$name»_sub: {
foreach "str:split($subelements)" {
const "subname",".";
const "subelt","$elt/*[@inkscape:label=$subname][1]";
choose {
when "not($subelt/@id)" {
if "$mandatory='yes'" {
error > «$widget_type» widget must have a «$name»/«$subname» element
}
| /* missing «$name»/«$subname» element */
}
otherwise {
| "«$subname»": id("«$subelt/@id»")`if "position()!=last()" > ,`
}
}
}
| },
}
}
}
}
}
def "func:escape_quotes" {
param "txt";
// have to use a python string to enter escaped quote
// const "frstln", "string-length($frst)";
choose {
when !"contains($txt,'\"')"! {
result !"concat(substring-before($txt,'\"'),'\\\"',func:escape_quotes(substring-after($txt,'\"')))"!;
}
otherwise {
result "$txt";
}
}
}