]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/DragImage.py
copy the metadata file into the docs archive too
[wxWidgets.git] / wxPython / demo / DragImage.py
CommitLineData
f6bcfd97 1
8fa876ca
RD
2import wx
3import images
96bfd053 4
f6bcfd97
BP
5#----------------------------------------------------------------------
6
7class DragShape:
8 def __init__(self, bmp):
9 self.bmp = bmp
8fa876ca 10 self.pos = (0,0)
1e4a197e 11 self.shown = True
f6bcfd97 12 self.text = None
1e4a197e 13 self.fullscreen = False
f6bcfd97 14
f6bcfd97
BP
15 def HitTest(self, pt):
16 rect = self.GetRect()
1e4a197e 17 return rect.InsideXY(pt.x, pt.y)
f6bcfd97 18
f6bcfd97 19 def GetRect(self):
8fa876ca 20 return wx.Rect(self.pos[0], self.pos[1],
f6bcfd97
BP
21 self.bmp.GetWidth(), self.bmp.GetHeight())
22
8fa876ca 23 def Draw(self, dc, op = wx.COPY):
f6bcfd97 24 if self.bmp.Ok():
8fa876ca 25 memDC = wx.MemoryDC()
f6bcfd97
BP
26 memDC.SelectObject(self.bmp)
27
372bde9b 28 dc.Blit((self.pos[0], self.pos[1]),
fd3f2efe
RD
29 (self.bmp.GetWidth(), self.bmp.GetHeight()),
30 memDC, (0, 0), op, True)
f6bcfd97 31
1e4a197e 32 return True
f6bcfd97 33 else:
1e4a197e 34 return False
f6bcfd97
BP
35
36
37
38#----------------------------------------------------------------------
39
8fa876ca 40class DragCanvas(wx.ScrolledWindow):
f6bcfd97 41 def __init__(self, parent, ID):
8fa876ca 42 wx.ScrolledWindow.__init__(self, parent, ID)
f6bcfd97
BP
43 self.shapes = []
44 self.dragImage = None
45 self.dragShape = None
10e07c70 46 self.hiliteShape = None
f6bcfd97 47
8fa876ca 48 self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
96bfd053 49 self.bg_bmp = images.getBackgroundBitmap()
f6bcfd97 50
f6bcfd97
BP
51 # Make a shape from an image and mask. This one will demo
52 # dragging outside the window
96bfd053 53 bmp = images.getTestStarBitmap()
f6bcfd97 54 shape = DragShape(bmp)
8fa876ca 55 shape.pos = (5, 5)
1e4a197e 56 shape.fullscreen = True
f6bcfd97
BP
57 self.shapes.append(shape)
58
f6bcfd97
BP
59 # Make a shape from some text
60 text = "Some Text"
8fa876ca
RD
61 bg_colour = wx.Colour(57, 115, 57) # matches the bg image
62 font = wx.Font(15, wx.ROMAN, wx.NORMAL, wx.BOLD)
f6bcfd97 63 textExtent = self.GetFullTextExtent(text, font)
8fa876ca
RD
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()
f6bcfd97 70 dc.SelectObject(bmp)
8fa876ca 71 dc.SetBackground(wx.Brush(bg_colour, wx.SOLID))
f6bcfd97 72 dc.Clear()
8fa876ca 73 dc.SetTextForeground(wx.RED)
f6bcfd97 74 dc.SetFont(font)
fd3f2efe 75 dc.DrawText(text, (0, 0))
372bde9b
RD
76 dc.SelectObject(wx.NullBitmap)
77 mask = wx.MaskColour(bmp, bg_colour)
f6bcfd97
BP
78 bmp.SetMask(mask)
79 shape = DragShape(bmp)
8fa876ca 80 shape.pos = (5, 100)
f6bcfd97
BP
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
8fa876ca 87
96bfd053
RD
88 for card in ['_01c_', '_12h_', '_13d_', '_10s_']:
89 bmpFunc = getattr(images, "get%sBitmap" % card)
90 bmp = bmpFunc()
f6bcfd97 91 shape = DragShape(bmp)
8fa876ca 92 shape.pos = (x, 5)
f6bcfd97
BP
93 self.shapes.append(shape)
94 x = x + 80
95
96
8fa876ca
RD
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)
f6bcfd97 103
8fa876ca
RD
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.
d42e29c2
RD
108 def OnLeaveWindow(self, evt):
109 pass
110
f6bcfd97 111
8fa876ca 112 # tile the background bitmap
f6bcfd97 113 def TileBackground(self, dc):
f6bcfd97
BP
114 sz = self.GetClientSize()
115 w = self.bg_bmp.GetWidth()
116 h = self.bg_bmp.GetHeight()
117
118 x = 0
8fa876ca 119
f6bcfd97
BP
120 while x < sz.width:
121 y = 0
8fa876ca 122
f6bcfd97 123 while y < sz.height:
fd3f2efe 124 dc.DrawBitmap(self.bg_bmp, (x, y))
f6bcfd97 125 y = y + h
8fa876ca 126
f6bcfd97
BP
127 x = x + w
128
129
8fa876ca 130 # Go through our list of shapes and draw them in whatever place they are.
f6bcfd97
BP
131 def DrawShapes(self, dc):
132 for shape in self.shapes:
133 if shape.shown:
134 shape.Draw(dc)
135
8fa876ca
RD
136 # This is actually a sophisticated 'hit test', but in this
137 # case we're also determining which shape, if any, was 'hit'.
f6bcfd97
BP
138 def FindShape(self, pt):
139 for shape in self.shapes:
140 if shape.HitTest(pt):
141 return shape
142 return None
143
8fa876ca 144 # Remove a shape from the display
f6bcfd97
BP
145 def EraseShape(self, shape, dc):
146 r = shape.GetRect()
4da6d35e 147 dc.SetClippingRect(r)
f6bcfd97
BP
148 self.TileBackground(dc)
149 self.DrawShapes(dc)
150 dc.DestroyClippingRegion()
151
8fa876ca
RD
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.
f6bcfd97
BP
154 def OnEraseBackground(self, evt):
155 dc = evt.GetDC()
8fa876ca 156
f6bcfd97
BP
157 if not dc:
158 dc = wxClientDC(self)
b166c703 159 rect = self.GetUpdateRegion().GetBox()
4da6d35e 160 dc.SetClippingRect(rect)
f6bcfd97
BP
161 self.TileBackground(dc)
162
8fa876ca 163 # Fired whenever a paint event occurs
f6bcfd97 164 def OnPaint(self, evt):
8fa876ca 165 dc = wx.PaintDC(self)
f6bcfd97
BP
166 self.PrepareDC(dc)
167 self.DrawShapes(dc)
168
8fa876ca 169 # Left mouse button is down.
f6bcfd97 170 def OnLeftDown(self, evt):
8fa876ca 171 # Did the mouse go down on one of our shapes?
f6bcfd97 172 shape = self.FindShape(evt.GetPosition())
8fa876ca
RD
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.
f6bcfd97 177 if shape:
f6bcfd97
BP
178 self.dragShape = shape
179 self.dragStartPos = evt.GetPosition()
180
8fa876ca 181 # Left mouse button up.
f6bcfd97
BP
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
8fa876ca 188 # Hide the image, end dragging, and nuke out the drag image.
f6bcfd97
BP
189 self.dragImage.Hide()
190 self.dragImage.EndDrag()
191 self.dragImage = None
192
8fa876ca
RD
193 dc = wx.ClientDC(self)
194
10e07c70
RD
195 if self.hiliteShape:
196 self.hiliteShape.Draw(dc)
197 self.hiliteShape = None
198
199 # reposition and draw the shape
8fa876ca
RD
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
1e4a197e 219 self.dragShape.shown = True
f6bcfd97
BP
220 self.dragShape.Draw(dc)
221 self.dragShape = None
222
8fa876ca 223 # The mouse is moving
f6bcfd97 224 def OnMotion(self, evt):
8fa876ca 225 # Ignore mouse movement if we're not dragging.
f6bcfd97
BP
226 if not self.dragShape or not evt.Dragging() or not evt.LeftIsDown():
227 return
228
8b9a4190 229 # if we have a shape, but haven't started dragging yet
f6bcfd97
BP
230 if self.dragShape and not self.dragImage:
231
232 # only start the drag after having moved a couple pixels
10e07c70 233 tolerance = 2
f6bcfd97
BP
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
10e07c70 240 # erase the shape since it will be drawn independently now
8fa876ca 241 dc = wx.ClientDC(self)
1e4a197e 242 self.dragShape.shown = False
10e07c70
RD
243 self.EraseShape(self.dragShape, dc)
244
245
f6bcfd97 246 if self.dragShape.text:
8fa876ca
RD
247 self.dragImage = wx.DragString(self.dragShape.text,
248 wx.StockCursor(wx.CURSOR_HAND))
f6bcfd97 249 else:
8fa876ca
RD
250 self.dragImage = wx.DragImage(self.dragShape.bmp,
251 wx.StockCursor(wx.CURSOR_HAND))
f6bcfd97 252
10e07c70
RD
253 hotspot = self.dragStartPos - self.dragShape.pos
254 self.dragImage.BeginDrag(hotspot, self, self.dragShape.fullscreen)
f6bcfd97 255
10e07c70 256 self.dragImage.Move(pt)
f6bcfd97
BP
257 self.dragImage.Show()
258
259
10e07c70 260 # if we have shape and image then move it, posibly highlighting another shape.
f6bcfd97 261 elif self.dragShape and self.dragImage:
10e07c70 262 onShape = self.FindShape(evt.GetPosition())
1e4a197e
RD
263 unhiliteOld = False
264 hiliteNew = False
10e07c70
RD
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:
1e4a197e 269 unhiliteOld = True
10e07c70
RD
270
271 if onShape and onShape is not self.hiliteShape and onShape.shown:
1e4a197e 272 hiliteNew = True
10e07c70
RD
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:
8fa876ca 279 dc = wx.ClientDC(self)
10e07c70
RD
280 self.hiliteShape.Draw(dc)
281 self.hiliteShape = None
282
283 if hiliteNew:
8fa876ca 284 dc = wx.ClientDC(self)
10e07c70 285 self.hiliteShape = onShape
8fa876ca 286 self.hiliteShape.Draw(dc, wx.INVERT)
10e07c70
RD
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()
f6bcfd97
BP
292
293
294#----------------------------------------------------------------------
295
296def runTest(frame, nb, log):
8fa876ca
RD
297
298 win = wx.Panel(nb, -1)
70a357c2 299 canvas = DragCanvas(win, -1)
8fa876ca
RD
300
301 def onSize(evt, panel=win, canvas=canvas):
302 canvas.SetSize(panel.GetSize())
303
304 win.Bind(wx.EVT_SIZE, onSize)
f6bcfd97
BP
305 return win
306
307#----------------------------------------------------------------------
308
309
310
311overview = """\
8fa876ca
RD
312DragImage is used when you wish to drag an object on the screen, and a simple
313cursor is not enough.
314
315On Windows, the WIN32 API is used to do achieve smooth dragging. On other
316platforms, <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
320platforms, but uses the <code>DragImage</code> name.
321
322To 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
324drag progresses. Call BeginDrag to start, and EndDrag to stop the drag. To move
325the image, initially call Show and then Move. If you wish to update the screen
326contents during the drag (for example, highlight an item as in the example), first
327call Hide, update the screen, call Move, and then call Show.
328
329You can drag within one window, or you can use full-screen dragging either across
330the whole screen, or just restricted to one area of the screen to save resources.
331If you want the user to drag between two windows, then you will need to use
332full-screen dragging.
333
f6bcfd97 334"""
1e4a197e
RD
335
336
337if __name__ == '__main__':
338 import sys,os
339 import run
340 run.main(['', os.path.basename(sys.argv[0])])
341