SVGHMI: In order to allow widget signature and description to coexist in same ysl2 file, introduced widget_class, widget_defs to declare widget codegen templates and gen_index_xhtml to mark templates that are only usefull in gen_index_xhtml.xslt. svghmi
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Sun, 02 May 2021 23:01:08 +0200
branchsvghmi
changeset 3232 7bdb766c2a4d
parent 3231 5243c2a2f7f8
child 3233 315f17e74ef5
SVGHMI: In order to allow widget signature and description to coexist in same ysl2 file, introduced widget_class, widget_defs to declare widget codegen templates and gen_index_xhtml to mark templates that are only usefull in gen_index_xhtml.xslt.
svghmi/detachable_pages.ysl2
svghmi/widget_animate.ysl2
svghmi/widget_animaterotation.ysl2
svghmi/widget_back.ysl2
svghmi/widget_button.ysl2
svghmi/widget_circularbar.ysl2
svghmi/widget_circularslider.ysl2
svghmi/widget_customhtml.ysl2
svghmi/widget_display.ysl2
svghmi/widget_dropdown.ysl2
svghmi/widget_foreach.ysl2
svghmi/widget_input.ysl2
svghmi/widget_jsontable.ysl2
svghmi/widget_jump.ysl2
svghmi/widget_keypad.ysl2
svghmi/widget_list.ysl2
svghmi/widget_meter.ysl2
svghmi/widget_multistate.ysl2
svghmi/widget_scrollbar.ysl2
svghmi/widget_slider.ysl2
svghmi/widget_switch.ysl2
svghmi/widget_tooglebutton.ysl2
svghmi/widgets_common.ysl2
--- a/svghmi/detachable_pages.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/detachable_pages.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -193,8 +193,7 @@
     |         "«@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"{
+    apply "$parsed_widgets/widget[@id = $all_page_widgets/@id]", mode="widget_page"{
         with "page_desc", "$desc";
     }
     |   }`if "position()!=last()" > ,`
@@ -208,7 +207,7 @@
     | }
 }
 
