svghmi/widget_button.ysl2
author Edouard Tisserant <edouard.tisserant@gmail.com>
Sun, 02 May 2021 23:01:08 +0200
branchsvghmi
changeset 3232 7bdb766c2a4d
parent 3086 a70a97196654
child 3241 fe945f1f48b7
permissions -rw-r--r--
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.
// widget_button.ysl2

// Finite state machine
decl fsm(name);
decl state(name);
decl on_mouse(position);
decl on_dispatch(value);
decl jump(state);
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" {
        on_dispatch "false" jump "released";
        on_dispatch "true" jump "pressed";
    }

    state "pressing" {
        // show "waitactive";
        hmi_value "true";
        on_dispatch "true" jump "pressed";
        on_mouse "up" jump "shortpress";
    }
    state "pressed" {
        show "active";
        on_mouse "up" jump "releasing";
        on_dispatch "false" jump "released";
    }
    state "shortpress" {
        on_dispatch "true" jump "releasing";
        on_mouse "down" jump "pressing";
    }

    state "releasing" {
        // show "waitinactive";
        hmi_value "false";
        on_dispatch "false" jump "released";
        on_mouse "down" jump "shortrelease";
    }
    state "released" {
        show "inactive";
        on_mouse "down" jump "pressing";
        on_dispatch "true" jump "pressed";
    }
    state "shortrelease" {
        on_dispatch "false" jump "pressing";
        on_mouse "up" jump "releasing";
    }
}

template "fsm", mode="dispatch_transition" {
    |         switch (this.state) {
    apply "state", mode="dispatch_transition";
    |         }
}
template "state", mode="dispatch_transition" {
    |           case "«@name»":
       apply "on-dispatch";
    |             break;
}
template "on-dispatch" {
    |             if(value ==  «@value») {
    apply "jump", mode="transition";
    |             }
}

template "fsm", mode="mouse_transition" {
    param "position";
    |         switch (this.state) {
    apply "state", mode="mouse_transition" with "position", "$position";
    |         }
}
template "state", mode="mouse_transition" {
    param "position";
    |           case "«@name»":
    apply "on-mouse[@position = $position]";
    |             break;
}
template "on-mouse" {
    // up or down state is already assumed because apply statement filters it
    apply "jump", mode="transition";
}

template "jump", mode="transition" {
    |             this.state = "«@state»";
    |             this.«@state»_action();
}

template "fsm", mode="actions" {
    apply "state", mode="actions";
}
template "state", mode="actions" {
    |     «@name»_action(){
    //| console.log("Entering state «@name»");
    apply "*", mode="actions";
    |     }
}
template "show", mode="actions" {
    |         this.display = "«@eltname»";
    |         this.request_animate();
}
template "hmi-value", mode="actions" {
    |         this.apply_hmi_value(0, «@value»);
}

}

widget_class("Button"){
    const "fsm","exsl:node-set($_button_fsm)";
    |     frequency = 5;

    |     display = "inactive";
    |     state = "init";

    |     dispatch(value) {
    // |         console.log("dispatch"+value);
    apply "$fsm", mode="dispatch_transition";
    |     }

    |     onmouseup(evt) {
    |         svg_root.removeEventListener("pointerup", this.bound_onmouseup, true);
    // |         console.log("onmouseup");
    apply "$fsm", mode="mouse_transition" with "position", "'up'";
    |     }
    |     onmousedown(evt) {
    |         svg_root.addEventListener("pointerup", this.bound_onmouseup, true);
    // |         console.log("onmousedown");
    apply "$fsm", mode="mouse_transition" with "position", "'down'";
    |     }

    apply "$fsm", mode="actions";

    |     animate(){
    |         if (this.active_elt && this.inactive_elt) {
    foreach "str:split('active inactive')" {
    |             if(this.display == "«.»")
    |                 this.«.»_elt.style.display = "";
    |             else
    |                 this.«.»_elt.style.display = "none";
    }
    |         }
    |     }

    |     init() {
    |         this.bound_onmouseup = this.onmouseup.bind(this);
    |         this.element.addEventListener("pointerdown", this.onmousedown.bind(this));
    |     }
}

widget_defs("Button") {
    param "hmi_element";
    optional_labels("active inactive");
}