]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/CustomDragAndDrop.py
reSWIGged
[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):
f78241f6
RD
66 if self.HasCapture():
67 self.lines.append(self.curLine)
68 self.curLine = []
69 self.ReleaseMouse()
b1462dfa
RD
70
71 def OnRightUp(self, event):
72 self.lines = []
73 self.Refresh()
74
75 def OnMotion(self, event):
f78241f6 76 if self.HasCapture() and event.Dragging() and not self.mode == "Drag":
8fa876ca 77 dc = wx.ClientDC(self)
b1462dfa 78 dc.BeginDrawing()
8fa876ca 79 dc.SetPen(wx.Pen(wx.BLUE, 3))
0dfb2393 80 coords = ((self.x, self.y), event.GetPositionTuple())
b1462dfa 81 self.curLine.append(coords)
0dfb2393 82 dc.DrawLine(*coords)
b1462dfa
RD
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
8fa876ca 93 ldata = wx.CustomDataObject(wx.CustomDataFormat("DoodleLines"))
b1462dfa
RD
94 ldata.SetData(linesdata)
95
96 # Also create a Bitmap version of the drawing
97 size = self.GetSize()
8fa876ca
RD
98 bmp = wx.EmptyBitmap(size.width, size.height)
99 dc = wx.MemoryDC()
b1462dfa 100 dc.SelectObject(bmp)
8fa876ca 101 dc.SetBackground(wx.WHITE_BRUSH)
b1462dfa
RD
102 dc.Clear()
103 self.DrawSavedLines(dc)
8fa876ca 104 dc.SelectObject(wx.NullBitmap)
b1462dfa
RD
105
106 # Now make a data object for the bitmap and also a composite
107 # data object holding both of the others.
8fa876ca
RD
108 bdata = wx.BitmapDataObject(bmp)
109 data = wx.DataObjectComposite()
b1462dfa
RD
110 data.Add(ldata)
111 data.Add(bdata)
112
113 # And finally, create the drop source and begin the drag
114 # and drop opperation
8fa876ca 115 dropSource = wx.DropSource(self)
b1462dfa
RD
116 dropSource.SetData(data)
117 self.log.WriteText("Begining DragDrop\n")
8fa876ca 118 result = dropSource.DoDragDrop(wx.Drag_AllowMove)
b1462dfa 119 self.log.WriteText("DragDrop completed: %d\n" % result)
8fa876ca
RD
120
121 if result == wx.DragMove:
163f2606
RD
122 self.lines = []
123 self.Refresh()
f6bcfd97
BP
124
125
b1462dfa
RD
126#----------------------------------------------------------------------
127
128
8fa876ca 129class DoodleDropTarget(wx.PyDropTarget):
b1462dfa 130 def __init__(self, window, log):
8fa876ca 131 wx.PyDropTarget.__init__(self)
b1462dfa
RD
132 self.log = log
133 self.dv = window
f6bcfd97
BP
134
135 # specify the type of data we will accept
8fa876ca
RD
136 self.df = wx.CustomDataFormat("DoodleLines")
137 self.data = wx.CustomDataObject(self.df)
b1462dfa
RD
138 self.SetDataObject(self.data)
139
f6bcfd97
BP
140
141 # some virtual methods that track the progress of the drag
b1462dfa
RD
142 def OnEnter(self, x, y, d):
143 self.log.WriteText("OnEnter: %d, %d, %d\n" % (x, y, d))
163f2606
RD
144 return d
145
b1462dfa
RD
146 def OnLeave(self):
147 self.log.WriteText("OnLeave\n")
163f2606 148
b1462dfa
RD
149 def OnDrop(self, x, y):
150 self.log.WriteText("OnDrop: %d %d\n" % (x, y))
1e4a197e 151 return True
163f2606
RD
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
b1462dfa 164
f6bcfd97 165
1e4a197e 166 # Called when OnDrop returns True. We need to get the data and
f6bcfd97 167 # do something with it.
b1462dfa
RD
168 def OnData(self, x, y, d):
169 self.log.WriteText("OnData: %d, %d, %d\n" % (x, y, d))
f6bcfd97 170
163f2606 171 # copy the data from the drag source to our data object
b1462dfa 172 if self.GetData():
f6bcfd97 173 # convert it back to a list of lines and give it to the viewer
b1462dfa 174 linesdata = self.data.GetData()
0dfb2393 175 lines = cPickle.loads(linesdata)
b1462dfa 176 self.dv.SetLines(lines)
8fa876ca
RD
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
b1462dfa
RD
183
184
8fa876ca 185class DoodleViewer(wx.Window):
b1462dfa 186 def __init__(self, parent, log):
8fa876ca 187 wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
b1462dfa 188 self.log = log
8fa876ca 189 self.SetBackgroundColour(wx.WHITE)
b1462dfa
RD
190 self.lines = []
191 self.x = self.y = 0
192 dt = DoodleDropTarget(self, log)
193 self.SetDropTarget(dt)
8fa876ca 194 wx.EVT_PAINT(self, self.OnPaint)
b1462dfa 195
163f2606 196
b1462dfa
RD
197 def SetLines(self, lines):
198 self.lines = lines
199 self.Refresh()
200
201 def OnPaint(self, event):
8fa876ca 202 dc = wx.PaintDC(self)
b1462dfa
RD
203 self.DrawSavedLines(dc)
204
205 def DrawSavedLines(self, dc):
206 dc.BeginDrawing()
8fa876ca
RD
207 dc.SetPen(wx.Pen(wx.RED, 3))
208
b1462dfa
RD
209 for line in self.lines:
210 for coords in line:
0dfb2393 211 dc.DrawLine(*coords)
b1462dfa
RD
212 dc.EndDrawing()
213
214#----------------------------------------------------------------------
215
8fa876ca 216class CustomDnDPanel(wx.Panel):
b1462dfa 217 def __init__(self, parent, log):
8fa876ca 218 wx.Panel.__init__(self, parent, -1)
b1462dfa 219
8fa876ca 220 self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
b1462dfa 221
163f2606 222 # Make the controls
8fa876ca 223 text1 = wx.StaticText(self, -1,
899493dd 224 "Draw a little picture in this window\n"
7f3d6cbc
RD
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"
163f2606
RD
229 )
230
8fa876ca 231 rb1 = wx.RadioButton(self, -1, "Draw", style=wx.RB_GROUP)
1e4a197e 232 rb1.SetValue(True)
8fa876ca 233 rb2 = wx.RadioButton(self, -1, "Drag")
1e4a197e 234 rb2.SetValue(False)
163f2606 235
8fa876ca 236 text2 = wx.StaticText(self, -1,
163f2606
RD
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)
b1462dfa 243
163f2606 244 # put them in sizers
8fa876ca
RD
245 sizer = wx.BoxSizer(wx.HORIZONTAL)
246 box = wx.BoxSizer(wx.VERTICAL)
247 rbox = wx.BoxSizer(wx.HORIZONTAL)
163f2606
RD
248
249 rbox.Add(rb1)
250 rbox.Add(rb2)
372bde9b
RD
251 box.Add(text1, 0, wx.ALL, 10)
252 box.Add(rbox, 0, wx.ALIGN_CENTER)
fd3f2efe 253 box.Add((10,90))
372bde9b 254 box.Add(text2, 0, wx.ALL, 10)
163f2606
RD
255
256 sizer.Add(box)
257
8fa876ca
RD
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)
163f2606 261
8fa876ca 262 sizer.Add(dndsizer, 1, wx.EXPAND)
b1462dfa 263
1e4a197e 264 self.SetAutoLayout(True)
b1462dfa
RD
265 self.SetSizer(sizer)
266
163f2606 267 # Events
8fa876ca
RD
268 wx.EVT_RADIOBUTTON(self, rb1.GetId(), self.OnRadioButton)
269 wx.EVT_RADIOBUTTON(self, rb2.GetId(), self.OnRadioButton)
163f2606 270
b1462dfa 271
163f2606
RD
272 def OnRadioButton(self, evt):
273 rb = self.FindWindowById(evt.GetId())
274 self.pad.SetMode(rb.GetLabel())
b1462dfa
RD
275
276
277#----------------------------------------------------------------------
278#----------------------------------------------------------------------
279
8fa876ca 280class TestPanel(wx.Panel):
b1462dfa 281 def __init__(self, parent, log):
8fa876ca 282 wx.Panel.__init__(self, parent, -1)
b1462dfa 283
1e4a197e 284 self.SetAutoLayout(True)
8fa876ca 285 sizer = wx.BoxSizer(wx.VERTICAL)
b1462dfa 286
4120ef2b 287 msg = "Custom Drag-And-Drop"
8fa876ca
RD
288 text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE)
289 text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False))
4120ef2b
RD
290 text.SetLabel(msg)
291 w,h = text.GetTextExtent(msg)
8fa876ca
RD
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)
b1462dfa 296
8fa876ca 297 sizer.Add(CustomDnDPanel(self, log), 1, wx.EXPAND)
b1462dfa
RD
298
299 self.SetSizer(sizer)
300
301
302#----------------------------------------------------------------------
303
304def runTest(frame, nb, log):
163f2606
RD
305 #win = TestPanel(nb, log)
306 win = CustomDnDPanel(nb, log)
b1462dfa
RD
307 return win
308
899493dd
RD
309
310if __name__ == '__main__':
311 import sys
8fa876ca 312
899493dd
RD
313 class DummyLog:
314 def WriteText(self, text):
315 sys.stdout.write(text)
316
8fa876ca 317 class TestApp(wx.App):
899493dd 318 def OnInit(self):
8fa876ca 319 wx.InitAllImageHandlers()
899493dd 320 self.MakeFrame()
1e4a197e 321 return True
899493dd
RD
322
323 def MakeFrame(self, event=None):
8fa876ca
RD
324 frame = wx.Frame(None, -1, "Custom Drag and Drop", size=(550,400))
325 menu = wx.Menu()
899493dd 326 menu.Append(6543, "Window")
8fa876ca 327 mb = wx.MenuBar()
899493dd
RD
328 mb.Append(menu, "New")
329 frame.SetMenuBar(mb)
8fa876ca 330 wx.EVT_MENU(frame, 6543, self.MakeFrame)
899493dd 331 panel = TestPanel(frame, DummyLog())
1e4a197e 332 frame.Show(True)
899493dd
RD
333 self.SetTopWindow(frame)
334
8fa876ca 335 #----------------------------------------------------------------------
899493dd
RD
336
337 app = TestApp(0)
338 app.MainLoop()
339
b1462dfa
RD
340#----------------------------------------------------------------------
341
342
1e4a197e
RD
343overview = """<html><body>
344This demo shows Drag and Drop using a custom data type and a custom
345data object. A type called "DoodleLines" is created and a Python
346Pickle of a list is actually transfered in the drag and drop
347opperation.
b1462dfa 348
1e4a197e
RD
349A second data object is also created containing a bitmap of the image
350and is made available to any drop target that accepts bitmaps, such as
351MS Word.
b1462dfa 352
8fa876ca 353The two data objects are combined in a wx.DataObjectComposite and the
1e4a197e
RD
354rest is handled by the framework.
355</body></html>
356"""
b1462dfa 357