--- a/PLCOpenEditor.py Thu Apr 09 15:31:56 2009 +0200
+++ b/PLCOpenEditor.py Thu Apr 09 15:34:35 2009 +0200
@@ -447,10 +447,22 @@
self.OnPouSelectedChanged)
self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE,
self.OnPageClose)
+ self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG,
+ self.OnPageDragged)
self.AUIManager.AddPane(self.TabsOpened, wx.aui.AuiPaneInfo().CentrePane())
+
+ self.DebugVariablePanel = DebugVariablePanel(self, self.Controler)
+ self.AUIManager.AddPane(self.DebugVariablePanel, wx.aui.AuiPaneInfo().Caption("Variables").Right().Layer(0).BestSize(wx.Size(250, 600)).CloseButton(False))
else:
+ self.SecondSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORSECONDSPLITTER,
+ name='SecondSplitter', parent=self.MainSplitter, point=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.SP_3D)
+ self.SecondSplitter.SetMinimumPaneSize(1)
+
+ self.MainSplitter.SplitVertically(self.TreeNoteBook, self.SecondSplitter, 200)
+
self.TabsOpened = wx.Notebook(id=ID_PLCOPENEDITORTABSOPENED,
- name='TabsOpened', parent=self.MainSplitter, pos=wx.Point(0,
+ name='TabsOpened', parent=self.SecondSplitter, pos=wx.Point(0,
0), size=wx.Size(0, 0), style=0)
if wx.VERSION >= (2, 6, 0):
self.TabsOpened.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED,
@@ -458,8 +470,10 @@
else:
wx.EVT_NOTEBOOK_PAGE_CHANGED(self.TabsOpened, ID_PLCOPENEDITORTABSOPENED,
self.OnPouSelectedChanged)
-
- self.MainSplitter.SplitVertically(self.TreeNoteBook, self.TabsOpened, 200)
+
+ self.DebugVariablePanel = DebugVariablePanel(self.SecondSplitter, self.Controler)
+
+ self.SecondSplitter.SplitVertically(self.TabsOpened, self.DebugVariablePanel, -250)
else:
self.TreeNoteBook.AddPage(self.TypesTree, "Types")
self.TreeNoteBook.AddPage(self.InstancesTree, "Instances")
@@ -496,6 +510,8 @@
self.OnPouSelectedChanged)
self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE,
self.OnPageClose)
+ self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG,
+ self.OnPageDragged)
self.AUIManager.AddPane(self.TabsOpened, wx.aui.AuiPaneInfo().CentrePane().MinSize(wx.Size(0, 0)))
self.LibraryPanel = wx.Panel(id=ID_PLCOPENEDITORLIBRARYPANEL,
@@ -621,6 +637,8 @@
self.Errors = []
self.DrawingMode = FREEDRAWING_MODE
#self.DrawingMode = DRIVENDRAWING_MODE
+ if USE_AUI:
+ self.AuiTabCtrl = []
self.PrintData = wx.PrintData()
self.PrintData.SetPaperId(wx.PAPER_A4)
@@ -660,6 +678,11 @@
self.RefreshEditMenu()
self.RefreshDisplayMenu()
self.RefreshToolBar()
+ wx.CallAfter(self.RefreshTabCtrlEvent)
+ event.Skip()
+
+ def OnPageDragged(self, event):
+ wx.CallAfter(self.RefreshTabCtrlEvent)
event.Skip()
def GetCopyBuffer(self):
@@ -755,11 +778,22 @@
def AddPage(self, window, text):
self.TabsOpened.AddPage(window, text)
+ self.RefreshTabCtrlEvent()
+
+ def RefreshTabCtrlEvent(self):
if USE_AUI:
- children = self.TabsOpened.GetChildren()
- last_element = children[len(children) - 1]
- if isinstance(last_element, wx.aui.AuiTabCtrl):
- last_element.Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(last_element))
+ auitabctrl = []
+ for child in self.TabsOpened.GetChildren():
+ if isinstance(child, wx.aui.AuiTabCtrl):
+ auitabctrl.append(child)
+ if child not in self.AuiTabCtrl:
+ child.Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(child))
+ self.AuiTabCtrl = auitabctrl
+ if self.TabsOpened.GetPageCount() == 0:
+ pane = self.AUIManager.GetPane(self.TabsOpened)
+ if pane.IsMaximized():
+ self.AUIManager.RestorePane(pane)
+ self.AUIManager.Update()
def DeleteAllPages(self):
if USE_AUI:
@@ -1121,10 +1155,13 @@
event.Skip()
def OnSelectAllMenu(self, event):
- selected = self.TabsOpened.GetSelection()
- if selected != -1:
- window = self.TabsOpened.GetPage(selected)
- window.SelectAll()
+ control = self.FindFocus()
+ if isinstance(control, (Viewer, TextViewer)):
+ control.SelectAll()
+ elif isinstance(control, wx.TextCtrl):
+ control.SetSelection(0, control.GetLastPosition())
+ elif isinstance(control, wx.ComboBox):
+ control.SetMark(0, control.GetLastPosition() + 1)
event.Skip()
def OnDeleteMenu(self, event):
@@ -1938,11 +1975,14 @@
var_path = "%s.%s"%(parent_name, var_path)
parent_item = self.InstancesTree.GetItemParent(parent_item)
- new_window = GraphicViewer(self.TabsOpened, self, self.Controler, var_path)
- self.AddPage(new_window, "")
- new_window.SetFocus()
- self.RefreshPageTitles()
- event.Skip()
+ self.OpenGraphicViewer(var_path)
+ event.Skip()
+
+ def OpenGraphicViewer(self, var_path):
+ new_window = GraphicViewer(self.TabsOpened, self, self.Controler, var_path)
+ self.AddPage(new_window, "")
+ new_window.SetFocus()
+ self.RefreshPageTitles()
def OnInstancesTreeRightUp(self, event):
if wx.Platform == '__WXMSW__':
@@ -1973,10 +2013,7 @@
def AddVariableGraphicFunction(self, iec_path):
def AddVariableGraphic(event):
- new_window = GraphicViewer(self.TabsOpened, self, self.Controler, iec_path)
- self.AddPage(new_window, "")
- new_window.SetFocus()
- self.RefreshPageTitles()
+ self.OpenGraphicViewer(iec_path)
event.Skip()
return AddVariableGraphic
@@ -4078,23 +4115,25 @@
self.VariablesGrid = wx.grid.Grid(id=ID_VARIABLEEDITORPANELVARIABLESGRID,
name='VariablesGrid', parent=self, pos=wx.Point(0, 0),
- size=wx.Size(0, 150), style=wx.VSCROLL)
+ size=wx.Size(0, 0), style=wx.VSCROLL)
self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
'Sans'))
self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
False, 'Sans'))
self.VariablesGrid.SetSelectionBackground(wx.WHITE)
- self.VariablesGrid.SetSelectionForeground(wx.BLACK)
+ self.VariablesGrid.SetSelectionBackground(wx.BLACK)
if wx.VERSION >= (2, 6, 0):
self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
self.VariablesGrid.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnVariablesGridSelectCell)
self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown)
+ #self.VariablesGrid.Bind(wx.EVT_KEY_DOWN, self.OnChar)
else:
wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange)
wx.grid.EVT_GRID_SELECT_CELL(self.VariablesGrid, self.OnVariablesGridSelectCell)
wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick)
wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown)
+ #wx.EVT_KEY_DOWN(self.VariablesGrid, self.OnChar)
self.VariablesGrid.SetDropTarget(VariableDropTarget(self))
self.ControlPanel = wx.ScrolledWindow(id=ID_VARIABLEEDITORCONTROLPANEL,
@@ -4420,6 +4459,16 @@
wx.CallAfter(self.RefreshButtons)
event.Skip()
+ def OnChar(self, event):
+ keycode = event.GetKeyCode()
+ if keycode == wx.WXK_DELETE:
+ row = self.Table.GetRow(self.VariablesGrid.GetGridCursorRow())
+ self.Values.remove(row)
+ self.SaveValues()
+ self.RefreshValues()
+ self.RefreshButtons()
+ event.Skip()
+
def MoveValue(self, value_index, move):
new_index = max(0, min(value_index + move, len(self.Values) - 1))
if new_index != value_index:
@@ -4473,6 +4522,320 @@
self.Table.ClearErrors()
self.Table.ResetView(self.VariablesGrid)
+#-------------------------------------------------------------------------------
+# Variables Editor Panel
+#-------------------------------------------------------------------------------
+
+class VariableTableItem:
+
+ def __init__(self, parent, variable, value):
+ self.Parent = parent
+ self.Variable = variable
+ self.Value = value
+
+ def __del__(self):
+ self.Parent = None
+
+ def SetVariable(self, variable):
+ if self.Parent and self.Variable != variable:
+ self.Variable = variable
+ self.Parent.RefreshGrid()
+
+ def GetVariable(self):
+ return self.Variable
+
+ def SetValue(self, value):
+ if self.Parent and self.Value != value:
+ self.Value = value
+ self.Parent.RefreshGrid()
+
+ def GetValue(self):
+ return self.Value
+
+class DebugVariableTable(wx.grid.PyGridTableBase):
+
+ """
+ A custom wx.grid.Grid Table using user supplied data
+ """
+ def __init__(self, parent, data, colnames):
+ # The base class must be initialized *first*
+ wx.grid.PyGridTableBase.__init__(self)
+ self.data = data
+ self.colnames = colnames
+ self.Parent = parent
+ # XXX
+ # we need to store the row length and collength to
+ # see if the table has changed size
+ self._rows = self.GetNumberRows()
+ self._cols = self.GetNumberCols()
+
+ def GetNumberCols(self):
+ return len(self.colnames)
+
+ def GetNumberRows(self):
+ return len(self.data)
+
+ def GetColLabelValue(self, col):
+ if col < len(self.colnames):
+ return self.colnames[col]
+
+ def GetRowLabelValues(self, row):
+ return row
+
+ def GetValue(self, row, col):
+ if row < self.GetNumberRows():
+ return self.GetValueByName(row, self.GetColLabelValue(col))
+ return ""
+
+ def SetValue(self, row, col, value):
+ if col < len(self.colnames):
+ self.SetValueByName(row, self.GetColLabelValue(col), value)
+
+ def GetValueByName(self, row, colname):
+ if row < self.GetNumberRows():
+ if colname == "Variable":
+ return self.data[row].GetVariable()
+ elif colname == "Value":
+ return self.data[row].GetValue()
+ return ""
+
+ def SetValueByName(self, row, colname, value):
+ if row < self.GetNumberRows():
+ if colname == "Variable":
+ self.data[row].SetVariable(value)
+ elif colname == "Value":
+ self.data[row].SetValue(value)
+
+ def ResetView(self, grid):
+ """
+ (wx.grid.Grid) -> Reset the grid view. Call this to
+ update the grid if rows and columns have been added or deleted
+ """
+ grid.BeginBatch()
+ for current, new, delmsg, addmsg in [
+ (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED),
+ (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED),
+ ]:
+ if new < current:
+ msg = wx.grid.GridTableMessage(self,delmsg,new,current-new)
+ grid.ProcessTableMessage(msg)
+ elif new > current:
+ msg = wx.grid.GridTableMessage(self,addmsg,new-current)
+ grid.ProcessTableMessage(msg)
+ self.UpdateValues(grid)
+ grid.EndBatch()
+
+ self._rows = self.GetNumberRows()
+ self._cols = self.GetNumberCols()
+ # update the column rendering scheme
+ self._updateColAttrs(grid)
+
+ # update the scrollbars and the displayed part of the grid
+ grid.AdjustScrollbars()
+ grid.ForceRefresh()
+
+ def UpdateValues(self, grid):
+ """Update all displayed values"""
+ # This sends an event to the grid table to update all of the values
+ msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
+ grid.ProcessTableMessage(msg)
+
+ def _updateColAttrs(self, grid):
+ """
+ wx.grid.Grid -> update the column attributes to add the
+ appropriate renderer given the column name.
+
+ Otherwise default to the default renderer.
+ """
+
+ for row in range(self.GetNumberRows()):
+ for col in range(self.GetNumberCols()):
+ grid.SetReadOnly(row, col, True)
+
+ def SetData(self, data):
+ self.data = data
+
+ def GetData(self):
+ return self.data
+
+ def AppendItem(self, data):
+ self.data.append(data)
+
+ def InsertItem(self, idx, data):
+ self.data.insert(idx, data)
+
+ def RemoveItem(self, idx):
+ self.data.pop(idx)
+
+ def MoveItem(self, idx, new_idx):
+ self.data.insert(new_idx, self.data.pop(idx))
+
+ def GetItem(self, idx):
+ return self.data[idx]
+
+ def Empty(self):
+ self.data = []
+
+class DebugVariableDropTarget(wx.TextDropTarget):
+
+ def __init__(self, parent):
+ wx.TextDropTarget.__init__(self)
+ self.ParentWindow = parent
+
+ def OnDropText(self, x, y, data):
+ x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y)
+ row = self.ParentWindow.VariablesGrid.YToRow(y - self.ParentWindow.VariablesGrid.GetColLabelSize())
+ if row == wx.NOT_FOUND:
+ row = self.ParentWindow.Table.GetNumberRows()
+ message = None
+ try:
+ values = eval(data)
+ except:
+ message = "Invalid value \"%s\" for debug variable"%data
+ values = None
+ if not isinstance(values, TupleType):
+ message = "Invalid value \"%s\" for debug variable"%data
+ values = None
+ if values is not None and values[1] == "debug":
+ self.ParentWindow.InsertValue(row, values[0])
+ if message is not None:
+ wx.CallAfter(self.ShowMessage, message)
+
+ def ShowMessage(self, message):
+ message = wx.MessageDialog(self.ParentWindow, message, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+
+[ID_DEBUGVARIABLEPANEL, ID_DEBUGVARIABLEPANELVARIABLESGRID,
+ ID_DEBUGVARIABLEPANELUPBUTTON, ID_DEBUGVARIABLEPANELDOWNBUTTON,
+ ID_DEBUGVARIABLEPANELDELETEBUTTON,
+] = [wx.NewId() for _init_ctrls in range(5)]
+
+class DebugVariablePanel(wx.Panel):
+
+ if wx.VERSION < (2, 6, 0):
+ def Bind(self, event, function, id = None):
+ if id is not None:
+ event(self, id, function)
+ else:
+ event(self, function)
+
+ def _init_coll_MainSizer_Items(self, parent):
+ parent.AddSizer(self.ButtonPanelSizer, 0, border=5, flag=wx.ALIGN_RIGHT|wx.ALL)
+ parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
+
+ def _init_coll_MainSizer_Growables(self, parent):
+ parent.AddGrowableCol(0)
+ parent.AddGrowableRow(1)
+
+ def _init_coll_ButtonPanelSizer_Items(self, parent):
+ parent.AddWindow(self.UpButton, 0, border=5, flag=wx.RIGHT)
+ parent.AddWindow(self.DownButton, 0, border=5, flag=wx.RIGHT)
+ parent.AddWindow(self.DeleteButton, 0, border=0, flag=0)
+
+ def _init_sizers(self):
+ self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0)
+ self.ButtonPanelSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ self._init_coll_MainSizer_Items(self.MainSizer)
+ self._init_coll_MainSizer_Growables(self.MainSizer)
+ self._init_coll_ButtonPanelSizer_Items(self.ButtonPanelSizer)
+
+ self.SetSizer(self.MainSizer)
+
+ def _init_ctrls(self, prnt):
+ wx.Panel.__init__(self, id=ID_DEBUGVARIABLEPANEL,
+ name='DebugVariablePanel', parent=prnt, pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+ self.VariablesGrid = wx.grid.Grid(id=ID_DEBUGVARIABLEPANELVARIABLESGRID,
+ name='VariablesGrid', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(0, 150), style=wx.VSCROLL)
+ self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
+ 'Sans'))
+ self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
+ False, 'Sans'))
+ self.VariablesGrid.SetSelectionBackground(wx.WHITE)
+ self.VariablesGrid.SetSelectionForeground(wx.BLACK)
+ self.VariablesGrid.SetDropTarget(DebugVariableDropTarget(self))
+
+ self.UpButton = wx.Button(id=ID_DEBUGVARIABLEPANELUPBUTTON, label='^',
+ name='UpButton', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(32, 32), style=0)
+ self.Bind(wx.EVT_BUTTON, self.OnUpButton, id=ID_DEBUGVARIABLEPANELUPBUTTON)
+
+ self.DownButton = wx.Button(id=ID_DEBUGVARIABLEPANELDOWNBUTTON, label='v',
+ name='DownButton', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(32, 32), style=0)
+ self.Bind(wx.EVT_BUTTON, self.OnDownButton, id=ID_DEBUGVARIABLEPANELDOWNBUTTON)
+
+ self.DeleteButton = wx.Button(id=ID_DEBUGVARIABLEPANELDELETEBUTTON, label='Delete',
+ name='DeleteButton', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(72, 32), style=0)
+ self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, id=ID_DEBUGVARIABLEPANELDELETEBUTTON)
+
+ self._init_sizers()
+
+ def __init__(self, parent, controler):
+ self._init_ctrls(parent)
+ self.Controler = controler
+
+ self.Table = DebugVariableTable(self, [], ["Variable", "Value"])
+ self.VariablesGrid.SetTable(self.Table)
+ self.VariablesGrid.SetRowLabelSize(0)
+
+ for col in range(self.Table.GetNumberCols()):
+ attr = wx.grid.GridCellAttr()
+ attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER)
+ self.VariablesGrid.SetColAttr(col, attr)
+ self.VariablesGrid.SetColSize(col, 100)
+
+ self.Table.ResetView(self.VariablesGrid)
+
+ def __del__(self):
+ for item in self.Table.GetData():
+ self.Controler.UnsubscribeDebugIECVariable(item.GetVariable().upper(), item)
+
+ def RefreshGrid(self):
+ self.Table.ResetView(self.VariablesGrid)
+
+ def OnDeleteButton(self, event):
+ idx = self.VariablesGrid.GetGridCursorRow()
+ item = self.Table.GetItem(idx)
+ self.Controler.UnsubscribeDebugIECVariable(item.GetVariable().upper(), item)
+ self.Table.RemoveItem(idx)
+ self.RefreshGrid()
+ event.Skip()
+
+ def OnUpButton(self, event):
+ self.MoveValue(self.VariablesGrid.GetGridCursorRow(), -1)
+ event.Skip()
+
+ def OnDownButton(self, event):
+ self.MoveValue(self.VariablesGrid.GetGridCursorRow(), 1)
+ event.Skip()
+
+ def InsertValue(self, idx, iec_path):
+ for item in self.Table.GetData():
+ if iec_path == item.GetVariable():
+ return
+ item = VariableTableItem(self, iec_path, "")
+ result = self.Controler.SubscribeDebugIECVariable(iec_path.upper(), item)
+ if result is not None:
+ self.Table.InsertItem(idx, item)
+ self.RefreshGrid()
+
+ def MoveValue(self, idx, move):
+ new_idx = max(0, min(idx + move, self.Table.GetNumberRows() - 1))
+ if new_idx != idx:
+ self.Table.MoveItem(idx, new_idx)
+ self.RefreshGrid()
+ self.VariablesGrid.SetGridCursor(new_idx, self.VariablesGrid.GetGridCursorCol())
+
+#-------------------------------------------------------------------------------
+# Viewer Printout
+#-------------------------------------------------------------------------------
+
UPPER_DIV = lambda x, y: (x / y) + {True : 0, False : 1}[(x % y) == 0]
class GraphicPrintout(wx.Printout):