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 75, 110, wx
.Pen(wx
.BLUE
, 3), wx
.GREEN_BRUSH
, "Circle"
264 ogl
.TextShape(120, 45),
265 160, 35, wx
.GREEN_PEN
, wx
.LIGHT_GREY_BRUSH
, "OGL is now a\npure Python lib!"
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
)
331 for line
in text
.split('\n'):
333 #shape.SetShadowMode(ogl.SHADOW_RIGHT)
334 self
.diagram
.AddShape(shape
)
337 evthandler
= MyEvtHandler(self
.log
, self
.frame
)
338 evthandler
.SetShape(shape
)
339 evthandler
.SetPreviousHandler(shape
.GetEventHandler())
340 shape
.SetEventHandler(evthandler
)
342 self
.shapes
.append(shape
)
346 def OnBeginDragLeft(self
, x
, y
, keys
):
347 self
.log
.write("OnBeginDragLeft: %s, %s, %s\n" % (x
, y
, keys
))
349 def OnEndDragLeft(self
, x
, y
, keys
):
350 self
.log
.write("OnEndDragLeft: %s, %s, %s\n" % (x
, y
, keys
))
353 #----------------------------------------------------------------------
355 def runTest(frame
, nb
, log
):
356 # This creates some pens and brushes that the OGL library uses.
357 # It should be called after the app object has been created, but
358 # before OGL is used.
361 win
= TestWindow(nb
, log
, frame
)
364 #----------------------------------------------------------------------
367 overview
= """<html><body>
368 <h2>Object Graphics Library</h2>
370 The Object Graphics Library is a library supporting the creation and
371 manipulation of simple and complex graphic images on a canvas.
373 <p>The OGL library was originally written in C++ and provided to
374 wxPython via an extension module wrapper as is most of the rest of
375 wxPython. The code has now been ported to Python (with many thanks to
376 Pierre Hjälm!) in order to make it be more easily maintainable and
377 less likely to get rusty because nobody cares about the C++ lib any
380 <p>The Python version should be mostly drop-in compatible with the
381 wrapped C++ version, except for the location of the package
382 (wx.lib.ogl instead of wx.ogl) and that the base class methods are
383 called the normal Python way (superclass.Method(self, ...)) instead of the
384 hacky way that had to be done to support overloaded methods with the
385 old SWIG (self.base_Method(...))
390 if __name__
== '__main__':
393 run
.main(['', os
.path
.basename(sys
.argv
[0])] + sys
.argv
[1:])