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