]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/CustomDragAndDrop.py
fixed extraneous scrolling when scrollbars are added/removed (patch 788026; bug 746618)
[wxWidgets.git] / wxPython / demo / CustomDragAndDrop.py
CommitLineData
b1462dfa
RD
1
2from wxPython.wx import *
3
4import cPickle
5
6#----------------------------------------------------------------------
7
8
9class 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
163f2606 16 self.SetMode("Draw")
b1462dfa
RD
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)
f6bcfd97 22 EVT_PAINT(self, self.OnPaint)
b1462dfa
RD
23
24
163f2606
RD
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
b1462dfa
RD
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):
163f2606 47 if self.mode == "Drag":
b1462dfa 48 self.StartDragOpperation()
163f2606 49 elif self.mode == "Draw":
b1462dfa
RD
50 self.curLine = []
51 self.x, self.y = event.GetPositionTuple()
52 self.CaptureMouse()
163f2606
RD
53 else:
54 wxBell()
55 self.log.write("unknown mode!\n")
b1462dfa
RD
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):
163f2606 68 if event.Dragging() and not self.mode == "Drag":
b1462dfa
RD
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")
e7d0a414 110 result = dropSource.DoDragDrop(wxDrag_AllowMove)
b1462dfa 111 self.log.WriteText("DragDrop completed: %d\n" % result)
163f2606
RD
112 if result == wxDragMove:
113 self.lines = []
114 self.Refresh()
f6bcfd97
BP
115
116
b1462dfa
RD
117#----------------------------------------------------------------------
118
119
120class DoodleDropTarget(wxPyDropTarget):
121 def __init__(self, window, log):
122 wxPyDropTarget.__init__(self)
123 self.log = log
124 self.dv = window
f6bcfd97
BP
125
126 # specify the type of data we will accept
1e4a197e
RD
127 self.df = wxCustomDataFormat("DoodleLines")
128 self.data = wxCustomDataObject(self.df)
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
RD
165 linesdata = self.data.GetData()
166 lines = cPickle.loads(linesdata)
167 self.dv.SetLines(lines)
163f2606
RD
168 return d # what is returned signals the source what to do
169 # with the original data (move, copy, etc.) In this
170 # case we just return the suggested value given to us.
b1462dfa 171
b1462dfa
RD
172
173
174
175class DoodleViewer(wxWindow):
176 def __init__(self, parent, log):
177 wxWindow.__init__(self, parent, -1, style=wxSUNKEN_BORDER)
178 self.log = log
179 self.SetBackgroundColour(wxWHITE)
180 self.lines = []
181 self.x = self.y = 0
182 dt = DoodleDropTarget(self, log)
183 self.SetDropTarget(dt)
f6bcfd97 184 EVT_PAINT(self, self.OnPaint)
b1462dfa 185
163f2606 186
b1462dfa
RD
187 def SetLines(self, lines):
188 self.lines = lines
189 self.Refresh()
190
191 def OnPaint(self, event):
192 dc = wxPaintDC(self)
193 self.DrawSavedLines(dc)
194
195 def DrawSavedLines(self, dc):
196 dc.BeginDrawing()
197 dc.SetPen(wxPen(wxRED, 3))
198 for line in self.lines:
199 for coords in line:
200 apply(dc.DrawLine, coords)
201 dc.EndDrawing()
202
203#----------------------------------------------------------------------
204
205class CustomDnDPanel(wxPanel):
206 def __init__(self, parent, log):
207 wxPanel.__init__(self, parent, -1)
208
1e4a197e 209 self.SetFont(wxFont(10, wxSWISS, wxNORMAL, wxBOLD, False))
b1462dfa 210
163f2606
RD
211 # Make the controls
212 text1 = wxStaticText(self, -1,
899493dd 213 "Draw a little picture in this window\n"
7f3d6cbc
RD
214 "then switch the mode below and drag the\n"
215 "picture to the lower window or to another\n"
216 "application that accepts BMP's as a drop\n"
217 "target.\n"
163f2606
RD
218 )
219
220 rb1 = wxRadioButton(self, -1, "Draw", style=wxRB_GROUP)
1e4a197e 221 rb1.SetValue(True)
163f2606 222 rb2 = wxRadioButton(self, -1, "Drag")
1e4a197e 223 rb2.SetValue(False)
163f2606
RD
224
225 text2 = wxStaticText(self, -1,
226 "The lower window is accepting a\n"
227 "custom data type that is a pickled\n"
228 "Python list of lines data.")
229
230 self.pad = DoodlePad(self, log)
231 view = DoodleViewer(self, log)
b1462dfa 232
163f2606
RD
233 # put them in sizers
234 sizer = wxBoxSizer(wxHORIZONTAL)
235 box = wxBoxSizer(wxVERTICAL)
236 rbox = wxBoxSizer(wxHORIZONTAL)
237
238 rbox.Add(rb1)
239 rbox.Add(rb2)
240 box.Add(text1, 0, wxALL, 10)
241 box.Add(rbox, 0, wxALIGN_CENTER)
242 box.Add(10,90)
243 box.Add(text2, 0, wxALL, 10)
244
245 sizer.Add(box)
246
247 dndsizer = wxBoxSizer(wxVERTICAL)
248 dndsizer.Add(self.pad, 1, wxEXPAND|wxALL, 5)
249 dndsizer.Add(view, 1, wxEXPAND|wxALL, 5)
250
251 sizer.Add(dndsizer, 1, wxEXPAND)
b1462dfa 252
1e4a197e 253 self.SetAutoLayout(True)
b1462dfa
RD
254 self.SetSizer(sizer)
255
163f2606
RD
256 # Events
257 EVT_RADIOBUTTON(self, rb1.GetId(), self.OnRadioButton)
258 EVT_RADIOBUTTON(self, rb2.GetId(), self.OnRadioButton)
259
b1462dfa 260
163f2606
RD
261 def OnRadioButton(self, evt):
262 rb = self.FindWindowById(evt.GetId())
263 self.pad.SetMode(rb.GetLabel())
b1462dfa
RD
264
265
266#----------------------------------------------------------------------
267#----------------------------------------------------------------------
268
269class TestPanel(wxPanel):
270 def __init__(self, parent, log):
271 wxPanel.__init__(self, parent, -1)
272
1e4a197e 273 self.SetAutoLayout(True)
b1462dfa
RD
274 sizer = wxBoxSizer(wxVERTICAL)
275
4120ef2b 276 msg = "Custom Drag-And-Drop"
b1462dfa 277 text = wxStaticText(self, -1, "", style=wxALIGN_CENTRE)
1e4a197e 278 text.SetFont(wxFont(24, wxSWISS, wxNORMAL, wxBOLD, False))
4120ef2b
RD
279 text.SetLabel(msg)
280 w,h = text.GetTextExtent(msg)
281 text.SetSize(wxSize(w,h+1))
b1462dfa
RD
282 text.SetForegroundColour(wxBLUE)
283 sizer.Add(text, 0, wxEXPAND|wxALL, 5)
284 sizer.Add(wxStaticLine(self, -1), 0, wxEXPAND)
285
286 sizer.Add(CustomDnDPanel(self, log), 1, wxEXPAND)
287
288 self.SetSizer(sizer)
289
290
291#----------------------------------------------------------------------
292
293def runTest(frame, nb, log):
163f2606
RD
294 #win = TestPanel(nb, log)
295 win = CustomDnDPanel(nb, log)
b1462dfa
RD
296 return win
297
899493dd
RD
298
299if __name__ == '__main__':
300 import sys
301 class DummyLog:
302 def WriteText(self, text):
303 sys.stdout.write(text)
304
305 class TestApp(wxApp):
306 def OnInit(self):
1e4a197e 307 wxInitAllImageHandlers()
899493dd 308 self.MakeFrame()
1e4a197e 309 return True
899493dd
RD
310
311 def MakeFrame(self, event=None):
312 frame = wxFrame(None, -1, "Custom Drag and Drop", size=(550,400))
313 menu = wxMenu()
314 menu.Append(6543, "Window")
315 mb = wxMenuBar()
316 mb.Append(menu, "New")
317 frame.SetMenuBar(mb)
318 EVT_MENU(frame, 6543, self.MakeFrame)
319 panel = TestPanel(frame, DummyLog())
1e4a197e 320 frame.Show(True)
899493dd
RD
321 self.SetTopWindow(frame)
322
323
324
325 app = TestApp(0)
326 app.MainLoop()
327
b1462dfa
RD
328#----------------------------------------------------------------------
329
330
1e4a197e
RD
331overview = """<html><body>
332This demo shows Drag and Drop using a custom data type and a custom
333data object. A type called "DoodleLines" is created and a Python
334Pickle of a list is actually transfered in the drag and drop
335opperation.
b1462dfa 336
1e4a197e
RD
337A second data object is also created containing a bitmap of the image
338and is made available to any drop target that accepts bitmaps, such as
339MS Word.
b1462dfa 340
1e4a197e
RD
341The two data objects are combined in a wxDataObjectComposite and the
342rest is handled by the framework.
343</body></html>
344"""
b1462dfa
RD
345
346
347