controls/DebugVariablePanel.py
changeset 887 d3c6c4ab8b28
parent 878 37256069baed
child 888 baf5dbfd28f4
equal deleted inserted replaced
886:ace92afe9100 887:d3c6c4ab8b28
    20 #
    20 #
    21 #You should have received a copy of the GNU General Public
    21 #You should have received a copy of the GNU General Public
    22 #License along with this library; if not, write to the Free Software
    22 #License along with this library; if not, write to the Free Software
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    24 
    24 
    25 from types import TupleType
    25 from types import TupleType, FloatType
       
    26 from time import time as gettime
       
    27 import numpy
    26 
    28 
    27 import wx
    29 import wx
    28 import wx.lib.buttons
    30 import wx.lib.buttons
    29 
    31 import matplotlib
    30 from graphics import DebugDataConsumer, DebugViewer
    32 matplotlib.use('WX')
       
    33 import matplotlib.pyplot
       
    34 from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas
       
    35 from mpl_toolkits.mplot3d import Axes3D
       
    36 
       
    37 from graphics import DebugDataConsumer, DebugViewer, REFRESH_PERIOD
    31 from controls import CustomGrid, CustomTable
    38 from controls import CustomGrid, CustomTable
    32 from dialogs.ForceVariableDialog import ForceVariableDialog
    39 from dialogs.ForceVariableDialog import ForceVariableDialog
    33 from util.BitmapLibrary import GetBitmap
    40 from util.BitmapLibrary import GetBitmap
    34 
    41 
    35 def AppendMenu(parent, help, id, kind, text):
    42 def AppendMenu(parent, help, id, kind, text):
    36     parent.Append(help=help, id=id, kind=kind, text=text)
    43     parent.Append(help=help, id=id, kind=kind, text=text)
    37 
    44 
    38 def GetDebugVariablesTableColnames():
    45 def GetDebugVariablesTableColnames():
    39     _ = lambda x : x
    46     _ = lambda x : x
    40     return [_("Variable"), _("Value")]
    47     return [_("Variable"), _("Value"), _("3DAxis")]
    41 
    48 
    42 class VariableTableItem(DebugDataConsumer):
    49 class VariableTableItem(DebugDataConsumer):
    43     
    50     
    44     def __init__(self, parent, variable, value):
    51     def __init__(self, parent, variable):
    45         DebugDataConsumer.__init__(self)
    52         DebugDataConsumer.__init__(self)
    46         self.Parent = parent
    53         self.Parent = parent
    47         self.Variable = variable
    54         self.Variable = variable
    48         self.Value = value
    55         self.RefreshVariableType()
       
    56         self.Value = ""
       
    57         self.Axis3D = False
    49     
    58     
    50     def __del__(self):
    59     def __del__(self):
    51         self.Parent = None
    60         self.Parent = None
    52     
    61     
    53     def SetVariable(self, variable):
    62     def SetVariable(self, variable):
    54         if self.Parent and self.Variable != variable:
    63         if self.Parent and self.Variable != variable:
    55             self.Variable = variable
    64             self.Variable = variable
       
    65             self.RefreshVariableType()
    56             self.Parent.RefreshGrid()
    66             self.Parent.RefreshGrid()
    57     
    67     
    58     def GetVariable(self):
    68     def GetVariable(self):
    59         return self.Variable
    69         return self.Variable
       
    70     
       
    71     def RefreshVariableType(self):
       
    72         self.VariableType = self.Parent.GetDataType(self.Variable)
       
    73         self.ResetData()
       
    74     
       
    75     def GetVariableType(self):
       
    76         return self.VariableType
       
    77     
       
    78     def GetData(self):
       
    79         return self.Data
       
    80     
       
    81     def ResetData(self):
       
    82         if self.IsNumVariable():
       
    83             self.Data = numpy.array([]).reshape(0, 2)
       
    84         else:
       
    85             self.Data = None
       
    86     
       
    87     def IsNumVariable(self):
       
    88         return self.Parent.IsNumType(self.VariableType)
       
    89     
       
    90     def NewValue(self, tick, value, forced=False):
       
    91         if self.IsNumVariable():
       
    92             value = {True:1., False:0.}.get(value, float(value))
       
    93             self.Data = numpy.append(self.Data, [[float(tick), value]], axis=0)
       
    94             self.Parent.HasNewData = True
       
    95         DebugDataConsumer.NewValue(self, tick, value, forced)
    60     
    96     
    61     def SetForced(self, forced):
    97     def SetForced(self, forced):
    62         if self.Forced != forced:
    98         if self.Forced != forced:
    63             self.Forced = forced
    99             self.Forced = forced
    64             self.Parent.HasNewData = True
   100             self.Parent.HasNewData = True
    67         if self.Value != value:
   103         if self.Value != value:
    68             self.Value = value
   104             self.Value = value
    69             self.Parent.HasNewData = True
   105             self.Parent.HasNewData = True
    70             
   106             
    71     def GetValue(self):
   107     def GetValue(self):
    72         variable_type = self.Parent.GetDataType(self.Variable.upper())
   108         if self.VariableType == "STRING":
    73         if variable_type == "STRING":
       
    74             return "'%s'" % self.Value
   109             return "'%s'" % self.Value
    75         elif variable_type == "WSTRING":
   110         elif self.VariableType == "WSTRING":
    76             return "\"%s\"" % self.Value
   111             return "\"%s\"" % self.Value
       
   112         elif isinstance(self.Value, FloatType):
       
   113             return "%.6g" % self.Value
    77         return self.Value
   114         return self.Value
       
   115 
       
   116     def SetAxis3D(self, axis_3d):
       
   117         if self.IsNumVariable():
       
   118             self.Axis3D = axis_3d
       
   119         
       
   120     def GetAxis3D(self):
       
   121         if self.IsNumVariable():
       
   122             return self.Axis3D
       
   123         return ""
    78 
   124 
    79 class DebugVariableTable(CustomTable):
   125 class DebugVariableTable(CustomTable):
    80     
   126     
    81     def GetValue(self, row, col):
   127     def GetValue(self, row, col):
    82         if row < self.GetNumberRows():
   128         if row < self.GetNumberRows():
    91         if row < self.GetNumberRows():
   137         if row < self.GetNumberRows():
    92             if colname == "Variable":
   138             if colname == "Variable":
    93                 return self.data[row].GetVariable()
   139                 return self.data[row].GetVariable()
    94             elif colname == "Value":
   140             elif colname == "Value":
    95                 return self.data[row].GetValue()
   141                 return self.data[row].GetValue()
       
   142             elif colname == "3DAxis":
       
   143                 return self.data[row].GetAxis3D()
    96         return ""
   144         return ""
    97 
   145 
    98     def SetValueByName(self, row, colname, value):
   146     def SetValueByName(self, row, colname, value):
    99         if row < self.GetNumberRows():
   147         if row < self.GetNumberRows():
   100             if colname == "Variable":
   148             if colname == "Variable":
   101                 self.data[row].SetVariable(value)
   149                 self.data[row].SetVariable(value)
   102             elif colname == "Value":
   150             elif colname == "Value":
   103                 self.data[row].SetValue(value)
   151                 self.data[row].SetValue(value)
       
   152             elif colname == "3DAxis":
       
   153                 self.data[row].SetAxis3D(value)
   104     
   154     
   105     def IsForced(self, row):
   155     def IsForced(self, row):
   106         if row < self.GetNumberRows():
   156         if row < self.GetNumberRows():
   107             return self.data[row].IsForced()
   157             return self.data[row].IsForced()
   108         return False
   158         return False
   109     
   159     
       
   160     def IsNumVariable(self, row):
       
   161         if row < self.GetNumberRows():
       
   162             return self.data[row].IsNumVariable()
       
   163         return False
       
   164     
   110     def _updateColAttrs(self, grid):
   165     def _updateColAttrs(self, grid):
   111         """
   166         """
   112         wx.grid.Grid -> update the column attributes to add the
   167         wx.grid.Grid -> update the column attributes to add the
   113         appropriate renderer given the column name.
   168         appropriate renderer given the column name.
   114 
   169 
   115         Otherwise default to the default renderer.
   170         Otherwise default to the default renderer.
   116         """
   171         """
   117         
   172         
   118         for row in range(self.GetNumberRows()):
   173         for row in range(self.GetNumberRows()):
   119             for col in range(self.GetNumberCols()):
   174             for col in range(self.GetNumberCols()):
   120                 if self.GetColLabelValue(col, False) == "Value":
   175                 colname = self.GetColLabelValue(col, False)
   121                     if self.IsForced(row):
   176                 if colname == "3DAxis":
   122                         grid.SetCellTextColour(row, col, wx.BLUE)
   177                     if self.IsNumVariable(row):
       
   178                         grid.SetCellRenderer(row, col, wx.grid.GridCellBoolRenderer())
       
   179                         grid.SetCellEditor(row, col, wx.grid.GridCellBoolEditor())
       
   180                         grid.SetReadOnly(row, col, False)
   123                     else:
   181                     else:
   124                         grid.SetCellTextColour(row, col, wx.BLACK)
   182                         grid.SetReadOnly(row, col, True)
   125                 grid.SetReadOnly(row, col, True)
   183                 else:
       
   184                     if colname == "Value":
       
   185                         if self.IsForced(row):
       
   186                             grid.SetCellTextColour(row, col, wx.BLUE)
       
   187                         else:
       
   188                             grid.SetCellTextColour(row, col, wx.BLACK)
       
   189                     grid.SetReadOnly(row, col, True)
   126             self.ResizeRow(grid, row)
   190             self.ResizeRow(grid, row)
   127                 
   191                 
   128     def AppendItem(self, data):
   192     def AppendItem(self, data):
   129         self.data.append(data)
   193         self.data.append(data)
   130     
   194     
   168     def ShowMessage(self, message):
   232     def ShowMessage(self, message):
   169         dialog = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
   233         dialog = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
   170         dialog.ShowModal()
   234         dialog.ShowModal()
   171         dialog.Destroy()
   235         dialog.Destroy()
   172 
   236 
   173 class DebugVariablePanel(wx.Panel, DebugViewer):
   237 SCROLLBAR_UNIT = 10
       
   238 
       
   239 class DebugVariablePanel(wx.SplitterWindow, DebugViewer):
   174     
   240     
   175     def __init__(self, parent, producer):
   241     def __init__(self, parent, producer):
   176         wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL)
   242         wx.SplitterWindow.__init__(self, parent, style=wx.SP_3D)
   177         DebugViewer.__init__(self, producer, True)
   243         DebugViewer.__init__(self, producer, True)
   178         
   244         
   179         main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
   245         self.SetSashGravity(0.5)
   180         main_sizer.AddGrowableCol(0)
   246         self.SetNeedUpdating(True)
   181         main_sizer.AddGrowableRow(1)
   247         self.SetMinimumPaneSize(1)
       
   248         
       
   249         self.MainPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL)
       
   250         
       
   251         main_panel_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
       
   252         main_panel_sizer.AddGrowableCol(0)
       
   253         main_panel_sizer.AddGrowableRow(1)
   182         
   254         
   183         button_sizer = wx.BoxSizer(wx.HORIZONTAL)
   255         button_sizer = wx.BoxSizer(wx.HORIZONTAL)
   184         main_sizer.AddSizer(button_sizer, border=5, 
   256         main_panel_sizer.AddSizer(button_sizer, border=5, 
   185               flag=wx.ALIGN_RIGHT|wx.ALL)
   257               flag=wx.ALIGN_RIGHT|wx.ALL)
   186         
   258         
   187         for name, bitmap, help in [
   259         for name, bitmap, help in [
   188                 ("DeleteButton", "remove_element", _("Remove debug variable")),
   260                 ("DeleteButton", "remove_element", _("Remove debug variable")),
   189                 ("UpButton", "up", _("Move debug variable up")),
   261                 ("UpButton", "up", _("Move debug variable up")),
   190                 ("DownButton", "down", _("Move debug variable down"))]:
   262                 ("DownButton", "down", _("Move debug variable down"))]:
   191             button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), 
   263             button = wx.lib.buttons.GenBitmapButton(self.MainPanel, bitmap=GetBitmap(bitmap), 
   192                   size=wx.Size(28, 28), style=wx.NO_BORDER)
   264                   size=wx.Size(28, 28), style=wx.NO_BORDER)
   193             button.SetToolTipString(help)
   265             button.SetToolTipString(help)
   194             setattr(self, name, button)
   266             setattr(self, name, button)
   195             button_sizer.AddWindow(button, border=5, flag=wx.LEFT)
   267             button_sizer.AddWindow(button, border=5, flag=wx.LEFT)
   196         
   268         
   197         self.VariablesGrid = CustomGrid(self, size=wx.Size(0, 150), style=wx.VSCROLL)
   269         self.VariablesGrid = CustomGrid(self.MainPanel, size=wx.Size(-1, 150), style=wx.VSCROLL)
   198         self.VariablesGrid.SetDropTarget(DebugVariableDropTarget(self))
   270         self.VariablesGrid.SetDropTarget(DebugVariableDropTarget(self))
   199         self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, 
   271         self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, 
   200               self.OnVariablesGridCellRightClick)
   272               self.OnVariablesGridCellRightClick)
   201         main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW)
   273         self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, 
   202         
   274               self.OnVariablesGridCellChange)
   203         self.SetSizer(main_sizer)
   275         main_panel_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW)
       
   276         
       
   277         self.MainPanel.SetSizer(main_panel_sizer)
   204         
   278         
   205         self.HasNewData = False
   279         self.HasNewData = False
   206         
   280         
   207         self.Table = DebugVariableTable(self, [], GetDebugVariablesTableColnames())
   281         self.Table = DebugVariableTable(self, [], GetDebugVariablesTableColnames())
   208         self.VariablesGrid.SetTable(self.Table)
   282         self.VariablesGrid.SetTable(self.Table)
   216         
   290         
   217         def _DeleteVariable(row):
   291         def _DeleteVariable(row):
   218             item = self.Table.GetItem(row)
   292             item = self.Table.GetItem(row)
   219             self.RemoveDataConsumer(item)
   293             self.RemoveDataConsumer(item)
   220             self.Table.RemoveItem(row)
   294             self.Table.RemoveItem(row)
       
   295             self.ResetGraphics()
   221             self.RefreshGrid()
   296             self.RefreshGrid()
   222         setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable)
   297         setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable)
   223         
   298         
   224         def _MoveVariable(row, move):
   299         def _MoveVariable(row, move):
   225             new_row = max(0, min(row + move, self.Table.GetNumberRows() - 1))
   300             new_row = max(0, min(row + move, self.Table.GetNumberRows() - 1))
   226             if new_row != row:
   301             if new_row != row:
   227                 self.Table.MoveItem(row, new_row)
   302                 self.Table.MoveItem(row, new_row)
       
   303                 self.ResetGraphics()
   228                 self.RefreshGrid()
   304                 self.RefreshGrid()
   229             return new_row
   305             return new_row
   230         setattr(self.VariablesGrid, "_MoveRow", _MoveVariable)
   306         setattr(self.VariablesGrid, "_MoveRow", _MoveVariable)
   231         
   307         
   232         self.VariablesGrid.SetRowLabelSize(0)
   308         self.VariablesGrid.SetRowLabelSize(0)
   233         
   309         
   234         for col in range(self.Table.GetNumberCols()):
   310         for col in range(self.Table.GetNumberCols()):
   235             attr = wx.grid.GridCellAttr()
   311             attr = wx.grid.GridCellAttr()
   236             attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER)
   312             if self.Table.GetColLabelValue(col, False) == "3DAxis":
       
   313                 attr.SetAlignment(wx.ALIGN_CENTER, wx.ALIGN_CENTER)
       
   314             else:
       
   315                 attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER)
   237             self.VariablesGrid.SetColAttr(col, attr)
   316             self.VariablesGrid.SetColAttr(col, attr)
   238             self.VariablesGrid.SetColSize(col, 100)
   317             self.VariablesGrid.SetColSize(col, 100)
   239         
   318         
   240         self.Table.ResetView(self.VariablesGrid)
   319         self.Table.ResetView(self.VariablesGrid)
   241         self.VariablesGrid.RefreshButtons()
   320         self.VariablesGrid.RefreshButtons()
       
   321         
       
   322         self.GraphicsPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL)
       
   323         
       
   324         graphics_panel_sizer = wx.BoxSizer(wx.VERTICAL)
       
   325         
       
   326         self.GraphicsCanvasWindow = wx.ScrolledWindow(self.GraphicsPanel, style=wx.HSCROLL|wx.VSCROLL)
       
   327         self.GraphicsCanvasWindow.Bind(wx.EVT_SIZE, self.OnGraphicsCanvasWindowResize)
       
   328         graphics_panel_sizer.AddWindow(self.GraphicsCanvasWindow, 1, flag=wx.GROW)
       
   329         
       
   330         graphics_canvas_window_sizer = wx.BoxSizer(wx.VERTICAL)
       
   331         
       
   332         self.GraphicsFigure = matplotlib.figure.Figure()
       
   333         self.GraphicsFigure.subplots_adjust(hspace=0)
       
   334         self.GraphicsAxes = []
       
   335         
       
   336         self.GraphicsCanvas = FigureCanvas(self.GraphicsCanvasWindow, -1, self.GraphicsFigure)
       
   337         graphics_canvas_window_sizer.AddWindow(self.GraphicsCanvas, 1, flag=wx.GROW)
       
   338         
       
   339         self.GraphicsCanvasWindow.SetSizer(graphics_canvas_window_sizer)
       
   340         
       
   341         self.Graphics3DFigure = matplotlib.figure.Figure()
       
   342         self.Graphics3DFigure.subplotpars.update(left=0.0, right=1.0, bottom=0.0, top=1.0)
       
   343         
       
   344         self.LastMotionTime = gettime()
       
   345         self.Graphics3DAxes = self.Graphics3DFigure.gca(projection='3d')
       
   346         self.Graphics3DAxes.set_color_cycle(['b'])
       
   347         setattr(self.Graphics3DAxes, "_on_move", self.OnGraphics3DMotion)
       
   348         
       
   349         self.Graphics3DCanvas = FigureCanvas(self.GraphicsPanel, -1, self.Graphics3DFigure)
       
   350         self.Graphics3DCanvas.SetMinSize(wx.Size(0, 0))
       
   351         graphics_panel_sizer.AddWindow(self.Graphics3DCanvas, 1, flag=wx.GROW)
       
   352         
       
   353         self.Graphics3DAxes.mouse_init()
       
   354         
       
   355         self.GraphicsPanel.SetSizer(graphics_panel_sizer)
       
   356         
       
   357         self.SplitHorizontally(self.MainPanel, self.GraphicsPanel, -200)
       
   358         
       
   359         self.ResetGraphics()
   242     
   360     
   243     def RefreshNewData(self):
   361     def RefreshNewData(self):
   244         if self.HasNewData:
   362         if self.HasNewData:
   245             self.HasNewData = False
   363             self.HasNewData = False
   246             self.RefreshGrid()
   364             self.RefreshGrid(only_values=True)
   247         DebugViewer.RefreshNewData(self)
   365         DebugViewer.RefreshNewData(self)
   248     
   366     
   249     def RefreshGrid(self):
   367     def RefreshGrid(self, only_values=False):
   250         self.Freeze()
   368         self.Freeze()
   251         self.Table.ResetView(self.VariablesGrid)
   369         if only_values:
       
   370             for col in xrange(self.Table.GetNumberCols()):
       
   371                 if self.Table.GetColLabelValue(col, False) == "Value":
       
   372                     for row in xrange(self.Table.GetNumberRows()):
       
   373                         self.VariablesGrid.SetCellValue(row, col, str(self.Table.GetValueByName(row, "Value")))
       
   374         else:
       
   375             self.Table.ResetView(self.VariablesGrid)
   252         self.VariablesGrid.RefreshButtons()
   376         self.VariablesGrid.RefreshButtons()
       
   377         
       
   378         # Refresh graphics
       
   379         idx = 0
       
   380         for item in self.Table.GetData():
       
   381             data = item.GetData()
       
   382             if data is not None:
       
   383                 self.GraphicsAxes[idx].clear()
       
   384                 self.GraphicsAxes[idx].plot(data[:, 0], data[:, 1])
       
   385                 idx += 1
       
   386         self.GraphicsCanvas.draw()
       
   387                 
       
   388         # Refresh 3D graphics
       
   389         while len(self.Graphics3DAxes.lines) > 0:
       
   390             self.Graphics3DAxes.lines.pop()
       
   391         if self.Axis3DValues is not None:
       
   392             self.Graphics3DAxes.plot(
       
   393                 self.Axis3DValues[0][1].GetData()[self.Axis3DValues[0][0]:, 1],
       
   394                 self.Axis3DValues[1][1].GetData()[self.Axis3DValues[1][0]:, 1],
       
   395                 zs = self.Axis3DValues[2][1].GetData()[self.Axis3DValues[2][0]:, 1])
       
   396         self.Graphics3DCanvas.draw()
       
   397         
   253         self.Thaw()
   398         self.Thaw()
   254     
   399         
   255     def UnregisterObsoleteData(self):
   400     def UnregisterObsoleteData(self):
   256         items = [(idx, item) for idx, item in enumerate(self.Table.GetData())]
   401         items = [(idx, item) for idx, item in enumerate(self.Table.GetData())]
   257         items.reverse()
   402         items.reverse()
   258         for idx, item in items:
   403         for idx, item in items:
   259             iec_path = item.GetVariable().upper()
   404             iec_path = item.GetVariable().upper()
   260             if self.GetDataType(iec_path) is None:
   405             if self.GetDataType(iec_path) is None:
   261                 self.RemoveDataConsumer(item)
   406                 self.RemoveDataConsumer(item)
   262                 self.Table.RemoveItem(idx)
   407                 self.Table.RemoveItem(idx)
   263             else:
   408             else:
   264                 self.AddDataConsumer(iec_path, item)
   409                 self.AddDataConsumer(iec_path, item)
       
   410                 item.RefreshVariableType()
   265         self.Freeze()
   411         self.Freeze()
   266         self.Table.ResetView(self.VariablesGrid)
   412         self.Table.ResetView(self.VariablesGrid)
   267         self.VariablesGrid.RefreshButtons()
   413         self.VariablesGrid.RefreshButtons()
   268         self.Thaw()
   414         self.Thaw()
   269     
   415     
   272         self.Table.Empty()
   418         self.Table.Empty()
   273         self.Freeze()
   419         self.Freeze()
   274         self.Table.ResetView(self.VariablesGrid)
   420         self.Table.ResetView(self.VariablesGrid)
   275         self.VariablesGrid.RefreshButtons()
   421         self.VariablesGrid.RefreshButtons()
   276         self.Thaw()
   422         self.Thaw()
       
   423         self.ResetGraphics()
   277     
   424     
   278     def GetForceVariableMenuFunction(self, iec_path, item):
   425     def GetForceVariableMenuFunction(self, iec_path, item):
   279         iec_type = self.GetDataType(iec_path)
   426         iec_type = self.GetDataType(iec_path)
   280         def ForceVariableFunction(event):
   427         def ForceVariableFunction(event):
   281             if iec_type is not None:
   428             if iec_type is not None:
   312             self.PopupMenu(menu)
   459             self.PopupMenu(menu)
   313             
   460             
   314             menu.Destroy()
   461             menu.Destroy()
   315         event.Skip()
   462         event.Skip()
   316     
   463     
   317     def InsertValue(self, iec_path, idx = None, force=False):
   464     def OnVariablesGridCellChange(self, event):
       
   465         row, col = event.GetRow(), event.GetCol()
       
   466         if self.Table.GetColLabelValue(col, False) == "3DAxis":
       
   467             wx.CallAfter(self.Reset3DGraphics)
       
   468         event.Skip()
       
   469     
       
   470     def InsertValue(self, iec_path, idx = None, force=False, axis3D=False):
   318         if idx is None:
   471         if idx is None:
   319             idx = self.Table.GetNumberRows()
   472             idx = self.Table.GetNumberRows()
   320         for item in self.Table.GetData():
   473         for item in self.Table.GetData():
   321             if iec_path == item.GetVariable():
   474             if iec_path == item.GetVariable():
   322                 return
   475                 return
   323         item = VariableTableItem(self, iec_path, "")
   476         item = VariableTableItem(self, iec_path)
   324         result = self.AddDataConsumer(iec_path.upper(), item)
   477         result = self.AddDataConsumer(iec_path.upper(), item)
   325         if result is not None or force:
   478         if result is not None or force:
   326             self.Table.InsertItem(idx, item)
   479             self.Table.InsertItem(idx, item)
       
   480             item.SetAxis3D(int(axis3D))
       
   481             self.ResetGraphics()
   327             self.RefreshGrid()
   482             self.RefreshGrid()
   328         
   483             
   329     def GetDebugVariables(self):
   484     def GetDebugVariables(self):
   330         return [item.GetVariable() for item in self.Table.GetData()]
   485         return [item.GetVariable() for item in self.Table.GetData()]
       
   486     
       
   487     def GetAxis3D(self):
       
   488         return [item.GetVariable() for item in self.Table.GetData() if item.GetAxis3D()]
       
   489     
       
   490     def ResetGraphicsValues(self):
       
   491         for item in self.Table.GetData():
       
   492             item.ResetData()
       
   493     
       
   494     def ResetGraphics(self):
       
   495         self.GraphicsFigure.clear()
       
   496         self.GraphicsAxes = []
       
   497         
       
   498         axes_num = 0
       
   499         for item in self.Table.GetData():    
       
   500             if item.IsNumVariable():
       
   501                 axes_num += 1
       
   502         
       
   503         for idx in xrange(axes_num):
       
   504             if idx == 0:
       
   505                 axes = self.GraphicsFigure.add_subplot(axes_num, 1, idx + 1)
       
   506             else:
       
   507                 axes = self.GraphicsFigure.add_subplot(axes_num, 1, idx + 1, sharex=self.GraphicsAxes[0])
       
   508             self.GraphicsAxes.append(axes)
       
   509         
       
   510         self.RefreshGraphicsCanvasWindowScrollbars()
       
   511         self.GraphicsCanvas.draw()
       
   512         
       
   513         self.Reset3DGraphics()
       
   514     
       
   515     def Reset3DGraphics(self):
       
   516         axis = [item for item in self.Table.GetData() if item.GetAxis3D()]
       
   517         if len(axis) == 3:
       
   518             max_tick = None
       
   519             xaxis, yaxis, zaxis = [item.GetData() for item in axis]
       
   520             if len(xaxis) > 0 and len(yaxis) > 0 and len(zaxis) > 0:
       
   521                 max_tick = max(xaxis[0, 0], yaxis[0, 0], zaxis[0, 0])
       
   522             if max_tick is not None:
       
   523                 self.Axis3DValues = [(numpy.argmin(abs(item.GetData()[:, 0] - max_tick)), item)
       
   524                                      for item in axis]
       
   525             else:
       
   526                self.Axis3DValues = [(0, item) for item in axis]
       
   527         else:
       
   528             self.Axis3DValues = None
       
   529     
       
   530     def OnGraphics3DMotion(self, event):
       
   531         current_time = gettime()
       
   532         if current_time - self.LastMotionTime > REFRESH_PERIOD:
       
   533             self.LastMotionTime = current_time
       
   534             Axes3D._on_move(self.Graphics3DAxes, event)
       
   535 
       
   536     def RefreshGraphicsCanvasWindowScrollbars(self):
       
   537         xstart, ystart = self.GraphicsCanvasWindow.GetViewStart()
       
   538         window_size = self.GraphicsCanvasWindow.GetClientSize()
       
   539         vwidth, vheight = (window_size[0], (len(self.GraphicsAxes) + 1) * 50)
       
   540         self.GraphicsCanvas.SetMinSize(wx.Size(vwidth, vheight))
       
   541         posx = max(0, min(xstart, (vwidth - window_size[0]) / SCROLLBAR_UNIT))
       
   542         posy = max(0, min(ystart, (vheight - window_size[1]) / SCROLLBAR_UNIT))
       
   543         self.GraphicsCanvasWindow.Scroll(posx, posy)
       
   544         self.GraphicsCanvasWindow.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
       
   545                 vwidth / SCROLLBAR_UNIT, vheight / SCROLLBAR_UNIT, posx, posy)
       
   546     
       
   547     def OnGraphicsCanvasWindowResize(self, event):
       
   548         self.RefreshGraphicsCanvasWindowScrollbars()
       
   549         event.Skip()