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