]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/PseudoDC.py
Added the PseudoDC class from Paul Lanier. It provides a way to
[wxWidgets.git] / wxPython / demo / PseudoDC.py
CommitLineData
7e664d85
RD
1
2import wx
3import images
4import random
5
6#---------------------------------------------------------------------------
7
8W = 1000
9H = 1000
10SW = 150
11SH = 150
12SHAPE_COUNT = 100
13MOVING_COUNT = 10
14
15#---------------------------------------------------------------------------
16
17colours = [
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
39class 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
255def runTest(frame, nb, log):
256 win = MyCanvas(nb, wx.ID_ANY, log)
257 return win
258
259#---------------------------------------------------------------------------
260
261
262
263overview = """
264<html>
265<body>
266The wx.PseudoDC class provides a way to record operations on a DC and then
267play them back later. The PseudoDC can be passed to a drawing routine as
268if it were a real DC. All Drawing methods are supported except Blit but
269GetXXX methods are not supported and none of the drawing methods return
270a value. The PseudoDC records the drawing to an operation
271list. The operations can be played back to a real DC using:<pre>
272DrawToDC(dc)
273</pre>
274The operations can be tagged with an id in order to associated them with a
275specific object. To do this use:<pre>
276SetId(id)
277</pre>
278Every operation after this will be associated with id until SetId is called
279again. The PseudoDC also supports object level clipping. To enable this use:<pre>
280SetIdBounds(id,rect)
281</pre>
282for each object that should be clipped. Then use:<pre>
283DrawToDCClipped(dc, clippingRect)
284</pre>
285To draw the PseudoDC to a real dc. This is useful for large scrolled windows
286where many objects are offscreen.
287
288Objects can be moved around without re-drawing using:<pre>
289TranslateId(id, dx, dy)
290</pre>
291
292To re-draw an object use:<pre>
293ClearId(id)
294SetId(id)
295</pre>
296and then re-draw the object.
297</body>
298</html>
299"""
300
301
302if __name__ == '__main__':
303 import sys,os
304 import run
305 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
306