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