--- a/controls/DebugVariablePanel.py Tue Feb 05 23:28:35 2013 +1100
+++ b/controls/DebugVariablePanel.py Wed Feb 06 01:21:01 2013 +0100
@@ -26,6 +26,7 @@
from time import time as gettime
@@ -35,6 +36,8 @@
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
+ from matplotlib.backends.backend_wxagg import _convert_agg_to_wx_bitmap + from matplotlib.backends.backend_agg import FigureCanvasAgg from mpl_toolkits.mplot3d import Axes3D
@@ -51,7 +54,10 @@
def GetDebugVariablesTableColnames():
return [_("Variable"), _("Value")]
+CRC_MASK = 2 ** CRC_SIZE - 1 class VariableTableItem(DebugDataConsumer):
def __init__(self, parent, variable):
@@ -70,12 +76,21 @@
self.RefreshVariableType()
self.Parent.RefreshView()
- def GetVariable(self, max_size=None):
+ def GetVariable(self, mask=None): - if max_size is not None:
- max_size = max(max_size, 10)
- if len(variable) > max_size:
- variable = "..." + variable[-(max_size - 3):]
+ parts = variable.split('.') + mask = mask + ['*'] * max(0, len(parts) - len(mask)) + for m, v in zip(mask, parts): + elif last is None or last == '*': def RefreshVariableType(self):
@@ -105,23 +120,34 @@
+ def GetRawValue(self, idx): + if self.VariableType in ["STRING", "WSTRING"] and idx < len(self.RawData): + return self.RawData[idx][0] return self.MinValue, self.MaxValue
- self.Data = numpy.array([]).reshape(0, 2)
+ self.Data = numpy.array([]).reshape(0, 3) + if self.VariableType in ["STRING", "WSTRING"]: - return self.Parent.IsNumType(self.VariableType)
+ return (self.Parent.IsNumType(self.VariableType) or + self.VariableType in ["STRING", "WSTRING"]) def NewValue(self, tick, value, forced=False):
if USE_MPL and self.IsNumVariable():
- num_value = {True:1., False:0.}.get(value, float(value))
+ if self.VariableType in ["STRING", "WSTRING"]: + num_value = binascii.crc32(value) & CRC_MASK + num_value = float(value) if self.MinValue is None:
self.MinValue = num_value
@@ -130,7 +156,17 @@
self.MaxValue = num_value
self.MaxValue = max(self.MaxValue, num_value)
- self.Data = numpy.append(self.Data, [[float(tick), num_value]], axis=0)
+ forced_value = float(forced) + if self.VariableType in ["STRING", "WSTRING"]: + raw_data = (value, forced_value) + if len(self.RawData) == 0 or self.RawData[-1] != raw_data: + extra_value = len(self.RawData) + self.RawData.append(raw_data) + extra_value = len(self.RawData) - 1 + extra_value = forced_value + self.Data = numpy.append(self.Data, [[float(tick), num_value, extra_value]], axis=0) self.Parent.HasNewData = True
DebugDataConsumer.NewValue(self, tick, value, forced)
@@ -147,13 +183,29 @@
self.Parent.HasNewData = True
- if self.VariableType == "STRING":
- return "'%s'" % self.Value
- elif self.VariableType == "WSTRING":
- return "\"%s\"" % self.Value
- elif isinstance(self.Value, FloatType):
- return "%.6g" % self.Value
+ def GetValue(self, tick=None, raw=False): + if tick is not None and self.IsNumVariable() and len(self.Data) > 0: + idx = numpy.argmin(abs(self.Data[:, 0] - tick)) + if self.VariableType in ["STRING", "WSTRING"]: + value, forced = self.RawData[int(self.Data[idx, 2])] + if self.VariableType == "STRING": + value = self.Data[idx, 1] + if not raw and isinstance(value, FloatType): + return value, self.IsForced() + if self.VariableType == "STRING": + return "'%s'" % self.Value + elif self.VariableType == "WSTRING": + return '"%s"' % self.Value + elif isinstance(self.Value, FloatType): + return "%.6g" % self.Value def GetNearestData(self, tick, adjust):
@@ -280,12 +332,9 @@
self.ParentWindow.InsertValue(values[0], target_idx, force=True)
- ax, ay, aw, ah = self.ParentControl.Axes.get_position().bounds
- rect = wx.Rect(ax * width, height - (ay + ah) * height,
- aw * width, ah * height)
+ rect = self.ParentControl.GetAxesBoundingBox() - merge_rect = wx.Rect(ax * width, height - (ay + ah) * height,
- aw * width / 2., ah * height)
+ merge_rect = wx.Rect(rect.x, rect.y, rect.width / 2., rect.height) if merge_rect.InsideXY(x, y):
merge_type = GRAPH_ORTHOGONAL
wx.CallAfter(self.ParentWindow.MergeGraphs, values[0], target_idx, merge_type, force=True)
@@ -307,9 +356,11 @@
+ SECOND = 1000 * MILLISECOND ZOOM_VALUES = map(lambda x:("x %.1f" % x, x), [math.sqrt(2) ** i for i in xrange(8)])
RANGE_VALUES = map(lambda x: (str(x), x), [25 * 2 ** i for i in xrange(6)])
@@ -323,7 +374,7 @@
- for var_name, data in variables:
+ for item, data in variables: @@ -357,6 +408,7 @@
self.ParentWindow = window
+ self.ResetVariableNameMask() self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0)
@@ -388,17 +440,29 @@
return self.Items[0].GetVariable()
+ def ResetVariableNameMask(self): + if len(self.Items) > 1: + self.VariableNameMask = reduce(compute_mask, + [item.GetVariable().split('.') for item in self.Items]) + elif len(self.Items) > 0: + self.VariableNameMask = self.Items[0].GetVariable().split('.')[:-1] + ['*'] + self.VariableNameMask = [] + self.ResetVariableNameMask() def RemoveItem(self, item):
+ self.ResetVariableNameMask() self.ParentWindow.RemoveDataConsumer(item)
+ self.ResetVariableNameMask() return len(self.Items) == 0
@@ -412,6 +476,7 @@
self.ParentWindow.AddDataConsumer(iec_path, item)
item.RefreshVariableType()
+ self.ResetVariableNameMask() @@ -428,7 +493,7 @@
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL,
- text=item.GetVariable(20))
+ text=item.GetVariable(self.VariableNameMask)) self.GetForceVariableMenuFunction(item),
@@ -443,7 +508,7 @@
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL,
- text=item.GetVariable(20))
+ text=item.GetVariable(self.VariableNameMask)) self.GetReleaseVariableMenuFunction(item),
@@ -459,7 +524,7 @@
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL,
- text=item.GetVariable(20))
+ text=item.GetVariable(self.VariableNameMask)) self.GetDeleteValueMenuFunction(item),
@@ -545,22 +610,76 @@
self.ValueLabel.SetForegroundColour(wx.BLACK)
self.ValueLabel.SetSelection(self.ValueLabel.GetLastPosition(), -1)
+ def compute_mask(x, y): + for xp, yp in zip(x, y): + class DraggingFigureCanvas(FigureCanvas): + def __init__(self, parent, window, *args, **kwargs): + FigureCanvas.__init__(self, parent, *args, **kwargs) + self.ParentWindow = window + def draw(self, drawDC=None): + FigureCanvasAgg.draw(self) + self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(), None) + if self.ParentWindow.IsDragging(): + destBBox = self.ParentWindow.GetDraggingAxesClippingRegion(self.Parent) + if destBBox.width > 0 and destBBox.height > 0: + srcPanel = self.ParentWindow.DraggingAxesPanel + srcBBox = srcPanel.GetAxesBoundingBox() + srcX = srcBBox.x + srcBBox.width - destBBox.width + srcY = srcBBox.y + srcBBox.height - destBBox.height + srcBmp = _convert_agg_to_wx_bitmap(srcPanel.Canvas.get_renderer(), None) + srcDC.SelectObject(srcBmp) + destDC.SelectObject(self.bitmap) + destDC.Blit(destBBox.x, destBBox.y, + int(destBBox.width), int(destBBox.height), + self.gui_repaint(drawDC=drawDC) class DebugVariableGraphic(DebugVariableViewer):
def __init__(self, parent, window, items, graph_type):
DebugVariableViewer.__init__(self, parent, window, items)
self.GraphType = graph_type
self.Figure = matplotlib.figure.Figure(facecolor='w')
- self.Canvas = FigureCanvas(self, -1, self.Figure)
+ self.Canvas = DraggingFigureCanvas(self, self.ParentWindow, -1, self.Figure) self.Canvas.SetMinSize(wx.Size(200, 200))
self.Canvas.SetDropTarget(DebugVariableDropTarget(self.ParentWindow, self))
- self.Canvas.Bind(wx.EVT_LEFT_DOWN, self.OnCanvasClick)
+ self.Canvas.Bind(wx.EVT_LEFT_DOWN, self.OnCanvasLeftDown) + self.Canvas.mpl_connect('motion_notify_event', self.OnCanvasMotion) + self.Canvas.mpl_connect('button_release_event', self.OnCanvasLeftUp) self.MainSizer.AddWindow(self.Canvas, flag=wx.GROW)
@@ -582,16 +701,26 @@
setattr(self, name, button)
self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button)
button_sizer.AddWindow(button, border=5, flag=wx.LEFT)
- def OnCanvasClick(self, event):
+ def GetAxesBoundingBox(self, absolute=False): + width, height = self.Canvas.GetSize() + ax, ay, aw, ah = self.Axes.get_position().bounds + bbox = wx.Rect(ax * width, height - (ay + ah) * height - 1, + aw * width + 2, ah * height + 1) + xw, yw = self.GetPosition() + def OnCanvasLeftDown(self, event): x, y = event.GetPosition()
width, height = self.Canvas.GetSize()
- ax, ay, aw, ah = self.Axes.get_position().bounds
- rect = wx.Rect(ax * width, height - (ay + ah) * height,
- aw * width, ah * height)
+ rect = self.GetAxesBoundingBox()
+ xw, yw = self.GetPosition() + self.ParentWindow.StartDragNDrop(self, x + xw, y + yw) elif self.Legend is not None:
@@ -606,19 +735,57 @@
+ def OnCanvasLeftUp(self, event): + if self.ParentWindow.IsDragging(): + width, height = self.Canvas.GetSize() + xw, yw = self.GetPosition() + self.ParentWindow.StopDragNDrop( + self.Items[0].GetVariable(), def DoDragDrop(self, item_idx):
+ self.ParentWindow.ResetCursorTickRatio() data = wx.TextDataObject(str((self.Items[item_idx].GetVariable(), "debug", "move")))
dragSource = wx.DropSource(self.Canvas)
- def OnMotion(self, event):
+ def OnAxesMotion(self, event): if current_time - self.LastMotionTime > REFRESH_PERIOD:
self.LastMotionTime = current_time
Axes3D._on_move(self.Axes, event)
+ def OnCanvasMotion(self, event): + if self.ParentWindow.IsDragging(): + width, height = self.Canvas.GetSize() + xw, yw = self.GetPosition() + self.ParentWindow.MoveDragNDrop( + elif not self.Is3DCanvas(): + if event.inaxes == self.Axes: + start_tick, end_tick = self.ParentWindow.GetRange() + cursor_tick_ratio = None + if self.GraphType == GRAPH_ORTHOGONAL: + x_data = self.Items[0].GetData(start_tick, end_tick) + y_data = self.Items[1].GetData(start_tick, end_tick) + if len(x_data) > 0 and len(y_data) > 0: + length = min(len(x_data), len(y_data)) + d = numpy.sqrt((x_data[:length,1]-event.xdata) ** 2 + (y_data[:length,1]-event.ydata) ** 2) + cursor_tick_ratio = float(x_data[numpy.argmin(d), 0] - start_tick) / (end_tick - start_tick) + data = self.Items[0].GetData(start_tick, end_tick) + x_min, x_max = self.Axes.get_xlim() + cursor_tick_ratio = float(event.xdata - x_min) / (x_max - x_min) + if cursor_tick_ratio is not None: + self.ParentWindow.SetCursorTickRatio(cursor_tick_ratio) + self.ParentWindow.ResetCursorTickRatio() def OnSplitButton(self, event):
if len(self.Items) == 2 or self.GraphType == GRAPH_ORTHOGONAL:
wx.CallAfter(self.ParentWindow.SplitGraphs, self)
@@ -627,7 +794,7 @@
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL,
- text=item.GetVariable(20))
+ text=item.GetVariable(self.VariableNameMask)) self.GetSplitGraphMenuFunction(item),
@@ -645,15 +812,19 @@
self.Axes = self.Figure.gca(projection='3d')
self.Axes.set_color_cycle(['b'])
self.LastMotionTime = gettime()
- setattr(self.Axes, "_on_move", self.OnMotion)
+ setattr(self.Axes, "_on_move", self.OnAxesMotion) self.Axes = self.Figure.gca()
if self.GraphType == GRAPH_ORTHOGONAL:
self.Figure.subplotpars.update(bottom=0.15)
+ self.Axes.set_title('.'.join(self.VariableNameMask)) self.SplitButton.Enable(len(self.Items) > 1)
DebugVariableViewer.AddItem(self, item)
@@ -661,16 +832,21 @@
def RemoveItem(self, item):
DebugVariableViewer.RemoveItem(self, item)
+ self.ResetVariableNameMask() def UnregisterObsoleteData(self):
DebugVariableViewer.UnregisterObsoleteData(self)
+ self.ResetVariableNameMask() return self.GraphType == GRAPH_ORTHOGONAL and len(self.Items) == 3
+ def SetCursorTick(self, cursor_tick): + self.CursorTick = cursor_tick def Refresh(self, refresh_graphics=True):
@@ -707,6 +883,23 @@
x_min, x_max = start_tick, end_tick
y_min, y_max = y_center - y_range * 0.55, y_center + y_range * 0.55
+ if self.CursorTick is not None: + self.VLine = self.Axes.axvline(self.CursorTick, color='r') + self.VLine.set_xdata((self.CursorTick, self.CursorTick)) + self.VLine.set_visible(True) + tick_label = self.ParentWindow.GetTickLabel(self.CursorTick) + if self.TickLabel is None: + self.TickLabel = self.Axes.text(0.5, 0.05, tick_label, + size = 'small', transform = self.Axes.transAxes) + self.TickLabel.set_text(tick_label) + if self.VLine is not None: + self.VLine.set_visible(False) + if self.TickLabel is not None: + self.TickLabel.set_text("") min_start_tick = reduce(max, [item.GetData()[0, 0]
@@ -715,6 +908,9 @@
end_tick = max(end_tick, min_start_tick)
x_data, x_min, x_max = OrthogonalData(self.Items[0], start_tick, end_tick)
y_data, y_min, y_max = OrthogonalData(self.Items[1], start_tick, end_tick)
+ if self.CursorTick is not None: + x_cursor, x_forced = self.Items[0].GetValue(self.CursorTick, raw=True) + y_cursor, y_forced = self.Items[1].GetValue(self.CursorTick, raw=True) if x_data is not None and y_data is not None:
length = min(len(x_data), len(y_data))
@@ -728,23 +924,64 @@
+ if self.CursorTick is not None: + self.VLine = self.Axes.axvline(x_cursor, color='r') + self.VLine.set_xdata((x_cursor, x_cursor)) + self.HLine = self.Axes.axhline(y_cursor, color='r') + self.HLine.set_ydata((y_cursor, y_cursor)) + self.VLine.set_visible(True) + self.HLine.set_visible(True) + tick_label = self.ParentWindow.GetTickLabel(self.CursorTick) + if self.TickLabel is None: + self.TickLabel = self.Axes.text(0.05, 0.90, tick_label, + size = 'small', transform = self.Axes.transAxes) + self.TickLabel.set_text(tick_label) + if self.VLine is not None: + self.VLine.set_visible(False) + if self.HLine is not None: + self.HLine.set_visible(False) + if self.TickLabel is not None: + self.TickLabel.set_text("") while len(self.Axes.lines) > 0:
z_data, z_min, z_max = OrthogonalData(self.Items[2], start_tick, end_tick)
+ if self.CursorTick is not None: + z_cursor, z_forced = self.Items[2].GetValue(self.CursorTick, raw=True) if x_data is not None and y_data is not None and z_data is not None:
length = min(length, len(z_data))
self.Axes.plot(x_data[:, 1][:length],
zs = z_data[:, 1][:length])
self.Axes.set_zlim(z_min, z_max)
+ if self.CursorTick is not None: + for kwargs in [{"xs": numpy.array([x_min, x_max])}, + {"ys": numpy.array([y_min, y_max])}, + {"zs": numpy.array([z_min, z_max])}]: + for param, value in [("xs", numpy.array([x_cursor, x_cursor])), + ("ys", numpy.array([y_cursor, y_cursor])), + ("zs", numpy.array([z_cursor, z_cursor]))]: + kwargs.setdefault(param, value) + self.Axes.plot(**kwargs) self.Axes.set_xlim(x_min, x_max)
self.Axes.set_ylim(y_min, y_max)
- labels = ["%s: %s" % (item.GetVariable(40), item.GetValue())
- for item in self.Items]
- colors = [{True: 'b', False: 'k'}[item.IsForced()] for item in self.Items]
+ if self.CursorTick is not None: + values, forced = apply(zip, [item.GetValue(self.CursorTick) for item in self.Items]) + values, forced = apply(zip, [(item.GetValue(), item.IsForced()) for item in self.Items]) + names = [item.GetVariable(self.VariableNameMask) for item in self.Items] + labels = map(lambda x: "%s: %s" % x, zip(names, values)) + colors = map(lambda x: {True: 'b', False: 'k'}[x], forced) if self.GraphType == GRAPH_PARALLEL:
self.Legend = self.Axes.legend(self.Plots, labels,
loc="upper left", frameon=False,
@@ -786,6 +1023,11 @@
+ self.CursorTickRatio = None + self.DraggingAxesPanel = None + self.DraggingAxesBoundingBox = None + self.DraggingAxesMousePos = None graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
@@ -923,8 +1165,13 @@
self.Ticks = numpy.append(self.Ticks, [tick])
if not self.Fixed or tick < self.StartTick + self.CurrentRange:
self.StartTick = max(self.StartTick, tick - self.CurrentRange)
+ self.ResetCursorTick(False) DebugViewer.NewDataAvailable(self, tick, *args, **kwargs)
+ def ForceRefresh(self): + wx.CallAfter(self.NewDataAvailable, None, True) def RefreshGraphicsSizer(self):
self.GraphicsSizer.Clear()
@@ -934,6 +1181,99 @@
self.GraphicsSizer.Layout()
self.RefreshGraphicsWindowScrollbars()
+ def SetCursorTickRatio(self, cursor_tick_ratio): + self.CursorTickRatio = cursor_tick_ratio + def ResetCursorTickRatio(self): + self.CursorTickRatio = None + def ResetCursorTick(self, force_refresh=True): + if self.CursorTickRatio is not None and len(self.Ticks) > 0: + raw_tick = self.StartTick + self.CursorTickRatio * self.CurrentRange + cursor_tick = self.Ticks[numpy.argmin(abs(self.Ticks - raw_tick))] + for panel in self.GraphicPanels: + if isinstance(panel, DebugVariableGraphic): + panel.SetCursorTick(cursor_tick) + def GetTickLabel(self, tick): + label = "Tick: %d" % tick + tick_duration = int(tick * self.Ticktime) + for value, format in [(tick_duration / DAY, "%dd"), + ((tick_duration % DAY) / HOUR, "%dh"), + ((tick_duration % HOUR) / MINUTE, "%dm"), + ((tick_duration % MINUTE) / SECOND, "%ds")]: + if value > 0 or not_null: + duration += format % value + duration += "%gms" % (float(tick_duration % SECOND) / MILLISECOND) + label += "(%s)" % duration + def StartDragNDrop(self, panel, x_mouse, y_mouse): + self.DraggingAxesPanel = panel + self.DraggingAxesBoundingBox = panel.GetAxesBoundingBox(absolute=True) + self.DraggingAxesMousePos = wx.Point( + x_mouse - self.DraggingAxesBoundingBox.x, + y_mouse - self.DraggingAxesBoundingBox.y) + self.ResetCursorTickRatio() + def MoveDragNDrop(self, x_mouse, y_mouse): + self.DraggingAxesBoundingBox.x = x_mouse - self.DraggingAxesMousePos.x + self.DraggingAxesBoundingBox.y = y_mouse - self.DraggingAxesMousePos.y + return self.DraggingAxesPanel is not None + def GetDraggingAxesClippingRegion(self, panel): + x, y = panel.GetPosition() + width, height = panel.Canvas.GetSize() + bbox = wx.Rect(x, y, width, height) + bbox = bbox.Intersect(self.DraggingAxesBoundingBox) + def StopDragNDrop(self, variable, x_mouse, y_mouse): + self.DraggingAxesPanel = None + self.DraggingAxesBoundingBox = None + self.DraggingAxesMousePos = None + for idx, panel in enumerate(self.GraphicPanels): + xw, yw = panel.GetPosition() + width, height = panel.Canvas.GetSize() + bbox = wx.Rect(xw, yw, width, height) + if bbox.InsideXY(x_mouse, y_mouse): + merge_type = GRAPH_PARALLEL + if y_mouse > yw + height / 2: + wx.CallAfter(self.MoveGraph, variable, idx) + rect = panel.GetAxesBoundingBox(True) + if rect.InsideXY(x_mouse, y_mouse): + merge_rect = wx.Rect(rect.x, rect.y, rect.width / 2., rect.height) + if merge_rect.InsideXY(x_mouse, y_mouse): + merge_type = GRAPH_ORTHOGONAL + wx.CallAfter(self.MergeGraphs, variable, idx, merge_type, force=True) + if y_mouse > yw + height / 2: + wx.CallAfter(self.MoveGraph, variable, idx) def RefreshView(self, only_values=False):
self.RefreshCanvasPosition()
@@ -972,6 +1312,14 @@
for panel in self.GraphicPanels:
panel.UnregisterObsoleteData()
+ if panel.Canvas.HasCapture(): + panel.Canvas.ReleaseMouse() + self.GraphicPanels.remove(panel) + self.RefreshGraphicsSizer() items = [(idx, item) for idx, item in enumerate(self.Table.GetData())]
@@ -1086,8 +1434,7 @@
self.StartTick = min(self.StartTick, self.Ticks[-1] - self.CurrentRange)
self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange)
def OnRangeChanged(self, event):
@@ -1105,26 +1452,33 @@
for panel in self.GraphicPanels:
def OnCurrentButton(self, event):
self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange)
def CopyDataToClipboard(self, variables):
- text = "tick;%s;\n" % ";".join([var_name for var_name, data in variables])
+ text = "tick;%s;\n" % ";".join([item.GetVariable() for item, data in variables]) next_tick = NextTick(variables)
while next_tick is not None:
- for var_name, data in variables:
+ for item, data in variables: if next_tick == data[0][0]:
- values.append("%.3f" % data.pop(0)[1])
+ var_type = item.GetVariableType() + if var_type in ["STRING", "WSTRING"]: + value = item.GetRawValue(int(data.pop(0)[2])) + if var_type == "STRING": + values.append("'%s'" % value) + values.append('"%s"' % value) + values.append("%.3f" % data.pop(0)[1]) @@ -1135,9 +1489,15 @@
def OnExportGraphButton(self, event):
- for item in self.Table.GetData():
+ for panel in self.GraphicPanels: + items.extend(panel.GetItems()) + items = self.Table.GetData() - variables.append((item.GetVariable(), [entry for entry in item.GetData()]))
+ variables.append((item, [entry for entry in item.GetData()])) wx.CallAfter(self.CopyDataToClipboard, variables)
@@ -1145,8 +1505,7 @@
self.StartTick = self.Ticks[0] + event.GetPosition()
- wx.CallAfter(self.NewDataAvailable, None, True)
@@ -1187,7 +1546,7 @@
self.Table.InsertItem(idx, item)
def MoveGraph(self, iec_path, idx = None):
@@ -1210,7 +1569,7 @@
panel = DebugVariableGraphic(self.GraphicsWindow, self, [item], GRAPH_PARALLEL)
self.GraphicPanels.insert(idx, panel)
self.RefreshGraphicsSizer()
def SplitGraphs(self, source_panel, item=None):
source_idx = self.GetViewerIndex(source_panel)
@@ -1238,7 +1597,7 @@
self.GraphicPanels.insert(source_idx + 1, panel)
self.RefreshGraphicsSizer()
def MergeGraphs(self, source, target_idx, merge_type, force=False):
@@ -1277,7 +1636,7 @@
target_panel.ResetGraphics()
self.RefreshGraphicsSizer()
def DeleteValue(self, source_panel, item=None):
source_idx = self.GetViewerIndex(source_panel)
@@ -1294,7 +1653,7 @@
self.GraphicPanels.remove(source_panel)
self.RefreshGraphicsSizer()
def GetDebugVariables(self):
@@ -1323,7 +1682,7 @@
self.RefreshGraphicsSizer()
self.InsertValue(variable, force=True)
for variable in variables:
if isinstance(variable, (ListType, TupleType)):
@@ -1351,4 +1710,4 @@
def OnGraphicsWindowResize(self, event):
self.RefreshGraphicsWindowScrollbars()
\ No newline at end of file