71 html xmlns="http://www.w3.org/1999/xhtml" |
73 html xmlns="http://www.w3.org/1999/xhtml" |
72 xmlns:svg="http://www.w3.org/2000/svg" |
74 xmlns:svg="http://www.w3.org/2000/svg" |
73 xmlns:xlink="http://www.w3.org/1999/xlink" { |
75 xmlns:xlink="http://www.w3.org/1999/xlink" { |
74 head; |
76 head; |
75 body style="margin:0;overflow:hidden;" { |
77 body style="margin:0;overflow:hidden;" { |
|
78 // Inline SVG |
76 copy "$result_svg"; |
79 copy "$result_svg"; |
77 script{ |
80 script{ |
78 call "scripts"; |
81 call "scripts"; |
79 } |
82 } |
80 } |
83 } |
81 } |
84 } |
82 } |
85 } |
83 |
86 |
84 function "scripts" |
87 function "scripts" |
85 { |
88 { |
86 | //(function(){ |
|
87 | |
89 | |
88 | id = idstr => document.getElementById(idstr); |
90 | id = idstr => document.getElementById(idstr); |
89 | |
91 | |
90 | var hmi_hash = [«$hmitree/@hash»]; |
92 | var hmi_hash = [«$hmitree/@hash»]; |
91 |
|
92 /* TODO re-enable |
|
93 || |
|
94 function evaluate_js_from_descriptions() { |
|
95 var Page; |
|
96 var Input; |
|
97 var Display; |
|
98 var res = []; |
|
99 || |
|
100 const "midmark" > \n«$mark» |
|
101 apply """//*[contains(child::svg:desc, $midmark) or \ |
|
102 starts-with(child::svg:desc, $mark)]""",2 |
|
103 mode="code_from_descs"; |
|
104 || |
|
105 return res; |
|
106 } |
|
107 || |
|
108 */ |
|
109 |
93 |
110 | var hmi_widgets = { |
94 | var hmi_widgets = { |
111 apply "$hmi_elements", mode="hmi_elements"; |
95 apply "$hmi_elements", mode="hmi_elements"; |
112 | } |
96 | } |
113 | |
97 | |
135 |
119 |
136 | |
120 | |
137 | var default_page = "«$default_page»"; |
121 | var default_page = "«$default_page»"; |
138 | var svg_root = id("«/svg:svg/@id»"); |
122 | var svg_root = id("«/svg:svg/@id»"); |
139 include text svghmi.js |
123 include text svghmi.js |
140 | //})(); |
|
141 } |
|
142 |
|
143 // template "*", mode="code_from_descs" { |
|
144 // || |
|
145 // { |
|
146 // var path, role, name, priv; |
|
147 // var id = "«@id»"; |
|
148 // || |
|
149 |
|
150 // /* if label is used, use it as default name */ |
|
151 // if "@inkscape:label" |
|
152 // |> name = "«@inkscape:label»"; |
|
153 |
|
154 // | /* -------------- */ |
|
155 |
|
156 // // this breaks indent, but fixing indent could break string literals |
|
157 // value "substring-after(svg:desc, $mark)"; |
|
158 // // nobody reads generated code anyhow... |
|
159 |
|
160 // || |
|
161 |
|
162 // /* -------------- */ |
|
163 // res.push({ |
|
164 // path:path, |
|
165 // role:role, |
|
166 // name:name, |
|
167 // priv:priv |
|
168 // }) |
|
169 // } |
|
170 // || |
|
171 // } |
|
172 |
|
173 |
|
174 template "widget[@type='Display']", mode="widget_defs" { |
|
175 param "hmi_element"; |
|
176 | frequency: 5, |
|
177 | dispatch: function(value) { |
|
178 choose { |
|
179 when "$hmi_element[self::svg:text]"{ |
|
180 // TODO : care about <tspan> ? |
|
181 | this.element.textContent = String(value); |
|
182 } |
|
183 otherwise { |
|
184 warning > Display widget as a group not implemented |
|
185 } |
|
186 } |
|
187 | }, |
|
188 |
|
189 } |
|
190 template "widget[@type='Meter']", mode="widget_defs" { |
|
191 param "hmi_element"; |
|
192 | frequency: 10, |
|
193 labels("needle range"); |
|
194 optional_labels("value min max"); |
|
195 | dispatch: function(value) { |
|
196 | if(this.value_elt) |
|
197 | this.value_elt.textContent = String(value); |
|
198 | let [min,max,totallength] = this.range; |
|
199 | let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min))); |
|
200 | let tip = this.range_elt.getPointAtLength(length); |
|
201 | this.needle_elt.setAttribute('d', "M "+this.origin.x+","+this.origin.y+" "+tip.x+","+tip.y); |
|
202 | }, |
|
203 | origin: undefined, |
|
204 | range: undefined, |
|
205 | init: function() { |
|
206 | let min = this.min_elt ? |
|
207 | Number(this.min_elt.textContent) : |
|
208 | this.args.length >= 1 ? this.args[0] : 0; |
|
209 | let max = this.max_elt ? |
|
210 | Number(this.max_elt.textContent) : |
|
211 | this.args.length >= 2 ? this.args[1] : 100; |
|
212 | this.range = [min, max, this.range_elt.getTotalLength()] |
|
213 | this.origin = this.needle_elt.getPointAtLength(0); |
|
214 | }, |
|
215 } |
|
216 |
|
217 def "func:escape_quotes" { |
|
218 param "txt"; |
|
219 // have to use a python string to enter escaped quote |
|
220 const "frst", !"substring-before($txt,'\"')"!; |
|
221 const "frstln", "string-length($frst)"; |
|
222 choose { |
|
223 when "$frstln > 0 and string-length($txt) > $frstln" { |
|
224 result !"concat($frst,'\\\"',func:escape_quotes(substring-after($txt,'\"')))"!; |
|
225 } |
|
226 otherwise { |
|
227 result "$txt"; |
|
228 } |
|
229 } |
|
230 } |
|
231 |
|
232 template "widget[@type='Input']", mode="widget_defs" { |
|
233 param "hmi_element"; |
|
234 const "value_elt" { |
|
235 optional_labels("value"); |
|
236 } |
|
237 const "have_value","string-length($value_elt)>0"; |
|
238 value "$value_elt"; |
|
239 if "$have_value" |
|
240 | frequency: 5, |
|
241 |
|
242 | dispatch: function(value) { |
|
243 |
|
244 if "$have_value" |
|
245 | this.value_elt.textContent = String(value); |
|
246 |
|
247 | }, |
|
248 const "edit_elt_id","$hmi_element/*[@inkscape:label='edit'][1]/@id"; |
|
249 | init: function() { |
|
250 if "$edit_elt_id" { |
|
251 | id("«$edit_elt_id»").addEventListener( |
|
252 | "click", |
|
253 | evt => alert('XXX TODO : Edit value')); |
|
254 } |
|
255 foreach "$hmi_element/*[regexp:test(@inkscape:label,'^[=+\-].+')]" { |
|
256 | id("«@id»").addEventListener( |
|
257 | "click", |
|
258 | evt => {let new_val = change_hmi_value(this.indexes[0], "«func:escape_quotes(@inkscape:label)»"); |
|
259 if "$have_value"{ |
|
260 | this.value_elt.textContent = String(new_val); |
|
261 } |
|
262 | }); |
|
263 /* TODO gray out value until refreshed */ |
|
264 } |
|
265 | }, |
|
266 } |
|
267 template "widget[@type='Button']", mode="widget_defs" { |
|
268 } |
|
269 template "widget[@type='Toggle']", mode="widget_defs" { |
|
270 | frequency: 5, |
|
271 } |
|
272 template "widget[@type='Switch']", mode="widget_defs" { |
|
273 param "hmi_element"; |
|
274 | frequency: 5, |
|
275 | dispatch: function(value) { |
|
276 | for(let choice of this.choices){ |
|
277 | if(value != choice.value){ |
|
278 | choice.elt.setAttribute("style", "display:none"); |
|
279 | } else { |
|
280 | choice.elt.setAttribute("style", choice.style); |
|
281 | } |
|
282 | } |
|
283 | }, |
|
284 | init: function() { |
|
285 | // Hello Switch |
|
286 | }, |
|
287 | choices: [ |
|
288 const "regex",!"'^(\"[^\"].*\"|\-?[0-9]+)(#.*)?$'"!; |
|
289 foreach "$hmi_element/*[regexp:test(@inkscape:label,$regex)]" { |
|
290 const "literal", "regexp:match(@inkscape:label,$regex)[2]"; |
|
291 | { |
|
292 | elt:id("«@id»"), |
|
293 | style:"«@style»", |
|
294 | value:«$literal» |
|
295 | }`if "position()!=last()" > ,` |
|
296 } |
|
297 | ], |
|
298 } |
|
299 template "widget[@type='Jump']", mode="widget_defs" { |
|
300 param "hmi_element"; |
|
301 | on_click: function(evt) { |
|
302 | switch_page(this.args[0], this.indexes[0]); |
|
303 | }, |
|
304 | init: function() { |
|
305 /* registering event this way doies not "click" through svg:use |
|
306 | this.element.onclick = evt => switch_page(this.args[0]); |
|
307 event must be registered by adding attribute to element instead |
|
308 TODO : generalize mouse event handling by global event capture + getElementsAtPoint() |
|
309 */ |
|
310 | this.element.setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_click(evt)"); |
|
311 | }, |
|
312 } |
124 } |
313 } |
125 } |