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