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