-
-import cPickle
-import wx
-
-#----------------------------------------------------------------------
-
-
-class DoodlePad(wx.Window):
- def __init__(self, parent, log):
- wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
- self.log = log
- self.SetBackgroundColour(wx.WHITE)
- self.lines = []
- self.x = self.y = 0
- self.SetMode("Draw")
-
- self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
- self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
- self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
- self.Bind(wx.EVT_MOTION, self.OnMotion)
- self.Bind(wx.EVT_PAINT, self.OnPaint)
-
-
- def SetMode(self, mode):
- self.mode = mode
- if self.mode == "Draw":
- self.SetCursor(wx.StockCursor(wx.CURSOR_PENCIL))
- else:
- self.SetCursor(wx.STANDARD_CURSOR)
-
-
- def OnPaint(self, event):
- dc = wx.PaintDC(self)
- self.DrawSavedLines(dc)
-
- def DrawSavedLines(self, dc):
- dc.BeginDrawing()
- dc.SetPen(wx.Pen(wx.BLUE, 3))
- for line in self.lines:
- for coords in line:
- dc.DrawLine(*coords)
- dc.EndDrawing()
-
-
- def OnLeftDown(self, event):
- if self.mode == "Drag":
- self.StartDragOpperation()
- elif self.mode == "Draw":
- self.curLine = []
- self.x, self.y = event.GetPositionTuple()
- self.CaptureMouse()
- else:
- wx.Bell()
- self.log.write("unknown mode!\n")
-
-
- def OnLeftUp(self, event):
- if self.HasCapture():
- self.lines.append(self.curLine)
- self.curLine = []
- self.ReleaseMouse()
-
- def OnRightUp(self, event):
- self.lines = []
- self.Refresh()
-
- def OnMotion(self, event):
- if self.HasCapture() and event.Dragging() and not self.mode == "Drag":
- dc = wx.ClientDC(self)
- dc.BeginDrawing()
- dc.SetPen(wx.Pen(wx.BLUE, 3))
- coords = (self.x, self.y) + event.GetPositionTuple()
- self.curLine.append(coords)
- dc.DrawLine(*coords)
- self.x, self.y = event.GetPositionTuple()
- dc.EndDrawing()
-
-
- def StartDragOpperation(self):
- # pickle the lines list
- linesdata = cPickle.dumps(self.lines, 1)
-
- # create our own data format and use it in a
- # custom data object
- ldata = wx.CustomDataObject("DoodleLines")
- ldata.SetData(linesdata)
-
- # Also create a Bitmap version of the drawing
- size = self.GetSize()
- bmp = wx.EmptyBitmap(size.width, size.height)
- dc = wx.MemoryDC()
- dc.SelectObject(bmp)
- dc.SetBackground(wx.WHITE_BRUSH)
- dc.Clear()
- self.DrawSavedLines(dc)
- dc.SelectObject(wx.NullBitmap)
-
- # Now make a data object for the bitmap and also a composite
- # data object holding both of the others.
- bdata = wx.BitmapDataObject(bmp)
- data = wx.DataObjectComposite()
- data.Add(ldata)
- data.Add(bdata)
-
- # And finally, create the drop source and begin the drag
- # and drop opperation
- dropSource = wx.DropSource(self)
- dropSource.SetData(data)
- self.log.WriteText("Begining DragDrop\n")
- result = dropSource.DoDragDrop(wx.Drag_AllowMove)
- self.log.WriteText("DragDrop completed: %d\n" % result)
-
- if result == wx.DragMove:
- self.lines = []
- self.Refresh()
-
-
-#----------------------------------------------------------------------
-
-
-class DoodleDropTarget(wx.PyDropTarget):
- def __init__(self, window, log):
- wx.PyDropTarget.__init__(self)
- self.log = log
- self.dv = window
-
- # specify the type of data we will accept
- self.data = wx.CustomDataObject("DoodleLines")
- self.SetDataObject(self.data)
-
-
- # some virtual methods that track the progress of the drag
- def OnEnter(self, x, y, d):
- self.log.WriteText("OnEnter: %d, %d, %d\n" % (x, y, d))
- return d
-
- def OnLeave(self):
- self.log.WriteText("OnLeave\n")
-
- def OnDrop(self, x, y):
- self.log.WriteText("OnDrop: %d %d\n" % (x, y))
- return True
-
- def OnDragOver(self, x, y, d):
- #self.log.WriteText("OnDragOver: %d, %d, %d\n" % (x, y, d))
-
- # The value returned here tells the source what kind of visual
- # feedback to give. For example, if wxDragCopy is returned then
- # only the copy cursor will be shown, even if the source allows
- # moves. You can use the passed in (x,y) to determine what kind
- # of feedback to give. In this case we return the suggested value
- # which is based on whether the Ctrl key is pressed.
- return d
-
-
-
- # Called when OnDrop returns True. We need to get the data and
- # do something with it.
- def OnData(self, x, y, d):
- self.log.WriteText("OnData: %d, %d, %d\n" % (x, y, d))
-
- # copy the data from the drag source to our data object
- if self.GetData():
- # convert it back to a list of lines and give it to the viewer
- linesdata = self.data.GetData()
- lines = cPickle.loads(linesdata)
- self.dv.SetLines(lines)
-
- # what is returned signals the source what to do
- # with the original data (move, copy, etc.) In this
- # case we just return the suggested value given to us.
- return d
-
-
-
-class DoodleViewer(wx.Window):
- def __init__(self, parent, log):
- wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
- self.log = log
- self.SetBackgroundColour(wx.WHITE)
- self.lines = []
- self.x = self.y = 0
- dt = DoodleDropTarget(self, log)
- self.SetDropTarget(dt)
- self.Bind(wx.EVT_PAINT, self.OnPaint)
-
-
- def SetLines(self, lines):
- self.lines = lines
- self.Refresh()
-
- def OnPaint(self, event):
- dc = wx.PaintDC(self)
- self.DrawSavedLines(dc)
-
- def DrawSavedLines(self, dc):
- dc.BeginDrawing()
- dc.SetPen(wx.Pen(wx.RED, 3))
-
- for line in self.lines:
- for coords in line:
- dc.DrawLine(*coords)
- dc.EndDrawing()
-
-#----------------------------------------------------------------------
-
-class CustomDnDPanel(wx.Panel):
- def __init__(self, parent, log):
- wx.Panel.__init__(self, parent, -1)
-
- self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
-
- # Make the controls
- text1 = wx.StaticText(self, -1,
- "Draw a little picture in this window\n"
- "then switch the mode below and drag the\n"
- "picture to the lower window or to another\n"
- "application that accepts Bitmaps as a\n"
- "drop target.\n"
- )
-
- rb1 = wx.RadioButton(self, -1, "Draw", style=wx.RB_GROUP)
- rb1.SetValue(True)
- rb2 = wx.RadioButton(self, -1, "Drag")
- rb2.SetValue(False)
-
- text2 = wx.StaticText(self, -1,
- "The lower window is accepting a\n"
- "custom data type that is a pickled\n"
- "Python list of lines data.")
-
- self.pad = DoodlePad(self, log)
- view = DoodleViewer(self, log)
-
- # put them in sizers
- sizer = wx.BoxSizer(wx.HORIZONTAL)
- box = wx.BoxSizer(wx.VERTICAL)
- rbox = wx.BoxSizer(wx.HORIZONTAL)
-
- rbox.Add(rb1)
- rbox.Add(rb2)
- box.Add(text1, 0, wx.ALL, 10)
- box.Add(rbox, 0, wx.ALIGN_CENTER)
- box.Add((10,90))
- box.Add(text2, 0, wx.ALL, 10)
-
- sizer.Add(box)
-
- dndsizer = wx.BoxSizer(wx.VERTICAL)
- dndsizer.Add(self.pad, 1, wx.EXPAND|wx.ALL, 5)
- dndsizer.Add(view, 1, wx.EXPAND|wx.ALL, 5)
-
- sizer.Add(dndsizer, 1, wx.EXPAND)
-
- self.SetAutoLayout(True)
- self.SetSizer(sizer)
-
- # Events
- self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton, rb1)
- self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton, rb2)
-
-
- def OnRadioButton(self, evt):
- rb = self.FindWindowById(evt.GetId())
- self.pad.SetMode(rb.GetLabel())
-
-
-#----------------------------------------------------------------------
-#----------------------------------------------------------------------
-
-class TestPanel(wx.Panel):
- def __init__(self, parent, log):
- wx.Panel.__init__(self, parent, -1)
-
- self.SetAutoLayout(True)
- sizer = wx.BoxSizer(wx.VERTICAL)
-
- msg = "Custom Drag-And-Drop"
- text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE)
- text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False))
- text.SetLabel(msg)
- w,h = text.GetTextExtent(msg)
- text.SetSize(wx.Size(w,h+1))
- text.SetForegroundColour(wx.BLUE)
- sizer.Add(text, 0, wx.EXPAND|wx.ALL, 5)
- sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND)
-
- sizer.Add(CustomDnDPanel(self, log), 1, wx.EXPAND)
-
- self.SetSizer(sizer)
-
-
-#----------------------------------------------------------------------
-
-def runTest(frame, nb, log):
- #win = TestPanel(nb, log)
- win = CustomDnDPanel(nb, log)
- return win
-
-
-if __name__ == '__main__':
- import sys
-
- class DummyLog:
- def WriteText(self, text):
- sys.stdout.write(text)
-
- class TestApp(wx.App):
- def OnInit(self):
- wx.InitAllImageHandlers()
- self.MakeFrame()
- return True
-
- def MakeFrame(self, event=None):
- frame = wx.Frame(None, -1, "Custom Drag and Drop", size=(550,400))
- menu = wx.Menu()
- item = menu.Append(-1, "Window")
- mb = wx.MenuBar()
- mb.Append(menu, "New")
- frame.SetMenuBar(mb)
- frame.Bind(wx.EVT_MENU, self.MakeFrame, item)
- panel = TestPanel(frame, DummyLog())
- frame.Show(True)
- self.SetTopWindow(frame)
-
- #----------------------------------------------------------------------
-
- app = TestApp(0)
- app.MainLoop()
-
-#----------------------------------------------------------------------
-
-
-overview = """<html><body>
-This demo shows Drag and Drop using a custom data type and a custom
-data object. A type called "DoodleLines" is created and a Python
-Pickle of a list is actually transfered in the drag and drop
-opperation.
-
-A second data object is also created containing a bitmap of the image
-and is made available to any drop target that accepts bitmaps, such as
-MS Word.
-
-The two data objects are combined in a wx.DataObjectComposite and the
-rest is handled by the framework.
-</body></html>
-"""
-