]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/DragImage.py
Upport latest changes from 2_8 branch (print dialog
[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
3c69a2ec
RD
61 bmp = images.getTheKidBitmap()
62 shape = DragShape(bmp)
63 shape.pos = (200, 5)
64 self.shapes.append(shape)
65
f6bcfd97
BP
66 # Make a shape from some text
67 text = "Some Text"
8fa876ca
RD
68 bg_colour = wx.Colour(57, 115, 57) # matches the bg image
69 font = wx.Font(15, wx.ROMAN, wx.NORMAL, wx.BOLD)
f6bcfd97 70 textExtent = self.GetFullTextExtent(text, font)
8fa876ca
RD
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()
f6bcfd97 77 dc.SelectObject(bmp)
8fa876ca 78 dc.SetBackground(wx.Brush(bg_colour, wx.SOLID))
f6bcfd97 79 dc.Clear()
8fa876ca 80 dc.SetTextForeground(wx.RED)
f6bcfd97 81 dc.SetFont(font)
d7403ad2 82 dc.DrawText(text, 0, 0)
372bde9b 83 dc.SelectObject(wx.NullBitmap)
d7403ad2 84 mask = wx.Mask(bmp, bg_colour)
f6bcfd97
BP
85 bmp.SetMask(mask)
86 shape = DragShape(bmp)
8fa876ca 87 shape.pos = (5, 100)
f6bcfd97
BP
88 shape.text = "Some dragging text"
89 self.shapes.append(shape)
90
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
f6bcfd97 139
8fa876ca
RD
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.
f6bcfd97
BP
142 def OnEraseBackground(self, evt):
143 dc = evt.GetDC()
144 if not dc:
ce6b371d 145 dc = wx.ClientDC(self)
b166c703 146 rect = self.GetUpdateRegion().GetBox()
4da6d35e 147 dc.SetClippingRect(rect)
f6bcfd97
BP
148 self.TileBackground(dc)
149
8fa876ca 150 # Fired whenever a paint event occurs
f6bcfd97 151 def OnPaint(self, evt):
8fa876ca 152 dc = wx.PaintDC(self)
f6bcfd97
BP
153 self.PrepareDC(dc)
154 self.DrawShapes(dc)
155
8fa876ca 156 # Left mouse button is down.
f6bcfd97 157 def OnLeftDown(self, evt):
8fa876ca 158 # Did the mouse go down on one of our shapes?
f6bcfd97 159 shape = self.FindShape(evt.GetPosition())
8fa876ca
RD
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.
f6bcfd97 164 if shape:
f6bcfd97
BP
165 self.dragShape = shape
166 self.dragStartPos = evt.GetPosition()
167
8fa876ca 168 # Left mouse button up.
f6bcfd97
BP
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
8fa876ca 175 # Hide the image, end dragging, and nuke out the drag image.
f6bcfd97
BP
176 self.dragImage.Hide()
177 self.dragImage.EndDrag()
178 self.dragImage = None
179
10e07c70 180 if self.hiliteShape:
ce6b371d 181 self.RefreshRect(self.hiliteShape.GetRect())
10e07c70
RD
182 self.hiliteShape = None
183
184 # reposition and draw the shape
8fa876ca
RD
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
1e4a197e 204 self.dragShape.shown = True
ce6b371d 205 self.RefreshRect(self.dragShape.GetRect())
f6bcfd97
BP
206 self.dragShape = None
207
ce6b371d 208
8fa876ca 209 # The mouse is moving
f6bcfd97 210 def OnMotion(self, evt):
8fa876ca 211 # Ignore mouse movement if we're not dragging.
f6bcfd97
BP
212 if not self.dragShape or not evt.Dragging() or not evt.LeftIsDown():
213 return
214
8b9a4190 215 # if we have a shape, but haven't started dragging yet
f6bcfd97
BP
216 if self.dragShape and not self.dragImage:
217
218 # only start the drag after having moved a couple pixels
10e07c70 219 tolerance = 2
f6bcfd97
BP
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
0b0849b5
RD
226 # refresh the area of the window where the shape was so it
227 # will get erased.
1e4a197e 228 self.dragShape.shown = False
0b0849b5
RD
229 self.RefreshRect(self.dragShape.GetRect(), True)
230 self.Update()
10e07c70 231
f6bcfd97 232 if self.dragShape.text:
8fa876ca
RD
233 self.dragImage = wx.DragString(self.dragShape.text,
234 wx.StockCursor(wx.CURSOR_HAND))
f6bcfd97 235 else:
8fa876ca
RD
236 self.dragImage = wx.DragImage(self.dragShape.bmp,
237 wx.StockCursor(wx.CURSOR_HAND))
f6bcfd97 238
10e07c70
RD
239 hotspot = self.dragStartPos - self.dragShape.pos
240 self.dragImage.BeginDrag(hotspot, self, self.dragShape.fullscreen)
f6bcfd97 241
10e07c70 242 self.dragImage.Move(pt)
f6bcfd97
BP
243 self.dragImage.Show()
244
245
10e07c70 246 # if we have shape and image then move it, posibly highlighting another shape.
f6bcfd97 247 elif self.dragShape and self.dragImage:
10e07c70 248 onShape = self.FindShape(evt.GetPosition())
1e4a197e
RD
249 unhiliteOld = False
250 hiliteNew = False
10e07c70
RD
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:
1e4a197e 255 unhiliteOld = True
10e07c70
RD
256
257 if onShape and onShape is not self.hiliteShape and onShape.shown:
1e4a197e 258 hiliteNew = True
10e07c70
RD
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:
8fa876ca 265 dc = wx.ClientDC(self)
10e07c70
RD
266 self.hiliteShape.Draw(dc)
267 self.hiliteShape = None
268
269 if hiliteNew:
8fa876ca 270 dc = wx.ClientDC(self)
10e07c70 271 self.hiliteShape = onShape
8fa876ca 272 self.hiliteShape.Draw(dc, wx.INVERT)
10e07c70
RD
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()
f6bcfd97
BP
278
279
280#----------------------------------------------------------------------
281
282def runTest(frame, nb, log):
8fa876ca
RD
283
284 win = wx.Panel(nb, -1)
70a357c2 285 canvas = DragCanvas(win, -1)
8fa876ca
RD
286
287 def onSize(evt, panel=win, canvas=canvas):
288 canvas.SetSize(panel.GetSize())
289
290 win.Bind(wx.EVT_SIZE, onSize)
f6bcfd97
BP
291 return win
292
293#----------------------------------------------------------------------
294
295
296
297overview = """\
8fa876ca
RD
298DragImage is used when you wish to drag an object on the screen, and a simple
299cursor is not enough.
300
301On Windows, the WIN32 API is used to do achieve smooth dragging. On other
302platforms, <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
306platforms, but uses the <code>DragImage</code> name.
307
308To 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
310drag progresses. Call BeginDrag to start, and EndDrag to stop the drag. To move
311the image, initially call Show and then Move. If you wish to update the screen
312contents during the drag (for example, highlight an item as in the example), first
313call Hide, update the screen, call Move, and then call Show.
314
315You can drag within one window, or you can use full-screen dragging either across
316the whole screen, or just restricted to one area of the screen to save resources.
317If you want the user to drag between two windows, then you will need to use
318full-screen dragging.
319
f6bcfd97 320"""
1e4a197e
RD
321
322
323if __name__ == '__main__':
324 import sys,os
325 import run
8eca4fef 326 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
1e4a197e 327