svghmi/widget_button.ysl2
changeset 3302 c89fc366bebd
parent 3241 fe945f1f48b7
child 3413 2e84a2782295
equal deleted inserted replaced
2744:577118ebd179 3302:c89fc366bebd
       
     1 // widget_button.ysl2
       
     2 
       
     3 widget_desc("Button") {
       
     4     longdesc
       
     5     ||
       
     6     Button widget takes one boolean variable path, and reflect current true
       
     7     or false value by showing "active" or "inactive" labeled element
       
     8     respectively. Pressing and releasing button changes variable to true and
       
     9     false respectively. Potential inconsistency caused by quick consecutive
       
    10     presses on the button is mitigated by using a state machine that wait for
       
    11     previous state change to be reflected on variable before applying next one.
       
    12     ||
       
    13 
       
    14     shortdesc > Push button reflecting consistently given boolean variable
       
    15 
       
    16     path name="value" accepts="HMI_BOOL" > Boolean variable
       
    17     
       
    18 }
       
    19 
       
    20 // Finite state machine
       
    21 decl fsm(name);
       
    22 decl state(name);
       
    23 decl on_mouse(position);
       
    24 decl on_dispatch(value);
       
    25 decl jump(state);
       
    26 decl show(eltname);
       
    27 decl hmi_value(value);
       
    28 
       
    29 gen_index_xhtml {
       
    30 
       
    31 // State machine to drive HMI_BOOL on a potentially laggy connection
       
    32 const "_button_fsm" fsm {
       
    33     state "init" {
       
    34         on_dispatch "false" jump "released";
       
    35         on_dispatch "true" jump "pressed";
       
    36     }
       
    37 
       
    38     state "pressing" {
       
    39         // show "waitactive";
       
    40         hmi_value "true";
       
    41         on_dispatch "true" jump "pressed";
       
    42         on_mouse "up" jump "shortpress";
       
    43     }
       
    44     state "pressed" {
       
    45         show "active";
       
    46         on_mouse "up" jump "releasing";
       
    47         on_dispatch "false" jump "released";
       
    48     }
       
    49     state "shortpress" {
       
    50         on_dispatch "true" jump "releasing";
       
    51         on_mouse "down" jump "pressing";
       
    52     }
       
    53 
       
    54     state "releasing" {
       
    55         // show "waitinactive";
       
    56         hmi_value "false";
       
    57         on_dispatch "false" jump "released";
       
    58         on_mouse "down" jump "shortrelease";
       
    59     }
       
    60     state "released" {
       
    61         show "inactive";
       
    62         on_mouse "down" jump "pressing";
       
    63         on_dispatch "true" jump "pressed";
       
    64     }
       
    65     state "shortrelease" {
       
    66         on_dispatch "false" jump "pressing";
       
    67         on_mouse "up" jump "releasing";
       
    68     }
       
    69 }
       
    70 
       
    71 template "fsm", mode="dispatch_transition" {
       
    72     |         switch (this.state) {
       
    73     apply "state", mode="dispatch_transition";
       
    74     |         }
       
    75 }
       
    76 template "state", mode="dispatch_transition" {
       
    77     |           case "«@name»":
       
    78        apply "on-dispatch";
       
    79     |             break;
       
    80 }
       
    81 template "on-dispatch" {
       
    82     |             if(value ==  «@value») {
       
    83     apply "jump", mode="transition";
       
    84     |             }
       
    85 }
       
    86 
       
    87 template "fsm", mode="mouse_transition" {
       
    88     param "position";
       
    89     |         switch (this.state) {
       
    90     apply "state", mode="mouse_transition" with "position", "$position";
       
    91     |         }
       
    92 }
       
    93 template "state", mode="mouse_transition" {
       
    94     param "position";
       
    95     |           case "«@name»":
       
    96     apply "on-mouse[@position = $position]";
       
    97     |             break;
       
    98 }
       
    99 template "on-mouse" {
       
   100     // up or down state is already assumed because apply statement filters it
       
   101     apply "jump", mode="transition";
       
   102 }
       
   103 
       
   104 template "jump", mode="transition" {
       
   105     |             this.state = "«@state»";
       
   106     |             this.«@state»_action();
       
   107 }
       
   108 
       
   109 template "fsm", mode="actions" {
       
   110     apply "state", mode="actions";
       
   111 }
       
   112 template "state", mode="actions" {
       
   113     |     «@name»_action(){
       
   114     //| console.log("Entering state «@name»");
       
   115     apply "*", mode="actions";
       
   116     |     }
       
   117 }
       
   118 template "show", mode="actions" {
       
   119     |         this.display = "«@eltname»";
       
   120     |         this.request_animate();
       
   121 }
       
   122 template "hmi-value", mode="actions" {
       
   123     |         this.apply_hmi_value(0, «@value»);
       
   124 }
       
   125 
       
   126 }
       
   127 
       
   128 widget_class("Button"){
       
   129     const "fsm","exsl:node-set($_button_fsm)";
       
   130     |     frequency = 5;
       
   131 
       
   132     |     display = "inactive";
       
   133     |     state = "init";
       
   134 
       
   135     |     dispatch(value) {
       
   136     // |         console.log("dispatch"+value);
       
   137     apply "$fsm", mode="dispatch_transition";
       
   138     |     }
       
   139 
       
   140     |     onmouseup(evt) {
       
   141     |         svg_root.removeEventListener("pointerup", this.bound_onmouseup, true);
       
   142     // |         console.log("onmouseup");
       
   143     apply "$fsm", mode="mouse_transition" with "position", "'up'";
       
   144     |     }
       
   145     |     onmousedown(evt) {
       
   146     |         svg_root.addEventListener("pointerup", this.bound_onmouseup, true);
       
   147     // |         console.log("onmousedown");
       
   148     apply "$fsm", mode="mouse_transition" with "position", "'down'";
       
   149     |     }
       
   150 
       
   151     apply "$fsm", mode="actions";
       
   152 
       
   153     |     animate(){
       
   154     |         if (this.active_elt && this.inactive_elt) {
       
   155     foreach "str:split('active inactive')" {
       
   156     |             if(this.display == "«.»")
       
   157     |                 this.«.»_elt.style.display = "";
       
   158     |             else
       
   159     |                 this.«.»_elt.style.display = "none";
       
   160     }
       
   161     |         }
       
   162     |     }
       
   163 
       
   164     |     init() {
       
   165     |         this.bound_onmouseup = this.onmouseup.bind(this);
       
   166     |         this.element.addEventListener("pointerdown", this.onmousedown.bind(this));
       
   167     |     }
       
   168 }
       
   169 
       
   170 widget_defs("Button") {
       
   171     optional_labels("active inactive");
       
   172 }