--- a/svghmi/gen_index_xhtml.ysl2 Fri Aug 19 10:22:16 2022 +0200
+++ b/svghmi/gen_index_xhtml.ysl2 Tue Aug 23 12:19:44 2022 +0200
@@ -84,6 +84,8 @@
+ include text pythonic.js | \n//\n//\n// Early independent declarations \n//\n//
apply "document('')/*/preamble:*";
@@ -98,8 +100,6 @@
- include text pythonic.js
| \n//\n//\n// Declarations from SVG scripts (inkscape document properties) \n//\n//
--- a/svghmi/parse_labels.ysl2 Fri Aug 19 10:22:16 2022 +0200
+++ b/svghmi/parse_labels.ysl2 Tue Aug 23 12:19:44 2022 +0200
@@ -2,7 +2,7 @@
-// "HMI:WidgetType|freq:param1:param2@path1,path1min,path1max@path2#"
+// "HMI:WidgetType|freq:param1:param2@a=path1,path1min,path1max@b=path2#a+b>3" // widget type="WidgetType" id="blah456" {
@@ -13,7 +13,7 @@
// path value="path4" index="path4" type="HMI_LOCAL";
-const "pathregex",!"'^([^\[,]+)(\[[^\]]+\])?([-.\d,]*)$'"!;
+const "pathregex",!"'^(\w+=)?([^,=]+)([-.\d,]*)$'"!; const "twonewlines", "concat($newline,$newline)";
@@ -66,7 +66,7 @@
if "not(regexp:test($freq,'^[0-9]*(\.[0-9]+)?[smh]?'))" {
- error > Widget id:«$id» label:«full_decl» has wrong syntax of frequency forcing «$freq»
+ error > Widget id:«$id» label:«$full_decl» has wrong syntax of frequency forcing «$freq» @@ -75,39 +75,48 @@
+ // find "#" + JS expr at the end const "tail", "substring-after($declaration,'@')";
const "taillen","string-length($tail)";
- const "has_enable", "substring($tail,$taillen,1)='#'";
+ const "has_enable", "contains($tail, '#')"; - value "substring($tail,1,$taillen - 1)";
+ value "substring-before($tail,'#')"; - attrib "has_enable" > yes
+ const "enable_expr", "substring-after($tail,'#')"; + attrib "enable_expr" value "$enable_expr"; + // for stricter syntax checking, this should make error + // if $paths contains "@@" or ends with "@" (empty paths) foreach "str:split($paths, '@')" {
if "string-length(.) > 0" path {
const "path_match", "regexp:match(.,$pathregex)";
+ const "pathassign", "substring-before($path_match[2],'=')"; const "pathminmax", "str:split($path_match[4],',')";
- const "path", "$path_match[2]";
- const "path_accepts", "$path_match[3]";
+ const "path", "$path_match[3]"; const "pathminmaxcount", "count($pathminmax)";
- attrib "value" > «$path»
- if "string-length($path_accepts)"
- attrib "accepts" > «$path_accepts»
+ error > Widget id:«$id» label:«$full_decl» has wrong syntax + attrib "value" value "$path"; + attrib "assign" value "$pathassign"; when "$pathminmaxcount = 2" {
attrib "min" > «$pathminmax[1]»
attrib "max" > «$pathminmax[2]»
when "$pathminmaxcount = 1 or $pathminmaxcount > 2" {
- error > Widget id:«$id» label:«full_decl» has wrong syntax of path section «$pathminmax»
+ error > Widget id:«$id» label:«$full_decl» has wrong syntax of path section «$pathminmax» if "$indexed_hmitree" choose {
@@ -121,7 +130,7 @@
const "item", "$indexed_hmitree/*[@hmipath = $path]";
const "pathtype", "local-name($item)";
if "$pathminmaxcount = 3 and not($pathtype = 'HMI_INT' or $pathtype = 'HMI_REAL')" {
- error > Widget id:«$id» label:«full_decl» path section «$pathminmax» use min and max on non mumeric value
+ error > Widget id:«$id» label:«$full_decl» path section «$pathminmax» use min and max on non mumeric value attrib "index" > «$item/@index»
--- a/svghmi/pythonic.js Fri Aug 19 10:22:16 2022 +0200
+++ b/svghmi/pythonic.js Tue Aug 23 12:19:44 2022 +0200
@@ -165,8 +165,11 @@
const _zip = longest => (...iterables) => {
- if (iterables.length < 2) {
- throw new TypeError("zip takes 2 iterables at least, "+iterables.length+" given");
+ if (iterables.length == 0) { + // works starting with 1 iterable + // [a,b,c] -> [[a],[b],[c]] + // [a,b,c],[d,e,f] -> [[a,d],[b,e],[c,f]] + throw new TypeError("zip takes 1 iterables at least, "+iterables.length+" given"); return new Iterator(function * () {
--- a/svghmi/ui.py Fri Aug 19 10:22:16 2022 +0200
+++ b/svghmi/ui.py Tue Aug 23 12:19:44 2022 +0200
@@ -648,14 +648,6 @@
self.AddPathToSignature(path)
- # for widget in widgets:
- # widget_type = widget.get("type")
- # for path in widget.iterchildren("path"):
- # path_value = path.get("value")
- # str.strip, path.get("accepts", '')[1:-1].split(','))
self.main_panel.SetupScrolling(scroll_x=False)
def GetWidgetParams(self, _context):
--- a/svghmi/widgets_common.ysl2 Fri Aug 19 10:22:16 2022 +0200
+++ b/svghmi/widgets_common.ysl2 Tue Aug 23 12:19:44 2022 +0200
@@ -65,6 +65,11 @@
const "args" foreach "$widget/arg" > "«func:escape_quotes(@value)»"`if "position()!=last()" > ,`
const "indexes" foreach "$widget/path" {
+ if "position()!=last()" > , + const "variables" foreach "$widget/path" { @@ -84,16 +89,15 @@
- if "position()!=last()" > ,
- const "minmaxes" foreach "$widget/path" {
+ > minmax:[«@min», «@max»] if "position()!=last()" > ,
@@ -104,14 +108,34 @@
- const "has_enable" choose {
- when "$widget/@has_enable = 'yes'"
+ const "enable_expr" choose{ + when "$widget/@enable_expr" - | "«@id»": new «$widget/@type»Widget ("«@id»",«$freq»,[«$args»],[«$indexes»],[«$minmaxes»],«$has_enable»,{
+ | "«@id»": new «$widget/@type»Widget ("«@id»",«$freq»,[«$args»],[«$variables»],«$enable_expr»,{ + if "$widget/@enable_expr" { + | compute_enable: function(value, oldval, varnum) { + foreach "$widget/path" { + const "varid","generate-id()"; + const "varnum","position()-1"; + if "@assign" foreach "$widget/path[@assign]" if "$varid = generate-id()" { + | if(varnum == «$varnum») this.assignments[«position()-1»] = value; + | let «@assign» = this.assignments[«position()-1»]; + | if(«@assign» == undefined) break; + | result = «$widget/@enable_expr»; apply "$widget", mode="widget_defs" with "hmi_element",".";
| })`if "position()!=last()" > ,`
@@ -225,23 +249,22 @@
- constructor(elt_id, freq, args, indexes, minmaxes, has_enable, members){
+ constructor(elt_id, freq, args, variables, enable_expr, members){ this.element_id = elt_id;
this.element = id(elt_id);
- this.indexes = indexes;
- this.indexes_length = indexes.length;
- this.minmaxes = minmaxes;
- this.has_enable = has_enable;
+ [this.indexes, this.variables_options] = (variables.length>0) ? zip(...variables) : [[],[]]; + this.indexes_length = this.indexes.length; + this.enable_expr = enable_expr; Object.keys(members).forEach(prop => this[prop]=members[prop]);
- this.lastapply = indexes.map(() => undefined);
- this.inhibit = indexes.map(() => undefined);
- this.pending = indexes.map(() => undefined);
+ this.lastapply = this.indexes.map(() => undefined); + this.inhibit = this.indexes.map(() => undefined); + this.pending = this.indexes.map(() => undefined); this.bound_uninhibit = this.uninhibit.bind(this);
- this.lastdispatch = indexes.map(() => undefined);
- this.deafen = indexes.map(() => undefined);
- this.incoming = indexes.map(() => undefined);
+ this.lastdispatch = this.indexes.map(() => undefined); + this.deafen = this.indexes.map(() => undefined); + this.incoming = this.indexes.map(() => undefined); this.bound_undeafen = this.undeafen.bind(this);
this.forced_frequency = freq;
@@ -277,7 +300,7 @@
this.disabled_elt = null;
this.enable_state = false;
@@ -363,7 +386,7 @@
clip_min_max(index, new_val) {
- let minmax = this.minmaxes[index];
+ let minmax = this.variables_options[index].minmax; if(minmax !== undefined && typeof new_val == "number") {
@@ -483,8 +506,7 @@
_dispatch(value, oldval, varnum) {
let dispatch = this.dispatch;
let has_dispatch = dispatch != undefined;
- let is_enable_var = this.has_enable && (varnum == (this.indexes_length - 1));
- if(has_dispatch || is_enable_var){
+ if(has_dispatch || this.enable_expr){ if(this.deafen[varnum] == undefined){
let min_interval = 1000/this.frequency;
@@ -496,8 +518,8 @@
- if(is_enable_var) try {
- this.enable(Boolean(value));
+ if(this.enable_expr) try { + this.compute_enable(value, oldval, varnum); @@ -515,9 +537,9 @@
- if(this.animate != undefined && (!this.has_enable || this.enable_state))
+ if(this.animate != undefined && (!this.enable_expr || this.enable_state)) this.pending_animate = false;
--- a/tests/projects/svghmi_scrollbar/svghmi_0@svghmi/svghmi.svg Fri Aug 19 10:22:16 2022 +0200
+++ b/tests/projects/svghmi_scrollbar/svghmi_0@svghmi/svghmi.svg Tue Aug 23 12:19:44 2022 +0200
@@ -59,9 +59,9 @@
inkscape:current-layer="hmi0"
- inkscape:zoom="0.90509668"
- inkscape:cx="474.80696"
- inkscape:cy="335.41469"
+ inkscape:cx="864.62819" + inkscape:cy="344.83986" inkscape:window-width="1600"
inkscape:window-height="836"
@@ -748,10 +748,10 @@
inkscape:label="HMI:ScrollBar\"
transform="translate(-202)">
+ id="desc150">@range=.range
+#pos>10&&range>50