]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/DragImage.py
Committing in .
[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 self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
51
52 # Make a shape from an image and mask. This one will demo
53 # dragging outside the window
54 bmp = images.getTestStarBitmap()
55 #bmp = wx.Bitmap('bitmaps/toucan.png')
56 shape = DragShape(bmp)
57 shape.pos = (5, 5)
58 shape.fullscreen = True
59 self.shapes.append(shape)
60
61 # Make a shape from some text
62 text = "Some Text"
63 bg_colour = wx.Colour(57, 115, 57) # matches the bg image
64 font = wx.Font(15, wx.ROMAN, wx.NORMAL, wx.BOLD)
65 textExtent = self.GetFullTextExtent(text, font)
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()
72 dc.SelectObject(bmp)
73 dc.SetBackground(wx.Brush(bg_colour, wx.SOLID))
74 dc.Clear()
75 dc.SetTextForeground(wx.RED)
76 dc.SetFont(font)
77 dc.DrawText(text, 0, 0)
78 dc.SelectObject(wx.NullBitmap)
79 mask = wx.Mask(bmp, bg_colour)
80 bmp.SetMask(mask)
81 shape = DragShape(bmp)
82 shape.pos = (5, 100)
83 shape.text = "Some dragging text"
84 self.shapes.append(shape)
85
86
87 bmp = images.getTheKidBitmap()
88 shape = DragShape(bmp)
89 shape.pos = (200, 5)
90 self.shapes.append(shape)
91
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)
98
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.
103 def OnLeaveWindow(self, evt):
104 pass
105
106
107 # tile the background bitmap
108 def TileBackground(self, dc):
109 sz = self.GetClientSize()
110 w = self.bg_bmp.GetWidth()
111 h = self.bg_bmp.GetHeight()
112
113 x = 0
114
115 while x < sz.width:
116 y = 0
117
118 while y < sz.height:
119 dc.DrawBitmap(self.bg_bmp, x, y)
120 y = y + h
121
122 x = x + w
123
124
125 # Go through our list of shapes and draw them in whatever place they are.
126 def DrawShapes(self, dc):
127 for shape in self.shapes:
128 if shape.shown:
129 shape.Draw(dc)
130
131 # This is actually a sophisticated 'hit test', but in this
132 # case we're also determining which shape, if any, was 'hit'.
133 def FindShape(self, pt):
134 for shape in self.shapes:
135 if shape.HitTest(pt):
136 return shape
137 return None
138
139 # Remove a shape from the display
140 def EraseShape(self, shape, dc):
141 r = shape.GetRect()
142 dc.SetClippingRect(r)
143 self.TileBackground(dc)
144 self.DrawShapes(dc)
145 dc.DestroyClippingRegion()
146
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.
149 def OnEraseBackground(self, evt):
150 dc = evt.GetDC()
151
152 if not dc:
153 dc = wxClientDC(self)
154 rect = self.GetUpdateRegion().GetBox()
155 dc.SetClippingRect(rect)
156 self.TileBackground(dc)
157
158 # Fired whenever a paint event occurs
159 def OnPaint(self, evt):
160 dc = wx.PaintDC(self)
161 self.PrepareDC(dc)
162 self.DrawShapes(dc)
163
164 # Left mouse button is down.
165 def OnLeftDown(self, evt):
166 # Did the mouse go down on one of our shapes?
167 shape = self.FindShape(evt.GetPosition())
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.
172 if shape:
173 self.dragShape = shape
174 self.dragStartPos = evt.GetPosition()
175
176 # Left mouse button up.
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
183 # Hide the image, end dragging, and nuke out the drag image.
184 self.dragImage.Hide()
185 self.dragImage.EndDrag()
186 self.dragImage = None
187
188 dc = wx.ClientDC(self)
189
190 if self.hiliteShape:
191 self.hiliteShape.Draw(dc)
192 self.hiliteShape = None
193
194 # reposition and draw the shape
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
214 self.dragShape.shown = True
215 self.dragShape.Draw(dc)
216 self.dragShape = None
217
218 # The mouse is moving
219 def OnMotion(self, evt):
220 # Ignore mouse movement if we're not dragging.
221 if not self.dragShape or not evt.Dragging() or not evt.LeftIsDown():
222 return
223
224 # if we have a shape, but haven't started dragging yet
225 if self.dragShape and not self.dragImage:
226
227 # only start the drag after having moved a couple pixels
228 tolerance = 2
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
235 # erase the shape since it will be drawn independently now
236 dc = wx.ClientDC(self)
237 self.dragShape.shown = False
238 self.EraseShape(self.dragShape, dc)
239
240
241 if self.dragShape.text:
242 self.dragImage = wx.DragString(self.dragShape.text,
243 wx.StockCursor(wx.CURSOR_HAND))
244 else:
245 self.dragImage = wx.DragImage(self.dragShape.bmp,
246 wx.StockCursor(wx.CURSOR_HAND))
247
248 hotspot = self.dragStartPos - self.dragShape.pos
249 self.dragImage.BeginDrag(hotspot, self, self.dragShape.fullscreen)
250
251 self.dragImage.Move(pt)
252 self.dragImage.Show()
253
254
255 # if we have shape and image then move it, posibly highlighting another shape.
256 elif self.dragShape and self.dragImage:
257 onShape = self.FindShape(evt.GetPosition())
258 unhiliteOld = False
259 hiliteNew = False
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:
264 unhiliteOld = True
265
266 if onShape and onShape is not self.hiliteShape and onShape.shown:
267 hiliteNew = True
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:
274 dc = wx.ClientDC(self)
275 self.hiliteShape.Draw(dc)
276 self.hiliteShape = None
277
278 if hiliteNew:
279 dc = wx.ClientDC(self)
280 self.hiliteShape = onShape
281 self.hiliteShape.Draw(dc, wx.INVERT)
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()
287
288
289 #----------------------------------------------------------------------
290
291 def runTest(frame, nb, log):
292
293 win = wx.Panel(nb, -1)
294 canvas = DragCanvas(win, -1)
295
296 def onSize(evt, panel=win, canvas=canvas):
297 canvas.SetSize(panel.GetSize())
298
299 win.Bind(wx.EVT_SIZE, onSize)
300 return win
301
302 #----------------------------------------------------------------------
303
304
305
306 overview = """\
307 DragImage is used when you wish to drag an object on the screen, and a simple
308 cursor is not enough.
309
310 On Windows, the WIN32 API is used to do achieve smooth dragging. On other
311 platforms, <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
315 platforms, but uses the <code>DragImage</code> name.
316
317 To 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
319 drag progresses. Call BeginDrag to start, and EndDrag to stop the drag. To move
320 the image, initially call Show and then Move. If you wish to update the screen
321 contents during the drag (for example, highlight an item as in the example), first
322 call Hide, update the screen, call Move, and then call Show.
323
324 You can drag within one window, or you can use full-screen dragging either across
325 the whole screen, or just restricted to one area of the screen to save resources.
326 If you want the user to drag between two windows, then you will need to use
327 full-screen dragging.
328
329 """
330
331
332 if __name__ == '__main__':
333 import sys,os
334 import run
335 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
336