]>
Commit | Line | Data |
---|---|---|
7e664d85 RD |
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 | The wx.PseudoDC class provides a way to record operations on a DC and then | |
267 | play them back later. The PseudoDC can be passed to a drawing routine as | |
268 | if it were a real DC. All Drawing methods are supported except Blit but | |
269 | GetXXX methods are not supported and none of the drawing methods return | |
270 | a value. The PseudoDC records the drawing to an operation | |
271 | list. The operations can be played back to a real DC using:<pre> | |
272 | DrawToDC(dc) | |
273 | </pre> | |
274 | The operations can be tagged with an id in order to associated them with a | |
275 | specific object. To do this use:<pre> | |
276 | SetId(id) | |
277 | </pre> | |
278 | Every operation after this will be associated with id until SetId is called | |
279 | again. The PseudoDC also supports object level clipping. To enable this use:<pre> | |
280 | SetIdBounds(id,rect) | |
281 | </pre> | |
282 | for each object that should be clipped. Then use:<pre> | |
283 | DrawToDCClipped(dc, clippingRect) | |
284 | </pre> | |
285 | To draw the PseudoDC to a real dc. This is useful for large scrolled windows | |
286 | where many objects are offscreen. | |
287 | ||
288 | Objects can be moved around without re-drawing using:<pre> | |
289 | TranslateId(id, dx, dy) | |
290 | </pre> | |
291 | ||
292 | To re-draw an object use:<pre> | |
293 | ClearId(id) | |
294 | SetId(id) | |
295 | </pre> | |
296 | and then re-draw the object. | |
297 | </body> | |
298 | </html> | |
299 | """ | |
300 | ||
301 | ||
302 | if __name__ == '__main__': | |
303 | import sys,os | |
304 | import run | |
305 | run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) | |
306 |