# HG changeset patch # User Edouard Tisserant # Date 1622448482 -7200 # Node ID 7282b40374b0d2c7ca50474d2cf1c2dda86985d5 # Parent c441181247cf65e68eb49042ce240fd2528d1c15 SVGHMI: UI now have multiple HMI tree variables DnD to widget paths. Still no type checking, WIP. diff -r c441181247cf -r 7282b40374b0 svghmi/ui.py --- a/svghmi/ui.py Thu May 20 12:16:51 2021 +0200 +++ b/svghmi/ui.py Mon May 31 10:08:02 2021 +0200 @@ -27,17 +27,25 @@ ScriptDirectory = paths.AbsDir(__file__) +HMITreeDndMagicWord = "text/beremiz-hmitree" + class HMITreeSelector(wx.TreeCtrl): def __init__(self, parent): - global on_hmitree_update + wx.TreeCtrl.__init__(self, parent, style=( wx.TR_MULTIPLE | wx.TR_HAS_BUTTONS | wx.SUNKEN_BORDER | wx.TR_LINES_AT_ROOT)) + self.ordered_items = [] + self.parent = parent + self.MakeTree() + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeNodeSelection) + self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag) + def _recurseTree(self, current_hmitree_root, current_tc_root): for c in current_hmitree_root.children: if hasattr(c, "children"): @@ -52,6 +60,37 @@ tc_child = self.AppendItem(current_tc_root, display_name) self.SetPyData(tc_child, c) + def OnTreeNodeSelection(self, event): + items = self.GetSelections() + items_pydata = [self.GetPyData(item) for item in items] + + # append new items to ordered item list + for item_pydata in items_pydata: + if item_pydata not in self.ordered_items: + self.ordered_items.append(item_pydata) + + # filter out vanished items + self.ordered_items = [ + item_pydata + for item_pydata in self.ordered_items + if item_pydata in items_pydata] + + self.parent.OnHMITreeNodeSelection(self.ordered_items) + + def OnTreeBeginDrag(self, event): + """ + Called when a drag is started in tree + @param event: wx.TreeEvent + """ + if self.ordered_items: + print("boink") + # Just send a recognizable mime-type, drop destination + # will get python data from parent + data = wx.CustomDataObject(HMITreeDndMagicWord) + dragSource = wx.DropSource(self) + dragSource.SetData(data) + dragSource.DoDragDrop() + def MakeTree(self, hmi_tree_root=None): self.Freeze() @@ -127,21 +166,32 @@ self.Thaw() -class PathEditor(wx.Panel): - def __init__(self, parent, path): - - wx.Panel.__init__(self, parent) - label = path.get("name") + ": " + path.text + "(" + path.get("accepts") + ")" +class PathDropTarget(wx.DropTarget): + + def __init__(self, parent): + data = wx.CustomDataObject(HMITreeDndMagicWord) + wx.DropTarget.__init__(self, data) + self.ParentWindow = parent + + def OnDrop(self, x, y): + self.ParentWindow.OnHMITreeDnD() + return True + +class ParamEditor(wx.Panel): + def __init__(self, parent, paramdesc): + + wx.Panel.__init__(self, parent.main_panel) + label = paramdesc.get("name")+ ": " + paramdesc.get("accepts") + if paramdesc.text: + label += "\n\"" + paramdesc.text + "\"" self.desc = wx.StaticText(self, label=label) - self.focus_sbmp = wx.StaticBitmap(self, -1, wx.ArtProvider.GetBitmap(wx.ART_GO_FORWARD, wx.ART_TOOLBAR, (32,32))) - self.valid_bmp = wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK, wx.ART_TOOLBAR, (32,32)) - self.invalid_bmp = wx.ArtProvider.GetBitmap(wx.ART_CROSS_MARK, wx.ART_TOOLBAR, (32,32)) + self.valid_bmp = wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK, wx.ART_TOOLBAR, (16,16)) + self.invalid_bmp = wx.ArtProvider.GetBitmap(wx.ART_CROSS_MARK, wx.ART_TOOLBAR, (16,16)) self.validity_sbmp = wx.StaticBitmap(self, -1, self.invalid_bmp) self.edit = wx.TextCtrl(self) - self.edit_sizer = wx.FlexGridSizer(cols=3, hgap=0, rows=1, vgap=0) - self.edit_sizer.AddGrowableCol(1) + self.edit_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) + self.edit_sizer.AddGrowableCol(0) self.edit_sizer.AddGrowableRow(0) - self.edit_sizer.Add(self.focus_sbmp, flag=wx.GROW) self.edit_sizer.Add(self.edit, flag=wx.GROW) self.edit_sizer.Add(self.validity_sbmp, flag=wx.GROW) self.main_sizer = wx.BoxSizer(wx.VERTICAL) @@ -150,6 +200,28 @@ self.SetSizer(self.main_sizer) self.main_sizer.Fit(self) +class ArgEditor(ParamEditor): + pass + +class PathEditor(ParamEditor): + def __init__(self, parent, pathdesc): + ParamEditor.__init__(self, parent, pathdesc) + self.ParentObj = parent + DropTarget = PathDropTarget(self) + self.edit.SetDropTarget(DropTarget) + self.Bind(wx.EVT_TEXT_ENTER, self.OnPathChanged, self.edit) + + def OnHMITreeDnD(self): + self.ParentObj.GotPathDnDOn(self) + + def SetPathValue(self, value): + self.edit.SetValue(value) + + def OnPathChanged(self, event): + # TODO : update validity + event.Skip() + + _conf_key = "SVGHMIWidgetLib" _preview_height = 200 _preview_margin = 5 @@ -162,7 +234,7 @@ self.bmp = None self.msg = None - self.hmitree_node = None + self.hmitree_nodes = [] self.selected_SVG = None self.Config = wx.ConfigBase.Get() @@ -197,11 +269,22 @@ self.main_sizer.AddGrowableCol(0) self.main_sizer.AddGrowableRow(2) + self.staticmsg = wx.StaticText(self, label = _("Drag selected Widget from here to Inkscape")) self.preview = wx.Panel(self.main_panel, size=(-1, _preview_height + _preview_margin*2)) - self.staticmsg = wx.StaticText(self) self.signature_sizer = wx.BoxSizer(wx.VERTICAL) + self.args_box = wx.StaticBox(self.main_panel, -1, + _("Widget's arguments"), + style = wx.ALIGN_RIGHT) + self.args_sizer = wx.StaticBoxSizer(self.args_box, wx.VERTICAL) + self.paths_box = wx.StaticBox(self.main_panel, -1, + _("Widget's variables"), + style = wx.ALIGN_RIGHT) + self.paths_sizer = wx.StaticBoxSizer(self.paths_box, wx.VERTICAL) + self.signature_sizer.Add(self.args_sizer, flag=wx.GROW) + self.signature_sizer.AddSpacer(5) + self.signature_sizer.Add(self.paths_sizer, flag=wx.GROW) + self.main_sizer.Add(self.staticmsg, flag=wx.GROW) self.main_sizer.Add(self.preview, flag=wx.GROW) - self.main_sizer.Add(self.staticmsg, flag=wx.GROW) self.main_sizer.Add(self.signature_sizer, flag=wx.GROW) self.main_sizer.Layout() self.main_panel.SetAutoLayout(True) @@ -216,21 +299,38 @@ self.picker_desc_splitter.SplitHorizontally(self.picker_panel, self.desc, 400) self.SplitVertically(self.main_panel, self.picker_desc_splitter, 300) - self.msg = _("Drag selected Widget from here to Inkscape") self.tempf = None + self.args_editors = [] self.paths_editors = [] def ResetSignature(self): - self.signature_sizer.Clear() + self.args_sizer.Clear() + for editor in self.args_editors: + editor.Destroy() + self.args_editors = [] + + self.paths_sizer.Clear() for editor in self.paths_editors: editor.Destroy() self.paths_editors = [] + def AddArgToSignature(self, arg): + new_editor = ArgEditor(self, arg) + self.args_editors.append(new_editor) + self.args_sizer.Add(new_editor, flag=wx.GROW) + def AddPathToSignature(self, path): - new_editor = PathEditor(self.main_panel, path) + new_editor = PathEditor(self, path) self.paths_editors.append(new_editor) - self.signature_sizer.Add(new_editor, flag=wx.GROW) + self.paths_sizer.Add(new_editor, flag=wx.GROW) + + def GotPathDnDOn(self, target_editor): + dndindex = self.paths_editors.index(target_editor) + + for selected,editor in zip(self.hmitree_nodes, + self.paths_editors[dndindex:]): + editor.SetPath(selected.hmi_path()) def RecallLibDir(self): conf = self.Config.Read(_conf_key) @@ -283,8 +383,6 @@ self.DrawPreview() event.Skip() - self.staticmsg.SetLabel(self.msg) - def GenThumbnail(self, svgpath, thumbpath): inkpath = get_inkscape_path() if inkpath is None: @@ -335,7 +433,14 @@ self.selected_SVG = svgpath if have_thumb else None - self.AnalyseWidgetAndUpdateUI() + self.AnalyseWidgetAndUpdateUI(fname) + + if self.msg: + self.staticmsg.Show() + self.staticmsg.SetLabel(self.msg) + else: + self.staticmsg.Hide() + except IOError: self.msg = _("Widget library must be writable") @@ -344,9 +449,10 @@ event.Skip() def OnHMITreeNodeSelection(self, hmitree_nodes): - self.hmitree_node = hmitree_nodes[0] if len(hmitree_nodes) else None - self.ValidateWidget() - self.Refresh() + self.hmitree_nodes = hmitree_nodes + # [0] if len(hmitree_nodes) else None + # self.ValidateWidget() + # self.Refresh() def OnLeftDown(self, evt): if self.tempf is not None: @@ -368,7 +474,7 @@ def GetSubHMITree(self, _context): return [self.hmitree_node.etree()] - def AnalyseWidgetAndUpdateUI(self): + def AnalyseWidgetAndUpdateUI(self, fname): self.msg = "" self.ResetSignature() @@ -389,9 +495,10 @@ except Exception as e: self.msg += str(e) except XSLTApplyError as e: - self.msg += "Widget analysis error: " + e.message + self.msg += "Widget " + fname + " analysis error: " + e.message else: + self.msg += "Widget " + fname + ": OK" print(etree.tostring(signature, pretty_print=True)) widgets = signature.getroot() @@ -401,10 +508,15 @@ self.desc.SetValue(defs.find("type").text + ":\n" + "\n\n".join(map( lambda s:s.replace("\n"," ").replace(" ", " "), defs.find("longdesc").text.split("\n\n")))) - for arg in defs.iter("arg"): + args = [arg for arg in defs.iter("arg")] + self.args_box.Show(len(args)!=0) + for arg in args: + self.AddArgToSignature(arg) print(arg.get("name")) print(arg.get("accepts")) - for path in defs.iter("path"): + paths = [path for path in defs.iter("path")] + self.paths_box.Show(len(paths)!=0) + for path in paths: self.AddPathToSignature(path) print(path.get("name")) print(path.get("accepts")) @@ -467,32 +579,13 @@ wx.SplitterWindow.__init__(self, parent, style=wx.SUNKEN_BORDER | wx.SP_3D) - self.ordered_items = [] - self.SelectionTree = HMITreeSelector(self) self.Staging = WidgetLibBrowser(self) self.SplitVertically(self.SelectionTree, self.Staging, 300) register_for_HMI_tree_updates(weakref.ref(self)) - self.Bind(wx.EVT_TREE_SEL_CHANGED, - self.OnHMITreeNodeSelection, self.SelectionTree) - - def OnHMITreeNodeSelection(self, event): - items = self.SelectionTree.GetSelections() - items_pydata = [self.SelectionTree.GetPyData(item) for item in items] - - # append new items to ordered item list - for item_pydata in items_pydata: - if item_pydata not in self.ordered_items: - self.ordered_items.append(item_pydata) - - # filter out vanished items - self.ordered_items = [ - item_pydata - for item_pydata in self.ordered_items - if item_pydata in items_pydata] - - self.Staging.OnHMITreeNodeSelection(items_pydata) def HMITreeUpdate(self, hmi_tree_root): - self.SelectionTree.MakeTree(hmi_tree_root) - + self.SelectionTree.MakeTree(hmi_tree_root) + + def OnHMITreeNodeSelection(self, hmitree_nodes): + self.Staging.OnHMITreeNodeSelection(hmitree_nodes)