]>
Commit | Line | Data |
---|---|---|
7e664d85 RD |
1 | |
2 | import wx | |
3 | import images | |
4 | import random | |
5 | ||
6 | #--------------------------------------------------------------------------- | |
7 | ||
b2bfee6c RD |
8 | W = 2000 |
9 | H = 2000 | |
7e664d85 RD |
10 | SW = 150 |
11 | SH = 150 | |
b2bfee6c | 12 | SHAPE_COUNT = 2500 |
6f67d537 | 13 | hitradius = 5 |
7e664d85 RD |
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) | |
6f67d537 | 68 | self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse) |
7e664d85 | 69 | |
6f67d537 RD |
70 | # vars for handling mouse clicks |
71 | self.dragid = -1 | |
72 | self.lastpos = (0,0) | |
73 | ||
74 | def ConvertEventCoords(self, event): | |
75 | xView, yView = self.GetViewStart() | |
76 | xDelta, yDelta = self.GetScrollPixelsPerUnit() | |
77 | return (event.GetX() + (xView * xDelta), | |
78 | event.GetY() + (yView * yDelta)) | |
7e664d85 | 79 | |
6f67d537 RD |
80 | def OffsetRect(self, r): |
81 | xView, yView = self.GetViewStart() | |
82 | xDelta, yDelta = self.GetScrollPixelsPerUnit() | |
83 | r.OffsetXY(-(xView*xDelta),-(yView*yDelta)) | |
84 | ||
85 | def OnMouse(self, event): | |
86 | global hitradius | |
87 | if event.LeftDown(): | |
88 | x,y = self.ConvertEventCoords(event) | |
89 | #l = self.pdc.FindObjectsByBBox(x, y) | |
90 | l = self.pdc.FindObjects(x, y, hitradius) | |
91 | for id in l: | |
92 | if not self.pdc.GetIdGreyedOut(id): | |
93 | self.dragid = id | |
94 | self.lastpos = (event.GetX(),event.GetY()) | |
95 | break | |
96 | elif event.RightDown(): | |
97 | x,y = self.ConvertEventCoords(event) | |
98 | #l = self.pdc.FindObjectsByBBox(x, y) | |
99 | l = self.pdc.FindObjects(x, y, hitradius) | |
100 | if l: | |
101 | self.pdc.SetIdGreyedOut(l[0], not self.pdc.GetIdGreyedOut(l[0])) | |
102 | r = self.pdc.GetIdBounds(l[0]) | |
103 | r.Inflate(4,4) | |
104 | self.OffsetRect(r) | |
105 | self.RefreshRect(r, False) | |
106 | elif event.Dragging() or event.LeftUp(): | |
107 | if self.dragid != -1: | |
108 | x,y = self.lastpos | |
109 | dx = event.GetX() - x | |
110 | dy = event.GetY() - y | |
111 | r = self.pdc.GetIdBounds(self.dragid) | |
112 | self.pdc.TranslateId(self.dragid, dx, dy) | |
113 | r2 = self.pdc.GetIdBounds(self.dragid) | |
114 | r = r.Union(r2) | |
115 | r.Inflate(4,4) | |
116 | self.OffsetRect(r) | |
7e664d85 | 117 | self.RefreshRect(r, False) |
6f67d537 RD |
118 | self.lastpos = (event.GetX(),event.GetY()) |
119 | if event.LeftUp(): | |
120 | self.dragid = -1 | |
7e664d85 RD |
121 | |
122 | def RandomPen(self): | |
123 | c = random.choice(colours) | |
124 | t = random.randint(1, 4) | |
125 | if not self.pen_cache.has_key( (c, t) ): | |
126 | self.pen_cache[(c, t)] = wx.Pen(c, t) | |
127 | return self.pen_cache[(c, t)] | |
128 | ||
129 | ||
130 | def RandomBrush(self): | |
131 | c = random.choice(colours) | |
132 | if not self.brush_cache.has_key(c): | |
133 | self.brush_cache[c] = wx.Brush(c) | |
134 | ||
135 | return self.brush_cache[c] | |
136 | ||
137 | def RandomColor(self): | |
138 | return random.choice(colours) | |
139 | ||
140 | ||
141 | def OnPaint(self, event): | |
142 | # Create a buffered paint DC. It will create the real | |
143 | # wx.PaintDC and then blit the bitmap to it when dc is | |
144 | # deleted. | |
145 | dc = wx.BufferedPaintDC(self) | |
6f67d537 RD |
146 | # use PrepateDC to set position correctly |
147 | self.PrepareDC(dc) | |
7e664d85 RD |
148 | # we need to clear the dc BEFORE calling PrepareDC |
149 | bg = wx.Brush(self.GetBackgroundColour()) | |
150 | dc.SetBackground(bg) | |
151 | dc.Clear() | |
7e664d85 RD |
152 | # create a clipping rect from our position and size |
153 | # and the Update Region | |
154 | xv, yv = self.GetViewStart() | |
155 | dx, dy = self.GetScrollPixelsPerUnit() | |
156 | x, y = (xv * dx, yv * dy) | |
157 | rgn = self.GetUpdateRegion() | |
158 | rgn.Offset(x,y) | |
159 | r = rgn.GetBox() | |
160 | # draw to the dc using the calculated clipping rect | |
161 | self.pdc.DrawToDCClipped(dc,r) | |
162 | ||
163 | def DoDrawing(self, dc): | |
164 | random.seed() | |
165 | self.objids = [] | |
166 | self.boundsdict = {} | |
167 | dc.BeginDrawing() | |
168 | for i in range(SHAPE_COUNT): | |
169 | id = wx.NewId() | |
170 | dc.SetId(id) | |
171 | choice = random.randint(0,8) | |
172 | if choice in (0,1): | |
173 | x = random.randint(0, W) | |
174 | y = random.randint(0, H) | |
6f67d537 RD |
175 | pen = self.RandomPen() |
176 | dc.SetPen(pen) | |
7e664d85 | 177 | dc.DrawPoint(x,y) |
6f67d537 RD |
178 | r = wx.Rect(x,y,1,1) |
179 | r.Inflate(pen.GetWidth(),pen.GetWidth()) | |
180 | dc.SetIdBounds(id,r) | |
7e664d85 RD |
181 | elif choice in (2,3): |
182 | x1 = random.randint(0, W-SW) | |
183 | y1 = random.randint(0, H-SH) | |
184 | x2 = random.randint(x1, x1+SW) | |
185 | y2 = random.randint(y1, y1+SH) | |
6f67d537 RD |
186 | pen = self.RandomPen() |
187 | dc.SetPen(pen) | |
7e664d85 | 188 | dc.DrawLine(x1,y1,x2,y2) |
6f67d537 RD |
189 | r = wx.Rect(x1,y1,x2-x1,y2-y1) |
190 | r.Inflate(pen.GetWidth(),pen.GetWidth()) | |
191 | dc.SetIdBounds(id,r) | |
7e664d85 RD |
192 | elif choice in (4,5): |
193 | w = random.randint(10, SW) | |
194 | h = random.randint(10, SH) | |
195 | x = random.randint(0, W - w) | |
196 | y = random.randint(0, H - h) | |
6f67d537 RD |
197 | pen = self.RandomPen() |
198 | dc.SetPen(pen) | |
7e664d85 RD |
199 | dc.SetBrush(self.RandomBrush()) |
200 | dc.DrawRectangle(x,y,w,h) | |
6f67d537 RD |
201 | r = wx.Rect(x,y,w,h) |
202 | r.Inflate(pen.GetWidth(),pen.GetWidth()) | |
203 | dc.SetIdBounds(id,r) | |
7e664d85 RD |
204 | self.objids.append(id) |
205 | elif choice == 6: | |
206 | Np = 8 # number of characters in text | |
207 | word = [] | |
208 | for i in range(Np): | |
209 | c = chr( random.randint(48, 122) ) | |
210 | word.append( c ) | |
211 | word = "".join(word) | |
212 | w,h = self.GetFullTextExtent(word)[0:2] | |
213 | x = random.randint(0, W-w) | |
214 | y = random.randint(0, H-h) | |
6f67d537 | 215 | dc.SetFont(self.GetFont()) |
7e664d85 RD |
216 | dc.SetTextForeground(self.RandomColor()) |
217 | dc.SetTextBackground(self.RandomColor()) | |
218 | dc.DrawText(word, x, y) | |
6f67d537 RD |
219 | r = wx.Rect(x,y,w,h) |
220 | r.Inflate(2,2) | |
221 | dc.SetIdBounds(id, r) | |
7e664d85 RD |
222 | self.objids.append(id) |
223 | elif choice == 7: | |
224 | Np = 8 # number of points per polygon | |
225 | poly = [] | |
226 | minx = SW | |
227 | miny = SH | |
228 | maxx = 0 | |
229 | maxy = 0 | |
230 | for i in range(Np): | |
231 | x = random.randint(0, SW) | |
232 | y = random.randint(0, SH) | |
233 | if x < minx: minx = x | |
234 | if x > maxx: maxx = x | |
235 | if y < miny: miny = y | |
236 | if y > maxy: maxy = y | |
237 | poly.append(wx.Point(x,y)) | |
238 | x = random.randint(0, W-SW) | |
239 | y = random.randint(0, H-SH) | |
6f67d537 RD |
240 | pen = self.RandomPen() |
241 | dc.SetPen(pen) | |
7e664d85 RD |
242 | dc.SetBrush(self.RandomBrush()) |
243 | dc.DrawPolygon(poly, x,y) | |
6f67d537 RD |
244 | r = wx.Rect(minx+x,miny+y,maxx-minx,maxy-miny) |
245 | r.Inflate(pen.GetWidth(),pen.GetWidth()) | |
246 | dc.SetIdBounds(id,r) | |
7e664d85 RD |
247 | self.objids.append(id) |
248 | elif choice == 8: | |
249 | w,h = self.bmp.GetSize() | |
250 | x = random.randint(0, W-w) | |
251 | y = random.randint(0, H-h) | |
252 | dc.DrawBitmap(self.bmp,x,y,True) | |
253 | dc.SetIdBounds(id,wx.Rect(x,y,w,h)) | |
254 | self.objids.append(id) | |
255 | dc.EndDrawing() | |
256 | ||
6f67d537 RD |
257 | class ControlPanel(wx.Panel): |
258 | def __init__(self, parent, id, pos=wx.DefaultPosition, | |
259 | size=wx.DefaultSize, style = wx.TAB_TRAVERSAL): | |
260 | wx.Panel.__init__(self,parent,id,pos,size,style) | |
261 | lbl = wx.StaticText(self, wx.ID_ANY, "Hit Test Radius: ") | |
262 | lbl2 = wx.StaticText(self, wx.ID_ANY, "Left Click to drag, Right Click to enable/disable") | |
263 | sc = wx.SpinCtrl(self, wx.ID_ANY, "5") | |
264 | sc.SetRange(0,100) | |
265 | global hitradius | |
266 | sc.SetValue(hitradius) | |
267 | self.sc = sc | |
268 | sz = wx.BoxSizer(wx.HORIZONTAL) | |
269 | sz.Add(lbl,0,wx.EXPAND) | |
270 | sz.Add(sc,0) | |
271 | sz.Add(lbl2,0,wx.LEFT,5) | |
272 | sz.Add((10,10),1,wx.EXPAND) | |
273 | self.SetSizerAndFit(sz) | |
274 | sc.Bind(wx.EVT_SPINCTRL,self.OnChange) | |
275 | sc.Bind(wx.EVT_TEXT,self.OnChange) | |
276 | ||
277 | def OnChange(self, event): | |
278 | global hitradius | |
279 | hitradius = self.sc.GetValue() | |
280 | ||
7e664d85 RD |
281 | |
282 | #--------------------------------------------------------------------------- | |
283 | ||
284 | def runTest(frame, nb, log): | |
6f67d537 RD |
285 | pnl = wx.Panel(nb, wx.ID_ANY,size=(200,30)) |
286 | pnl2 = ControlPanel(pnl,wx.ID_ANY) | |
287 | win = MyCanvas(pnl, wx.ID_ANY, log) | |
288 | sz = wx.BoxSizer(wx.VERTICAL) | |
289 | sz.Add(pnl2,0,wx.EXPAND|wx.ALL,5) | |
290 | sz.Add(win,1,wx.EXPAND) | |
291 | pnl.SetSizerAndFit(sz) | |
292 | return pnl | |
7e664d85 RD |
293 | |
294 | #--------------------------------------------------------------------------- | |
295 | ||
296 | ||
297 | ||
298 | overview = """ | |
299 | <html> | |
300 | <body> | |
619d5930 RD |
301 | <h2>wx.PseudoDC</h2> |
302 | ||
7e664d85 RD |
303 | The wx.PseudoDC class provides a way to record operations on a DC and then |
304 | play them back later. The PseudoDC can be passed to a drawing routine as | |
305 | if it were a real DC. All Drawing methods are supported except Blit but | |
306 | GetXXX methods are not supported and none of the drawing methods return | |
307 | a value. The PseudoDC records the drawing to an operation | |
308 | list. The operations can be played back to a real DC using:<pre> | |
309 | DrawToDC(dc) | |
310 | </pre> | |
311 | The operations can be tagged with an id in order to associated them with a | |
312 | specific object. To do this use:<pre> | |
619d5930 | 313 | SetId(id) |
7e664d85 RD |
314 | </pre> |
315 | Every operation after this will be associated with id until SetId is called | |
316 | again. The PseudoDC also supports object level clipping. To enable this use:<pre> | |
619d5930 | 317 | SetIdBounds(id,rect) |
7e664d85 RD |
318 | </pre> |
319 | for each object that should be clipped. Then use:<pre> | |
619d5930 | 320 | DrawToDCClipped(dc, clippingRect) |
7e664d85 RD |
321 | </pre> |
322 | To draw the PseudoDC to a real dc. This is useful for large scrolled windows | |
323 | where many objects are offscreen. | |
324 | ||
325 | Objects can be moved around without re-drawing using:<pre> | |
619d5930 | 326 | TranslateId(id, dx, dy) |
7e664d85 RD |
327 | </pre> |
328 | ||
329 | To re-draw an object use:<pre> | |
619d5930 RD |
330 | ClearId(id) |
331 | SetId(id) | |
7e664d85 RD |
332 | </pre> |
333 | and then re-draw the object. | |
334 | </body> | |
335 | </html> | |
336 | """ | |
337 | ||
338 | ||
339 | if __name__ == '__main__': | |
340 | import sys,os | |
341 | import run | |
342 | run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) | |
343 |