laurent@2022: import wx laurent@2026: import wx.grid laurent@2038: import wx.gizmos laurent@2022: laurent@2053: from controls import CustomGrid, CustomTable Laurent@2071: from editors.ConfTreeNodeEditor import ConfTreeNodeEditor, SCROLLBAR_UNIT laurent@2022: laurent@2022: [ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE] = range(3) laurent@2022: laurent@2022: def AppendMenu(parent, help, id, kind, text): laurent@2022: if wx.VERSION >= (2, 6, 0): laurent@2022: parent.Append(help=help, id=id, kind=kind, text=text) laurent@2022: else: laurent@2022: parent.Append(helpString=help, id=id, kind=kind, item=text) laurent@2022: laurent@2029: def GetSyncManagersTableColnames(): laurent@2029: _ = lambda x : x laurent@2029: return ["#", _("Name"), _("Start Address"), _("Default Size"), _("Control Byte"), _("Enable")] laurent@2029: laurent@2029: class SyncManagersTable(CustomTable): laurent@2029: laurent@2029: def GetValue(self, row, col): laurent@2029: if row < self.GetNumberRows(): laurent@2029: if col == 0: laurent@2029: return row laurent@2029: return self.data[row].get(self.GetColLabelValue(col, False), "") laurent@2022: laurent@2022: def GetVariablesTableColnames(): laurent@2022: _ = lambda x : x laurent@2038: return ["#", _("Name"), _("Index"), _("SubIndex"), _("Type"), _("PDO index"), _("PDO name"), _("PDO type")] laurent@2029: laurent@2041: [ID_NODEEDITOR, ID_NODEEDITORVENDORLABEL, laurent@2041: ID_NODEEDITORVENDOR, ID_NODEEDITORPRODUCTCODELABEL, laurent@2041: ID_NODEEDITORPRODUCTCODE, ID_NODEEDITORREVISIONNUMBERLABEL, laurent@2041: ID_NODEEDITORREVISIONNUMBER, ID_NODEEDITORPHYSICSLABEL, laurent@2041: ID_NODEEDITORPHYSICS, ID_NODEEDITORSYNCMANAGERSLABEL, laurent@2041: ID_NODEEDITORSYNCMANAGERSGRID, ID_NODEEDITORVARIABLESLABEL, laurent@2041: ID_NODEEDITORVARIABLESGRID, laurent@2034: ] = [wx.NewId() for _init_ctrls in range(13)] laurent@2034: laurent@2053: class NodeEditor(ConfTreeNodeEditor): laurent@2041: laurent@2041: ID = ID_NODEEDITOR laurent@2022: laurent@2022: def _init_coll_MainSizer_Items(self, parent): laurent@2034: parent.AddSizer(self.SlaveInfosDetailsSizer, 0, border=5, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) laurent@2034: parent.AddWindow(self.SyncManagersLabel, 0, border=5, flag=wx.LEFT|wx.RIGHT|wx.GROW) laurent@2034: parent.AddWindow(self.SyncManagersGrid, 0, border=5, flag=wx.LEFT|wx.RIGHT|wx.GROW) laurent@2034: parent.AddWindow(self.VariablesLabel, 0, border=5, flag=wx.LEFT|wx.RIGHT|wx.GROW) laurent@2034: parent.AddWindow(self.VariablesGrid, 0, border=5, flag=wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.GROW) laurent@2034: laurent@2022: def _init_coll_MainSizer_Growables(self, parent): laurent@2022: parent.AddGrowableCol(0) laurent@2029: parent.AddGrowableRow(2, 1) laurent@2029: parent.AddGrowableRow(4, 2) laurent@2023: laurent@2022: def _init_coll_SlaveInfosDetailsSizer_Items(self, parent): laurent@2022: parent.AddWindow(self.VendorLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.GROW) laurent@2022: parent.AddWindow(self.Vendor, 0, border=0, flag=wx.GROW) laurent@2022: parent.AddWindow(self.ProductCodeLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.GROW) laurent@2022: parent.AddWindow(self.ProductCode, 0, border=0, flag=wx.GROW) laurent@2022: parent.AddWindow(self.RevisionNumberLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.GROW) laurent@2022: parent.AddWindow(self.RevisionNumber, 0, border=0, flag=wx.GROW) laurent@2022: parent.AddWindow(self.PhysicsLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.GROW) laurent@2022: parent.AddWindow(self.Physics, 0, border=0, flag=wx.GROW) laurent@2022: laurent@2022: def _init_coll_SlaveInfosDetailsSizer_Growables(self, parent): laurent@2022: parent.AddGrowableCol(1) laurent@2022: parent.AddGrowableCol(3) laurent@2022: laurent@2022: def _init_sizers(self): laurent@2034: self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=5, vgap=5) laurent@2022: self.SlaveInfosDetailsSizer = wx.FlexGridSizer(cols=4, hgap=5, rows=2, vgap=5) laurent@2022: laurent@2022: self._init_coll_MainSizer_Growables(self.MainSizer) laurent@2022: self._init_coll_MainSizer_Items(self.MainSizer) laurent@2022: self._init_coll_SlaveInfosDetailsSizer_Growables(self.SlaveInfosDetailsSizer) laurent@2022: self._init_coll_SlaveInfosDetailsSizer_Items(self.SlaveInfosDetailsSizer) laurent@2022: laurent@2055: self.ConfNodeEditor.SetSizer(self.MainSizer) laurent@2055: laurent@2055: def _init_ConfNodeEditor(self, prnt): Laurent@2058: self.ConfNodeEditor = wx.ScrolledWindow(id=-1, name='SlavePanel', parent=prnt, Laurent@2058: size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER|wx.HSCROLL|wx.VSCROLL) Laurent@2058: self.ConfNodeEditor.Bind(wx.EVT_SIZE, self.OnConfNodeEditorResize) laurent@2022: laurent@2041: self.VendorLabel = wx.StaticText(id=ID_NODEEDITORVENDORLABEL, laurent@2055: label=_('Vendor:'), name='VendorLabel', parent=self.ConfNodeEditor, laurent@2041: pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) laurent@2041: laurent@2041: self.Vendor = wx.TextCtrl(id=ID_NODEEDITORVENDOR, value='', laurent@2055: name='Vendor', parent=self.ConfNodeEditor, pos=wx.Point(0, 0), laurent@2041: size=wx.Size(0, 24), style=wx.TE_READONLY) laurent@2041: laurent@2041: self.ProductCodeLabel = wx.StaticText(id=ID_NODEEDITORPRODUCTCODELABEL, laurent@2055: label=_('Product code:'), name='ProductCodeLabel', parent=self.ConfNodeEditor, laurent@2041: pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) laurent@2041: laurent@2041: self.ProductCode = wx.TextCtrl(id=ID_NODEEDITORPRODUCTCODE, value='', laurent@2055: name='ProductCode', parent=self.ConfNodeEditor, pos=wx.Point(0, 0), laurent@2041: size=wx.Size(0, 24), style=wx.TE_READONLY) laurent@2041: laurent@2041: self.RevisionNumberLabel = wx.StaticText(id=ID_NODEEDITORREVISIONNUMBERLABEL, laurent@2055: label=_('Revision number:'), name='RevisionNumberLabel', parent=self.ConfNodeEditor, laurent@2041: pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) laurent@2041: laurent@2041: self.RevisionNumber = wx.TextCtrl(id=ID_NODEEDITORREVISIONNUMBER, value='', laurent@2055: name='RevisionNumber', parent=self.ConfNodeEditor, pos=wx.Point(0, 0), laurent@2041: size=wx.Size(0, 24), style=wx.TE_READONLY) laurent@2041: laurent@2041: self.PhysicsLabel = wx.StaticText(id=ID_NODEEDITORPHYSICSLABEL, laurent@2055: label=_('Physics:'), name='PhysicsLabel', parent=self.ConfNodeEditor, laurent@2041: pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) laurent@2041: laurent@2041: self.Physics = wx.TextCtrl(id=ID_NODEEDITORPHYSICS, value='', laurent@2055: name='Physics', parent=self.ConfNodeEditor, pos=wx.Point(0, 0), laurent@2041: size=wx.Size(0, 24), style=wx.TE_READONLY) laurent@2041: laurent@2041: self.SyncManagersLabel = wx.StaticText(id=ID_NODEEDITORSYNCMANAGERSLABEL, laurent@2055: label=_('Sync managers:'), name='SyncManagersLabel', parent=self.ConfNodeEditor, laurent@2041: pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) laurent@2041: laurent@2041: self.SyncManagersGrid = CustomGrid(id=ID_NODEEDITORSYNCMANAGERSGRID, laurent@2055: name='SyncManagersGrid', parent=self.ConfNodeEditor, pos=wx.Point(0, 0), Laurent@2058: size=wx.Size(0, 200), style=wx.VSCROLL) laurent@2029: laurent@2041: self.VariablesLabel = wx.StaticText(id=ID_NODEEDITORVARIABLESLABEL, laurent@2056: label=_('Variable entries:'), name='VariablesLabel', parent=self.ConfNodeEditor, laurent@2022: pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) laurent@2022: laurent@2041: self.VariablesGrid = wx.gizmos.TreeListCtrl(id=ID_NODEEDITORVARIABLESGRID, laurent@2055: name='VariablesGrid', parent=self.ConfNodeEditor, pos=wx.Point(0, 0), Laurent@2058: size=wx.Size(0, 400), style=wx.TR_DEFAULT_STYLE | Laurent@2058: wx.TR_ROW_LINES | Laurent@2058: wx.TR_COLUMN_LINES | Laurent@2058: wx.TR_HIDE_ROOT | Laurent@2058: wx.TR_FULL_ROW_HIGHLIGHT) laurent@2038: self.VariablesGrid.GetMainWindow().Bind(wx.EVT_LEFT_DOWN, self.OnVariablesGridLeftClick) laurent@2038: laurent@2022: self._init_sizers() laurent@2041: laurent@2041: def __init__(self, parent, controler, window): laurent@2056: ConfTreeNodeEditor.__init__(self, parent, controler, window) laurent@2041: laurent@2029: self.SyncManagersTable = SyncManagersTable(self, [], GetSyncManagersTableColnames()) laurent@2029: self.SyncManagersGrid.SetTable(self.SyncManagersTable) laurent@2029: self.SyncManagersGridColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, laurent@2029: wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT] laurent@2029: self.SyncManagersGridColSizes = [40, 150, 100, 100, 100, 100] laurent@2029: self.SyncManagersGrid.SetRowLabelSize(0) laurent@2029: for col in range(self.SyncManagersTable.GetNumberCols()): laurent@2029: attr = wx.grid.GridCellAttr() laurent@2029: attr.SetAlignment(self.SyncManagersGridColAlignements[col], wx.ALIGN_CENTRE) laurent@2029: self.SyncManagersGrid.SetColAttr(col, attr) laurent@2029: self.SyncManagersGrid.SetColMinimalWidth(col, self.SyncManagersGridColSizes[col]) laurent@2029: self.SyncManagersGrid.AutoSizeColumn(col, False) laurent@2056: laurent@2038: for colname, colsize, colalign in zip(GetVariablesTableColnames(), laurent@2038: [40, 150, 100, 100, 150, 100, 150, 100], laurent@2038: [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, laurent@2038: wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, laurent@2038: wx.ALIGN_LEFT, wx.ALIGN_LEFT]): Laurent@2072: self.VariablesGrid.AddColumn(_(colname), colsize, colalign) laurent@2038: self.VariablesGrid.SetMainColumn(1) laurent@2041: laurent@2041: def GetBufferState(self): laurent@2041: return False, False laurent@2041: laurent@2041: def RefreshView(self): Laurent@2060: ConfTreeNodeEditor.RefreshView(self) Laurent@2067: Laurent@2067: self.RefreshSlaveInfos() Laurent@2067: Laurent@2067: def RefreshSlaveInfos(self): laurent@2041: slave_infos = self.Controler.GetSlaveInfos() laurent@2022: if slave_infos is not None: laurent@2022: self.Vendor.SetValue(slave_infos["vendor"]) laurent@2022: self.ProductCode.SetValue(slave_infos["product_code"]) laurent@2022: self.RevisionNumber.SetValue(slave_infos["revision_number"]) laurent@2022: self.Physics.SetValue(slave_infos["physics"]) laurent@2029: self.SyncManagersTable.SetData(slave_infos["sync_managers"]) laurent@2029: self.SyncManagersTable.ResetView(self.SyncManagersGrid) laurent@2038: self.RefreshVariablesGrid(slave_infos["entries"]) laurent@2022: else: laurent@2034: self.Vendor.SetValue("") laurent@2034: self.ProductCode.SetValue("") laurent@2034: self.RevisionNumber.SetValue("") laurent@2034: self.Physics.SetValue("") laurent@2034: self.SyncManagersTable.SetData([]) laurent@2034: self.SyncManagersTable.ResetView(self.SyncManagersGrid) laurent@2038: self.RefreshVariablesGrid([]) laurent@2041: laurent@2038: def RefreshVariablesGrid(self, entries): laurent@2038: root = self.VariablesGrid.GetRootItem() laurent@2038: if not root.IsOk(): laurent@2038: root = self.VariablesGrid.AddRoot("Slave entries") laurent@2038: self.GenerateVariablesGridBranch(root, entries, GetVariablesTableColnames()) laurent@2038: self.VariablesGrid.Expand(root) laurent@2038: laurent@2038: def GenerateVariablesGridBranch(self, root, entries, colnames, idx=0): laurent@2038: if wx.VERSION >= (2, 6, 0): laurent@2038: item, root_cookie = self.VariablesGrid.GetFirstChild(root) laurent@2038: else: laurent@2038: item, root_cookie = self.VariablesGrid.GetFirstChild(root, 0) laurent@2038: laurent@2056: no_more_items = not item.IsOk() laurent@2038: for entry in entries: laurent@2038: idx += 1 laurent@2056: if no_more_items: laurent@2038: item = self.VariablesGrid.AppendItem(root, "") laurent@2038: for col, colname in enumerate(colnames): laurent@2038: if col == 0: laurent@2038: self.VariablesGrid.SetItemText(item, str(idx), 0) laurent@2038: else: laurent@2038: self.VariablesGrid.SetItemText(item, entry.get(colname, ""), col) laurent@2038: if entry["PDOMapping"] == "": laurent@2038: self.VariablesGrid.SetItemBackgroundColour(item, wx.LIGHT_GREY) laurent@2038: self.VariablesGrid.SetItemPyData(item, entry) laurent@2056: idx = self.GenerateVariablesGridBranch(item, entry["children"], colnames, idx) laurent@2056: if not no_more_items: laurent@2041: item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie) laurent@2056: no_more_items = not item.IsOk() laurent@2056: laurent@2056: if not no_more_items: laurent@2056: to_delete = [] laurent@2056: while item.IsOk(): laurent@2056: to_delete.append(item) laurent@2056: item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie) laurent@2056: for item in to_delete: laurent@2056: self.VariablesGrid.Delete(item) laurent@2038: laurent@2038: return idx laurent@2038: laurent@2038: def OnVariablesGridLeftClick(self, event): laurent@2038: item, flags, col = self.VariablesGrid.HitTest(event.GetPosition()) laurent@2038: if item.IsOk(): laurent@2038: entry = self.VariablesGrid.GetItemPyData(item) laurent@2038: data_type = entry.get("Type", "") laurent@2038: pdo_mapping = entry.get("PDOMapping", "") laurent@2029: laurent@2038: if (col == -1 and pdo_mapping != "" and laurent@2038: self.Controler.GetSizeOfType(data_type) is not None): laurent@2038: laurent@2038: entry_index = self.Controler.ExtractHexDecValue(entry.get("Index", "0")) laurent@2038: entry_subindex = self.Controler.ExtractHexDecValue(entry.get("SubIndex", "0")) Edouard@2048: var_name = "%s_%4.4x_%2.2x" % (self.Controler.CTNName(), entry_index, entry_subindex) laurent@2038: if pdo_mapping == "R": laurent@2038: dir = "%I" laurent@2038: else: laurent@2038: dir = "%Q" laurent@2038: location = "%s%s" % (dir, self.Controler.GetSizeOfType(data_type)) + \ laurent@2041: ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation() + (self.Controler.GetSlavePos(), entry_index, entry_subindex))) laurent@2038: laurent@2038: data = wx.TextDataObject(str((location, "location", data_type, var_name, ""))) laurent@2038: dragSource = wx.DropSource(self.VariablesGrid) laurent@2038: dragSource.SetData(data) laurent@2038: dragSource.DoDragDrop() laurent@2038: laurent@2022: event.Skip() laurent@2022: Laurent@2058: def OnConfNodeEditorResize(self, event): Laurent@2058: self.ConfNodeEditor.GetBestSize() Laurent@2058: xstart, ystart = self.ConfNodeEditor.GetViewStart() Laurent@2058: window_size = self.ConfNodeEditor.GetClientSize() Laurent@2058: maxx, maxy = self.ConfNodeEditor.GetMinSize() Laurent@2058: posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT)) Laurent@2058: posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT)) Laurent@2058: self.ConfNodeEditor.Scroll(posx, posy) Laurent@2058: self.ConfNodeEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, Laurent@2058: maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy) Laurent@2058: event.Skip() Laurent@2058: laurent@2053: CIA402NodeEditor = NodeEditor