dgaberscek@2944: // widget_button.ysl2 dgaberscek@2944: Edouard@3085: // Finite state machine Edouard@3085: decl fsm(name); Edouard@3085: decl state(name); Edouard@3085: decl on_mouse(position); Edouard@3085: decl on_dispatch(value); Edouard@3085: decl jump(state); Edouard@3085: decl show(eltname); Edouard@3085: decl hmi_value(value); Edouard@3085: Edouard@3085: // State machine to drive HMI_BOOL on a potentially laggy connection Edouard@3085: const "_button_fsm" fsm { Edouard@3085: state "init" { Edouard@3085: on_dispatch "false" jump "released"; Edouard@3085: on_dispatch "true" jump "pressed"; Edouard@3085: } Edouard@3085: Edouard@3085: state "pressing" { Edouard@3085: // show "waitactive"; Edouard@3085: hmi_value "true"; Edouard@3085: on_dispatch "true" jump "pressed"; Edouard@3085: on_mouse "up" jump "shortpress"; Edouard@3085: } Edouard@3085: state "pressed" { Edouard@3085: show "active"; Edouard@3085: on_mouse "up" jump "releasing"; Edouard@3085: on_dispatch "false" jump "released"; Edouard@3085: } Edouard@3085: state "shortpress" { Edouard@3085: on_dispatch "true" jump "releasing"; Edouard@3085: on_mouse "down" jump "pressing"; Edouard@3085: } Edouard@3085: Edouard@3085: state "releasing" { Edouard@3085: // show "waitinactive"; Edouard@3085: hmi_value "false"; Edouard@3085: on_dispatch "false" jump "released"; Edouard@3085: on_mouse "down" jump "shortrelease"; Edouard@3085: } Edouard@3085: state "released" { Edouard@3085: show "inactive"; Edouard@3085: on_mouse "down" jump "pressing"; Edouard@3085: on_dispatch "true" jump "pressed"; Edouard@3085: } Edouard@3085: state "shortrelease" { Edouard@3085: on_dispatch "false" jump "pressing"; Edouard@3085: on_mouse "up" jump "releasing"; Edouard@3085: } Edouard@3085: } Edouard@3085: Edouard@3085: template "fsm", mode="dispatch_transition" { Edouard@3085: | switch (this.state) { Edouard@3085: apply "state", mode="dispatch_transition"; Edouard@3085: | } Edouard@3085: } Edouard@3085: template "state", mode="dispatch_transition" { Edouard@3085: | case "«@name»": Edouard@3086: apply "on-dispatch"; Edouard@3085: | break; Edouard@3085: } Edouard@3085: template "on-dispatch" { Edouard@3086: | if(value == «@value») { Edouard@3086: apply "jump", mode="transition"; Edouard@3086: | } Edouard@3085: } Edouard@3085: Edouard@3085: template "fsm", mode="mouse_transition" { Edouard@3085: param "position"; Edouard@3085: | switch (this.state) { Edouard@3085: apply "state", mode="mouse_transition" with "position", "$position"; Edouard@3085: | } Edouard@3085: } Edouard@3085: template "state", mode="mouse_transition" { Edouard@3085: param "position"; Edouard@3085: | case "«@name»": Edouard@3085: apply "on-mouse[@position = $position]"; Edouard@3085: | break; Edouard@3085: } Edouard@3085: template "on-mouse" { Edouard@3086: // up or down state is already assumed because apply statement filters it Edouard@3086: apply "jump", mode="transition"; Edouard@3085: } Edouard@3085: Edouard@3085: template "jump", mode="transition" { Edouard@3085: | this.state = "«@state»"; Edouard@3085: | this.«@state»_action(); Edouard@3085: } Edouard@3085: Edouard@3085: template "fsm", mode="actions" { Edouard@3085: apply "state", mode="actions"; Edouard@3085: } Edouard@3085: template "state", mode="actions" { Edouard@3086: | «@name»_action(){ Edouard@3085: //| console.log("Entering state «@name»"); Edouard@3085: apply "*", mode="actions"; Edouard@3086: | } Edouard@3085: } Edouard@3085: template "show", mode="actions" { Edouard@3085: | this.display = "«@eltname»"; Edouard@3085: | this.request_animate(); Edouard@3085: } Edouard@3085: template "hmi-value", mode="actions" { Edouard@3086: | this.apply_hmi_value(0, «@value»); Edouard@3085: } Edouard@3085: Edouard@3024: template "widget[@type='Button']", mode="widget_class"{ Edouard@3085: const "fsm","exsl:node-set($_button_fsm)"; Edouard@3085: | class ButtonWidget extends Widget{ Edouard@3085: | frequency = 5; usveticic@3009: Edouard@3085: | display = "inactive"; Edouard@3085: | state = "init"; usveticic@3059: Edouard@3085: | dispatch(value) { Edouard@3085: // | console.log("dispatch"+value); Edouard@3085: apply "$fsm", mode="dispatch_transition"; Edouard@3085: | } usveticic@3056: Edouard@3085: | onmouseup(evt) { Edouard@3085: | svg_root.removeEventListener("pointerup", this.bound_onmouseup, true); Edouard@3085: // | console.log("onmouseup"); Edouard@3085: apply "$fsm", mode="mouse_transition" with "position", "'up'"; Edouard@3085: | } Edouard@3085: | onmousedown(evt) { Edouard@3085: | svg_root.addEventListener("pointerup", this.bound_onmouseup, true); Edouard@3085: // | console.log("onmousedown"); Edouard@3085: apply "$fsm", mode="mouse_transition" with "position", "'down'"; Edouard@3085: | } usveticic@3009: Edouard@3085: apply "$fsm", mode="actions"; usveticic@3056: Edouard@3085: | animate(){ Edouard@3085: | if (this.active_elt && this.inactive_elt) { Edouard@3085: foreach "str:split('active inactive')" { Edouard@3085: | if(this.display == "«.»") Edouard@3085: | this.«.»_elt.style.display = ""; Edouard@3085: | else Edouard@3085: | this.«.»_elt.style.display = "none"; Edouard@3085: } Edouard@3085: | } Edouard@3085: | } usveticic@3009: Edouard@3085: | init() { Edouard@3085: | this.bound_onmouseup = this.onmouseup.bind(this); Edouard@3085: | this.element.addEventListener("pointerdown", this.onmousedown.bind(this)); Edouard@3085: | } Edouard@3085: | } Edouard@3024: } usveticic@3009: usveticic@3009: dgaberscek@2976: template "widget[@type='Button']", mode="widget_defs" { dgaberscek@2976: param "hmi_element"; dgaberscek@2976: optional_labels("active inactive"); edouard@3000: }