]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/CustomDragAndDrop.py
The great wxVScrolledWindow refactoring: allow using it both horizontal and
[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 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)
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("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.data = wx.CustomDataObject("DoodleLines")
129 self.SetDataObject(self.data)
130
131
132 # some virtual methods that track the progress of the drag
133 def OnEnter(self, x, y, d):
134 self.log.WriteText("OnEnter: %d, %d, %d\n" % (x, y, d))
135 return d
136
137 def OnLeave(self):
138 self.log.WriteText("OnLeave\n")
139
140 def OnDrop(self, x, y):
141 self.log.WriteText("OnDrop: %d %d\n" % (x, y))
142 return True
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
155
156
157 # Called when OnDrop returns True. We need to get the data and
158 # do something with it.
159 def OnData(self, x, y, d):
160 self.log.WriteText("OnData: %d, %d, %d\n" % (x, y, d))
161
162 # copy the data from the drag source to our data object
163 if self.GetData():
164 # convert it back to a list of lines and give it to the viewer
165 linesdata = self.data.GetData()
166 lines = cPickle.loads(linesdata)
167 self.dv.SetLines(lines)
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
174
175
176 class DoodleViewer(wx.Window):
177 def __init__(self, parent, log):
178 wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
179 self.log = log
180 self.SetBackgroundColour(wx.WHITE)
181 self.lines = []
182 self.x = self.y = 0
183 dt = DoodleDropTarget(self, log)
184 self.SetDropTarget(dt)
185 self.Bind(wx.EVT_PAINT, self.OnPaint)
186
187
188 def SetLines(self, lines):
189 self.lines = lines
190 self.Refresh()
191
192 def OnPaint(self, event):
193 dc = wx.PaintDC(self)
194 self.DrawSavedLines(dc)
195
196 def DrawSavedLines(self, dc):
197 dc.BeginDrawing()
198 dc.SetPen(wx.Pen(wx.RED, 3))
199
200 for line in self.lines:
201 for coords in line:
202 dc.DrawLine(*coords)
203 dc.EndDrawing()
204
205 #----------------------------------------------------------------------
206
207 class CustomDnDPanel(wx.Panel):
208 def __init__(self, parent, log):
209 wx.Panel.__init__(self, parent, -1)
210
211 self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
212
213 # Make the controls
214 text1 = wx.StaticText(self, -1,
215 "Draw a little picture in this window\n"
216 "then switch the mode below and drag the\n"
217 "picture to the lower window or to another\n"
218 "application that accepts Bitmaps as a\n"
219 "drop target.\n"
220 )
221
222 rb1 = wx.RadioButton(self, -1, "Draw", style=wx.RB_GROUP)
223 rb1.SetValue(True)
224 rb2 = wx.RadioButton(self, -1, "Drag")
225 rb2.SetValue(False)
226
227 text2 = wx.StaticText(self, -1,
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)
234
235 # put them in sizers
236 sizer = wx.BoxSizer(wx.HORIZONTAL)
237 box = wx.BoxSizer(wx.VERTICAL)
238 rbox = wx.BoxSizer(wx.HORIZONTAL)
239
240 rbox.Add(rb1)
241 rbox.Add(rb2)
242 box.Add(text1, 0, wx.ALL, 10)
243 box.Add(rbox, 0, wx.ALIGN_CENTER)
244 box.Add((10,90))
245 box.Add(text2, 0, wx.ALL, 10)
246
247 sizer.Add(box)
248
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)
252
253 sizer.Add(dndsizer, 1, wx.EXPAND)
254
255 self.SetAutoLayout(True)
256 self.SetSizer(sizer)
257
258 # Events
259 self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton, rb1)
260 self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton, rb2)
261
262
263 def OnRadioButton(self, evt):
264 rb = self.FindWindowById(evt.GetId())
265 self.pad.SetMode(rb.GetLabel())
266
267
268 #----------------------------------------------------------------------
269 #----------------------------------------------------------------------
270
271 class TestPanel(wx.Panel):
272 def __init__(self, parent, log):
273 wx.Panel.__init__(self, parent, -1)
274
275 self.SetAutoLayout(True)
276 sizer = wx.BoxSizer(wx.VERTICAL)
277
278 msg = "Custom Drag-And-Drop"
279 text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE)
280 text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False))
281 text.SetLabel(msg)
282 w,h = text.GetTextExtent(msg)
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)
287
288 sizer.Add(CustomDnDPanel(self, log), 1, wx.EXPAND)
289
290 self.SetSizer(sizer)
291
292
293 #----------------------------------------------------------------------
294
295 def runTest(frame, nb, log):
296 #win = TestPanel(nb, log)
297 win = CustomDnDPanel(nb, log)
298 return win
299
300
301 if __name__ == '__main__':
302 import sys
303
304 class DummyLog:
305 def WriteText(self, text):
306 sys.stdout.write(text)
307
308 class TestApp(wx.App):
309 def OnInit(self):
310 wx.InitAllImageHandlers()
311 self.MakeFrame()
312 return True
313
314 def MakeFrame(self, event=None):
315 frame = wx.Frame(None, -1, "Custom Drag and Drop", size=(550,400))
316 menu = wx.Menu()
317 item = menu.Append(-1, "Window")
318 mb = wx.MenuBar()
319 mb.Append(menu, "New")
320 frame.SetMenuBar(mb)
321 frame.Bind(wx.EVT_MENU, self.MakeFrame, item)
322 panel = TestPanel(frame, DummyLog())
323 frame.Show(True)
324 self.SetTopWindow(frame)
325
326 #----------------------------------------------------------------------
327
328 app = TestApp(0)
329 app.MainLoop()
330
331 #----------------------------------------------------------------------
332
333
334 overview = """<html><body>
335 This demo shows Drag and Drop using a custom data type and a custom
336 data object. A type called "DoodleLines" is created and a Python
337 Pickle of a list is actually transfered in the drag and drop
338 opperation.
339
340 A second data object is also created containing a bitmap of the image
341 and is made available to any drop target that accepts bitmaps, such as
342 MS Word.
343
344 The two data objects are combined in a wx.DataObjectComposite and the
345 rest is handled by the framework.
346 </body></html>
347 """
348