dgaberscek@2944: // widget_button.ysl2 dgaberscek@2944: edouard@3241: widget_desc("Button") { edouard@3241: longdesc edouard@3241: || edouard@3241: Button widget takes one boolean variable path, and reflect current true edouard@3241: or false value by showing "active" or "inactive" labeled element edouard@3241: respectively. Pressing and releasing button changes variable to true and edouard@3241: false respectively. Potential inconsistency caused by quick consecutive edouard@3241: presses on the button is mitigated by using a state machine that wait for edouard@3241: previous state change to be reflected on variable before applying next one. edouard@3241: || edouard@3241: edouard@3241: shortdesc > Push button reflecting consistently given boolean variable edouard@3241: edouard@3241: path name="value" accepts="HMI_BOOL" > Boolean variable edouard@3241: edouard@3241: } edouard@3241: 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@3232: gen_index_xhtml { edouard@3232: 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@3232: } edouard@3232: edouard@3232: widget_class("Button"){ Edouard@3085: const "fsm","exsl:node-set($_button_fsm)"; 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@3024: } usveticic@3009: edouard@3232: widget_defs("Button") { dgaberscek@2976: optional_labels("active inactive"); edouard@3000: }