# HG changeset patch # User Laurent Bessard # Date 1360109936 -3600 # Node ID 5f9dd88a605b66a83f7d4efd135f51f28ad78362 # Parent 5f2cc382be8c692bd9f23387c51bcb368c99da0e Added support for drag'n drop variable from one graph to another with visible graph diff -r 5f2cc382be8c -r 5f9dd88a605b controls/DebugVariablePanel.py --- a/controls/DebugVariablePanel.py Tue Feb 05 16:42:52 2013 +0100 +++ b/controls/DebugVariablePanel.py Wed Feb 06 01:18:56 2013 +0100 @@ -36,6 +36,8 @@ matplotlib.use('WX') import matplotlib.pyplot 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 USE_MPL = True except: @@ -330,12 +332,9 @@ else: self.ParentWindow.InsertValue(values[0], target_idx, force=True) else: - 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() if rect.InsideXY(x, y): - 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) @@ -619,7 +618,49 @@ else: mask.append("*") return mask - + + 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() + + if destBBox.x == 0: + srcX = srcBBox.x + srcBBox.width - destBBox.width + else: + srcX = srcBBox.x + if destBBox.y == 0: + srcY = srcBBox.y + srcBBox.height - destBBox.height + else: + srcY = srcBBox.y + + srcBmp = _convert_agg_to_wx_bitmap(srcPanel.Canvas.get_renderer(), None) + srcDC = wx.MemoryDC() + srcDC.SelectObject(srcBmp) + + destDC = wx.MemoryDC() + destDC.SelectObject(self.bitmap) + + destDC.BeginDrawing() + destDC.Blit(destBBox.x, destBBox.y, + int(destBBox.width), int(destBBox.height), + srcDC, srcX, srcY) + destDC.EndDrawing() + + self._isDrawn = True + self.gui_repaint(drawDC=drawDC) + class DebugVariableGraphic(DebugVariableViewer): def __init__(self, parent, window, items, graph_type): @@ -633,11 +674,12 @@ def AddViewer(self): 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.OnCanvasLeftDown) self.Canvas.mpl_connect('motion_notify_event', self.OnCanvasMotion) - self.Canvas.Bind(wx.EVT_LEFT_DOWN, self.OnCanvasClick) + self.Canvas.mpl_connect('button_release_event', self.OnCanvasLeftUp) self.MainSizer.AddWindow(self.Canvas, flag=wx.GROW) @@ -659,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) + if absolute: + xw, yw = self.GetPosition() + bbox.x += xw + bbox.y += yw + return bbox + + def OnCanvasLeftDown(self, event): x, y = event.GetPosition() width, height = self.Canvas.GetSize() if len(self.Items) == 1: - 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() if rect.InsideXY(x, y): - self.DoDragDrop(0) + xw, yw = self.GetPosition() + self.ParentWindow.StartDragNDrop(self, x + xw, y + yw) return elif self.Legend is not None: item_idx = None @@ -683,6 +735,15 @@ return event.Skip() + def OnCanvasLeftUp(self, event): + if self.ParentWindow.IsDragging(): + width, height = self.Canvas.GetSize() + xw, yw = self.GetPosition() + self.ParentWindow.StopDragNDrop( + self.Items[0].GetVariable(), + xw + event.x, + yw + height - event.y) + def DoDragDrop(self, item_idx): self.ParentWindow.ResetCursorTickRatio() data = wx.TextDataObject(str((self.Items[item_idx].GetVariable(), "debug", "move"))) @@ -698,7 +759,13 @@ Axes3D._on_move(self.Axes, event) def OnCanvasMotion(self, event): - if not self.Is3DCanvas(): + if self.ParentWindow.IsDragging(): + width, height = self.Canvas.GetSize() + xw, yw = self.GetPosition() + self.ParentWindow.MoveDragNDrop( + xw + event.x, + yw + height - event.y) + elif not self.Is3DCanvas(): if event.inaxes == self.Axes: start_tick, end_tick = self.ParentWindow.GetRange() cursor_tick_ratio = None @@ -956,6 +1023,10 @@ self.StartTick = 0 self.Fixed = False self.Force = False + self.CursorTickRatio = None + self.DraggingAxesPanel = None + self.DraggingAxesBoundingBox = None + self.DraggingAxesMousePos = None self.GraphicPanels = [] @@ -1005,7 +1076,6 @@ self.GraphicsWindow.SetSizer(self.GraphicsSizer) self.RefreshCanvasRange() - self.CursorTickRatio = None else: main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) @@ -1150,6 +1220,60 @@ label += "(%s)" % duration return label + 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 + self.ForceRefresh() + + def IsDragging(self): + 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) + bbox.x -= x + bbox.y -= y + return bbox + + 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 panel.Is3DCanvas(): + if y_mouse > yw + height / 2: + idx += 1 + wx.CallAfter(self.MoveGraph, variable, idx) + return + else: + 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) + else: + if y_mouse > yw + height / 2: + idx += 1 + wx.CallAfter(self.MoveGraph, variable, idx) + break + self.ForceRefresh() + def RefreshView(self, only_values=False): if USE_MPL: self.RefreshCanvasPosition()