]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/PseudoDC.py
workaround sizing bug on Mac
[wxWidgets.git] / wxPython / demo / PseudoDC.py
1
2 import wx
3 import images
4 import random
5
6 #---------------------------------------------------------------------------
7
8 W = 1000
9 H = 1000
10 SW = 150
11 SH = 150
12 SHAPE_COUNT = 100
13 MOVING_COUNT = 10
14
15 #---------------------------------------------------------------------------
16
17 colours = [
18 "BLACK",
19 "BLUE",
20 "BLUE VIOLET",
21 "BROWN",
22 "CYAN",
23 "DARK GREY",
24 "DARK GREEN",
25 "GOLD",
26 "GREY",
27 "GREEN",
28 "MAGENTA",
29 "NAVY",
30 "PINK",
31 "RED",
32 "SKY BLUE",
33 "VIOLET",
34 "YELLOW",
35 ]
36
37
38
39 class MyCanvas(wx.ScrolledWindow):
40 def __init__(self, parent, id, log, size = wx.DefaultSize):
41 wx.ScrolledWindow.__init__(self, parent, id, (0, 0), size=size, style=wx.SUNKEN_BORDER)
42
43 self.lines = []
44 self.maxWidth = W
45 self.maxHeight = H
46 self.x = self.y = 0
47 self.curLine = []
48 self.drawing = False
49
50 self.SetBackgroundColour("WHITE")
51 bmp = images.getTest2Bitmap()
52 mask = wx.Mask(bmp, wx.BLUE)
53 bmp.SetMask(mask)
54 self.bmp = bmp
55
56 self.SetVirtualSize((self.maxWidth, self.maxHeight))
57 self.SetScrollRate(20,20)
58
59 # create a PseudoDC to record our drawing
60 self.pdc = wx.PseudoDC()
61 self.pen_cache = {}
62 self.brush_cache = {}
63 self.DoDrawing(self.pdc)
64 log.write('Created PseudoDC draw list with %d operations!'%self.pdc.GetLen())
65
66 self.Bind(wx.EVT_PAINT, self.OnPaint)
67 self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
68
69 # use timer to move one of the objects around
70 self.timer = wx.Timer()
71 self.timer.SetOwner(self)
72 self.Bind(wx.EVT_TIMER, self.OnTimer)
73 self.timer.Start(50)
74 self.movingids = random.sample(self.objids, MOVING_COUNT)
75 self.velocitydict = {}
76 for id in self.movingids:
77 vx = random.randint(1,5) * random.choice([-1,1])
78 vy = random.randint(1,5) * random.choice([-1,1])
79 self.velocitydict[id] = (vx,vy)
80
81 def OnTimer(self, event):
82 # get the current position
83 xv, yv = self.GetViewStart()
84 dx, dy = self.GetScrollPixelsPerUnit()
85 x, y = (xv * dx, yv * dy)
86 w, h = self.GetClientSizeTuple()
87 clip = wx.Rect(x,y,w,h)
88 refreshed = False
89 for id in self.movingids:
90 r = self.pdc.GetIdBounds(id)
91 # get new object position
92 (vx,vy) = self.velocitydict[id]
93 x = r.x + vx
94 y = r.y + vy
95 # check for bounce
96 if x < 0:
97 x = -x
98 vx = -vx
99 if x >= W:
100 x = W - (x - W)
101 vx = -vx
102 if y < 0:
103 y = -y
104 vy = -vy
105 if y >= H:
106 y = H - (y - H)
107 vy = -vy
108 self.velocitydict[id] = (vx,vy)
109 # get change
110 dx = x - r.x
111 dy = y - r.y
112 # translate the object
113 self.pdc.TranslateId(id, dx, dy)
114 # redraw
115 r.x -= 20
116 if dx < 0:
117 r.x = x
118 r.y -= 20
119 if dy < 0:
120 r.y = y
121 r.width += abs(dx) + 40
122 r.height += abs(dy) + 40
123 if r.Intersects(clip):
124 r.x -= clip.x
125 r.y -= clip.y
126 refreshed = True
127 self.RefreshRect(r, False)
128
129 def RandomPen(self):
130 c = random.choice(colours)
131 t = random.randint(1, 4)
132 if not self.pen_cache.has_key( (c, t) ):
133 self.pen_cache[(c, t)] = wx.Pen(c, t)
134 return self.pen_cache[(c, t)]
135
136
137 def RandomBrush(self):
138 c = random.choice(colours)
139 if not self.brush_cache.has_key(c):
140 self.brush_cache[c] = wx.Brush(c)
141
142 return self.brush_cache[c]
143
144 def RandomColor(self):
145 return random.choice(colours)
146
147
148 def OnPaint(self, event):
149 # Create a buffered paint DC. It will create the real
150 # wx.PaintDC and then blit the bitmap to it when dc is
151 # deleted.
152 dc = wx.BufferedPaintDC(self)
153 # we need to clear the dc BEFORE calling PrepareDC
154 bg = wx.Brush(self.GetBackgroundColour())
155 dc.SetBackground(bg)
156 dc.Clear()
157 # use PrepateDC to set position correctly
158 self.PrepareDC(dc)
159 # create a clipping rect from our position and size
160 # and the Update Region
161 xv, yv = self.GetViewStart()
162 dx, dy = self.GetScrollPixelsPerUnit()
163 x, y = (xv * dx, yv * dy)
164 rgn = self.GetUpdateRegion()
165 rgn.Offset(x,y)
166 r = rgn.GetBox()
167 # draw to the dc using the calculated clipping rect
168 self.pdc.DrawToDCClipped(dc,r)
169
170 def DoDrawing(self, dc):
171 random.seed()
172 self.objids = []
173 self.boundsdict = {}
174 dc.BeginDrawing()
175 for i in range(SHAPE_COUNT):
176 id = wx.NewId()
177 dc.SetId(id)
178 choice = random.randint(0,8)
179 if choice in (0,1):
180 x = random.randint(0, W)
181 y = random.randint(0, H)
182 dc.SetPen(self.RandomPen())
183 dc.DrawPoint(x,y)
184 dc.SetIdBounds(id,wx.Rect(x,y,1,1))
185 elif choice in (2,3):
186 x1 = random.randint(0, W-SW)
187 y1 = random.randint(0, H-SH)
188 x2 = random.randint(x1, x1+SW)
189 y2 = random.randint(y1, y1+SH)
190 dc.SetPen(self.RandomPen())
191 dc.DrawLine(x1,y1,x2,y2)
192 dc.SetIdBounds(id,wx.Rect(x1,y1,x2-x1,y2-y1))
193 elif choice in (4,5):
194 w = random.randint(10, SW)
195 h = random.randint(10, SH)
196 x = random.randint(0, W - w)
197 y = random.randint(0, H - h)
198 dc.SetPen(self.RandomPen())
199 dc.SetBrush(self.RandomBrush())
200 dc.DrawRectangle(x,y,w,h)
201 dc.SetIdBounds(id,wx.Rect(x,y,w,h))
202 self.objids.append(id)
203 elif choice == 6:
204 Np = 8 # number of characters in text
205 word = []
206 for i in range(Np):
207 c = chr( random.randint(48, 122) )
208 word.append( c )
209 word = "".join(word)
210 w,h = self.GetFullTextExtent(word)[0:2]
211 x = random.randint(0, W-w)
212 y = random.randint(0, H-h)
213 dc.SetTextForeground(self.RandomColor())
214 dc.SetTextBackground(self.RandomColor())
215 dc.DrawText(word, x, y)
216 dc.SetIdBounds(id,wx.Rect(x,y,w,h))
217 self.objids.append(id)
218 elif choice == 7:
219 Np = 8 # number of points per polygon
220 poly = []
221 minx = SW
222 miny = SH
223 maxx = 0
224 maxy = 0
225 for i in range(Np):
226 x = random.randint(0, SW)
227 y = random.randint(0, SH)
228 if x < minx: minx = x
229 if x > maxx: maxx = x
230 if y < miny: miny = y
231 if y > maxy: maxy = y
232 poly.append(wx.Point(x,y))
233 x = random.randint(0, W-SW)
234 y = random.randint(0, H-SH)
235 dc.SetPen(self.RandomPen())
236 dc.SetBrush(self.RandomBrush())
237 dc.DrawPolygon(poly, x,y)
238 dc.SetIdBounds(id,wx.Rect(minx+x,miny+y,maxx-minx+x,maxy-miny+y))
239 self.objids.append(id)
240 elif choice == 8:
241 w,h = self.bmp.GetSize()
242 x = random.randint(0, W-w)
243 y = random.randint(0, H-h)
244 dc.DrawBitmap(self.bmp,x,y,True)
245 dc.SetIdBounds(id,wx.Rect(x,y,w,h))
246 self.objids.append(id)
247 dc.EndDrawing()
248
249 def ShutdownDemo(self):
250 self.timer.Stop()
251 del self.timer
252
253 #---------------------------------------------------------------------------
254
255 def runTest(frame, nb, log):
256 win = MyCanvas(nb, wx.ID_ANY, log)
257 return win
258
259 #---------------------------------------------------------------------------
260
261
262
263 overview = """
264 <html>
265 <body>
266 <h2>wx.PseudoDC</h2>
267
268 The wx.PseudoDC class provides a way to record operations on a DC and then
269 play them back later. The PseudoDC can be passed to a drawing routine as
270 if it were a real DC. All Drawing methods are supported except Blit but
271 GetXXX methods are not supported and none of the drawing methods return
272 a value. The PseudoDC records the drawing to an operation
273 list. The operations can be played back to a real DC using:<pre>
274 DrawToDC(dc)
275 </pre>
276 The operations can be tagged with an id in order to associated them with a
277 specific object. To do this use:<pre>
278 SetId(id)
279 </pre>
280 Every operation after this will be associated with id until SetId is called
281 again. The PseudoDC also supports object level clipping. To enable this use:<pre>
282 SetIdBounds(id,rect)
283 </pre>
284 for each object that should be clipped. Then use:<pre>
285 DrawToDCClipped(dc, clippingRect)
286 </pre>
287 To draw the PseudoDC to a real dc. This is useful for large scrolled windows
288 where many objects are offscreen.
289
290 Objects can be moved around without re-drawing using:<pre>
291 TranslateId(id, dx, dy)
292 </pre>
293
294 To re-draw an object use:<pre>
295 ClearId(id)
296 SetId(id)
297 </pre>
298 and then re-draw the object.
299 </body>
300 </html>
301 """
302
303
304 if __name__ == '__main__':
305 import sys,os
306 import run
307 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
308