git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@31635 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			349 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			349 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
 | |
| 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")
 | |
| 
 | |
|         wx.EVT_LEFT_DOWN(self, self.OnLeftDown)
 | |
|         wx.EVT_LEFT_UP(self, self.OnLeftUp)
 | |
|         wx.EVT_RIGHT_UP(self, self.OnRightUp)
 | |
|         wx.EVT_MOTION(self, self.OnMotion)
 | |
|         wx.EVT_PAINT(self, 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)
 | |
|         wx.EVT_PAINT(self, 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
 | |
|         wx.EVT_RADIOBUTTON(self, rb1.GetId(), self.OnRadioButton)
 | |
|         wx.EVT_RADIOBUTTON(self, rb2.GetId(), self.OnRadioButton)
 | |
| 
 | |
| 
 | |
|     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()
 | |
|             menu.Append(6543, "Window")
 | |
|             mb = wx.MenuBar()
 | |
|             mb.Append(menu, "New")
 | |
|             frame.SetMenuBar(mb)
 | |
|             wx.EVT_MENU(frame, 6543, self.MakeFrame)
 | |
|             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>
 | |
| """
 | |
| 
 |