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