]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/DragImage.py
better handling of empty MDI parent frame visibility: show it only when there are...
[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()
6c75a4cf 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
6c75a4cf
RD
86 bmp = images.getTheKidBitmap()
87 shape = DragShape(bmp)
88 shape.pos = (200, 5)
89 self.shapes.append(shape)
f6bcfd97 90
8fa876ca
RD
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)
f6bcfd97 97
8fa876ca
RD
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.
d42e29c2
RD
102 def OnLeaveWindow(self, evt):
103 pass
104
f6bcfd97 105
8fa876ca 106 # tile the background bitmap
f6bcfd97 107 def TileBackground(self, dc):
f6bcfd97
BP
108 sz = self.GetClientSize()
109 w = self.bg_bmp.GetWidth()
110 h = self.bg_bmp.GetHeight()
111
112 x = 0
8fa876ca 113
f6bcfd97
BP
114 while x < sz.width:
115 y = 0
8fa876ca 116
f6bcfd97 117 while y < sz.height:
d7403ad2 118 dc.DrawBitmap(self.bg_bmp, x, y)
f6bcfd97 119 y = y + h
8fa876ca 120
f6bcfd97
BP
121 x = x + w
122
123
8fa876ca 124 # Go through our list of shapes and draw them in whatever place they are.
f6bcfd97
BP
125 def DrawShapes(self, dc):
126 for shape in self.shapes:
127 if shape.shown:
128 shape.Draw(dc)
129
8fa876ca
RD
130 # This is actually a sophisticated 'hit test', but in this
131 # case we're also determining which shape, if any, was 'hit'.
f6bcfd97
BP
132 def FindShape(self, pt):
133 for shape in self.shapes:
134 if shape.HitTest(pt):
135 return shape
136 return None
137
8fa876ca 138 # Remove a shape from the display
f6bcfd97
BP
139 def EraseShape(self, shape, dc):
140 r = shape.GetRect()
4da6d35e 141 dc.SetClippingRect(r)
f6bcfd97
BP
142 self.TileBackground(dc)
143 self.DrawShapes(dc)
144 dc.DestroyClippingRegion()
145
8fa876ca
RD
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.
f6bcfd97
BP
148 def OnEraseBackground(self, evt):
149 dc = evt.GetDC()
8fa876ca 150
f6bcfd97
BP
151 if not dc:
152 dc = wxClientDC(self)
b166c703 153 rect = self.GetUpdateRegion().GetBox()
4da6d35e 154 dc.SetClippingRect(rect)
f6bcfd97
BP
155 self.TileBackground(dc)
156
8fa876ca 157 # Fired whenever a paint event occurs
f6bcfd97 158 def OnPaint(self, evt):
8fa876ca 159 dc = wx.PaintDC(self)
f6bcfd97
BP
160 self.PrepareDC(dc)
161 self.DrawShapes(dc)
162
8fa876ca 163 # Left mouse button is down.
f6bcfd97 164 def OnLeftDown(self, evt):
8fa876ca 165 # Did the mouse go down on one of our shapes?
f6bcfd97 166 shape = self.FindShape(evt.GetPosition())
8fa876ca
RD
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.
f6bcfd97 171 if shape:
f6bcfd97
BP
172 self.dragShape = shape
173 self.dragStartPos = evt.GetPosition()
174
8fa876ca 175 # Left mouse button up.
f6bcfd97
BP
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
8fa876ca 182 # Hide the image, end dragging, and nuke out the drag image.
f6bcfd97
BP
183 self.dragImage.Hide()
184 self.dragImage.EndDrag()
185 self.dragImage = None
186
8fa876ca
RD
187 dc = wx.ClientDC(self)
188
10e07c70
RD
189 if self.hiliteShape:
190 self.hiliteShape.Draw(dc)
191 self.hiliteShape = None
192
193 # reposition and draw the shape
8fa876ca
RD
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
1e4a197e 213 self.dragShape.shown = True
f6bcfd97
BP
214 self.dragShape.Draw(dc)
215 self.dragShape = None
216
8fa876ca 217 # The mouse is moving
f6bcfd97 218 def OnMotion(self, evt):
8fa876ca 219 # Ignore mouse movement if we're not dragging.
f6bcfd97
BP
220 if not self.dragShape or not evt.Dragging() or not evt.LeftIsDown():
221 return
222
8b9a4190 223 # if we have a shape, but haven't started dragging yet
f6bcfd97
BP
224 if self.dragShape and not self.dragImage:
225
226 # only start the drag after having moved a couple pixels
10e07c70 227 tolerance = 2
f6bcfd97
BP
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
10e07c70 234 # erase the shape since it will be drawn independently now
8fa876ca 235 dc = wx.ClientDC(self)
1e4a197e 236 self.dragShape.shown = False
10e07c70
RD
237 self.EraseShape(self.dragShape, dc)
238
239
f6bcfd97 240 if self.dragShape.text:
8fa876ca
RD
241 self.dragImage = wx.DragString(self.dragShape.text,
242 wx.StockCursor(wx.CURSOR_HAND))
f6bcfd97 243 else:
8fa876ca
RD
244 self.dragImage = wx.DragImage(self.dragShape.bmp,
245 wx.StockCursor(wx.CURSOR_HAND))
f6bcfd97 246
10e07c70
RD
247 hotspot = self.dragStartPos - self.dragShape.pos
248 self.dragImage.BeginDrag(hotspot, self, self.dragShape.fullscreen)
f6bcfd97 249
10e07c70 250 self.dragImage.Move(pt)
f6bcfd97
BP
251 self.dragImage.Show()
252
253
10e07c70 254 # if we have shape and image then move it, posibly highlighting another shape.
f6bcfd97 255 elif self.dragShape and self.dragImage:
10e07c70 256 onShape = self.FindShape(evt.GetPosition())
1e4a197e
RD
257 unhiliteOld = False
258 hiliteNew = False
10e07c70
RD
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:
1e4a197e 263 unhiliteOld = True
10e07c70
RD
264
265 if onShape and onShape is not self.hiliteShape and onShape.shown:
1e4a197e 266 hiliteNew = True
10e07c70
RD
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:
8fa876ca 273 dc = wx.ClientDC(self)
10e07c70
RD
274 self.hiliteShape.Draw(dc)
275 self.hiliteShape = None
276
277 if hiliteNew:
8fa876ca 278 dc = wx.ClientDC(self)
10e07c70 279 self.hiliteShape = onShape
8fa876ca 280 self.hiliteShape.Draw(dc, wx.INVERT)
10e07c70
RD
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()
f6bcfd97
BP
286
287
288#----------------------------------------------------------------------
289
290def runTest(frame, nb, log):
8fa876ca
RD
291
292 win = wx.Panel(nb, -1)
70a357c2 293 canvas = DragCanvas(win, -1)
8fa876ca
RD
294
295 def onSize(evt, panel=win, canvas=canvas):
296 canvas.SetSize(panel.GetSize())
297
298 win.Bind(wx.EVT_SIZE, onSize)
f6bcfd97
BP
299 return win
300
301#----------------------------------------------------------------------
302
303
304
305overview = """\
8fa876ca
RD
306DragImage is used when you wish to drag an object on the screen, and a simple
307cursor is not enough.
308
309On Windows, the WIN32 API is used to do achieve smooth dragging. On other
310platforms, <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
314platforms, but uses the <code>DragImage</code> name.
315
316To 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
318drag progresses. Call BeginDrag to start, and EndDrag to stop the drag. To move
319the image, initially call Show and then Move. If you wish to update the screen
320contents during the drag (for example, highlight an item as in the example), first
321call Hide, update the screen, call Move, and then call Show.
322
323You can drag within one window, or you can use full-screen dragging either across
324the whole screen, or just restricted to one area of the screen to save resources.
325If you want the user to drag between two windows, then you will need to use
326full-screen dragging.
327
f6bcfd97 328"""
1e4a197e
RD
329
330
331if __name__ == '__main__':
332 import sys,os
333 import run
8eca4fef 334 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
1e4a197e 335