]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/CustomDragAndDrop.py
Don't allow parameterless wxDropSource
[wxWidgets.git] / wxPython / demo / CustomDragAndDrop.py
1
2 import cPickle
3 import wx
4
5 #----------------------------------------------------------------------
6
7
8 class DoodlePad(wx.Window):
9 def __init__(self, parent, log):
10 wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
11 self.log = log
12 self.SetBackgroundColour(wx.WHITE)
13 self.lines = []
14 self.x = self.y = 0
15 self.SetMode("Draw")
16
17 wx.EVT_LEFT_DOWN(self, self.OnLeftDown)
18 wx.EVT_LEFT_UP(self, self.OnLeftUp)
19 wx.EVT_RIGHT_UP(self, self.OnRightUp)
20 wx.EVT_MOTION(self, self.OnMotion)
21 wx.EVT_PAINT(self, self.OnPaint)
22
23
24 def SetMode(self, mode):
25 self.mode = mode
26 if self.mode == "Draw":
27 self.SetCursor(wx.StockCursor(wx.CURSOR_PENCIL))
28 else:
29 self.SetCursor(wx.STANDARD_CURSOR)
30
31
32 def OnPaint(self, event):
33 dc = wx.PaintDC(self)
34 self.DrawSavedLines(dc)
35
36 def DrawSavedLines(self, dc):
37 dc.BeginDrawing()
38 dc.SetPen(wx.Pen(wx.BLUE, 3))
39 for line in self.lines:
40 for coords in line:
41 dc.DrawLine(*coords)
42 dc.EndDrawing()
43
44
45 def OnLeftDown(self, event):
46 if self.mode == "Drag":
47 self.StartDragOpperation()
48 elif self.mode == "Draw":
49 self.curLine = []
50 self.x, self.y = event.GetPositionTuple()
51 self.CaptureMouse()
52 else:
53 wx.Bell()
54 self.log.write("unknown mode!\n")
55
56
57 def OnLeftUp(self, event):
58 if self.HasCapture():
59 self.lines.append(self.curLine)
60 self.curLine = []
61 self.ReleaseMouse()
62
63 def OnRightUp(self, event):
64 self.lines = []
65 self.Refresh()
66
67 def OnMotion(self, event):
68 if self.HasCapture() and event.Dragging() and not self.mode == "Drag":
69 dc = wx.ClientDC(self)
70 dc.BeginDrawing()
71 dc.SetPen(wx.Pen(wx.BLUE, 3))
72 coords = ((self.x, self.y), event.GetPositionTuple())
73 self.curLine.append(coords)
74 dc.DrawLine(*coords)
75 self.x, self.y = event.GetPositionTuple()
76 dc.EndDrawing()
77
78
79 def StartDragOpperation(self):
80 # pickle the lines list
81 linesdata = cPickle.dumps(self.lines, 1)
82
83 # create our own data format and use it in a
84 # custom data object
85 ldata = wx.CustomDataObject(wx.CustomDataFormat("DoodleLines"))
86 ldata.SetData(linesdata)
87
88 # Also create a Bitmap version of the drawing
89 size = self.GetSize()
90 bmp = wx.EmptyBitmap(size.width, size.height)
91 dc = wx.MemoryDC()
92 dc.SelectObject(bmp)
93 dc.SetBackground(wx.WHITE_BRUSH)
94 dc.Clear()
95 self.DrawSavedLines(dc)
96 dc.SelectObject(wx.NullBitmap)
97
98 # Now make a data object for the bitmap and also a composite
99 # data object holding both of the others.
100 bdata = wx.BitmapDataObject(bmp)
101 data = wx.DataObjectComposite()
102 data.Add(ldata)
103 data.Add(bdata)
104
105 # And finally, create the drop source and begin the drag
106 # and drop opperation
107 dropSource = wx.DropSource(self)
108 dropSource.SetData(data)
109 self.log.WriteText("Begining DragDrop\n")
110 result = dropSource.DoDragDrop(wx.Drag_AllowMove)
111 self.log.WriteText("DragDrop completed: %d\n" % result)
112
113 if result == wx.DragMove:
114 self.lines = []
115 self.Refresh()
116
117
118 #----------------------------------------------------------------------
119
120
121 class DoodleDropTarget(wx.PyDropTarget):
122 def __init__(self, window, log):
123 wx.PyDropTarget.__init__(self)
124 self.log = log
125 self.dv = window
126
127 # specify the type of data we will accept
128 self.df = wx.CustomDataFormat("DoodleLines")
129 self.data = wx.CustomDataObject(self.df)
130 self.SetDataObject(self.data)
131
132
133 # some virtual methods that track the progress of the drag
134 def OnEnter(self, x, y, d):
135 self.log.WriteText("OnEnter: %d, %d, %d\n" % (x, y, d))
136 return d
137
138 def OnLeave(self):
139 self.log.WriteText("OnLeave\n")
140
141 def OnDrop(self, x, y):
142 self.log.WriteText("OnDrop: %d %d\n" % (x, y))
143 return True
144
145 def OnDragOver(self, x, y, d):
146 #self.log.WriteText("OnDragOver: %d, %d, %d\n" % (x, y, d))
147
148 # The value returned here tells the source what kind of visual
149 # feedback to give. For example, if wxDragCopy is returned then
150 # only the copy cursor will be shown, even if the source allows
151 # moves. You can use the passed in (x,y) to determine what kind
152 # of feedback to give. In this case we return the suggested value
153 # which is based on whether the Ctrl key is pressed.
154 return d
155
156
157
158 # Called when OnDrop returns True. We need to get the data and
159 # do something with it.
160 def OnData(self, x, y, d):
161 self.log.WriteText("OnData: %d, %d, %d\n" % (x, y, d))
162
163 # copy the data from the drag source to our data object
164 if self.GetData():
165 # convert it back to a list of lines and give it to the viewer
166 linesdata = self.data.GetData()
167 lines = cPickle.loads(linesdata)
168 self.dv.SetLines(lines)
169
170 # what is returned signals the source what to do
171 # with the original data (move, copy, etc.) In this
172 # case we just return the suggested value given to us.
173 return d
174
175
176
177 class DoodleViewer(wx.Window):
178 def __init__(self, parent, log):
179 wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
180 self.log = log
181 self.SetBackgroundColour(wx.WHITE)
182 self.lines = []
183 self.x = self.y = 0
184 dt = DoodleDropTarget(self, log)
185 self.SetDropTarget(dt)
186 wx.EVT_PAINT(self, self.OnPaint)
187
188
189 def SetLines(self, lines):
190 self.lines = lines
191 self.Refresh()
192
193 def OnPaint(self, event):
194 dc = wx.PaintDC(self)
195 self.DrawSavedLines(dc)
196
197 def DrawSavedLines(self, dc):
198 dc.BeginDrawing()
199 dc.SetPen(wx.Pen(wx.RED, 3))
200
201 for line in self.lines:
202 for coords in line:
203 dc.DrawLine(*coords)
204 dc.EndDrawing()
205
206 #----------------------------------------------------------------------
207
208 class CustomDnDPanel(wx.Panel):
209 def __init__(self, parent, log):
210 wx.Panel.__init__(self, parent, -1)
211
212 self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
213
214 # Make the controls
215 text1 = wx.StaticText(self, -1,
216 "Draw a little picture in this window\n"
217 "then switch the mode below and drag the\n"
218 "picture to the lower window or to another\n"
219 "application that accepts BMP's as a drop\n"
220 "target.\n"
221 )
222
223 rb1 = wx.RadioButton(self, -1, "Draw", style=wx.RB_GROUP)
224 rb1.SetValue(True)
225 rb2 = wx.RadioButton(self, -1, "Drag")
226 rb2.SetValue(False)
227
228 text2 = wx.StaticText(self, -1,
229 "The lower window is accepting a\n"
230 "custom data type that is a pickled\n"
231 "Python list of lines data.")
232
233 self.pad = DoodlePad(self, log)
234 view = DoodleViewer(self, log)
235
236 # put them in sizers
237 sizer = wx.BoxSizer(wx.HORIZONTAL)
238 box = wx.BoxSizer(wx.VERTICAL)
239 rbox = wx.BoxSizer(wx.HORIZONTAL)
240
241 rbox.Add(rb1)
242 rbox.Add(rb2)
243 box.Add(text1, 0, wx.ALL, 10)
244 box.Add(rbox, 0, wx.ALIGN_CENTER)
245 box.Add((10,90))
246 box.Add(text2, 0, wx.ALL, 10)
247
248 sizer.Add(box)
249
250 dndsizer = wx.BoxSizer(wx.VERTICAL)
251 dndsizer.Add(self.pad, 1, wx.EXPAND|wx.ALL, 5)
252 dndsizer.Add(view, 1, wx.EXPAND|wx.ALL, 5)
253
254 sizer.Add(dndsizer, 1, wx.EXPAND)
255
256 self.SetAutoLayout(True)
257 self.SetSizer(sizer)
258
259 # Events
260 wx.EVT_RADIOBUTTON(self, rb1.GetId(), self.OnRadioButton)
261 wx.EVT_RADIOBUTTON(self, rb2.GetId(), self.OnRadioButton)
262
263
264 def OnRadioButton(self, evt):
265 rb = self.FindWindowById(evt.GetId())
266 self.pad.SetMode(rb.GetLabel())
267
268
269 #----------------------------------------------------------------------
270 #----------------------------------------------------------------------
271
272 class TestPanel(wx.Panel):
273 def __init__(self, parent, log):
274 wx.Panel.__init__(self, parent, -1)
275
276 self.SetAutoLayout(True)
277 sizer = wx.BoxSizer(wx.VERTICAL)
278
279 msg = "Custom Drag-And-Drop"
280 text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE)
281 text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False))
282 text.SetLabel(msg)
283 w,h = text.GetTextExtent(msg)
284 text.SetSize(wx.Size(w,h+1))
285 text.SetForegroundColour(wx.BLUE)
286 sizer.Add(text, 0, wx.EXPAND|wx.ALL, 5)
287 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND)
288
289 sizer.Add(CustomDnDPanel(self, log), 1, wx.EXPAND)
290
291 self.SetSizer(sizer)
292
293
294 #----------------------------------------------------------------------
295
296 def runTest(frame, nb, log):
297 #win = TestPanel(nb, log)
298 win = CustomDnDPanel(nb, log)
299 return win
300
301
302 if __name__ == '__main__':
303 import sys
304
305 class DummyLog:
306 def WriteText(self, text):
307 sys.stdout.write(text)
308
309 class TestApp(wx.App):
310 def OnInit(self):
311 wx.InitAllImageHandlers()
312 self.MakeFrame()
313 return True
314
315 def MakeFrame(self, event=None):
316 frame = wx.Frame(None, -1, "Custom Drag and Drop", size=(550,400))
317 menu = wx.Menu()
318 menu.Append(6543, "Window")
319 mb = wx.MenuBar()
320 mb.Append(menu, "New")
321 frame.SetMenuBar(mb)
322 wx.EVT_MENU(frame, 6543, self.MakeFrame)
323 panel = TestPanel(frame, DummyLog())
324 frame.Show(True)
325 self.SetTopWindow(frame)
326
327 #----------------------------------------------------------------------
328
329 app = TestApp(0)
330 app.MainLoop()
331
332 #----------------------------------------------------------------------
333
334
335 overview = """<html><body>
336 This demo shows Drag and Drop using a custom data type and a custom
337 data object. A type called "DoodleLines" is created and a Python
338 Pickle of a list is actually transfered in the drag and drop
339 opperation.
340
341 A second data object is also created containing a bitmap of the image
342 and is made available to any drop target that accepts bitmaps, such as
343 MS Word.
344
345 The two data objects are combined in a wx.DataObjectComposite and the
346 rest is handled by the framework.
347 </body></html>
348 """
349