1 # -*- coding: iso-8859-1 -*-
2 # 11/20/2003 - Jeff Grimmett (grimmtooth@softhome.net)
4 # o Updated for wx namespace
6 # 20040508 - Pierre Hjälm
8 # o Changed to use the python version of OGL
9 # o Added TextShape, CompositeShape and CompositeShape with divisions
13 import wx
.lib
.ogl
as ogl
17 #----------------------------------------------------------------------
19 class DiamondShape(ogl
.PolygonShape
):
20 def __init__(self
, w
=0.0, h
=0.0):
21 ogl
.PolygonShape
.__init
__(self
)
27 points
= [ (0.0, -h
/2.0),
36 #----------------------------------------------------------------------
38 class RoundedRectangleShape(ogl
.RectangleShape
):
39 def __init__(self
, w
=0.0, h
=0.0):
40 ogl
.RectangleShape
.__init
__(self
, w
, h
)
41 self
.SetCornerRadius(-0.3)
44 #----------------------------------------------------------------------
46 class CompositeDivisionShape(ogl
.CompositeShape
):
47 def __init__(self
, canvas
):
48 ogl
.CompositeShape
.__init
__(self
)
50 self
.SetCanvas(canvas
)
52 # create a division in the composite
55 # add a shape to the original division
56 shape2
= ogl
.RectangleShape(40, 60)
57 self
.GetDivisions()[0].AddChild(shape2
)
59 # now divide the division so we get 2
60 self
.GetDivisions()[0].Divide(wx
.HORIZONTAL
)
62 # and add a shape to the second division (and move it to the
63 # centre of the division)
64 shape3
= ogl
.CircleShape(40)
65 shape3
.SetBrush(wx
.CYAN_BRUSH
)
66 self
.GetDivisions()[1].AddChild(shape3
)
67 shape3
.SetX(self
.GetDivisions()[1].GetX())
69 for division
in self
.GetDivisions():
70 division
.SetSensitivityFilter(0)
72 #----------------------------------------------------------------------
74 class CompositeShape(ogl
.CompositeShape
):
75 def __init__(self
, canvas
):
76 ogl
.CompositeShape
.__init
__(self
)
78 self
.SetCanvas(canvas
)
80 constraining_shape
= ogl
.RectangleShape(120, 100)
81 constrained_shape1
= ogl
.CircleShape(50)
82 constrained_shape2
= ogl
.RectangleShape(80, 20)
84 constraining_shape
.SetBrush(wx
.BLUE_BRUSH
)
85 constrained_shape2
.SetBrush(wx
.RED_BRUSH
)
87 self
.AddChild(constraining_shape
)
88 self
.AddChild(constrained_shape1
)
89 self
.AddChild(constrained_shape2
)
91 constraint
= ogl
.Constraint(ogl
.CONSTRAINT_MIDALIGNED_BOTTOM
, constraining_shape
, [constrained_shape1
, constrained_shape2
])
92 self
.AddConstraint(constraint
)
95 # If we don't do this, the shapes will be able to move on their
96 # own, instead of moving the composite
97 constraining_shape
.SetDraggable(False)
98 constrained_shape1
.SetDraggable(False)
99 constrained_shape2
.SetDraggable(False)
101 # If we don't do this the shape will take all left-clicks for itself
102 constraining_shape
.SetSensitivityFilter(0)
105 #----------------------------------------------------------------------
107 class DividedShape(ogl
.DividedShape
):
108 def __init__(self
, width
, height
, canvas
):
109 ogl
.DividedShape
.__init
__(self
, width
, height
)
111 region1
= ogl
.ShapeRegion()
112 region1
.SetText('DividedShape')
113 region1
.SetProportions(0.0, 0.2)
114 region1
.SetFormatMode(ogl
.FORMAT_CENTRE_HORIZ
)
115 self
.AddRegion(region1
)
117 region2
= ogl
.ShapeRegion()
118 region2
.SetText('This is Region number two.')
119 region2
.SetProportions(0.0, 0.3)
120 region2
.SetFormatMode(ogl
.FORMAT_CENTRE_HORIZ|ogl
.FORMAT_CENTRE_VERT
)
121 self
.AddRegion(region2
)
123 region3
= ogl
.ShapeRegion()
124 region3
.SetText('Region 3\nwith embedded\nline breaks')
125 region3
.SetProportions(0.0, 0.5)
126 region3
.SetFormatMode(ogl
.FORMAT_NONE
)
127 self
.AddRegion(region3
)
129 self
.SetRegionSizes()
130 self
.ReformatRegions(canvas
)
133 def ReformatRegions(self
, canvas
=None):
137 canvas
= self
.GetCanvas()
139 dc
= wx
.ClientDC(canvas
) # used for measuring
141 for region
in self
.GetRegions():
142 text
= region
.GetText()
143 self
.FormatText(dc
, text
, rnum
)
147 def OnSizingEndDragLeft(self
, pt
, x
, y
, keys
, attch
):
149 ogl
.DividedShape
.OnSizingEndDragLeft(self
, pt
, x
, y
, keys
, attch
)
150 self
.SetRegionSizes()
151 self
.ReformatRegions()
152 self
.GetCanvas().Refresh()
155 #----------------------------------------------------------------------
157 class MyEvtHandler(ogl
.ShapeEvtHandler
):
158 def __init__(self
, log
, frame
):
159 ogl
.ShapeEvtHandler
.__init
__(self
)
161 self
.statbarFrame
= frame
163 def UpdateStatusBar(self
, shape
):
164 x
, y
= shape
.GetX(), shape
.GetY()
165 width
, height
= shape
.GetBoundingBoxMax()
166 self
.statbarFrame
.SetStatusText("Pos: (%d, %d) Size: (%d, %d)" %
167 (x
, y
, width
, height
))
170 def OnLeftClick(self
, x
, y
, keys
=0, attachment
=0):
171 shape
= self
.GetShape()
172 canvas
= shape
.GetCanvas()
173 dc
= wx
.ClientDC(canvas
)
177 shape
.Select(False, dc
)
181 shapeList
= canvas
.GetDiagram().GetShapeList()
186 # If we unselect it now then some of the objects in
187 # shapeList will become invalid (the control points are
188 # shapes too!) and bad things will happen...
191 shape
.Select(True, dc
)
199 self
.UpdateStatusBar(shape
)
202 def OnEndDragLeft(self
, x
, y
, keys
=0, attachment
=0):
203 shape
= self
.GetShape()
204 ogl
.ShapeEvtHandler
.OnEndDragLeft(self
, x
, y
, keys
, attachment
)
206 if not shape
.Selected():
207 self
.OnLeftClick(x
, y
, keys
, attachment
)
209 self
.UpdateStatusBar(shape
)
212 def OnSizingEndDragLeft(self
, pt
, x
, y
, keys
, attch
):
213 ogl
.ShapeEvtHandler
.OnSizingEndDragLeft(self
, pt
, x
, y
, keys
, attch
)
214 self
.UpdateStatusBar(self
.GetShape())
217 def OnMovePost(self
, dc
, x
, y
, oldX
, oldY
, display
):
218 ogl
.ShapeEvtHandler
.OnMovePost(self
, dc
, x
, y
, oldX
, oldY
, display
)
219 self
.UpdateStatusBar(self
.GetShape())
222 def OnRightClick(self
, *dontcare
):
223 self
.log
.WriteText("%s\n" % self
.GetShape())
226 #----------------------------------------------------------------------
228 class TestWindow(ogl
.ShapeCanvas
):
229 def __init__(self
, parent
, log
, frame
):
230 ogl
.ShapeCanvas
.__init
__(self
, parent
)
234 self
.SetScrollbars(20, 20, maxWidth
/20, maxHeight
/20)
238 self
.SetBackgroundColour("LIGHT BLUE") #wx.WHITE)
239 self
.diagram
= ogl
.Diagram()
240 self
.SetDiagram(self
.diagram
)
241 self
.diagram
.SetCanvas(self
)
245 rRectBrush
= wx
.Brush("MEDIUM TURQUOISE", wx
.SOLID
)
246 dsBrush
= wx
.Brush("WHEAT", wx
.SOLID
)
249 CompositeDivisionShape(self
),
250 310, 310, wx
.BLACK_PEN
, wx
.BLUE_BRUSH
, "Division"
254 CompositeShape(self
),
255 100, 260, wx
.BLACK_PEN
, wx
.RED_BRUSH
, "Composite"
260 100, 100, wx
.Pen(wx
.BLUE
, 3), wx
.GREEN_BRUSH
, "Circle"
264 ogl
.TextShape(45, 30),
265 205, 60, wx
.GREEN_PEN
, wx
.LIGHT_GREY_BRUSH
, "Text"
269 ogl
.RectangleShape(85, 50),
270 305, 60, wx
.BLACK_PEN
, wx
.LIGHT_GREY_BRUSH
, "Rectangle"
273 ds
= self
.MyAddShape(
274 DividedShape(140, 150, self
),
275 515, 145, wx
.BLACK_PEN
, dsBrush
, ''
279 DiamondShape(90, 90),
280 445, 305, wx
.Pen(wx
.BLUE
, 3, wx
.DOT
), wx
.RED_BRUSH
, "Polygon"
284 RoundedRectangleShape(95, 70),
285 345, 145, wx
.Pen(wx
.RED
, 2), rRectBrush
, "Rounded Rect"
288 bmp
= images
.getTest2Bitmap()
289 mask
= wx
.Mask(bmp
, wx
.BLUE
)
292 s
= ogl
.BitmapShape()
294 self
.MyAddShape(s
, 225, 130, None, None, "Bitmap")
296 dc
= wx
.ClientDC(self
)
299 for x
in range(len(self
.shapes
)):
300 fromShape
= self
.shapes
[x
]
301 if x
+1 == len(self
.shapes
):
302 toShape
= self
.shapes
[0]
304 toShape
= self
.shapes
[x
+1]
306 line
= ogl
.LineShape()
308 line
.SetPen(wx
.BLACK_PEN
)
309 line
.SetBrush(wx
.BLACK_BRUSH
)
310 line
.AddArrow(ogl
.ARROW_ARROW
)
311 line
.MakeLineControlPoints(2)
312 fromShape
.AddLine(line
, toShape
)
313 self
.diagram
.AddShape(line
)
317 def MyAddShape(self
, shape
, x
, y
, pen
, brush
, text
):
318 # Composites have to be moved for all children to get in place
319 if isinstance(shape
, ogl
.CompositeShape
):
320 dc
= wx
.ClientDC(self
)
324 shape
.SetDraggable(True, True)
325 shape
.SetCanvas(self
)
328 if pen
: shape
.SetPen(pen
)
329 if brush
: shape
.SetBrush(brush
)
330 if text
: shape
.AddText(text
)
331 #shape.SetShadowMode(ogl.SHADOW_RIGHT)
332 self
.diagram
.AddShape(shape
)
335 evthandler
= MyEvtHandler(self
.log
, self
.frame
)
336 evthandler
.SetShape(shape
)
337 evthandler
.SetPreviousHandler(shape
.GetEventHandler())
338 shape
.SetEventHandler(evthandler
)
340 self
.shapes
.append(shape
)
344 def OnBeginDragLeft(self
, x
, y
, keys
):
345 self
.log
.write("OnBeginDragLeft: %s, %s, %s\n" % (x
, y
, keys
))
347 def OnEndDragLeft(self
, x
, y
, keys
):
348 self
.log
.write("OnEndDragLeft: %s, %s, %s\n" % (x
, y
, keys
))
351 #----------------------------------------------------------------------
353 def runTest(frame
, nb
, log
):
354 # This creates some pens and brushes that the OGL library uses.
355 # It should be called after the app object has been created, but
356 # before OGL is used.
359 win
= TestWindow(nb
, log
, frame
)
362 #----------------------------------------------------------------------
365 overview
= """<html><body>
366 <h2>Object Graphics Library</h2>
368 The Object Graphics Library is a library supporting the creation and
369 manipulation of simple and complex graphic images on a canvas.
371 <p>The OGL library was originally written in C++ and provided to
372 wxPython via an extension module wrapper as is most of the rest of
373 wxPython. The code has now been ported to Python (with many thanks to
374 Pierre Hjälm!) in order to make it be more easily maintainable and
375 less likely to get rusty because nobody cares about the C++ lib any
378 <p>The Python version should be mostly drop-in compatible with the
379 wrapped C++ version, except for the location of the package
380 (wx.lib.ogl instead of wx.ogl) and that the base class methods are
381 called the normal Python way (superclass.Method(self, ...)) instead of the
382 hacky way that had to be done to support overloaded methods with the
383 old SWIG (self.base_Method(...))
388 if __name__
== '__main__':
391 run
.main(['', os
.path
.basename(sys
.argv
[0])] + sys
.argv
[1:])