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