1 // widget_button.ysl2 |
1 // widget_button.ysl2 |
2 |
2 |
|
3 // Finite state machine |
|
4 decl fsm(name); |
|
5 decl state(name); |
|
6 decl on_mouse(position); |
|
7 decl on_dispatch(value); |
|
8 decl jump(state); |
|
9 decl show(eltname); |
|
10 decl hmi_value(value); |
|
11 |
|
12 // State machine to drive HMI_BOOL on a potentially laggy connection |
|
13 // TODO: make more robust in case other widget or PLC change value on their own |
|
14 const "_button_fsm" fsm { |
|
15 state "init" { |
|
16 on_dispatch "false" jump "released"; |
|
17 on_dispatch "true" jump "pressed"; |
|
18 } |
|
19 |
|
20 state "pressing" { |
|
21 // show "waitactive"; |
|
22 hmi_value "true"; |
|
23 on_dispatch "true" jump "pressed"; |
|
24 on_mouse "up" jump "shortpress"; |
|
25 } |
|
26 state "pressed" { |
|
27 show "active"; |
|
28 on_mouse "up" jump "releasing"; |
|
29 on_dispatch "false" jump "released"; |
|
30 } |
|
31 state "shortpress" { |
|
32 on_dispatch "true" jump "releasing"; |
|
33 on_mouse "down" jump "pressing"; |
|
34 } |
|
35 |
|
36 state "releasing" { |
|
37 // show "waitinactive"; |
|
38 hmi_value "false"; |
|
39 on_dispatch "false" jump "released"; |
|
40 on_mouse "down" jump "shortrelease"; |
|
41 } |
|
42 state "released" { |
|
43 show "inactive"; |
|
44 on_mouse "down" jump "pressing"; |
|
45 on_dispatch "true" jump "pressed"; |
|
46 } |
|
47 state "shortrelease" { |
|
48 on_dispatch "false" jump "pressing"; |
|
49 on_mouse "up" jump "releasing"; |
|
50 } |
|
51 } |
|
52 |
|
53 template "fsm", mode="dispatch_transition" { |
|
54 | switch (this.state) { |
|
55 apply "state", mode="dispatch_transition"; |
|
56 | } |
|
57 } |
|
58 template "state", mode="dispatch_transition" { |
|
59 | case "«@name»": |
|
60 apply "on-dispatch"; |
|
61 | break; |
|
62 } |
|
63 template "on-dispatch" { |
|
64 | if(value == «@value») { |
|
65 apply "jump", mode="transition"; |
|
66 | } |
|
67 } |
|
68 |
|
69 template "fsm", mode="mouse_transition" { |
|
70 param "position"; |
|
71 | switch (this.state) { |
|
72 apply "state", mode="mouse_transition" with "position", "$position"; |
|
73 | } |
|
74 } |
|
75 template "state", mode="mouse_transition" { |
|
76 param "position"; |
|
77 | case "«@name»": |
|
78 apply "on-mouse[@position = $position]"; |
|
79 | break; |
|
80 } |
|
81 template "on-mouse" { |
|
82 // up or down state is already assumed because apply statement filters it |
|
83 apply "jump", mode="transition"; |
|
84 } |
|
85 |
|
86 template "jump", mode="transition" { |
|
87 | this.state = "«@state»"; |
|
88 | this.«@state»_action(); |
|
89 } |
|
90 |
|
91 template "fsm", mode="actions" { |
|
92 apply "state", mode="actions"; |
|
93 } |
|
94 template "state", mode="actions" { |
|
95 | «@name»_action(){ |
|
96 //| console.log("Entering state «@name»"); |
|
97 apply "*", mode="actions"; |
|
98 | } |
|
99 } |
|
100 template "show", mode="actions" { |
|
101 | this.display = "«@eltname»"; |
|
102 | this.request_animate(); |
|
103 } |
|
104 template "hmi-value", mode="actions" { |
|
105 | this.apply_hmi_value(0, «@value»); |
|
106 } |
|
107 |
3 template "widget[@type='Button']", mode="widget_class"{ |
108 template "widget[@type='Button']", mode="widget_class"{ |
4 || |
109 const "fsm","exsl:node-set($_button_fsm)"; |
5 class ButtonWidget extends Widget{ |
110 | class ButtonWidget extends Widget{ |
6 frequency = 5; |
111 | frequency = 5; |
7 state_plc = 0; |
|
8 state_hmi = 0; |
|
9 plc_lock = false; |
|
10 active_style = undefined; |
|
11 inactive_style = undefined; |
|
12 |
112 |
13 dispatch(value) { |
113 | display = "inactive"; |
14 this.state_plc = value; |
114 | state = "init"; |
15 if(this.plc_lock){ |
|
16 if(this.state_plc == 1){ |
|
17 this.apply_hmi_value(0, 0); |
|
18 this.plc_lock = false; |
|
19 } |
|
20 } |
|
21 |
115 |
22 //redraw button |
116 | dispatch(value) { |
23 this.state_hmi = this.state_plc; |
117 // | console.log("dispatch"+value); |
24 this.request_animate(); |
118 apply "$fsm", mode="dispatch_transition"; |
25 } |
119 | } |
26 |
120 |
27 animate(){ |
121 | onmouseup(evt) { |
28 if (this.active_style && this.inactive_style) { |
122 | svg_root.removeEventListener("pointerup", this.bound_onmouseup, true); |
29 // redraw button on screen refresh |
123 // | console.log("onmouseup"); |
30 if (this.state_hmi) { |
124 apply "$fsm", mode="mouse_transition" with "position", "'up'"; |
31 this.active_elt.setAttribute("style", this.active_style); |
125 | } |
32 this.inactive_elt.setAttribute("style", "display:none"); |
126 | onmousedown(evt) { |
33 } else { |
127 | svg_root.addEventListener("pointerup", this.bound_onmouseup, true); |
34 this.inactive_elt.setAttribute("style", this.inactive_style); |
128 // | console.log("onmousedown"); |
35 this.active_elt.setAttribute("style", "display:none"); |
129 apply "$fsm", mode="mouse_transition" with "position", "'down'"; |
36 } |
130 | } |
37 } |
|
38 } |
|
39 |
131 |
40 on_click(evt) { |
132 apply "$fsm", mode="actions"; |
41 //set state and apply if plc is 0 |
|
42 this.plc_lock = true; |
|
43 if(this.state_plc == 0){ |
|
44 this.apply_hmi_value(0, 1); |
|
45 } |
|
46 //redraw button |
|
47 this.request_animate(); |
|
48 } |
|
49 |
133 |
50 on_press(evt) { |
134 | animate(){ |
51 //set graphic |
135 | if (this.active_elt && this.inactive_elt) { |
52 this.state_hmi = 1; |
136 foreach "str:split('active inactive')" { |
53 //redraw button |
137 | if(this.display == "«.»") |
54 this.request_animate(); |
138 | this.«.»_elt.style.display = ""; |
55 } |
139 | else |
|
140 | this.«.»_elt.style.display = "none"; |
|
141 } |
|
142 | } |
|
143 | } |
56 |
144 |
57 init() { |
145 | init() { |
58 this.active_style = this.active_elt ? this.active_elt.style.cssText : undefined; |
146 | this.bound_onmouseup = this.onmouseup.bind(this); |
59 this.inactive_style = this.inactive_elt ? this.inactive_elt.style.cssText : undefined; |
147 | this.element.addEventListener("pointerdown", this.onmousedown.bind(this)); |
60 |
148 | } |
61 if (this.active_style && this.inactive_style) { |
149 | } |
62 this.active_elt.setAttribute("style", "display:none"); |
|
63 this.inactive_elt.setAttribute("style", this.inactive_style); |
|
64 } |
|
65 |
|
66 this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)"); |
|
67 this.element.setAttribute("onmousedown", "hmi_widgets['"+this.element_id+"'].on_press(evt)"); |
|
68 } |
|
69 } |
|
70 || |
|
71 } |
150 } |
72 |
151 |
73 |
152 |
74 template "widget[@type='Button']", mode="widget_defs" { |
153 template "widget[@type='Button']", mode="widget_defs" { |
75 param "hmi_element"; |
154 param "hmi_element"; |