]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/DragImage.py
The bug is no longer there, but leave the workaround in place for
[wxWidgets.git] / wxPython / demo / DragImage.py
1
2 import wx
3 import images
4
5 #----------------------------------------------------------------------
6
7 class DragShape:
8 def __init__(self, bmp):
9 self.bmp = bmp
10 self.pos = (0,0)
11 self.shown = True
12 self.text = None
13 self.fullscreen = False
14
15 def HitTest(self, pt):
16 rect = self.GetRect()
17 return rect.InsideXY(pt.x, pt.y)
18
19 def GetRect(self):
20 return wx.Rect(self.pos[0], self.pos[1],
21 self.bmp.GetWidth(), self.bmp.GetHeight())
22
23 def Draw(self, dc, op = wx.COPY):
24 if self.bmp.Ok():
25 memDC = wx.MemoryDC()
26 memDC.SelectObject(self.bmp)
27
28 dc.Blit(self.pos[0], self.pos[1],
29 self.bmp.GetWidth(), self.bmp.GetHeight(),
30 memDC, 0, 0, op, True)
31
32 return True
33 else:
34 return False
35
36
37
38 #----------------------------------------------------------------------
39
40 class DragCanvas(wx.ScrolledWindow):
41 def __init__(self, parent, ID):
42 wx.ScrolledWindow.__init__(self, parent, ID)
43 self.shapes = []
44 self.dragImage = None
45 self.dragShape = None
46 self.hiliteShape = None
47
48 self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
49 self.bg_bmp = images.getBackgroundBitmap()
50
51 # Make a shape from an image and mask. This one will demo
52 # dragging outside the window
53 bmp = images.getTestStarBitmap()
54 ##bmp = wx.Bitmap('bitmaps/toucan.png')
55 shape = DragShape(bmp)
56 shape.pos = (5, 5)
57 shape.fullscreen = True
58 self.shapes.append(shape)
59
60 # Make a shape from some text
61 text = "Some Text"
62 bg_colour = wx.Colour(57, 115, 57) # matches the bg image
63 font = wx.Font(15, wx.ROMAN, wx.NORMAL, wx.BOLD)
64 textExtent = self.GetFullTextExtent(text, font)
65
66 # create a bitmap the same size as our text
67 bmp = wx.EmptyBitmap(textExtent[0], textExtent[1])
68
69 # 'draw' the text onto the bitmap
70 dc = wx.MemoryDC()
71 dc.SelectObject(bmp)
72 dc.SetBackground(wx.Brush(bg_colour, wx.SOLID))
73 dc.Clear()
74 dc.SetTextForeground(wx.RED)
75 dc.SetFont(font)
76 dc.DrawText(text, 0, 0)
77 dc.SelectObject(wx.NullBitmap)
78 mask = wx.Mask(bmp, bg_colour)
79 bmp.SetMask(mask)
80 shape = DragShape(bmp)
81 shape.pos = (5, 100)
82 shape.text = "Some dragging text"
83 self.shapes.append(shape)
84
85
86 # Make some shapes from some playing card images.
87 x = 200
88
89 for card in ['_01c_', '_12h_', '_13d_', '_10s_']:
90 bmpFunc = getattr(images, "get%sBitmap" % card)
91 bmp = bmpFunc()
92 shape = DragShape(bmp)
93 shape.pos = (x, 5)
94 self.shapes.append(shape)
95 x = x + 80
96
97
98 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
99 self.Bind(wx.EVT_PAINT, self.OnPaint)
100 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
101 self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
102 self.Bind(wx.EVT_MOTION, self.OnMotion)
103 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
104
105
106 # We're not doing anything here, but you might have reason to.
107 # for example, if you were dragging something, you might elect to
108 # 'drop it' when the cursor left the window.
109 def OnLeaveWindow(self, evt):
110 pass
111
112
113 # tile the background bitmap
114 def TileBackground(self, dc):
115 sz = self.GetClientSize()
116 w = self.bg_bmp.GetWidth()
117 h = self.bg_bmp.GetHeight()
118
119 x = 0
120
121 while x < sz.width:
122 y = 0
123
124 while y < sz.height:
125 dc.DrawBitmap(self.bg_bmp, x, y)
126 y = y + h
127
128 x = x + w
129
130
131 # Go through our list of shapes and draw them in whatever place they are.
132 def DrawShapes(self, dc):
133 for shape in self.shapes:
134 if shape.shown:
135 shape.Draw(dc)
136
137 # This is actually a sophisticated 'hit test', but in this
138 # case we're also determining which shape, if any, was 'hit'.
139 def FindShape(self, pt):
140 for shape in self.shapes:
141 if shape.HitTest(pt):
142 return shape
143 return None
144
145 # Remove a shape from the display
146 def EraseShape(self, shape, dc):
147 r = shape.GetRect()
148 dc.SetClippingRect(r)
149 self.TileBackground(dc)
150 self.DrawShapes(dc)
151 dc.DestroyClippingRegion()
152
153 # Clears the background, then redraws it. If the DC is passed, then
154 # we only do so in the area so designated. Otherwise, it's the whole thing.
155 def OnEraseBackground(self, evt):
156 dc = evt.GetDC()
157
158 if not dc:
159 dc = wxClientDC(self)
160 rect = self.GetUpdateRegion().GetBox()
161 dc.SetClippingRect(rect)
162 self.TileBackground(dc)
163
164 # Fired whenever a paint event occurs
165 def OnPaint(self, evt):
166 dc = wx.PaintDC(self)
167 self.PrepareDC(dc)
168 self.DrawShapes(dc)
169
170 # Left mouse button is down.
171 def OnLeftDown(self, evt):
172 # Did the mouse go down on one of our shapes?
173 shape = self.FindShape(evt.GetPosition())
174
175 # If a shape was 'hit', then set that as the shape we're going to
176 # drag around. Get our start position. Dragging has not yet started.
177 # That will happen once the mouse moves, OR the mouse is released.
178 if shape:
179 self.dragShape = shape
180 self.dragStartPos = evt.GetPosition()
181
182 # Left mouse button up.
183 def OnLeftUp(self, evt):
184 if not self.dragImage or not self.dragShape:
185 self.dragImage = None
186 self.dragShape = None
187 return
188
189 # Hide the image, end dragging, and nuke out the drag image.
190 self.dragImage.Hide()
191 self.dragImage.EndDrag()
192 self.dragImage = None
193
194 dc = wx.ClientDC(self)
195
196 if self.hiliteShape:
197 self.hiliteShape.Draw(dc)
198 self.hiliteShape = None
199
200 # reposition and draw the shape
201
202 # Note by jmg 11/28/03
203 # Here's the original:
204 #
205 # self.dragShape.pos = self.dragShape.pos + evt.GetPosition() - self.dragStartPos
206 #
207 # So if there are any problems associated with this, use that as
208 # a starting place in your investigation. I've tried to simulate the
209 # wx.Point __add__ method here -- it won't work for tuples as we
210 # have now from the various methods
211 #
212 # There must be a better way to do this :-)
213 #
214
215 self.dragShape.pos = (
216 self.dragShape.pos[0] + evt.GetPosition()[0] - self.dragStartPos[0],
217 self.dragShape.pos[1] + evt.GetPosition()[1] - self.dragStartPos[1]
218 )
219
220 self.dragShape.shown = True
221 self.dragShape.Draw(dc)
222 self.dragShape = None
223
224 # The mouse is moving
225 def OnMotion(self, evt):
226 # Ignore mouse movement if we're not dragging.
227 if not self.dragShape or not evt.Dragging() or not evt.LeftIsDown():
228 return
229
230 # if we have a shape, but haven't started dragging yet
231 if self.dragShape and not self.dragImage:
232
233 # only start the drag after having moved a couple pixels
234 tolerance = 2
235 pt = evt.GetPosition()
236 dx = abs(pt.x - self.dragStartPos.x)
237 dy = abs(pt.y - self.dragStartPos.y)
238 if dx <= tolerance and dy <= tolerance:
239 return
240
241 # erase the shape since it will be drawn independently now
242 dc = wx.ClientDC(self)
243 self.dragShape.shown = False
244 self.EraseShape(self.dragShape, dc)
245
246
247 if self.dragShape.text:
248 self.dragImage = wx.DragString(self.dragShape.text,
249 wx.StockCursor(wx.CURSOR_HAND))
250 else:
251 self.dragImage = wx.DragImage(self.dragShape.bmp,
252 wx.StockCursor(wx.CURSOR_HAND))
253
254 hotspot = self.dragStartPos - self.dragShape.pos
255 self.dragImage.BeginDrag(hotspot, self, self.dragShape.fullscreen)
256
257 self.dragImage.Move(pt)
258 self.dragImage.Show()
259
260
261 # if we have shape and image then move it, posibly highlighting another shape.
262 elif self.dragShape and self.dragImage:
263 onShape = self.FindShape(evt.GetPosition())
264 unhiliteOld = False
265 hiliteNew = False
266
267 # figure out what to hilite and what to unhilite
268 if self.hiliteShape:
269 if onShape is None or self.hiliteShape is not onShape:
270 unhiliteOld = True
271
272 if onShape and onShape is not self.hiliteShape and onShape.shown:
273 hiliteNew = True
274
275 # if needed, hide the drag image so we can update the window
276 if unhiliteOld or hiliteNew:
277 self.dragImage.Hide()
278
279 if unhiliteOld:
280 dc = wx.ClientDC(self)
281 self.hiliteShape.Draw(dc)
282 self.hiliteShape = None
283
284 if hiliteNew:
285 dc = wx.ClientDC(self)
286 self.hiliteShape = onShape
287 self.hiliteShape.Draw(dc, wx.INVERT)
288
289 # now move it and show it again if needed
290 self.dragImage.Move(evt.GetPosition())
291 if unhiliteOld or hiliteNew:
292 self.dragImage.Show()
293
294
295 #----------------------------------------------------------------------
296
297 def runTest(frame, nb, log):
298
299 win = wx.Panel(nb, -1)
300 canvas = DragCanvas(win, -1)
301
302 def onSize(evt, panel=win, canvas=canvas):
303 canvas.SetSize(panel.GetSize())
304
305 win.Bind(wx.EVT_SIZE, onSize)
306 return win
307
308 #----------------------------------------------------------------------
309
310
311
312 overview = """\
313 DragImage is used when you wish to drag an object on the screen, and a simple
314 cursor is not enough.
315
316 On Windows, the WIN32 API is used to do achieve smooth dragging. On other
317 platforms, <code>GenericDragImage</code> is used. Applications may also prefer to use
318 <code>GenericDragImage</code> on Windows, too.
319
320 <b>wxPython note</b>: wxPython uses <code>GenericDragImage</code> on all
321 platforms, but uses the <code>DragImage</code> name.
322
323 To use this class, when you wish to start dragging an image, create a
324 <code>DragImage</code> object and store it somewhere you can access it as the
325 drag progresses. Call BeginDrag to start, and EndDrag to stop the drag. To move
326 the image, initially call Show and then Move. If you wish to update the screen
327 contents during the drag (for example, highlight an item as in the example), first
328 call Hide, update the screen, call Move, and then call Show.
329
330 You can drag within one window, or you can use full-screen dragging either across
331 the whole screen, or just restricted to one area of the screen to save resources.
332 If you want the user to drag between two windows, then you will need to use
333 full-screen dragging.
334
335 """
336
337
338 if __name__ == '__main__':
339 import sys,os
340 import run
341 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
342