]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/OGL.py
use wx.ART_NEW
[wxWidgets.git] / wxPython / demo / OGL.py
1 # -*- coding: iso-8859-1 -*-
2 # 11/20/2003 - Jeff Grimmett (grimmtooth@softhome.net)
3 #
4 # o Updated for wx namespace
5 #
6 # 20040508 - Pierre Hjälm
7 #
8 # o Changed to use the python version of OGL
9 # o Added TextShape, CompositeShape and CompositeShape with divisions
10 #
11 # 20040830 - Pierre Hjälm
12 #
13 # o Added DrawnShape
14 #
15
16 import wx
17 import wx.lib.ogl as ogl
18
19 import images
20
21 #----------------------------------------------------------------------
22
23 class DrawnShape(ogl.DrawnShape):
24 def __init__(self):
25 ogl.DrawnShape.__init__(self)
26
27 self.SetDrawnBrush(wx.WHITE_BRUSH)
28 self.SetDrawnPen(wx.BLACK_PEN)
29 self.DrawArc((0, -10), (30, 0), (-30, 0))
30
31 self.SetDrawnPen(wx.Pen("#ff8030"))
32 self.DrawLine((-30, 5), (30, 5))
33
34 self.SetDrawnPen(wx.Pen("#00ee10"))
35 self.DrawRoundedRectangle((-20, 10, 40, 10), 5)
36
37 self.SetDrawnPen(wx.Pen("#9090f0"))
38 self.DrawEllipse((-30, 25, 60, 20))
39
40 self.SetDrawnTextColour(wx.BLACK)
41 self.SetDrawnFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL))
42 self.DrawText("DrawText", (-26, 28))
43
44 self.SetDrawnBrush(wx.GREEN_BRUSH)
45 self.DrawPolygon([(-100, 5), (-45, 30), (-35, 20), (-30, 5)])
46
47 self.SetDrawnPen(wx.BLACK_PEN)
48 self.DrawLines([(30, -45), (40, -45), (40 ,45), (30, 45)])
49
50 # Make sure to call CalculateSize when all drawing is done
51 self.CalculateSize()
52
53 #----------------------------------------------------------------------
54
55 class DiamondShape(ogl.PolygonShape):
56 def __init__(self, w=0.0, h=0.0):
57 ogl.PolygonShape.__init__(self)
58 if w == 0.0:
59 w = 60.0
60 if h == 0.0:
61 h = 60.0
62
63 points = [ (0.0, -h/2.0),
64 (w/2.0, 0.0),
65 (0.0, h/2.0),
66 (-w/2.0, 0.0),
67 ]
68
69 self.Create(points)
70
71
72 #----------------------------------------------------------------------
73
74 class RoundedRectangleShape(ogl.RectangleShape):
75 def __init__(self, w=0.0, h=0.0):
76 ogl.RectangleShape.__init__(self, w, h)
77 self.SetCornerRadius(-0.3)
78
79
80 #----------------------------------------------------------------------
81
82 class CompositeDivisionShape(ogl.CompositeShape):
83 def __init__(self, canvas):
84 ogl.CompositeShape.__init__(self)
85
86 self.SetCanvas(canvas)
87
88 # create a division in the composite
89 self.MakeContainer()
90
91 # add a shape to the original division
92 shape2 = ogl.RectangleShape(40, 60)
93 self.GetDivisions()[0].AddChild(shape2)
94
95 # now divide the division so we get 2
96 self.GetDivisions()[0].Divide(wx.HORIZONTAL)
97
98 # and add a shape to the second division (and move it to the
99 # centre of the division)
100 shape3 = ogl.CircleShape(40)
101 shape3.SetBrush(wx.CYAN_BRUSH)
102 self.GetDivisions()[1].AddChild(shape3)
103 shape3.SetX(self.GetDivisions()[1].GetX())
104
105 for division in self.GetDivisions():
106 division.SetSensitivityFilter(0)
107
108 #----------------------------------------------------------------------
109
110 class CompositeShape(ogl.CompositeShape):
111 def __init__(self, canvas):
112 ogl.CompositeShape.__init__(self)
113
114 self.SetCanvas(canvas)
115
116 constraining_shape = ogl.RectangleShape(120, 100)
117 constrained_shape1 = ogl.CircleShape(50)
118 constrained_shape2 = ogl.RectangleShape(80, 20)
119
120 constraining_shape.SetBrush(wx.BLUE_BRUSH)
121 constrained_shape2.SetBrush(wx.RED_BRUSH)
122
123 self.AddChild(constraining_shape)
124 self.AddChild(constrained_shape1)
125 self.AddChild(constrained_shape2)
126
127 constraint = ogl.Constraint(ogl.CONSTRAINT_MIDALIGNED_BOTTOM, constraining_shape, [constrained_shape1, constrained_shape2])
128 self.AddConstraint(constraint)
129 self.Recompute()
130
131 # If we don't do this, the shapes will be able to move on their
132 # own, instead of moving the composite
133 constraining_shape.SetDraggable(False)
134 constrained_shape1.SetDraggable(False)
135 constrained_shape2.SetDraggable(False)
136
137 # If we don't do this the shape will take all left-clicks for itself
138 constraining_shape.SetSensitivityFilter(0)
139
140
141 #----------------------------------------------------------------------
142
143 class DividedShape(ogl.DividedShape):
144 def __init__(self, width, height, canvas):
145 ogl.DividedShape.__init__(self, width, height)
146
147 region1 = ogl.ShapeRegion()
148 region1.SetText('DividedShape')
149 region1.SetProportions(0.0, 0.2)
150 region1.SetFormatMode(ogl.FORMAT_CENTRE_HORIZ)
151 self.AddRegion(region1)
152
153 region2 = ogl.ShapeRegion()
154 region2.SetText('This is Region number two.')
155 region2.SetProportions(0.0, 0.3)
156 region2.SetFormatMode(ogl.FORMAT_CENTRE_HORIZ|ogl.FORMAT_CENTRE_VERT)
157 self.AddRegion(region2)
158
159 region3 = ogl.ShapeRegion()
160 region3.SetText('Region 3\nwith embedded\nline breaks')
161 region3.SetProportions(0.0, 0.5)
162 region3.SetFormatMode(ogl.FORMAT_NONE)
163 self.AddRegion(region3)
164
165 self.SetRegionSizes()
166 self.ReformatRegions(canvas)
167
168
169 def ReformatRegions(self, canvas=None):
170 rnum = 0
171
172 if canvas is None:
173 canvas = self.GetCanvas()
174
175 dc = wx.ClientDC(canvas) # used for measuring
176
177 for region in self.GetRegions():
178 text = region.GetText()
179 self.FormatText(dc, text, rnum)
180 rnum += 1
181
182
183 def OnSizingEndDragLeft(self, pt, x, y, keys, attch):
184 print "***", self
185 ogl.DividedShape.OnSizingEndDragLeft(self, pt, x, y, keys, attch)
186 self.SetRegionSizes()
187 self.ReformatRegions()
188 self.GetCanvas().Refresh()
189
190
191 #----------------------------------------------------------------------
192
193 class MyEvtHandler(ogl.ShapeEvtHandler):
194 def __init__(self, log, frame):
195 ogl.ShapeEvtHandler.__init__(self)
196 self.log = log
197 self.statbarFrame = frame
198
199 def UpdateStatusBar(self, shape):
200 x, y = shape.GetX(), shape.GetY()
201 width, height = shape.GetBoundingBoxMax()
202 self.statbarFrame.SetStatusText("Pos: (%d, %d) Size: (%d, %d)" %
203 (x, y, width, height))
204
205
206 def OnLeftClick(self, x, y, keys=0, attachment=0):
207 shape = self.GetShape()
208 canvas = shape.GetCanvas()
209 dc = wx.ClientDC(canvas)
210 canvas.PrepareDC(dc)
211
212 if shape.Selected():
213 shape.Select(False, dc)
214 canvas.Redraw(dc)
215 else:
216 redraw = False
217 shapeList = canvas.GetDiagram().GetShapeList()
218 toUnselect = []
219
220 for s in shapeList:
221 if s.Selected():
222 # If we unselect it now then some of the objects in
223 # shapeList will become invalid (the control points are
224 # shapes too!) and bad things will happen...
225 toUnselect.append(s)
226
227 shape.Select(True, dc)
228
229 if toUnselect:
230 for s in toUnselect:
231 s.Select(False, dc)
232
233 canvas.Redraw(dc)
234
235 self.UpdateStatusBar(shape)
236
237
238 def OnEndDragLeft(self, x, y, keys=0, attachment=0):
239 shape = self.GetShape()
240 ogl.ShapeEvtHandler.OnEndDragLeft(self, x, y, keys, attachment)
241
242 if not shape.Selected():
243 self.OnLeftClick(x, y, keys, attachment)
244
245 self.UpdateStatusBar(shape)
246
247
248 def OnSizingEndDragLeft(self, pt, x, y, keys, attch):
249 ogl.ShapeEvtHandler.OnSizingEndDragLeft(self, pt, x, y, keys, attch)
250 self.UpdateStatusBar(self.GetShape())
251
252
253 def OnMovePost(self, dc, x, y, oldX, oldY, display):
254 ogl.ShapeEvtHandler.OnMovePost(self, dc, x, y, oldX, oldY, display)
255 self.UpdateStatusBar(self.GetShape())
256
257
258 def OnRightClick(self, *dontcare):
259 self.log.WriteText("%s\n" % self.GetShape())
260
261
262 #----------------------------------------------------------------------
263
264 class TestWindow(ogl.ShapeCanvas):
265 def __init__(self, parent, log, frame):
266 ogl.ShapeCanvas.__init__(self, parent)
267
268 maxWidth = 1000
269 maxHeight = 1000
270 self.SetScrollbars(20, 20, maxWidth/20, maxHeight/20)
271
272 self.log = log
273 self.frame = frame
274 self.SetBackgroundColour("LIGHT BLUE") #wx.WHITE)
275 self.diagram = ogl.Diagram()
276 self.SetDiagram(self.diagram)
277 self.diagram.SetCanvas(self)
278 self.shapes = []
279 self.save_gdi = []
280
281 rRectBrush = wx.Brush("MEDIUM TURQUOISE", wx.SOLID)
282 dsBrush = wx.Brush("WHEAT", wx.SOLID)
283
284 self.MyAddShape(
285 CompositeDivisionShape(self),
286 270, 310, wx.BLACK_PEN, wx.BLUE_BRUSH, "Division"
287 )
288
289 self.MyAddShape(
290 CompositeShape(self),
291 100, 260, wx.BLACK_PEN, wx.RED_BRUSH, "Composite"
292 )
293
294 self.MyAddShape(
295 ogl.CircleShape(80),
296 75, 110, wx.Pen(wx.BLUE, 3), wx.GREEN_BRUSH, "Circle"
297 )
298
299 self.MyAddShape(
300 ogl.TextShape(120, 45),
301 160, 35, wx.GREEN_PEN, wx.LIGHT_GREY_BRUSH, "OGL is now a\npure Python lib!"
302 )
303
304 self.MyAddShape(
305 ogl.RectangleShape(85, 50),
306 305, 60, wx.BLACK_PEN, wx.LIGHT_GREY_BRUSH, "Rectangle"
307 )
308
309 self.MyAddShape(
310 DrawnShape(),
311 500, 80, wx.BLACK_PEN, wx.BLACK_BRUSH, "DrawnShape"
312 )
313
314 ds = self.MyAddShape(
315 DividedShape(140, 150, self),
316 520, 265, wx.BLACK_PEN, dsBrush, ''
317 )
318
319 self.MyAddShape(
320 DiamondShape(90, 90),
321 355, 260, wx.Pen(wx.BLUE, 3, wx.DOT), wx.RED_BRUSH, "Polygon"
322 )
323
324 self.MyAddShape(
325 RoundedRectangleShape(95, 70),
326 345, 145, wx.Pen(wx.RED, 2), rRectBrush, "Rounded Rect"
327 )
328
329 bmp = images.getTest2Bitmap()
330 mask = wx.Mask(bmp, wx.BLUE)
331 bmp.SetMask(mask)
332
333 s = ogl.BitmapShape()
334 s.SetBitmap(bmp)
335 self.MyAddShape(s, 225, 130, None, None, "Bitmap")
336
337 dc = wx.ClientDC(self)
338 self.PrepareDC(dc)
339
340 for x in range(len(self.shapes)):
341 fromShape = self.shapes[x]
342 if x+1 == len(self.shapes):
343 toShape = self.shapes[0]
344 else:
345 toShape = self.shapes[x+1]
346
347 line = ogl.LineShape()
348 line.SetCanvas(self)
349 line.SetPen(wx.BLACK_PEN)
350 line.SetBrush(wx.BLACK_BRUSH)
351 line.AddArrow(ogl.ARROW_ARROW)
352 line.MakeLineControlPoints(2)
353 fromShape.AddLine(line, toShape)
354 self.diagram.AddShape(line)
355 line.Show(True)
356
357
358 def MyAddShape(self, shape, x, y, pen, brush, text):
359 # Composites have to be moved for all children to get in place
360 if isinstance(shape, ogl.CompositeShape):
361 dc = wx.ClientDC(self)
362 self.PrepareDC(dc)
363 shape.Move(dc, x, y)
364 else:
365 shape.SetDraggable(True, True)
366 shape.SetCanvas(self)
367 shape.SetX(x)
368 shape.SetY(y)
369 if pen: shape.SetPen(pen)
370 if brush: shape.SetBrush(brush)
371 if text:
372 for line in text.split('\n'):
373 shape.AddText(line)
374 #shape.SetShadowMode(ogl.SHADOW_RIGHT)
375 self.diagram.AddShape(shape)
376 shape.Show(True)
377
378 evthandler = MyEvtHandler(self.log, self.frame)
379 evthandler.SetShape(shape)
380 evthandler.SetPreviousHandler(shape.GetEventHandler())
381 shape.SetEventHandler(evthandler)
382
383 self.shapes.append(shape)
384 return shape
385
386
387 def OnBeginDragLeft(self, x, y, keys):
388 self.log.write("OnBeginDragLeft: %s, %s, %s\n" % (x, y, keys))
389
390 def OnEndDragLeft(self, x, y, keys):
391 self.log.write("OnEndDragLeft: %s, %s, %s\n" % (x, y, keys))
392
393
394 #----------------------------------------------------------------------
395
396 def runTest(frame, nb, log):
397 # This creates some pens and brushes that the OGL library uses.
398 # It should be called after the app object has been created, but
399 # before OGL is used.
400 ogl.OGLInitialize()
401
402 win = TestWindow(nb, log, frame)
403 return win
404
405 #----------------------------------------------------------------------
406
407
408 overview = """<html><body>
409 <h2>Object Graphics Library</h2>
410
411 The Object Graphics Library is a library supporting the creation and
412 manipulation of simple and complex graphic images on a canvas.
413
414 <p>The OGL library was originally written in C++ and provided to
415 wxPython via an extension module wrapper as is most of the rest of
416 wxPython. The code has now been ported to Python (with many thanks to
417 Pierre Hjälm!) in order to make it be more easily maintainable and
418 less likely to get rusty because nobody cares about the C++ lib any
419 more.
420
421 <p>The Python version should be mostly drop-in compatible with the
422 wrapped C++ version, except for the location of the package
423 (wx.lib.ogl instead of wx.ogl) and that the base class methods are
424 called the normal Python way (superclass.Method(self, ...)) instead of the
425 hacky way that had to be done to support overloaded methods with the
426 old SWIG (self.base_Method(...))
427
428
429 """
430
431 if __name__ == '__main__':
432 import sys, os
433 import run
434 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
435