]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/DragImage.py
fixed wxVsnprintf() to write as much as it can if the output buffer is too short
[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 bmp = images.getTheKidBitmap()
62 shape = DragShape(bmp)
63 shape.pos = (200, 5)
64 self.shapes.append(shape)
65
66 # Make a shape from some text
67 text = "Some Text"
68 bg_colour = wx.Colour(57, 115, 57) # matches the bg image
69 font = wx.Font(15, wx.ROMAN, wx.NORMAL, wx.BOLD)
70 textExtent = self.GetFullTextExtent(text, font)
71
72 # create a bitmap the same size as our text
73 bmp = wx.EmptyBitmap(textExtent[0], textExtent[1])
74
75 # 'draw' the text onto the bitmap
76 dc = wx.MemoryDC()
77 dc.SelectObject(bmp)
78 dc.SetBackground(wx.Brush(bg_colour, wx.SOLID))
79 dc.Clear()
80 dc.SetTextForeground(wx.RED)
81 dc.SetFont(font)
82 dc.DrawText(text, 0, 0)
83 dc.SelectObject(wx.NullBitmap)
84 mask = wx.Mask(bmp, bg_colour)
85 bmp.SetMask(mask)
86 shape = DragShape(bmp)
87 shape.pos = (5, 100)
88 shape.text = "Some dragging text"
89 self.shapes.append(shape)
90
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
140 # Clears the background, then redraws it. If the DC is passed, then
141 # we only do so in the area so designated. Otherwise, it's the whole thing.
142 def OnEraseBackground(self, evt):
143 dc = evt.GetDC()
144 if not dc:
145 dc = wx.ClientDC(self)
146 rect = self.GetUpdateRegion().GetBox()
147 dc.SetClippingRect(rect)
148 self.TileBackground(dc)
149
150 # Fired whenever a paint event occurs
151 def OnPaint(self, evt):
152 dc = wx.PaintDC(self)
153 self.PrepareDC(dc)
154 self.DrawShapes(dc)
155
156 # Left mouse button is down.
157 def OnLeftDown(self, evt):
158 # Did the mouse go down on one of our shapes?
159 shape = self.FindShape(evt.GetPosition())
160
161 # If a shape was 'hit', then set that as the shape we're going to
162 # drag around. Get our start position. Dragging has not yet started.
163 # That will happen once the mouse moves, OR the mouse is released.
164 if shape:
165 self.dragShape = shape
166 self.dragStartPos = evt.GetPosition()
167
168 # Left mouse button up.
169 def OnLeftUp(self, evt):
170 if not self.dragImage or not self.dragShape:
171 self.dragImage = None
172 self.dragShape = None
173 return
174
175 # Hide the image, end dragging, and nuke out the drag image.
176 self.dragImage.Hide()
177 self.dragImage.EndDrag()
178 self.dragImage = None
179
180 if self.hiliteShape:
181 self.RefreshRect(self.hiliteShape.GetRect())
182 self.hiliteShape = None
183
184 # reposition and draw the shape
185
186 # Note by jmg 11/28/03
187 # Here's the original:
188 #
189 # self.dragShape.pos = self.dragShape.pos + evt.GetPosition() - self.dragStartPos
190 #
191 # So if there are any problems associated with this, use that as
192 # a starting place in your investigation. I've tried to simulate the
193 # wx.Point __add__ method here -- it won't work for tuples as we
194 # have now from the various methods
195 #
196 # There must be a better way to do this :-)
197 #
198
199 self.dragShape.pos = (
200 self.dragShape.pos[0] + evt.GetPosition()[0] - self.dragStartPos[0],
201 self.dragShape.pos[1] + evt.GetPosition()[1] - self.dragStartPos[1]
202 )
203
204 self.dragShape.shown = True
205 self.RefreshRect(self.dragShape.GetRect())
206 self.dragShape = None
207
208
209 # The mouse is moving
210 def OnMotion(self, evt):
211 # Ignore mouse movement if we're not dragging.
212 if not self.dragShape or not evt.Dragging() or not evt.LeftIsDown():
213 return
214
215 # if we have a shape, but haven't started dragging yet
216 if self.dragShape and not self.dragImage:
217
218 # only start the drag after having moved a couple pixels
219 tolerance = 2
220 pt = evt.GetPosition()
221 dx = abs(pt.x - self.dragStartPos.x)
222 dy = abs(pt.y - self.dragStartPos.y)
223 if dx <= tolerance and dy <= tolerance:
224 return
225
226 # refresh the area of the window where the shape was so it
227 # will get erased.
228 self.dragShape.shown = False
229 self.RefreshRect(self.dragShape.GetRect(), True)
230 self.Update()
231
232 if self.dragShape.text:
233 self.dragImage = wx.DragString(self.dragShape.text,
234 wx.StockCursor(wx.CURSOR_HAND))
235 else:
236 self.dragImage = wx.DragImage(self.dragShape.bmp,
237 wx.StockCursor(wx.CURSOR_HAND))
238
239 hotspot = self.dragStartPos - self.dragShape.pos
240 self.dragImage.BeginDrag(hotspot, self, self.dragShape.fullscreen)
241
242 self.dragImage.Move(pt)
243 self.dragImage.Show()
244
245
246 # if we have shape and image then move it, posibly highlighting another shape.
247 elif self.dragShape and self.dragImage:
248 onShape = self.FindShape(evt.GetPosition())
249 unhiliteOld = False
250 hiliteNew = False
251
252 # figure out what to hilite and what to unhilite
253 if self.hiliteShape:
254 if onShape is None or self.hiliteShape is not onShape:
255 unhiliteOld = True
256
257 if onShape and onShape is not self.hiliteShape and onShape.shown:
258 hiliteNew = True
259
260 # if needed, hide the drag image so we can update the window
261 if unhiliteOld or hiliteNew:
262 self.dragImage.Hide()
263
264 if unhiliteOld:
265 dc = wx.ClientDC(self)
266 self.hiliteShape.Draw(dc)
267 self.hiliteShape = None
268
269 if hiliteNew:
270 dc = wx.ClientDC(self)
271 self.hiliteShape = onShape
272 self.hiliteShape.Draw(dc, wx.INVERT)
273
274 # now move it and show it again if needed
275 self.dragImage.Move(evt.GetPosition())
276 if unhiliteOld or hiliteNew:
277 self.dragImage.Show()
278
279
280 #----------------------------------------------------------------------
281
282 def runTest(frame, nb, log):
283
284 win = wx.Panel(nb, -1)
285 canvas = DragCanvas(win, -1)
286
287 def onSize(evt, panel=win, canvas=canvas):
288 canvas.SetSize(panel.GetSize())
289
290 win.Bind(wx.EVT_SIZE, onSize)
291 return win
292
293 #----------------------------------------------------------------------
294
295
296
297 overview = """\
298 DragImage is used when you wish to drag an object on the screen, and a simple
299 cursor is not enough.
300
301 On Windows, the WIN32 API is used to do achieve smooth dragging. On other
302 platforms, <code>GenericDragImage</code> is used. Applications may also prefer to use
303 <code>GenericDragImage</code> on Windows, too.
304
305 <b>wxPython note</b>: wxPython uses <code>GenericDragImage</code> on all
306 platforms, but uses the <code>DragImage</code> name.
307
308 To use this class, when you wish to start dragging an image, create a
309 <code>DragImage</code> object and store it somewhere you can access it as the
310 drag progresses. Call BeginDrag to start, and EndDrag to stop the drag. To move
311 the image, initially call Show and then Move. If you wish to update the screen
312 contents during the drag (for example, highlight an item as in the example), first
313 call Hide, update the screen, call Move, and then call Show.
314
315 You can drag within one window, or you can use full-screen dragging either across
316 the whole screen, or just restricted to one area of the screen to save resources.
317 If you want the user to drag between two windows, then you will need to use
318 full-screen dragging.
319
320 """
321
322
323 if __name__ == '__main__':
324 import sys,os
325 import run
326 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
327