diff -r 0f41c1e2c121 -r 6dadc1690284 svghmi/svghmi.py --- a/svghmi/svghmi.py Wed Mar 24 05:34:46 2021 +0100 +++ b/svghmi/svghmi.py Thu Mar 25 13:07:52 2021 +0100 @@ -10,7 +10,6 @@ import os import shutil import hashlib -import weakref import shlex import time @@ -19,7 +18,6 @@ from lxml import etree from lxml.etree import XSLTApplyError -from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath import util.paths as paths from POULibrary import POULibrary from docutil import open_svg, get_inkscape_path @@ -29,8 +27,10 @@ import targets from editors.ConfTreeNodeEditor import ConfTreeNodeEditor from XSLTransform import XSLTransform -from svghmi.i18n import EtreeToMessages, SaveCatalog, ReadTranslations, MatchTranslations, TranslationToEtree, open_pofile +from svghmi.i18n import EtreeToMessages, SaveCatalog, ReadTranslations,\ + MatchTranslations, TranslationToEtree, open_pofile from svghmi.hmi_tree import HMI_TYPES, HMITreeNode, SPECIAL_NODES +from svghmi.ui import SVGHMI_UI ScriptDirectory = paths.AbsDir(__file__) @@ -146,7 +146,7 @@ self.FatalError("SVGHMI : " + message) if on_hmitree_update is not None: - on_hmitree_update() + on_hmitree_update(hmi_tree_root) variable_decl_array = [] extern_variables_declarations = [] @@ -237,295 +237,21 @@ # to ensure placement before other CTN generated code in execution order -def SVGHMIEditorUpdater(ref): - def SVGHMIEditorUpdate(): - o = ref() - if o is not None: - wx.CallAfter(o.MakeTree) - return SVGHMIEditorUpdate - -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)) - - on_hmitree_update = SVGHMIEditorUpdater(weakref.ref(self)) - self.MakeTree() - - def _recurseTree(self, current_hmitree_root, current_tc_root): - for c in current_hmitree_root.children: - if hasattr(c, "children"): - display_name = ('{} (class={})'.format(c.name, c.hmiclass)) \ - if c.hmiclass is not None else c.name - tc_child = self.AppendItem(current_tc_root, display_name) - self.SetPyData(tc_child, None) # TODO - - self._recurseTree(c,tc_child) - else: - display_name = '{} {}'.format(c.nodetype[4:], c.name) - tc_child = self.AppendItem(current_tc_root, display_name) - self.SetPyData(tc_child, None) # TODO - - def MakeTree(self): - global hmi_tree_root - - self.Freeze() - - self.root = None - self.DeleteAllItems() - - root_display_name = _("Please build to see HMI Tree") \ - if hmi_tree_root is None else "HMI" - self.root = self.AddRoot(root_display_name) - self.SetPyData(self.root, None) - - if hmi_tree_root is not None: - self._recurseTree(hmi_tree_root, self.root) - self.Expand(self.root) - - self.Thaw() - -class WidgetPicker(wx.TreeCtrl): - def __init__(self, parent, initialdir=None): - wx.TreeCtrl.__init__(self, parent, style=( - wx.TR_MULTIPLE | - wx.TR_HAS_BUTTONS | - wx.SUNKEN_BORDER | - wx.TR_LINES_AT_ROOT)) - - self.MakeTree(initialdir) - - def _recurseTree(self, current_dir, current_tc_root, dirlist): - """ - recurse through subdirectories, but creates tree nodes - only when (sub)directory conbtains .svg file - """ - res = [] - for f in sorted(os.listdir(current_dir)): - p = os.path.join(current_dir,f) - if os.path.isdir(p): - - r = self._recurseTree(p, current_tc_root, dirlist + [f]) - if len(r) > 0 : - res = r - dirlist = [] - current_tc_root = res.pop() - - elif os.path.splitext(f)[1].upper() == ".SVG": - if len(dirlist) > 0 : - res = [] - for d in dirlist: - current_tc_root = self.AppendItem(current_tc_root, d) - res.append(current_tc_root) - self.SetPyData(current_tc_root, None) - dirlist = [] - res.pop() - tc_child = self.AppendItem(current_tc_root, f) - self.SetPyData(tc_child, p) - return res - - def MakeTree(self, lib_dir = None): - global hmi_tree_root - - self.Freeze() - - self.root = None - self.DeleteAllItems() - - root_display_name = _("Please select widget library directory") \ - if lib_dir is None else os.path.basename(lib_dir) - self.root = self.AddRoot(root_display_name) - self.SetPyData(self.root, None) - - if lib_dir is not None: - self._recurseTree(lib_dir, self.root, []) - self.Expand(self.root) - - self.Thaw() - -_conf_key = "SVGHMIWidgetLib" -_preview_height = 200 -class WidgetLibBrowser(wx.Panel): - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, - size=wx.DefaultSize): - - wx.Panel.__init__(self, parent, id, pos, size) - - self.bmp = None - self.msg = None - self.hmitree_node = None - self.selected_SVG = None - - self.Config = wx.ConfigBase.Get() - self.libdir = self.RecallLibDir() - - sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=0) - sizer.AddGrowableCol(0) - sizer.AddGrowableRow(1) - self.libbutton = wx.Button(self, -1, _("Select SVG widget library")) - self.widgetpicker = WidgetPicker(self, self.libdir) - self.preview = wx.Panel(self, size=(-1, _preview_height + 10)) #, style=wx.SIMPLE_BORDER) - #self.preview.SetBackgroundColour(wx.WHITE) - sizer.AddWindow(self.libbutton, flag=wx.GROW) - sizer.AddWindow(self.widgetpicker, flag=wx.GROW) - sizer.AddWindow(self.preview, flag=wx.GROW) - sizer.Layout() - self.SetAutoLayout(True) - self.SetSizer(sizer) - sizer.Fit(self) - self.Bind(wx.EVT_BUTTON, self.OnSelectLibDir, self.libbutton) - self.preview.Bind(wx.EVT_PAINT, self.OnPaint) - - self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnWidgetSelection, self.widgetpicker) - - self.msg = _("Drag selected Widget from here to Inkscape") - - def RecallLibDir(self): - conf = self.Config.Read(_conf_key) - if len(conf) == 0: - return None - else: - return DecodeFileSystemPath(conf) - - def RememberLibDir(self, path): - self.Config.Write(_conf_key, - EncodeFileSystemPath(path)) - self.Config.Flush() - - def DrawPreview(self): - """ - Refresh preview panel - """ - # Init preview panel paint device context - dc = wx.PaintDC(self.preview) - dc.Clear() - - if self.bmp: - # Get Preview panel size - sz = self.preview.GetClientSize() - w = self.bmp.GetWidth() - dc.DrawBitmap(self.bmp, (sz.width - w)/2, 5) - - if self.msg: - dc.SetFont(self.GetFont()) - dc.DrawText(self.msg, 25,25) - - - def OnSelectLibDir(self, event): - defaultpath = self.RecallLibDir() - if defaultpath == None: - defaultpath = os.path.expanduser("~") - - dialog = wx.DirDialog(self, _("Choose a widget library"), defaultpath, - style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) - - if dialog.ShowModal() == wx.ID_OK: - self.libdir = dialog.GetPath() - self.RememberLibDir(self.libdir) - self.widgetpicker.MakeTree(self.libdir) - - dialog.Destroy() - - def OnPaint(self, event): - """ - Called when Preview panel needs to be redrawn - @param event: wx.PaintEvent - """ - self.DrawPreview() - event.Skip() - - def GenThumbnail(self, svgpath, thumbpath): - inkpath = get_inkscape_path() - if inkpath is None: - self.msg = _("Inkscape is not installed.") - return False - # TODO: spawn a thread, to decouple thumbnail gen - status, result, _err_result = ProcessLogger( - None, - '"' + inkpath + '" "' + svgpath + '" -e "' + thumbpath + - '" -D -h ' + str(_preview_height)).spin() - if status != 0: - self.msg = _("Inkscape couldn't generate thumbnail.") - return False - return True - - def OnWidgetSelection(self, event): - """ - Called when tree item is selected - @param event: wx.TreeEvent - """ - item_pydata = self.widgetpicker.GetPyData(event.GetItem()) - if item_pydata is not None: - svgpath = item_pydata - dname = os.path.dirname(svgpath) - fname = os.path.basename(svgpath) - hasher = hashlib.new('md5') - with open(svgpath, 'rb') as afile: - while True: - buf = afile.read(65536) - if len(buf) > 0: - hasher.update(buf) - else: - break - digest = hasher.hexdigest() - thumbfname = os.path.splitext(fname)[0]+"_"+digest+".png" - thumbdir = os.path.join(dname, ".svghmithumbs") - thumbpath = os.path.join(thumbdir, thumbfname) - - self.msg = None - have_thumb = os.path.exists(thumbpath) - - if not have_thumb: - try: - if not os.path.exists(thumbdir): - os.mkdir(thumbdir) - except IOError: - self.msg = _("Widget library must be writable") - else: - have_thumb = self.GenThumbnail(svgpath, thumbpath) - - self.bmp = wx.Bitmap(thumbpath) if have_thumb else None - - self.selected_SVG = svgpath if have_thumb else None - self.ValidateWidget() - - self.Refresh() - event.Skip() - - def OnHMITreeNodeSelection(self, hmitree_node): - self.hmitree_node = hmitree_node - self.ValidateWidget() - self.Refresh() - - def ValidateWidget(self): - if self.selected_SVG is not None: - if self.hmitree_node is not None: - pass - # XXX TODO: - # - check SVG is valid for selected HMI tree item - # - prepare for D'n'D - - -class HMITreeView(wx.SplitterWindow): - - def __init__(self, parent): - wx.SplitterWindow.__init__(self, parent, - style=wx.SUNKEN_BORDER | wx.SP_3D) - - self.SelectionTree = HMITreeSelector(self) - self.Staging = WidgetLibBrowser(self) - self.SplitVertically(self.SelectionTree, self.Staging, 300) +def Register_SVGHMI_UI_for_HMI_tree_updates(ref): + global on_hmitree_update + def HMITreeUpdate(_hmi_tree_root): + obj = ref() + if obj is not None: + obj.HMITreeUpdate(_hmi_tree_root) + + on_hmitree_update = HMITreeUpdate class SVGHMIEditor(ConfTreeNodeEditor): CONFNODEEDITOR_TABS = [ - (_("HMI Tree"), "CreateHMITreeView")] - - def CreateHMITreeView(self, parent): + (_("HMI Tree"), "CreateSVGHMI_UI")] + + def CreateSVGHMI_UI(self, parent): global hmi_tree_root if hmi_tree_root is None: @@ -535,10 +261,7 @@ hmitree_backup_file = open(hmitree_backup_path, 'rb') hmi_tree_root = HMITreeNode.from_etree(etree.parse(hmitree_backup_file).getroot()) - - #self.HMITreeView = HMITreeView(self) - #return HMITreeSelector(parent) - return HMITreeView(parent) + return SVGHMI_UI(parent, Register_SVGHMI_UI_for_HMI_tree_updates) class SVGHMI(object): XSD = """