25 |
25 |
26 from util.ProcessLogger import ProcessLogger |
26 from util.ProcessLogger import ProcessLogger |
27 |
27 |
28 ScriptDirectory = paths.AbsDir(__file__) |
28 ScriptDirectory = paths.AbsDir(__file__) |
29 |
29 |
|
30 HMITreeDndMagicWord = "text/beremiz-hmitree" |
|
31 |
30 class HMITreeSelector(wx.TreeCtrl): |
32 class HMITreeSelector(wx.TreeCtrl): |
31 def __init__(self, parent): |
33 def __init__(self, parent): |
32 global on_hmitree_update |
34 |
33 wx.TreeCtrl.__init__(self, parent, style=( |
35 wx.TreeCtrl.__init__(self, parent, style=( |
34 wx.TR_MULTIPLE | |
36 wx.TR_MULTIPLE | |
35 wx.TR_HAS_BUTTONS | |
37 wx.TR_HAS_BUTTONS | |
36 wx.SUNKEN_BORDER | |
38 wx.SUNKEN_BORDER | |
37 wx.TR_LINES_AT_ROOT)) |
39 wx.TR_LINES_AT_ROOT)) |
38 |
40 |
|
41 self.ordered_items = [] |
|
42 self.parent = parent |
|
43 |
39 self.MakeTree() |
44 self.MakeTree() |
|
45 |
|
46 self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeNodeSelection) |
|
47 self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag) |
40 |
48 |
41 def _recurseTree(self, current_hmitree_root, current_tc_root): |
49 def _recurseTree(self, current_hmitree_root, current_tc_root): |
42 for c in current_hmitree_root.children: |
50 for c in current_hmitree_root.children: |
43 if hasattr(c, "children"): |
51 if hasattr(c, "children"): |
44 display_name = ('{} (class={})'.format(c.name, c.hmiclass)) \ |
52 display_name = ('{} (class={})'.format(c.name, c.hmiclass)) \ |
49 self._recurseTree(c,tc_child) |
57 self._recurseTree(c,tc_child) |
50 else: |
58 else: |
51 display_name = '{} {}'.format(c.nodetype[4:], c.name) |
59 display_name = '{} {}'.format(c.nodetype[4:], c.name) |
52 tc_child = self.AppendItem(current_tc_root, display_name) |
60 tc_child = self.AppendItem(current_tc_root, display_name) |
53 self.SetPyData(tc_child, c) |
61 self.SetPyData(tc_child, c) |
|
62 |
|
63 def OnTreeNodeSelection(self, event): |
|
64 items = self.GetSelections() |
|
65 items_pydata = [self.GetPyData(item) for item in items] |
|
66 |
|
67 # append new items to ordered item list |
|
68 for item_pydata in items_pydata: |
|
69 if item_pydata not in self.ordered_items: |
|
70 self.ordered_items.append(item_pydata) |
|
71 |
|
72 # filter out vanished items |
|
73 self.ordered_items = [ |
|
74 item_pydata |
|
75 for item_pydata in self.ordered_items |
|
76 if item_pydata in items_pydata] |
|
77 |
|
78 self.parent.OnHMITreeNodeSelection(self.ordered_items) |
|
79 |
|
80 def OnTreeBeginDrag(self, event): |
|
81 """ |
|
82 Called when a drag is started in tree |
|
83 @param event: wx.TreeEvent |
|
84 """ |
|
85 if self.ordered_items: |
|
86 print("boink") |
|
87 # Just send a recognizable mime-type, drop destination |
|
88 # will get python data from parent |
|
89 data = wx.CustomDataObject(HMITreeDndMagicWord) |
|
90 dragSource = wx.DropSource(self) |
|
91 dragSource.SetData(data) |
|
92 dragSource.DoDragDrop() |
54 |
93 |
55 def MakeTree(self, hmi_tree_root=None): |
94 def MakeTree(self, hmi_tree_root=None): |
56 |
95 |
57 self.Freeze() |
96 self.Freeze() |
58 |
97 |
125 self._recurseTree(lib_dir, self.root, []) |
164 self._recurseTree(lib_dir, self.root, []) |
126 self.Expand(self.root) |
165 self.Expand(self.root) |
127 |
166 |
128 self.Thaw() |
167 self.Thaw() |
129 |
168 |
130 class PathEditor(wx.Panel): |
169 class PathDropTarget(wx.DropTarget): |
131 def __init__(self, parent, path): |
170 |
132 |
171 def __init__(self, parent): |
133 wx.Panel.__init__(self, parent) |
172 data = wx.CustomDataObject(HMITreeDndMagicWord) |
134 label = path.get("name") + ": " + path.text + "(" + path.get("accepts") + ")" |
173 wx.DropTarget.__init__(self, data) |
|
174 self.ParentWindow = parent |
|
175 |
|
176 def OnDrop(self, x, y): |
|
177 self.ParentWindow.OnHMITreeDnD() |
|
178 return True |
|
179 |
|
180 class ParamEditor(wx.Panel): |
|
181 def __init__(self, parent, paramdesc): |
|
182 |
|
183 wx.Panel.__init__(self, parent.main_panel) |
|
184 label = paramdesc.get("name")+ ": " + paramdesc.get("accepts") |
|
185 if paramdesc.text: |
|
186 label += "\n\"" + paramdesc.text + "\"" |
135 self.desc = wx.StaticText(self, label=label) |
187 self.desc = wx.StaticText(self, label=label) |
136 self.focus_sbmp = wx.StaticBitmap(self, -1, wx.ArtProvider.GetBitmap(wx.ART_GO_FORWARD, wx.ART_TOOLBAR, (32,32))) |
188 self.valid_bmp = wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK, wx.ART_TOOLBAR, (16,16)) |
137 self.valid_bmp = wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK, wx.ART_TOOLBAR, (32,32)) |
189 self.invalid_bmp = wx.ArtProvider.GetBitmap(wx.ART_CROSS_MARK, wx.ART_TOOLBAR, (16,16)) |
138 self.invalid_bmp = wx.ArtProvider.GetBitmap(wx.ART_CROSS_MARK, wx.ART_TOOLBAR, (32,32)) |
|
139 self.validity_sbmp = wx.StaticBitmap(self, -1, self.invalid_bmp) |
190 self.validity_sbmp = wx.StaticBitmap(self, -1, self.invalid_bmp) |
140 self.edit = wx.TextCtrl(self) |
191 self.edit = wx.TextCtrl(self) |
141 self.edit_sizer = wx.FlexGridSizer(cols=3, hgap=0, rows=1, vgap=0) |
192 self.edit_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) |
142 self.edit_sizer.AddGrowableCol(1) |
193 self.edit_sizer.AddGrowableCol(0) |
143 self.edit_sizer.AddGrowableRow(0) |
194 self.edit_sizer.AddGrowableRow(0) |
144 self.edit_sizer.Add(self.focus_sbmp, flag=wx.GROW) |
|
145 self.edit_sizer.Add(self.edit, flag=wx.GROW) |
195 self.edit_sizer.Add(self.edit, flag=wx.GROW) |
146 self.edit_sizer.Add(self.validity_sbmp, flag=wx.GROW) |
196 self.edit_sizer.Add(self.validity_sbmp, flag=wx.GROW) |
147 self.main_sizer = wx.BoxSizer(wx.VERTICAL) |
197 self.main_sizer = wx.BoxSizer(wx.VERTICAL) |
148 self.main_sizer.Add(self.desc, flag=wx.GROW) |
198 self.main_sizer.Add(self.desc, flag=wx.GROW) |
149 self.main_sizer.Add(self.edit_sizer, flag=wx.GROW) |
199 self.main_sizer.Add(self.edit_sizer, flag=wx.GROW) |
150 self.SetSizer(self.main_sizer) |
200 self.SetSizer(self.main_sizer) |
151 self.main_sizer.Fit(self) |
201 self.main_sizer.Fit(self) |
152 |
202 |
|
203 class ArgEditor(ParamEditor): |
|
204 pass |
|
205 |
|
206 class PathEditor(ParamEditor): |
|
207 def __init__(self, parent, pathdesc): |
|
208 ParamEditor.__init__(self, parent, pathdesc) |
|
209 self.ParentObj = parent |
|
210 DropTarget = PathDropTarget(self) |
|
211 self.edit.SetDropTarget(DropTarget) |
|
212 self.Bind(wx.EVT_TEXT_ENTER, self.OnPathChanged, self.edit) |
|
213 |
|
214 def OnHMITreeDnD(self): |
|
215 self.ParentObj.GotPathDnDOn(self) |
|
216 |
|
217 def SetPathValue(self, value): |
|
218 self.edit.SetValue(value) |
|
219 |
|
220 def OnPathChanged(self, event): |
|
221 # TODO : update validity |
|
222 event.Skip() |
|
223 |
|
224 |
153 _conf_key = "SVGHMIWidgetLib" |
225 _conf_key = "SVGHMIWidgetLib" |
154 _preview_height = 200 |
226 _preview_height = 200 |
155 _preview_margin = 5 |
227 _preview_margin = 5 |
156 class WidgetLibBrowser(wx.SplitterWindow): |
228 class WidgetLibBrowser(wx.SplitterWindow): |
157 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, |
229 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, |
195 |
267 |
196 self.main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=0) |
268 self.main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=0) |
197 self.main_sizer.AddGrowableCol(0) |
269 self.main_sizer.AddGrowableCol(0) |
198 self.main_sizer.AddGrowableRow(2) |
270 self.main_sizer.AddGrowableRow(2) |
199 |
271 |
|
272 self.staticmsg = wx.StaticText(self, label = _("Drag selected Widget from here to Inkscape")) |
200 self.preview = wx.Panel(self.main_panel, size=(-1, _preview_height + _preview_margin*2)) |
273 self.preview = wx.Panel(self.main_panel, size=(-1, _preview_height + _preview_margin*2)) |
201 self.staticmsg = wx.StaticText(self) |
|
202 self.signature_sizer = wx.BoxSizer(wx.VERTICAL) |
274 self.signature_sizer = wx.BoxSizer(wx.VERTICAL) |
|
275 self.args_box = wx.StaticBox(self.main_panel, -1, |
|
276 _("Widget's arguments"), |
|
277 style = wx.ALIGN_RIGHT) |
|
278 self.args_sizer = wx.StaticBoxSizer(self.args_box, wx.VERTICAL) |
|
279 self.paths_box = wx.StaticBox(self.main_panel, -1, |
|
280 _("Widget's variables"), |
|
281 style = wx.ALIGN_RIGHT) |
|
282 self.paths_sizer = wx.StaticBoxSizer(self.paths_box, wx.VERTICAL) |
|
283 self.signature_sizer.Add(self.args_sizer, flag=wx.GROW) |
|
284 self.signature_sizer.AddSpacer(5) |
|
285 self.signature_sizer.Add(self.paths_sizer, flag=wx.GROW) |
|
286 self.main_sizer.Add(self.staticmsg, flag=wx.GROW) |
203 self.main_sizer.Add(self.preview, flag=wx.GROW) |
287 self.main_sizer.Add(self.preview, flag=wx.GROW) |
204 self.main_sizer.Add(self.staticmsg, flag=wx.GROW) |
|
205 self.main_sizer.Add(self.signature_sizer, flag=wx.GROW) |
288 self.main_sizer.Add(self.signature_sizer, flag=wx.GROW) |
206 self.main_sizer.Layout() |
289 self.main_sizer.Layout() |
207 self.main_panel.SetAutoLayout(True) |
290 self.main_panel.SetAutoLayout(True) |
208 self.main_panel.SetSizer(self.main_sizer) |
291 self.main_panel.SetSizer(self.main_sizer) |
209 self.main_sizer.Fit(self.main_panel) |
292 self.main_sizer.Fit(self.main_panel) |
214 style=wx.TE_READONLY | wx.TE_MULTILINE) |
297 style=wx.TE_READONLY | wx.TE_MULTILINE) |
215 |
298 |
216 self.picker_desc_splitter.SplitHorizontally(self.picker_panel, self.desc, 400) |
299 self.picker_desc_splitter.SplitHorizontally(self.picker_panel, self.desc, 400) |
217 self.SplitVertically(self.main_panel, self.picker_desc_splitter, 300) |
300 self.SplitVertically(self.main_panel, self.picker_desc_splitter, 300) |
218 |
301 |
219 self.msg = _("Drag selected Widget from here to Inkscape") |
|
220 self.tempf = None |
302 self.tempf = None |
221 |
303 |
|
304 self.args_editors = [] |
222 self.paths_editors = [] |
305 self.paths_editors = [] |
223 |
306 |
224 def ResetSignature(self): |
307 def ResetSignature(self): |
225 self.signature_sizer.Clear() |
308 self.args_sizer.Clear() |
|
309 for editor in self.args_editors: |
|
310 editor.Destroy() |
|
311 self.args_editors = [] |
|
312 |
|
313 self.paths_sizer.Clear() |
226 for editor in self.paths_editors: |
314 for editor in self.paths_editors: |
227 editor.Destroy() |
315 editor.Destroy() |
228 self.paths_editors = [] |
316 self.paths_editors = [] |
229 |
317 |
|
318 def AddArgToSignature(self, arg): |
|
319 new_editor = ArgEditor(self, arg) |
|
320 self.args_editors.append(new_editor) |
|
321 self.args_sizer.Add(new_editor, flag=wx.GROW) |
|
322 |
230 def AddPathToSignature(self, path): |
323 def AddPathToSignature(self, path): |
231 new_editor = PathEditor(self.main_panel, path) |
324 new_editor = PathEditor(self, path) |
232 self.paths_editors.append(new_editor) |
325 self.paths_editors.append(new_editor) |
233 self.signature_sizer.Add(new_editor, flag=wx.GROW) |
326 self.paths_sizer.Add(new_editor, flag=wx.GROW) |
|
327 |
|
328 def GotPathDnDOn(self, target_editor): |
|
329 dndindex = self.paths_editors.index(target_editor) |
|
330 |
|
331 for selected,editor in zip(self.hmitree_nodes, |
|
332 self.paths_editors[dndindex:]): |
|
333 editor.SetPath(selected.hmi_path()) |
234 |
334 |
235 def RecallLibDir(self): |
335 def RecallLibDir(self): |
236 conf = self.Config.Read(_conf_key) |
336 conf = self.Config.Read(_conf_key) |
237 if len(conf) == 0: |
337 if len(conf) == 0: |
238 return None |
338 return None |
333 |
431 |
334 self.bmp = wx.Bitmap(thumbpath) if have_thumb else None |
432 self.bmp = wx.Bitmap(thumbpath) if have_thumb else None |
335 |
433 |
336 self.selected_SVG = svgpath if have_thumb else None |
434 self.selected_SVG = svgpath if have_thumb else None |
337 |
435 |
338 self.AnalyseWidgetAndUpdateUI() |
436 self.AnalyseWidgetAndUpdateUI(fname) |
|
437 |
|
438 if self.msg: |
|
439 self.staticmsg.Show() |
|
440 self.staticmsg.SetLabel(self.msg) |
|
441 else: |
|
442 self.staticmsg.Hide() |
|
443 |
339 |
444 |
340 except IOError: |
445 except IOError: |
341 self.msg = _("Widget library must be writable") |
446 self.msg = _("Widget library must be writable") |
342 |
447 |
343 self.Refresh() |
448 self.Refresh() |
344 event.Skip() |
449 event.Skip() |
345 |
450 |
346 def OnHMITreeNodeSelection(self, hmitree_nodes): |
451 def OnHMITreeNodeSelection(self, hmitree_nodes): |
347 self.hmitree_node = hmitree_nodes[0] if len(hmitree_nodes) else None |
452 self.hmitree_nodes = hmitree_nodes |
348 self.ValidateWidget() |
453 # [0] if len(hmitree_nodes) else None |
349 self.Refresh() |
454 # self.ValidateWidget() |
|
455 # self.Refresh() |
350 |
456 |
351 def OnLeftDown(self, evt): |
457 def OnLeftDown(self, evt): |
352 if self.tempf is not None: |
458 if self.tempf is not None: |
353 filename = self.tempf.name |
459 filename = self.tempf.name |
354 data = wx.FileDataObject() |
460 data = wx.FileDataObject() |
387 self.msg += "XSLT: " + entry.message + "\n" |
493 self.msg += "XSLT: " + entry.message + "\n" |
388 |
494 |
389 except Exception as e: |
495 except Exception as e: |
390 self.msg += str(e) |
496 self.msg += str(e) |
391 except XSLTApplyError as e: |
497 except XSLTApplyError as e: |
392 self.msg += "Widget analysis error: " + e.message |
498 self.msg += "Widget " + fname + " analysis error: " + e.message |
393 else: |
499 else: |
394 |
500 |
|
501 self.msg += "Widget " + fname + ": OK" |
395 |
502 |
396 print(etree.tostring(signature, pretty_print=True)) |
503 print(etree.tostring(signature, pretty_print=True)) |
397 widgets = signature.getroot() |
504 widgets = signature.getroot() |
398 for defs in widgets.iter("defs"): |
505 for defs in widgets.iter("defs"): |
399 |
506 |
400 # Keep double newlines (to mark paragraphs) |
507 # Keep double newlines (to mark paragraphs) |
401 self.desc.SetValue(defs.find("type").text + ":\n" + "\n\n".join(map( |
508 self.desc.SetValue(defs.find("type").text + ":\n" + "\n\n".join(map( |
402 lambda s:s.replace("\n"," ").replace(" ", " "), |
509 lambda s:s.replace("\n"," ").replace(" ", " "), |
403 defs.find("longdesc").text.split("\n\n")))) |
510 defs.find("longdesc").text.split("\n\n")))) |
404 for arg in defs.iter("arg"): |
511 args = [arg for arg in defs.iter("arg")] |
|
512 self.args_box.Show(len(args)!=0) |
|
513 for arg in args: |
|
514 self.AddArgToSignature(arg) |
405 print(arg.get("name")) |
515 print(arg.get("name")) |
406 print(arg.get("accepts")) |
516 print(arg.get("accepts")) |
407 for path in defs.iter("path"): |
517 paths = [path for path in defs.iter("path")] |
|
518 self.paths_box.Show(len(paths)!=0) |
|
519 for path in paths: |
408 self.AddPathToSignature(path) |
520 self.AddPathToSignature(path) |
409 print(path.get("name")) |
521 print(path.get("name")) |
410 print(path.get("accepts")) |
522 print(path.get("accepts")) |
411 |
523 |
412 for widget in widgets: |
524 for widget in widgets: |
465 |
577 |
466 def __init__(self, parent, register_for_HMI_tree_updates): |
578 def __init__(self, parent, register_for_HMI_tree_updates): |
467 wx.SplitterWindow.__init__(self, parent, |
579 wx.SplitterWindow.__init__(self, parent, |
468 style=wx.SUNKEN_BORDER | wx.SP_3D) |
580 style=wx.SUNKEN_BORDER | wx.SP_3D) |
469 |
581 |
470 self.ordered_items = [] |
|
471 |
|
472 self.SelectionTree = HMITreeSelector(self) |
582 self.SelectionTree = HMITreeSelector(self) |
473 self.Staging = WidgetLibBrowser(self) |
583 self.Staging = WidgetLibBrowser(self) |
474 self.SplitVertically(self.SelectionTree, self.Staging, 300) |
584 self.SplitVertically(self.SelectionTree, self.Staging, 300) |
475 register_for_HMI_tree_updates(weakref.ref(self)) |
585 register_for_HMI_tree_updates(weakref.ref(self)) |
476 self.Bind(wx.EVT_TREE_SEL_CHANGED, |
|
477 self.OnHMITreeNodeSelection, self.SelectionTree) |
|
478 |
|
479 def OnHMITreeNodeSelection(self, event): |
|
480 items = self.SelectionTree.GetSelections() |
|
481 items_pydata = [self.SelectionTree.GetPyData(item) for item in items] |
|
482 |
|
483 # append new items to ordered item list |
|
484 for item_pydata in items_pydata: |
|
485 if item_pydata not in self.ordered_items: |
|
486 self.ordered_items.append(item_pydata) |
|
487 |
|
488 # filter out vanished items |
|
489 self.ordered_items = [ |
|
490 item_pydata |
|
491 for item_pydata in self.ordered_items |
|
492 if item_pydata in items_pydata] |
|
493 |
|
494 self.Staging.OnHMITreeNodeSelection(items_pydata) |
|
495 |
586 |
496 def HMITreeUpdate(self, hmi_tree_root): |
587 def HMITreeUpdate(self, hmi_tree_root): |
497 self.SelectionTree.MakeTree(hmi_tree_root) |
588 self.SelectionTree.MakeTree(hmi_tree_root) |
498 |
589 |
|
590 def OnHMITreeNodeSelection(self, hmitree_nodes): |
|
591 self.Staging.OnHMITreeNodeSelection(hmitree_nodes) |