]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/PseudoDC.py
The great wxVScrolledWindow refactoring: allow using it both horizontal and
[wxWidgets.git] / wxPython / demo / PseudoDC.py
1
2 import wx
3 import images
4 import random
5
6 #---------------------------------------------------------------------------
7
8 W = 2000
9 H = 2000
10 SW = 150
11 SH = 150
12 SHAPE_COUNT = 2500
13 hitradius = 5
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 self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
69
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))
79
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)
117 self.RefreshRect(r, False)
118 self.lastpos = (event.GetX(),event.GetY())
119 if event.LeftUp():
120 self.dragid = -1
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)
146 # use PrepateDC to set position correctly
147 self.PrepareDC(dc)
148 # we need to clear the dc BEFORE calling PrepareDC
149 bg = wx.Brush(self.GetBackgroundColour())
150 dc.SetBackground(bg)
151 dc.Clear()
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)
175 pen = self.RandomPen()
176 dc.SetPen(pen)
177 dc.DrawPoint(x,y)
178 r = wx.Rect(x,y,1,1)
179 r.Inflate(pen.GetWidth(),pen.GetWidth())
180 dc.SetIdBounds(id,r)
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)
186 pen = self.RandomPen()
187 dc.SetPen(pen)
188 dc.DrawLine(x1,y1,x2,y2)
189 r = wx.Rect(x1,y1,x2-x1,y2-y1)
190 r.Inflate(pen.GetWidth(),pen.GetWidth())
191 dc.SetIdBounds(id,r)
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)
197 pen = self.RandomPen()
198 dc.SetPen(pen)
199 dc.SetBrush(self.RandomBrush())
200 dc.DrawRectangle(x,y,w,h)
201 r = wx.Rect(x,y,w,h)
202 r.Inflate(pen.GetWidth(),pen.GetWidth())
203 dc.SetIdBounds(id,r)
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)
215 dc.SetFont(self.GetFont())
216 dc.SetTextForeground(self.RandomColor())
217 dc.SetTextBackground(self.RandomColor())
218 dc.DrawText(word, x, y)
219 r = wx.Rect(x,y,w,h)
220 r.Inflate(2,2)
221 dc.SetIdBounds(id, r)
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)
240 pen = self.RandomPen()
241 dc.SetPen(pen)
242 dc.SetBrush(self.RandomBrush())
243 dc.DrawPolygon(poly, x,y)
244 r = wx.Rect(minx+x,miny+y,maxx-minx,maxy-miny)
245 r.Inflate(pen.GetWidth(),pen.GetWidth())
246 dc.SetIdBounds(id,r)
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
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
281
282 #---------------------------------------------------------------------------
283
284 def runTest(frame, nb, log):
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
293
294 #---------------------------------------------------------------------------
295
296
297
298 overview = """
299 <html>
300 <body>
301 <h2>wx.PseudoDC</h2>
302
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>
313 SetId(id)
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>
317 SetIdBounds(id,rect)
318 </pre>
319 for each object that should be clipped. Then use:<pre>
320 DrawToDCClipped(dc, clippingRect)
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>
326 TranslateId(id, dx, dy)
327 </pre>
328
329 To re-draw an object use:<pre>
330 ClearId(id)
331 SetId(id)
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