-template "*", mode="per_page_widget_template";
+template "*", mode="widget_page";
 
 
 emit "debug:detachable-pages" {
--- a/svghmi/widget_animate.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_animate.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_animate.ysl2
 
-template "widget[@type='Animate']", mode="widget_class"{
+widget_class("Animate") {
     ||
-    class AnimateWidget extends Widget{
         frequency = 5;
         speed = 0;
         start = false;
@@ -42,12 +41,6 @@
             let widget_pos = this.element.getBBox();
             this.widget_center = [(widget_pos.x+widget_pos.width/2), (widget_pos.y+widget_pos.height/2)];
         }
-    }
     ||
 }
 
-
-template "widget[@type='Animate']", mode="widget_defs" {
-    param "hmi_element";
-    |,
-}
--- a/svghmi/widget_animaterotation.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_animaterotation.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_animaterotation.ysl2
 
-template "widget[@type='AnimateRotation']", mode="widget_class"{
+widget_class("AnimateRotation") {
     ||
-    class AnimateRotationWidget extends Widget{
         frequency = 5;
         speed = 0;
         widget_center = undefined;
@@ -40,12 +39,11 @@
             let widget_pos = this.element.getBBox();
             this.widget_center = [(widget_pos.x+widget_pos.width/2), (widget_pos.y+widget_pos.height/2)];
         }
-    }
     ||
 }
 
 
-template "widget[@type='AnimateRotation']", mode="widget_defs" {
+widget_defs("AnimateRotation") {
     param "hmi_element";
     |,
 }
--- a/svghmi/widget_back.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_back.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_back.ysl2
 
-template "widget[@type='Back']", mode="widget_class"
+widget_class("Back")
     ||
-    class BackWidget extends Widget{
         on_click(evt) {
             if(jump_history.length > 1){
                jump_history.pop();
@@ -13,5 +12,4 @@
         init() {
             this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)");
         }
-    }
     ||
--- a/svghmi/widget_button.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_button.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -9,6 +9,8 @@
 decl show(eltname);
 decl hmi_value(value);
 
+gen_index_xhtml {
+
 // State machine to drive HMI_BOOL on a potentially laggy connection
 const "_button_fsm" fsm {
     state "init" {
@@ -104,9 +106,10 @@
     |         this.apply_hmi_value(0, «@value»);
 }
 
-template "widget[@type='Button']", mode="widget_class"{
+}
+
+widget_class("Button"){
     const "fsm","exsl:node-set($_button_fsm)";
-    | class ButtonWidget extends Widget{
     |     frequency = 5;
 
     |     display = "inactive";
@@ -145,11 +148,9 @@
     |         this.bound_onmouseup = this.onmouseup.bind(this);
     |         this.element.addEventListener("pointerdown", this.onmousedown.bind(this));
     |     }
-    | }
 }
 
-
-template "widget[@type='Button']", mode="widget_defs" {
+widget_defs("Button") {
     param "hmi_element";
     optional_labels("active inactive");
 }
--- a/svghmi/widget_circularbar.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_circularbar.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_circularbar.ysl2
 
-template "widget[@type='CircularBar']", mode="widget_class"{
+widget_class("CircularBar") {
     ||
-    class CircularBarWidget extends Widget{
         frequency = 10;
         range = undefined;
 
@@ -49,11 +48,10 @@
             this.center = [cx, cy];
             this.proportions = [rx, ry];
         }
-    }
     ||
 }
 
-template "widget[@type='CircularBar']", mode="widget_defs" {
+widget_defs("CircularBar") {
     param "hmi_element";
     labels("path");
     optional_labels("value min max");
--- a/svghmi/widget_circularslider.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_circularslider.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_circuralslider.ysl2
 
-template "widget[@type='CircularSlider']", mode="widget_class"
+widget_class("CircularSlider")
     ||
-    class CircularSliderWidget extends Widget{
         frequency = 5;
         range = undefined;
         circle = undefined;
@@ -228,10 +227,9 @@
             }
 
         }
-    }
     ||
 
-template "widget[@type='CircularSlider']", mode="widget_defs" {
+widget_defs("CircularSlider") {
     param "hmi_element";
     labels("handle range");
     optional_labels("value min max setpoint");
--- a/svghmi/widget_customhtml.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_customhtml.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_customhtml.ysl2
 
-template "widget[@type='CustomHtml']", mode="widget_class"{
+widget_class("CustomHtml"){
     ||
-    class CustomHtmlWidget extends Widget{
         frequency = 5;
         widget_size = undefined;
 
@@ -21,13 +20,11 @@
                 this.code_elt.textContent+
                 ' </foreignObject>';
         }
-    }
     ||
 }
 
 
-template "widget[@type='CustomHtml']", mode="widget_defs" {
+widget_defs("CustomHtml") {
     param "hmi_element";
     labels("container code");
-    |,
 }
--- a/svghmi/widget_display.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_display.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,18 +1,16 @@
 // widget_display.ysl2
 
 
-template "widget[@type='Display']", mode="widget_class"
+widget_class("Display")
     ||
-    class DisplayWidget extends Widget{
         frequency = 5;
         dispatch(value, oldval, index) {
             this.fields[index] = value;    
             this.request_animate();
         }
-    }
     ||
 
-template "widget[@type='Display']", mode="widget_defs" {
+widget_defs("Display") {
     param "hmi_element";
 
     const "format" optional_labels("format");
--- a/svghmi/widget_dropdown.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_dropdown.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,11 +1,7 @@
 // widget_dropdown.ysl2
 
-template "widget[@type='DropDown']", mode="widget_class"{
+widget_class("DropDown") {
 ||
-    function numb_event(e) {
-        e.stopPropagation();
-    }
-    class DropDownWidget extends Widget{
         dispatch(value) {
             if(!this.opened) this.set_selection(value);
         }
@@ -119,8 +115,8 @@
         }
         close(){
             // Stop hogging all click events
-            svg_root.removeEventListener("pointerdown", numb_event, true);
-            svg_root.removeEventListener("pointerup", numb_event, true);
+            svg_root.removeEventListener("pointerdown", this.numb_event, true);
+            svg_root.removeEventListener("pointerup", this.numb_event, true);
             svg_root.removeEventListener("click", this.bound_close_on_click_elsewhere, true);
             // Restore position and sixe of widget elements
             this.reset_text();
@@ -237,6 +233,9 @@
                 c++;
             }
         }
+        numb_event(e) {
+             e.stopPropagation();
+        }
         open(){
             let length = this.content.length;
             // systematically reset text, to strip eventual whitespace spans
@@ -264,8 +263,8 @@
             // Rise widget to top by moving it to last position among siblings
             this.element.parentNode.appendChild(this.element.parentNode.removeChild(this.element));
             // disable interaction with background
-            svg_root.addEventListener("pointerdown", numb_event, true);
-            svg_root.addEventListener("pointerup", numb_event, true);
+            svg_root.addEventListener("pointerdown", this.numb_event, true);
+            svg_root.addEventListener("pointerup", this.numb_event, true);
             svg_root.addEventListener("click", this.bound_close_on_click_elsewhere, true);
             this.highlight_selection();
 
@@ -329,11 +328,10 @@
             // b.width.baseVal.value = 2 * lmargin + m.width;
             b.height.baseVal.value = 2 * tmargin + m.height;
         }
-    }
 ||
 }
 
-template "widget[@type='DropDown']", mode="widget_defs" {
+widget_defs("DropDown") {
     param "hmi_element";
     labels("text box button highlight");
     // It is assumed that list content conforms to Array interface.
--- a/svghmi/widget_foreach.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_foreach.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,5 +1,5 @@
 
-template "widget[@type='ForEach']", mode="widget_defs" {
+widget_defs("ForEach") {
     param "hmi_element";
 
     if "count(path) != 1" error > ForEach widget «$hmi_element/@id» must have one HMI path given.
@@ -49,9 +49,8 @@
     |     item_offset: 0,
 }
 
-template "widget[@type='ForEach']", mode="widget_class"
+widget_class("ForEach")
 ||
-class ForEachWidget extends Widget{
 
     unsub_items(){
         for(let item of this.items){
@@ -117,6 +116,5 @@
         jumps_need_update = true;
         requestHMIAnimation();
     }
-}
 ||
 
--- a/svghmi/widget_input.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_input.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,44 +1,43 @@
 // widget_input.ysl2
 
-template "widget[@type='Input']", mode="widget_class"{
-||
-    class InputWidget extends Widget{
-         on_op_click(opstr) {
-             this.change_hmi_value(0, opstr);
-         }
-         edit_callback(new_val) {
-             this.apply_hmi_value(0, new_val);
-         }
-
-         is_inhibited = false;
-         alert(msg){
-             this.is_inhibited = true;
-             this.display = msg;
-             setTimeout(() => this.stopalert(), 1000);
-             this.request_animate();
-         }
-
-         stopalert(){
-             this.is_inhibited = false;
-             this.display = this.last_value;
-             this.request_animate();
-         }
-
-         overshot(new_val, max) {
-             this.alert("max");
-         }
-
-         undershot(new_val, min) {
-             this.alert("min");
-         }
 
 
-    }
-||
+
 }
 
-template "widget[@type='Input']", mode="widget_defs" {
-    param "hmi_element";
+widget_class("Input")
+||
+     on_op_click(opstr) {
+         this.change_hmi_value(0, opstr);
+     }
+     edit_callback(new_val) {
+         this.apply_hmi_value(0, new_val);
+     }
+
+     is_inhibited = false;
+     alert(msg){
+         this.is_inhibited = true;
+         this.display = msg;
+         setTimeout(() => this.stopalert(), 1000);
+         this.request_animate();
+     }
+
+     stopalert(){
+         this.is_inhibited = false;
+         this.display = this.last_value;
+         this.request_animate();
+     }
+
+     overshot(new_val, max) {
+         this.alert("max");
+     }
+
+     undershot(new_val, min) {
+         this.alert("min");
+     }
+||
+
+widget_defs("Input") {
 
     const "value_elt" optional_labels("value");
     const "have_value","string-length($value_elt)>0";
--- a/svghmi/widget_jsontable.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_jsontable.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_jsontable.ysl2
 
-template "widget[@type='JsonTable']", mode="widget_class"
+widget_class("JsonTable")
     ||
-    class JsonTableWidget extends Widget{
         // arbitrary defaults to avoid missing entries in query
         cache = [0,0,0];
         init_common() {
@@ -83,9 +82,10 @@
         // on_click(evt, ...options) {
         //     this.do_http_request(...options);
         // }
-    }
     ||
 
+gen_index_xhtml {
+
 template "svg:*", mode="json_table_elt_render" {
     error > JsonTable Widget can't contain element of type «local-name()».
 }
@@ -259,7 +259,9 @@
     |         }
 }
 
-template "widget[@type='JsonTable']", mode="widget_defs" {
+}
+
+widget_defs("JsonTable") {
     param "hmi_element";
     labels("data");
     const "data_elt", "$result_svg_ns//*[@id = $hmi_element/@id]/*[@inkscape:label = 'data']";
--- a/svghmi/widget_jump.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_jump.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,9 +1,7 @@
 // widget_jump.ysl2
 
-template "widget[@type='Jump']", mode="widget_class"{
+widget_class("Jump") {
 ||
-    class JumpWidget extends Widget{
-
         activable = false;
         active = false;
         disabled = false;
@@ -58,11 +56,10 @@
               this.update_activity();
             }
         }
-    }
 ||
 }
 
-template "widget[@type='Jump']", mode="widget_defs" {
+widget_defs("Jump") {
     param "hmi_element";
     const "activity" optional_labels("active inactive");
     const "have_activity","string-length($activity)>0";
@@ -90,7 +87,7 @@
     |     },
 }
 
-template "widget[@type='Jump']", mode="per_page_widget_template"{
+widget_page("Jump"){
     param "page_desc";
     /* check that given path is compatible with page's reference path */
     if "path" {
--- a/svghmi/widget_keypad.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_keypad.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -13,10 +13,8 @@
     | }
 }
 
-template "widget[@type='Keypad']", mode="widget_class"
+widget_class("Keypad")
     ||
-    class KeypadWidget extends Widget{
-
          on_key_click(symbols) {
              var syms = symbols.split(" ");
              this.shift |= this.caps;
@@ -110,10 +108,9 @@
                  (this.caps?this.activate_activable:this.inactivate_activable)(this.CapsLock_sub);
              }
          }
-    }
     ||
 
-template "widget[@type='Keypad']", mode="widget_defs" {
+widget_defs("Keypad") {
     param "hmi_element";
     labels("Esc Enter BackSpace Keys Info Value");
     optional_labels("Sign Space NumDot");
--- a/svghmi/widget_list.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_list.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,6 +1,6 @@
 // widget_list.ysl2
 
-template "widget[@type='List']", mode="widget_defs" {
+widget_defs("List") {
     param "hmi_element";
     |     items: {
     foreach "$hmi_element/*[@inkscape:label]" {
@@ -9,7 +9,7 @@
     |     },
 }
 
-template "widget[@type='TextStyleList']", mode="widget_defs" {
+widget_defs("TextStyleList") {
     param "hmi_element";
     |     styles: {
     foreach "$hmi_element/*[@inkscape:label]" {
--- a/svghmi/widget_meter.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_meter.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_meter.ysl2
 
-template "widget[@type='Meter']", mode="widget_class"{
+widget_class("Metter"){
     ||
-    class MeterWidget extends Widget{
         frequency = 10;
         origin = undefined;
         range = undefined;
@@ -29,12 +28,10 @@
             this.range = [min, max, this.range_elt.getTotalLength()]
             this.origin = this.needle_elt.getPointAtLength(0);
         }
-
-    }
     ||
 }
 
-template "widget[@type='Meter']", mode="widget_defs" {
+widget_defs("Meter") {
     param "hmi_element";
     labels("needle range");
     optional_labels("value min max");
--- a/svghmi/widget_multistate.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_multistate.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_multistate.ysl2
 
-template "widget[@type='MultiState']", mode="widget_class"
+widget_class("MultiState")
     ||
-    class MultiStateWidget extends Widget{
         frequency = 5;
         state = 0;
         dispatch(value) {
@@ -41,10 +40,9 @@
         init() {
             this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)");
         }
-    }
     ||
 
-template "widget[@type='MultiState']", mode="widget_defs" {
+widget_defs("MultiState") {
     param "hmi_element";
     |     choices: [
     const "regex",!"'^(\"[^\"].*\"|\-?[0-9]+|false|true)(#.*)?$'"!;
--- a/svghmi/widget_scrollbar.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_scrollbar.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_scrollbar.ysl2
 
-template "widget[@type='ScrollBar']", mode="widget_class"{
+widget_class("ScrollBar") {
     ||
-    class ScrollBarWidget extends Widget{
         frequency = 10;
         position = undefined;
         range = undefined;
@@ -89,11 +88,10 @@
             this.dragpos += movement * units / pixels;
             this.apply_position(this.dragpos);
         }
-    }
     ||
 }
 
-template "widget[@type='ScrollBar']", mode="widget_defs" {
+widget_defs("ScrollBar") {
     param "hmi_element";
     labels("cursor range");
 
--- a/svghmi/widget_slider.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_slider.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,6 +1,6 @@
 // widget_slider.ysl2
 
-template "widget[@type='Slider']", mode="widget_class"
+widget_class("Slider")
     ||
     class SliderWidget extends Widget{
         frequency = 5;
@@ -339,9 +339,8 @@
     }
     ||
 
-template "widget[@type='Slider']", mode="widget_defs" {
+widget_defs("Slider") {
     param "hmi_element";
     labels("handle range");
     optional_labels("value min max setpoint");
-    |,
 }
--- a/svghmi/widget_switch.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_switch.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,8 +1,7 @@
 // widget_switch.ysl2
 
-template "widget[@type='Switch']", mode="widget_class"
+widget_class("Switch")
     ||
-    class SwitchWidget extends Widget{
         frequency = 5;
         dispatch(value) {
             for(let choice of this.choices){
@@ -13,10 +12,9 @@
                 }
             }
         }
-    }
     ||
 
-template "widget[@type='Switch']", mode="widget_defs" {
+widget_defs("Switch") {
     param "hmi_element";
     |     choices: [
     const "regex",!"'^(\"[^\"].*\"|\-?[0-9]+|false|true)(#.*)?$'"!;
--- a/svghmi/widget_tooglebutton.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widget_tooglebutton.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -1,9 +1,8 @@
 // widget_tooglebutton.ysl2
 
 
-template "widget[@type='ToggleButton']", mode="widget_class"{
+widget_class("ToggleButton") {
     ||
-    class ToggleButtonWidget extends Widget{
         frequency = 5;
         state = 0;
         active_style = undefined;
@@ -41,11 +40,10 @@
             this.activate(false);
             this.element.onclick = (evt) => this.on_click(evt);
         }
-    }
     ||
 }
 
-template "widget[@type='ToggleButton']", mode="widget_defs" {
+widget_defs("ToggleButton") {
     param "hmi_element";
     optional_labels("active inactive");
 }
--- a/svghmi/widgets_common.ysl2	Thu Apr 15 09:15:23 2021 +0200
+++ b/svghmi/widgets_common.ysl2	Sun May 02 23:01:08 2021 +0200
@@ -21,6 +21,26 @@
     }
 };
 
+in xsl decl widget_class(%name, *clsname="%nameWidget", match="widget[@type='%name']", mode="widget_class") alias template {
+    | class `text **clsname` extends Widget{
+    content;
+    | }
+};
+
+in xsl decl widget_defs(%name, match="widget[@type='%name']", mode="widget_defs") alias template {
+    param "hmi_element";
+    content;
+};
+
+in xsl decl widget_page(%name, match="widget[@type='%name']", mode="widget_page") alias template {
+    param "page_desc";
+    content;
+};
+
+decl gen_index_xhtml alias - {
+    content;
+};
+
 template "svg:*", mode="hmi_widgets" {
     const "widget", "func:widget(@id)";
     const "eltid","@id";