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