]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/CustomDragAndDrop.py
synthetize 'button up' event before doubleclick, too
[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 switch the mode below and drag the\n"
214 "picture to the lower window or to another\n"
215 "application that accepts BMP's as a drop\n"
216 "target.\n"
217 )
218
219 rb1 = wxRadioButton(self, -1, "Draw", style=wxRB_GROUP)
220 rb1.SetValue(true)
221 rb2 = wxRadioButton(self, -1, "Drag")
222 rb2.SetValue(false)
223
224 text2 = wxStaticText(self, -1,
225 "The lower window is accepting a\n"
226 "custom data type that is a pickled\n"
227 "Python list of lines data.")
228
229 self.pad = DoodlePad(self, log)
230 view = DoodleViewer(self, log)
231
232 # put them in sizers
233 sizer = wxBoxSizer(wxHORIZONTAL)
234 box = wxBoxSizer(wxVERTICAL)
235 rbox = wxBoxSizer(wxHORIZONTAL)
236
237 rbox.Add(rb1)
238 rbox.Add(rb2)
239 box.Add(text1, 0, wxALL, 10)
240 box.Add(rbox, 0, wxALIGN_CENTER)
241 box.Add(10,90)
242 box.Add(text2, 0, wxALL, 10)
243
244 sizer.Add(box)
245
246 dndsizer = wxBoxSizer(wxVERTICAL)
247 dndsizer.Add(self.pad, 1, wxEXPAND|wxALL, 5)
248 dndsizer.Add(view, 1, wxEXPAND|wxALL, 5)
249
250 sizer.Add(dndsizer, 1, wxEXPAND)
251
252 self.SetAutoLayout(true)
253 self.SetSizer(sizer)
254
255 # Events
256 EVT_RADIOBUTTON(self, rb1.GetId(), self.OnRadioButton)
257 EVT_RADIOBUTTON(self, rb2.GetId(), self.OnRadioButton)
258
259
260 def OnRadioButton(self, evt):
261 rb = self.FindWindowById(evt.GetId())
262 self.pad.SetMode(rb.GetLabel())
263
264
265 #----------------------------------------------------------------------
266 #----------------------------------------------------------------------
267
268 class TestPanel(wxPanel):
269 def __init__(self, parent, log):
270 wxPanel.__init__(self, parent, -1)
271
272 self.SetAutoLayout(true)
273 sizer = wxBoxSizer(wxVERTICAL)
274
275 msg = "Custom Drag-And-Drop"
276 text = wxStaticText(self, -1, "", style=wxALIGN_CENTRE)
277 text.SetFont(wxFont(24, wxSWISS, wxNORMAL, wxBOLD, false))
278 text.SetLabel(msg)
279 w,h = text.GetTextExtent(msg)
280 text.SetSize(wxSize(w,h+1))
281 text.SetForegroundColour(wxBLUE)
282 sizer.Add(text, 0, wxEXPAND|wxALL, 5)
283 sizer.Add(wxStaticLine(self, -1), 0, wxEXPAND)
284
285 sizer.Add(CustomDnDPanel(self, log), 1, wxEXPAND)
286
287 self.SetSizer(sizer)
288
289
290 #----------------------------------------------------------------------
291
292 def runTest(frame, nb, log):
293 #win = TestPanel(nb, log)
294 win = CustomDnDPanel(nb, log)
295 return win
296
297
298 if __name__ == '__main__':
299 import sys
300 class DummyLog:
301 def WriteText(self, text):
302 sys.stdout.write(text)
303
304 class TestApp(wxApp):
305 def OnInit(self):
306 self.MakeFrame()
307 return true
308
309 def MakeFrame(self, event=None):
310 frame = wxFrame(None, -1, "Custom Drag and Drop", size=(550,400))
311 menu = wxMenu()
312 menu.Append(6543, "Window")
313 mb = wxMenuBar()
314 mb.Append(menu, "New")
315 frame.SetMenuBar(mb)
316 EVT_MENU(frame, 6543, self.MakeFrame)
317 panel = TestPanel(frame, DummyLog())
318 frame.Show(true)
319 self.SetTopWindow(frame)
320
321
322
323 app = TestApp(0)
324 app.MainLoop()
325
326 #----------------------------------------------------------------------
327
328
329
330
331
332
333
334
335
336
337
338
339 overview = """\
340 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.
341
342 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.
343
344 The two data objects are combined in a wxDataObjectComposite and the rest is handled by the framework.
345 """
346