# HG changeset patch # User Laurent Bessard # Date 1353674207 -3600 # Node ID d3c6c4ab8b2820142990d50cb3ddf716f2798204 # Parent ace92afe9100095660e55701718a0ec6dca91039 Adding support for displaying graphs of debugged numeric variables in 2D and 3D in DebugVariablePanel diff -r ace92afe9100 -r d3c6c4ab8b28 IDEFrame.py --- a/IDEFrame.py Thu Nov 15 23:49:08 2012 +0100 +++ b/IDEFrame.py Fri Nov 23 13:36:47 2012 +0100 @@ -931,6 +931,7 @@ project_infos["tabs"] = self.SaveTabLayout(self.TabsOpened) if self.EnableDebug: project_infos["debug_vars"] = self.DebugVariablePanel.GetDebugVariables() + project_infos["debug_axis3D"] = self.DebugVariablePanel.GetAxis3D() self.Config.Write("projects", cPickle.dumps(projects)) self.Config.Flush() @@ -947,8 +948,9 @@ if self.EnableDebug: try: + axis3D = project.get("debug_axis3D", []) for variable in project.get("debug_vars", []): - self.DebugVariablePanel.InsertValue(variable, force=True) + self.DebugVariablePanel.InsertValue(variable, force=True, axis3D=variable in axis3D) except: self.DebugVariablePanel.ResetGrid() @@ -2020,9 +2022,7 @@ self.TabsOpened.SetSelection(openedidx) elif instance_category in ITEMS_VARIABLE: - if self.Controler.IsOfType(instance_type, "ANY_NUM", True) or\ - self.Controler.IsOfType(instance_type, "ANY_BIT", True): - + if self.Controler.IsNumType(instance_type, True): new_window = GraphicViewer(self.TabsOpened, self, self.Controler, instance_path) icon = GetBitmap("GRAPH") @@ -2070,10 +2070,12 @@ return new_window def ResetGraphicViewers(self): - for i in xrange(self.TabsOpened.GetPageCount()): - editor = self.TabsOpened.GetPage(i) - if isinstance(editor, GraphicViewer): - editor.ResetView() + if self.EnableDebug: + for i in xrange(self.TabsOpened.GetPageCount()): + editor = self.TabsOpened.GetPage(i) + if isinstance(editor, GraphicViewer): + editor.ResetView() + self.DebugVariablePanel.ResetGraphicsValues() def CloseObsoleteDebugTabs(self): if self.EnableDebug: diff -r ace92afe9100 -r d3c6c4ab8b28 PLCControler.py --- a/PLCControler.py Thu Nov 15 23:49:08 2012 +0100 +++ b/PLCControler.py Fri Nov 23 13:36:47 2012 +0100 @@ -1677,6 +1677,10 @@ return basetype_content["name"] == "enum" return False + def IsNumType(self, type, debug = False): + return self.IsOfType(type, "ANY_NUM", debug) or\ + self.IsOfType(type, "ANY_BIT", debug) + def GetDataTypeRange(self, type, debug = False): if type in DataTypeRange: return DataTypeRange[type] diff -r ace92afe9100 -r d3c6c4ab8b28 controls/DebugVariablePanel.py --- a/controls/DebugVariablePanel.py Thu Nov 15 23:49:08 2012 +0100 +++ b/controls/DebugVariablePanel.py Fri Nov 23 13:36:47 2012 +0100 @@ -22,12 +22,19 @@ #License along with this library; if not, write to the Free Software #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -from types import TupleType +from types import TupleType, FloatType +from time import time as gettime +import numpy import wx import wx.lib.buttons - -from graphics import DebugDataConsumer, DebugViewer +import matplotlib +matplotlib.use('WX') +import matplotlib.pyplot +from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas +from mpl_toolkits.mplot3d import Axes3D + +from graphics import DebugDataConsumer, DebugViewer, REFRESH_PERIOD from controls import CustomGrid, CustomTable from dialogs.ForceVariableDialog import ForceVariableDialog from util.BitmapLibrary import GetBitmap @@ -37,15 +44,17 @@ def GetDebugVariablesTableColnames(): _ = lambda x : x - return [_("Variable"), _("Value")] + return [_("Variable"), _("Value"), _("3DAxis")] class VariableTableItem(DebugDataConsumer): - def __init__(self, parent, variable, value): + def __init__(self, parent, variable): DebugDataConsumer.__init__(self) self.Parent = parent self.Variable = variable - self.Value = value + self.RefreshVariableType() + self.Value = "" + self.Axis3D = False def __del__(self): self.Parent = None @@ -53,11 +62,38 @@ def SetVariable(self, variable): if self.Parent and self.Variable != variable: self.Variable = variable + self.RefreshVariableType() self.Parent.RefreshGrid() def GetVariable(self): return self.Variable + def RefreshVariableType(self): + self.VariableType = self.Parent.GetDataType(self.Variable) + self.ResetData() + + def GetVariableType(self): + return self.VariableType + + def GetData(self): + return self.Data + + def ResetData(self): + if self.IsNumVariable(): + self.Data = numpy.array([]).reshape(0, 2) + else: + self.Data = None + + def IsNumVariable(self): + return self.Parent.IsNumType(self.VariableType) + + def NewValue(self, tick, value, forced=False): + if self.IsNumVariable(): + value = {True:1., False:0.}.get(value, float(value)) + self.Data = numpy.append(self.Data, [[float(tick), value]], axis=0) + self.Parent.HasNewData = True + DebugDataConsumer.NewValue(self, tick, value, forced) + def SetForced(self, forced): if self.Forced != forced: self.Forced = forced @@ -69,13 +105,23 @@ self.Parent.HasNewData = True def GetValue(self): - variable_type = self.Parent.GetDataType(self.Variable.upper()) - if variable_type == "STRING": + if self.VariableType == "STRING": return "'%s'" % self.Value - elif variable_type == "WSTRING": + elif self.VariableType == "WSTRING": return "\"%s\"" % self.Value + elif isinstance(self.Value, FloatType): + return "%.6g" % self.Value return self.Value + def SetAxis3D(self, axis_3d): + if self.IsNumVariable(): + self.Axis3D = axis_3d + + def GetAxis3D(self): + if self.IsNumVariable(): + return self.Axis3D + return "" + class DebugVariableTable(CustomTable): def GetValue(self, row, col): @@ -93,6 +139,8 @@ return self.data[row].GetVariable() elif colname == "Value": return self.data[row].GetValue() + elif colname == "3DAxis": + return self.data[row].GetAxis3D() return "" def SetValueByName(self, row, colname, value): @@ -101,12 +149,19 @@ self.data[row].SetVariable(value) elif colname == "Value": self.data[row].SetValue(value) + elif colname == "3DAxis": + self.data[row].SetAxis3D(value) def IsForced(self, row): if row < self.GetNumberRows(): return self.data[row].IsForced() return False + def IsNumVariable(self, row): + if row < self.GetNumberRows(): + return self.data[row].IsNumVariable() + return False + def _updateColAttrs(self, grid): """ wx.grid.Grid -> update the column attributes to add the @@ -117,12 +172,21 @@ for row in range(self.GetNumberRows()): for col in range(self.GetNumberCols()): - if self.GetColLabelValue(col, False) == "Value": - if self.IsForced(row): - grid.SetCellTextColour(row, col, wx.BLUE) + colname = self.GetColLabelValue(col, False) + if colname == "3DAxis": + if self.IsNumVariable(row): + grid.SetCellRenderer(row, col, wx.grid.GridCellBoolRenderer()) + grid.SetCellEditor(row, col, wx.grid.GridCellBoolEditor()) + grid.SetReadOnly(row, col, False) else: - grid.SetCellTextColour(row, col, wx.BLACK) - grid.SetReadOnly(row, col, True) + grid.SetReadOnly(row, col, True) + else: + if colname == "Value": + if self.IsForced(row): + grid.SetCellTextColour(row, col, wx.BLUE) + else: + grid.SetCellTextColour(row, col, wx.BLACK) + grid.SetReadOnly(row, col, True) self.ResizeRow(grid, row) def AppendItem(self, data): @@ -170,37 +234,47 @@ dialog.ShowModal() dialog.Destroy() -class DebugVariablePanel(wx.Panel, DebugViewer): +SCROLLBAR_UNIT = 10 + +class DebugVariablePanel(wx.SplitterWindow, DebugViewer): def __init__(self, parent, producer): - wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) + wx.SplitterWindow.__init__(self, parent, style=wx.SP_3D) DebugViewer.__init__(self, producer, True) - main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) - main_sizer.AddGrowableCol(0) - main_sizer.AddGrowableRow(1) + self.SetSashGravity(0.5) + self.SetNeedUpdating(True) + self.SetMinimumPaneSize(1) + + self.MainPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL) + + main_panel_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) + main_panel_sizer.AddGrowableCol(0) + main_panel_sizer.AddGrowableRow(1) button_sizer = wx.BoxSizer(wx.HORIZONTAL) - main_sizer.AddSizer(button_sizer, border=5, + main_panel_sizer.AddSizer(button_sizer, border=5, flag=wx.ALIGN_RIGHT|wx.ALL) for name, bitmap, help in [ ("DeleteButton", "remove_element", _("Remove debug variable")), ("UpButton", "up", _("Move debug variable up")), ("DownButton", "down", _("Move debug variable down"))]: - button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), + button = wx.lib.buttons.GenBitmapButton(self.MainPanel, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) button_sizer.AddWindow(button, border=5, flag=wx.LEFT) - self.VariablesGrid = CustomGrid(self, size=wx.Size(0, 150), style=wx.VSCROLL) + self.VariablesGrid = CustomGrid(self.MainPanel, size=wx.Size(-1, 150), style=wx.VSCROLL) self.VariablesGrid.SetDropTarget(DebugVariableDropTarget(self)) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.OnVariablesGridCellRightClick) - main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW) - - self.SetSizer(main_sizer) + self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, + self.OnVariablesGridCellChange) + main_panel_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW) + + self.MainPanel.SetSizer(main_panel_sizer) self.HasNewData = False @@ -218,6 +292,7 @@ item = self.Table.GetItem(row) self.RemoveDataConsumer(item) self.Table.RemoveItem(row) + self.ResetGraphics() self.RefreshGrid() setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) @@ -225,6 +300,7 @@ new_row = max(0, min(row + move, self.Table.GetNumberRows() - 1)) if new_row != row: self.Table.MoveItem(row, new_row) + self.ResetGraphics() self.RefreshGrid() return new_row setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) @@ -233,25 +309,94 @@ for col in range(self.Table.GetNumberCols()): attr = wx.grid.GridCellAttr() - attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER) + if self.Table.GetColLabelValue(col, False) == "3DAxis": + attr.SetAlignment(wx.ALIGN_CENTER, wx.ALIGN_CENTER) + else: + attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER) self.VariablesGrid.SetColAttr(col, attr) self.VariablesGrid.SetColSize(col, 100) self.Table.ResetView(self.VariablesGrid) self.VariablesGrid.RefreshButtons() + + self.GraphicsPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL) + + graphics_panel_sizer = wx.BoxSizer(wx.VERTICAL) + + self.GraphicsCanvasWindow = wx.ScrolledWindow(self.GraphicsPanel, style=wx.HSCROLL|wx.VSCROLL) + self.GraphicsCanvasWindow.Bind(wx.EVT_SIZE, self.OnGraphicsCanvasWindowResize) + graphics_panel_sizer.AddWindow(self.GraphicsCanvasWindow, 1, flag=wx.GROW) + + graphics_canvas_window_sizer = wx.BoxSizer(wx.VERTICAL) + + self.GraphicsFigure = matplotlib.figure.Figure() + self.GraphicsFigure.subplots_adjust(hspace=0) + self.GraphicsAxes = [] + + self.GraphicsCanvas = FigureCanvas(self.GraphicsCanvasWindow, -1, self.GraphicsFigure) + graphics_canvas_window_sizer.AddWindow(self.GraphicsCanvas, 1, flag=wx.GROW) + + self.GraphicsCanvasWindow.SetSizer(graphics_canvas_window_sizer) + + self.Graphics3DFigure = matplotlib.figure.Figure() + self.Graphics3DFigure.subplotpars.update(left=0.0, right=1.0, bottom=0.0, top=1.0) + + self.LastMotionTime = gettime() + self.Graphics3DAxes = self.Graphics3DFigure.gca(projection='3d') + self.Graphics3DAxes.set_color_cycle(['b']) + setattr(self.Graphics3DAxes, "_on_move", self.OnGraphics3DMotion) + + self.Graphics3DCanvas = FigureCanvas(self.GraphicsPanel, -1, self.Graphics3DFigure) + self.Graphics3DCanvas.SetMinSize(wx.Size(0, 0)) + graphics_panel_sizer.AddWindow(self.Graphics3DCanvas, 1, flag=wx.GROW) + + self.Graphics3DAxes.mouse_init() + + self.GraphicsPanel.SetSizer(graphics_panel_sizer) + + self.SplitHorizontally(self.MainPanel, self.GraphicsPanel, -200) + + self.ResetGraphics() def RefreshNewData(self): if self.HasNewData: self.HasNewData = False - self.RefreshGrid() + self.RefreshGrid(only_values=True) DebugViewer.RefreshNewData(self) - def RefreshGrid(self): + def RefreshGrid(self, only_values=False): self.Freeze() - self.Table.ResetView(self.VariablesGrid) + if only_values: + for col in xrange(self.Table.GetNumberCols()): + if self.Table.GetColLabelValue(col, False) == "Value": + for row in xrange(self.Table.GetNumberRows()): + self.VariablesGrid.SetCellValue(row, col, str(self.Table.GetValueByName(row, "Value"))) + else: + self.Table.ResetView(self.VariablesGrid) self.VariablesGrid.RefreshButtons() + + # Refresh graphics + idx = 0 + for item in self.Table.GetData(): + data = item.GetData() + if data is not None: + self.GraphicsAxes[idx].clear() + self.GraphicsAxes[idx].plot(data[:, 0], data[:, 1]) + idx += 1 + self.GraphicsCanvas.draw() + + # Refresh 3D graphics + while len(self.Graphics3DAxes.lines) > 0: + self.Graphics3DAxes.lines.pop() + if self.Axis3DValues is not None: + self.Graphics3DAxes.plot( + self.Axis3DValues[0][1].GetData()[self.Axis3DValues[0][0]:, 1], + self.Axis3DValues[1][1].GetData()[self.Axis3DValues[1][0]:, 1], + zs = self.Axis3DValues[2][1].GetData()[self.Axis3DValues[2][0]:, 1]) + self.Graphics3DCanvas.draw() + self.Thaw() - + def UnregisterObsoleteData(self): items = [(idx, item) for idx, item in enumerate(self.Table.GetData())] items.reverse() @@ -262,6 +407,7 @@ self.Table.RemoveItem(idx) else: self.AddDataConsumer(iec_path, item) + item.RefreshVariableType() self.Freeze() self.Table.ResetView(self.VariablesGrid) self.VariablesGrid.RefreshButtons() @@ -274,6 +420,7 @@ self.Table.ResetView(self.VariablesGrid) self.VariablesGrid.RefreshButtons() self.Thaw() + self.ResetGraphics() def GetForceVariableMenuFunction(self, iec_path, item): iec_type = self.GetDataType(iec_path) @@ -314,17 +461,89 @@ menu.Destroy() event.Skip() - def InsertValue(self, iec_path, idx = None, force=False): + def OnVariablesGridCellChange(self, event): + row, col = event.GetRow(), event.GetCol() + if self.Table.GetColLabelValue(col, False) == "3DAxis": + wx.CallAfter(self.Reset3DGraphics) + event.Skip() + + def InsertValue(self, iec_path, idx = None, force=False, axis3D=False): if idx is None: idx = self.Table.GetNumberRows() for item in self.Table.GetData(): if iec_path == item.GetVariable(): return - item = VariableTableItem(self, iec_path, "") + item = VariableTableItem(self, iec_path) result = self.AddDataConsumer(iec_path.upper(), item) if result is not None or force: self.Table.InsertItem(idx, item) + item.SetAxis3D(int(axis3D)) + self.ResetGraphics() self.RefreshGrid() - + def GetDebugVariables(self): return [item.GetVariable() for item in self.Table.GetData()] + + def GetAxis3D(self): + return [item.GetVariable() for item in self.Table.GetData() if item.GetAxis3D()] + + def ResetGraphicsValues(self): + for item in self.Table.GetData(): + item.ResetData() + + def ResetGraphics(self): + self.GraphicsFigure.clear() + self.GraphicsAxes = [] + + axes_num = 0 + for item in self.Table.GetData(): + if item.IsNumVariable(): + axes_num += 1 + + for idx in xrange(axes_num): + if idx == 0: + axes = self.GraphicsFigure.add_subplot(axes_num, 1, idx + 1) + else: + axes = self.GraphicsFigure.add_subplot(axes_num, 1, idx + 1, sharex=self.GraphicsAxes[0]) + self.GraphicsAxes.append(axes) + + self.RefreshGraphicsCanvasWindowScrollbars() + self.GraphicsCanvas.draw() + + self.Reset3DGraphics() + + def Reset3DGraphics(self): + axis = [item for item in self.Table.GetData() if item.GetAxis3D()] + if len(axis) == 3: + max_tick = None + xaxis, yaxis, zaxis = [item.GetData() for item in axis] + if len(xaxis) > 0 and len(yaxis) > 0 and len(zaxis) > 0: + max_tick = max(xaxis[0, 0], yaxis[0, 0], zaxis[0, 0]) + if max_tick is not None: + self.Axis3DValues = [(numpy.argmin(abs(item.GetData()[:, 0] - max_tick)), item) + for item in axis] + else: + self.Axis3DValues = [(0, item) for item in axis] + else: + self.Axis3DValues = None + + def OnGraphics3DMotion(self, event): + current_time = gettime() + if current_time - self.LastMotionTime > REFRESH_PERIOD: + self.LastMotionTime = current_time + Axes3D._on_move(self.Graphics3DAxes, event) + + def RefreshGraphicsCanvasWindowScrollbars(self): + xstart, ystart = self.GraphicsCanvasWindow.GetViewStart() + window_size = self.GraphicsCanvasWindow.GetClientSize() + vwidth, vheight = (window_size[0], (len(self.GraphicsAxes) + 1) * 50) + self.GraphicsCanvas.SetMinSize(wx.Size(vwidth, vheight)) + posx = max(0, min(xstart, (vwidth - window_size[0]) / SCROLLBAR_UNIT)) + posy = max(0, min(ystart, (vheight - window_size[1]) / SCROLLBAR_UNIT)) + self.GraphicsCanvasWindow.Scroll(posx, posy) + self.GraphicsCanvasWindow.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, + vwidth / SCROLLBAR_UNIT, vheight / SCROLLBAR_UNIT, posx, posy) + + def OnGraphicsCanvasWindowResize(self, event): + self.RefreshGraphicsCanvasWindowScrollbars() + event.Skip() diff -r ace92afe9100 -r d3c6c4ab8b28 editors/GraphicViewer.py --- a/editors/GraphicViewer.py Thu Nov 15 23:49:08 2012 +0100 +++ b/editors/GraphicViewer.py Fri Nov 23 13:36:47 2012 +0100 @@ -165,7 +165,7 @@ # Initialize Viewer mode to Selection mode self.Mode = MODE_SELECTION - self.Datas = [] + self.Data = numpy.array([]).reshape(0, 2) self.StartTick = 0 self.StartIdx = 0 self.EndIdx = 0 @@ -202,7 +202,7 @@ wx.CallAfter(self.Canvas.canvas.SetCursor, wx.StockCursor(wx.CURSOR_HAND)) def ResetView(self, register=False): - self.Datas = [] + self.Data = numpy.array([]).reshape(0, 2) self.StartTick = 0 self.StartIdx = 0 self.EndIdx = 0 @@ -222,11 +222,11 @@ DebugViewer.RefreshNewData(self) def GetNearestData(self, tick, adjust): - ticks = numpy.array(zip(*self.Datas)[0]) + ticks = self.Data[:, 0] new_cursor = numpy.argmin(abs(ticks - tick)) if adjust == -1 and ticks[new_cursor] > tick and new_cursor > 0: new_cursor -= 1 - elif adjust == 1 and ticks[new_cursor] < tick and new_cursor < len(self.Datas): + elif adjust == 1 and ticks[new_cursor] < tick and new_cursor < len(ticks): new_cursor += 1 return new_cursor @@ -257,7 +257,7 @@ def RefreshView(self, force=False): self.Freeze() - if force or not self.Fixed or (len(self.Datas) > 0 and self.StartTick + self.CurrentRange > self.Datas[-1][0]): + if force or not self.Fixed or (len(self.Data) > 0 and self.StartTick + self.CurrentRange > self.Data[-1, 0]): if (self.MinValue is not None and self.MaxValue is not None and self.MinValue != self.MaxValue): @@ -265,15 +265,15 @@ else: Yrange = 2. / self.CurrentZoom - if not force and not self.Fixed and len(self.Datas) > 0: - self.YCenter = max(self.Datas[-1][1] - Yrange / 2, + if not force and not self.Fixed and len(self.Data) > 0: + self.YCenter = max(self.Data[-1, 1] - Yrange / 2, min(self.YCenter, - self.Datas[-1][1] + Yrange / 2)) + self.Data[-1, 1] + Yrange / 2)) var_name = self.InstancePath.split(".")[-1] self.GetBounds() - self.VariableGraphic = plot.PolyLine(self.Datas[self.StartIdx:self.EndIdx + 1], + self.VariableGraphic = plot.PolyLine(self.Data[self.StartIdx:self.EndIdx + 1], legend=var_name, colour=colours[0]) self.GraphicsObject = plot.PlotGraphics([self.VariableGraphic], _("%s Graphics") % var_name, _("Tick"), _("Values")) self.Canvas.Draw(self.GraphicsObject, @@ -296,7 +296,7 @@ def NewValue(self, tick, value, forced=False): value = {True:1., False:0.}.get(value, float(value)) - self.Datas.append((float(tick), value)) + self.Data = numpy.append(self.Data, [[float(tick), value]], axis=0) if self.MinValue is None: self.MinValue = value else: @@ -307,31 +307,31 @@ self.MaxValue = max(self.MaxValue, value) if not self.Fixed or tick < self.StartTick + self.CurrentRange: self.GetBounds() - while int(self.Datas[self.StartIdx][0]) < tick - self.CurrentRange: + while int(self.Data[self.StartIdx, 0]) < tick - self.CurrentRange: self.StartIdx += 1 self.EndIdx += 1 - self.StartTick = self.Datas[self.StartIdx][0] + self.StartTick = self.Data[self.StartIdx, 0] self.NewDataAvailable() def RefreshScrollBar(self): - if len(self.Datas) > 0: + if len(self.Data) > 0: self.GetBounds() - pos = int(self.Datas[self.StartIdx][0] - self.Datas[0][0]) - range = int(self.Datas[-1][0] - self.Datas[0][0]) + pos = int(self.Data[self.StartIdx, 0] - self.Data[0, 0]) + range = int(self.Data[-1, 0] - self.Data[0, 0]) else: pos = 0 range = 0 self.CanvasPosition.SetScrollbar(pos, self.CurrentRange, range, self.CurrentRange) def RefreshRange(self): - if len(self.Datas) > 0: - if self.Fixed and self.Datas[-1][0] - self.Datas[0][0] < self.CurrentRange: + if len(self.Data) > 0: + if self.Fixed and self.Data[-1, 0] - self.Data[0, 0] < self.CurrentRange: self.Fixed = False self.ResetBounds() if self.Fixed: - self.StartTick = min(self.StartTick, self.Datas[-1][0] - self.CurrentRange) + self.StartTick = min(self.StartTick, self.Data[-1, 0] - self.CurrentRange) else: - self.StartTick = max(self.Datas[0][0], self.Datas[-1][0] - self.CurrentRange) + self.StartTick = max(self.Data[0, 0], self.Data[-1, 0] - self.CurrentRange) self.RefreshView(True) def OnRangeChanged(self, event): @@ -351,9 +351,9 @@ event.Skip() def OnPositionChanging(self, event): - if len(self.Datas) > 0: + if len(self.Data) > 0: self.ResetBounds() - self.StartTick = self.Datas[0][0] + event.GetPosition() + self.StartTick = self.Data[0, 0] + event.GetPosition() self.Fixed = True self.NewDataAvailable(True) event.Skip() @@ -364,15 +364,15 @@ event.Skip() def OnCurrentButton(self, event): - if len(self.Datas) > 0: + if len(self.Data) > 0: self.ResetBounds() - self.StartTick = max(self.Datas[0][0], self.Datas[-1][0] - self.CurrentRange) + self.StartTick = max(self.Data[0, 0], self.Data[-1, 0] - self.CurrentRange) self.Fixed = False self.NewDataAvailable(True) event.Skip() def OnResetZoomOffsetButton(self, event): - if len(self.Datas) > 0: + if len(self.Data) > 0: self.YCenter = (self.MaxValue + self.MinValue) / 2 else: self.YCenter = 0.0 @@ -382,7 +382,7 @@ event.Skip() def OnExportGraphButtonClick(self, event): - data_copy = self.Datas[:] + data_copy = self.Data[:] text = "tick;%s;\n" % self.InstancePath for tick, value in data_copy: text += "%d;%.3f;\n" % (tick, value) @@ -392,7 +392,7 @@ def OnCanvasLeftDown(self, event): self.Fixed = True self.Canvas.canvas.CaptureMouse() - if len(self.Datas) > 0: + if len(self.Data) > 0: if self.Mode == MODE_SELECTION: self.Dragging = True pos = self.Canvas.PositionScreenToUser(event.GetPosition()) @@ -401,7 +401,7 @@ elif self.Mode == MODE_MOTION: self.GetBounds() self.CurrentMousePos = event.GetPosition() - self.CurrentMotionValue = self.Datas[self.StartIdx][0] + self.CurrentMotionValue = self.Data[self.StartIdx, 0] event.Skip() def OnCanvasLeftUp(self, event): @@ -416,10 +416,10 @@ def OnCanvasMiddleDown(self, event): self.Fixed = True self.Canvas.canvas.CaptureMouse() - if len(self.Datas) > 0: + if len(self.Data) > 0: self.GetBounds() self.CurrentMousePos = event.GetPosition() - self.CurrentMotionValue = self.Datas[self.StartIdx][0] + self.CurrentMotionValue = self.Data[self.StartIdx, 0] event.Skip() def OnCanvasMiddleUp(self, event): @@ -435,13 +435,13 @@ graphics, xAxis, yAxis = self.Canvas.last_draw self.CursorIdx = self.GetNearestData(max(xAxis[0], min(pos[0], xAxis[1])), -1) self.RefreshCursor() - elif self.CurrentMousePos is not None and len(self.Datas) > 0: + elif self.CurrentMousePos is not None and len(self.Data) > 0: oldpos = self.Canvas.PositionScreenToUser(self.CurrentMousePos) newpos = self.Canvas.PositionScreenToUser(event.GetPosition()) self.CurrentMotionValue += oldpos[0] - newpos[0] self.YCenter += oldpos[1] - newpos[1] self.ResetBounds() - self.StartTick = max(self.Datas[0][0], min(self.CurrentMotionValue, self.Datas[-1][0] - self.CurrentRange)) + self.StartTick = max(self.Data[0, 0], min(self.CurrentMotionValue, self.Data[-1, 0] - self.CurrentRange)) self.CurrentMousePos = event.GetPosition() self.NewDataAvailable(True) event.Skip() @@ -538,5 +538,5 @@ # Draw new time cursor if self.CursorIdx is not None: - self.LastCursor = self.Datas[self.CursorIdx] + self.LastCursor = self.Data[self.CursorIdx] self.DrawCursor(dc, *self.LastCursor) diff -r ace92afe9100 -r d3c6c4ab8b28 graphics/GraphicCommons.py --- a/graphics/GraphicCommons.py Thu Nov 15 23:49:08 2012 +0100 +++ b/graphics/GraphicCommons.py Fri Nov 23 13:36:47 2012 +0100 @@ -319,6 +319,8 @@ self.DeleteDataConsumers() if self.LastRefreshTimer is not None: self.LastRefreshTimer.Stop() + if self.HasAcquiredLock: + DEBUG_REFRESH_LOCK.release() def SetDataProducer(self, producer): if self.RegisterTick and self.Debug: @@ -352,9 +354,15 @@ def GetDataType(self, iec_path): if self.DataProducer is not None: - return self.DataProducer.GetDebugIECVariableType(iec_path) + infos = self.DataProducer.GetInstanceInfos(iec_path) + if infos is not None: + return infos["type"] + return self.DataProducer.GetDebugIECVariableType(iec_path.upper()) return None + def IsNumType(self, data_type): + return self.DataProducer.IsNumType(data_type) + def ForceDataValue(self, iec_path, value): if self.DataProducer is not None: self.DataProducer.ForceDebugIECVariable(iec_path, value) @@ -390,7 +398,7 @@ self.LastRefreshTimer.cancel() self.LastRefreshTimer=None self.TimerAccessLock.release() - if not self.Inhibited: + if self.IsShown() and not self.Inhibited: current_time = gettime() if current_time - self.LastRefreshTime > REFRESH_PERIOD and DEBUG_REFRESH_LOCK.acquire(False): self.AccessLock.acquire()