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