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
11 # 20040830 - Pierre Hjälm
17 import wx
.lib
.ogl
as ogl
21 #----------------------------------------------------------------------
23 class DrawnShape(ogl
.DrawnShape
):
25 ogl
.DrawnShape
.__init
__(self
)
27 self
.SetDrawnBrush(wx
.WHITE_BRUSH
)
28 self
.SetDrawnPen(wx
.BLACK_PEN
)
29 self
.DrawArc((0, -10), (30, 0), (-30, 0))
31 self
.SetDrawnPen(wx
.Pen("#ff8030"))
32 self
.DrawLine((-30, 5), (30, 5))
34 self
.SetDrawnPen(wx
.Pen("#00ee10"))
35 self
.DrawRoundedRectangle((-20, 10, 40, 10), 5)
37 self
.SetDrawnPen(wx
.Pen("#9090f0"))
38 self
.DrawEllipse((-30, 25, 60, 20))
40 self
.SetDrawnTextColour(wx
.BLACK
)
41 self
.SetDrawnFont(wx
.Font(8, wx
.SWISS
, wx
.NORMAL
, wx
.NORMAL
))
42 self
.DrawText("DrawText", (-26, 28))
44 self
.SetDrawnBrush(wx
.GREEN_BRUSH
)
45 self
.DrawPolygon([(-100, 5), (-45, 30), (-35, 20), (-30, 5)])
47 self
.SetDrawnPen(wx
.BLACK_PEN
)
48 self
.DrawLines([(30, -45), (40, -45), (40 ,45), (30, 45)])
50 # Make sure to call CalculateSize when all drawing is done
53 #----------------------------------------------------------------------
55 class DiamondShape(ogl
.PolygonShape
):
56 def __init__(self
, w
=0.0, h
=0.0):
57 ogl
.PolygonShape
.__init
__(self
)
63 points
= [ (0.0, -h
/2.0),
72 #----------------------------------------------------------------------
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)
80 #----------------------------------------------------------------------
82 class CompositeDivisionShape(ogl
.CompositeShape
):
83 def __init__(self
, canvas
):
84 ogl
.CompositeShape
.__init
__(self
)
86 self
.SetCanvas(canvas
)
88 # create a division in the composite
91 # add a shape to the original division
92 shape2
= ogl
.RectangleShape(40, 60)
93 self
.GetDivisions()[0].AddChild(shape2
)
95 # now divide the division so we get 2
96 self
.GetDivisions()[0].Divide(wx
.HORIZONTAL
)
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())
105 for division
in self
.GetDivisions():
106 division
.SetSensitivityFilter(0)
108 #----------------------------------------------------------------------
110 class CompositeShape(ogl
.CompositeShape
):
111 def __init__(self
, canvas
):
112 ogl
.CompositeShape
.__init
__(self
)
114 self
.SetCanvas(canvas
)
116 constraining_shape
= ogl
.RectangleShape(120, 100)
117 constrained_shape1
= ogl
.CircleShape(50)
118 constrained_shape2
= ogl
.RectangleShape(80, 20)
120 constraining_shape
.SetBrush(wx
.BLUE_BRUSH
)
121 constrained_shape2
.SetBrush(wx
.RED_BRUSH
)
123 self
.AddChild(constraining_shape
)
124 self
.AddChild(constrained_shape1
)
125 self
.AddChild(constrained_shape2
)
127 constraint
= ogl
.Constraint(ogl
.CONSTRAINT_MIDALIGNED_BOTTOM
, constraining_shape
, [constrained_shape1
, constrained_shape2
])
128 self
.AddConstraint(constraint
)
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)
137 # If we don't do this the shape will take all left-clicks for itself
138 constraining_shape
.SetSensitivityFilter(0)
141 #----------------------------------------------------------------------
143 class DividedShape(ogl
.DividedShape
):
144 def __init__(self
, width
, height
, canvas
):
145 ogl
.DividedShape
.__init
__(self
, width
, height
)
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
)
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
)
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
)
165 self
.SetRegionSizes()
166 self
.ReformatRegions(canvas
)
169 def ReformatRegions(self
, canvas
=None):
173 canvas
= self
.GetCanvas()
175 dc
= wx
.ClientDC(canvas
) # used for measuring
177 for region
in self
.GetRegions():
178 text
= region
.GetText()
179 self
.FormatText(dc
, text
, rnum
)
183 def OnSizingEndDragLeft(self
, pt
, x
, y
, keys
, attch
):
185 ogl
.DividedShape
.OnSizingEndDragLeft(self
, pt
, x
, y
, keys
, attch
)
186 self
.SetRegionSizes()
187 self
.ReformatRegions()
188 self
.GetCanvas().Refresh()
191 #----------------------------------------------------------------------
193 class MyEvtHandler(ogl
.ShapeEvtHandler
):
194 def __init__(self
, log
, frame
):
195 ogl
.ShapeEvtHandler
.__init
__(self
)
197 self
.statbarFrame
= frame
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
))
206 def OnLeftClick(self
, x
, y
, keys
=0, attachment
=0):
207 shape
= self
.GetShape()
208 canvas
= shape
.GetCanvas()
209 dc
= wx
.ClientDC(canvas
)
213 shape
.Select(False, dc
)
215 canvas
.Refresh(False)
218 shapeList
= canvas
.GetDiagram().GetShapeList()
223 # If we unselect it now then some of the objects in
224 # shapeList will become invalid (the control points are
225 # shapes too!) and bad things will happen...
228 shape
.Select(True, dc
)
235 canvas
.Refresh(False)
237 self
.UpdateStatusBar(shape
)
240 def OnEndDragLeft(self
, x
, y
, keys
=0, attachment
=0):
241 shape
= self
.GetShape()
242 ogl
.ShapeEvtHandler
.OnEndDragLeft(self
, x
, y
, keys
, attachment
)
244 if not shape
.Selected():
245 self
.OnLeftClick(x
, y
, keys
, attachment
)
247 self
.UpdateStatusBar(shape
)
250 def OnSizingEndDragLeft(self
, pt
, x
, y
, keys
, attch
):
251 ogl
.ShapeEvtHandler
.OnSizingEndDragLeft(self
, pt
, x
, y
, keys
, attch
)
252 self
.UpdateStatusBar(self
.GetShape())
255 def OnMovePost(self
, dc
, x
, y
, oldX
, oldY
, display
):
256 shape
= self
.GetShape()
257 ogl
.ShapeEvtHandler
.OnMovePost(self
, dc
, x
, y
, oldX
, oldY
, display
)
258 self
.UpdateStatusBar(shape
)
259 if "wxMac" in wx
.PlatformInfo
:
260 shape
.GetCanvas().Refresh(False)
262 def OnRightClick(self
, *dontcare
):
263 self
.log
.WriteText("%s\n" % self
.GetShape())
266 #----------------------------------------------------------------------
268 class TestWindow(ogl
.ShapeCanvas
):
269 def __init__(self
, parent
, log
, frame
):
270 ogl
.ShapeCanvas
.__init
__(self
, parent
)
274 self
.SetScrollbars(20, 20, maxWidth
/20, maxHeight
/20)
278 self
.SetBackgroundColour("LIGHT BLUE") #wx.WHITE)
279 self
.diagram
= ogl
.Diagram()
280 self
.SetDiagram(self
.diagram
)
281 self
.diagram
.SetCanvas(self
)
285 rRectBrush
= wx
.Brush("MEDIUM TURQUOISE", wx
.SOLID
)
286 dsBrush
= wx
.Brush("WHEAT", wx
.SOLID
)
289 CompositeDivisionShape(self
),
290 270, 310, wx
.BLACK_PEN
, wx
.BLUE_BRUSH
, "Division"
294 CompositeShape(self
),
295 100, 260, wx
.BLACK_PEN
, wx
.RED_BRUSH
, "Composite"
300 75, 110, wx
.Pen(wx
.BLUE
, 3), wx
.GREEN_BRUSH
, "Circle"
304 ogl
.TextShape(120, 45),
305 160, 35, wx
.GREEN_PEN
, wx
.LIGHT_GREY_BRUSH
, "OGL is now a\npure Python lib!"
309 ogl
.RectangleShape(85, 50),
310 305, 60, wx
.BLACK_PEN
, wx
.LIGHT_GREY_BRUSH
, "Rectangle"
315 500, 80, wx
.BLACK_PEN
, wx
.BLACK_BRUSH
, "DrawnShape"
318 ds
= self
.MyAddShape(
319 DividedShape(140, 150, self
),
320 520, 265, wx
.BLACK_PEN
, dsBrush
, ''
324 DiamondShape(90, 90),
325 355, 260, wx
.Pen(wx
.BLUE
, 3, wx
.DOT
), wx
.RED_BRUSH
, "Polygon"
329 RoundedRectangleShape(95, 70),
330 345, 145, wx
.Pen(wx
.RED
, 2), rRectBrush
, "Rounded Rect"
333 bmp
= images
.getTest2Bitmap()
334 mask
= wx
.Mask(bmp
, wx
.BLUE
)
337 s
= ogl
.BitmapShape()
339 self
.MyAddShape(s
, 225, 130, None, None, "Bitmap")
341 #dc = wx.ClientDC(self)
344 for x
in range(len(self
.shapes
)):
345 fromShape
= self
.shapes
[x
]
346 if x
+1 == len(self
.shapes
):
347 toShape
= self
.shapes
[0]
349 toShape
= self
.shapes
[x
+1]
351 line
= ogl
.LineShape()
353 line
.SetPen(wx
.BLACK_PEN
)
354 line
.SetBrush(wx
.BLACK_BRUSH
)
355 line
.AddArrow(ogl
.ARROW_ARROW
)
356 line
.MakeLineControlPoints(2)
357 fromShape
.AddLine(line
, toShape
)
358 self
.diagram
.AddShape(line
)
362 def MyAddShape(self
, shape
, x
, y
, pen
, brush
, text
):
363 # Composites have to be moved for all children to get in place
364 if isinstance(shape
, ogl
.CompositeShape
):
365 dc
= wx
.ClientDC(self
)
369 shape
.SetDraggable(True, True)
370 shape
.SetCanvas(self
)
373 if pen
: shape
.SetPen(pen
)
374 if brush
: shape
.SetBrush(brush
)
376 for line
in text
.split('\n'):
378 #shape.SetShadowMode(ogl.SHADOW_RIGHT)
379 self
.diagram
.AddShape(shape
)
382 evthandler
= MyEvtHandler(self
.log
, self
.frame
)
383 evthandler
.SetShape(shape
)
384 evthandler
.SetPreviousHandler(shape
.GetEventHandler())
385 shape
.SetEventHandler(evthandler
)
387 self
.shapes
.append(shape
)
391 def OnBeginDragLeft(self
, x
, y
, keys
):
392 self
.log
.write("OnBeginDragLeft: %s, %s, %s\n" % (x
, y
, keys
))
394 def OnEndDragLeft(self
, x
, y
, keys
):
395 self
.log
.write("OnEndDragLeft: %s, %s, %s\n" % (x
, y
, keys
))
398 #----------------------------------------------------------------------
400 def runTest(frame
, nb
, log
):
401 # This creates some pens and brushes that the OGL library uses.
402 # It should be called after the app object has been created, but
403 # before OGL is used.
406 win
= TestWindow(nb
, log
, frame
)
409 #----------------------------------------------------------------------
412 overview
= """<html><body>
413 <h2>Object Graphics Library</h2>
415 The Object Graphics Library is a library supporting the creation and
416 manipulation of simple and complex graphic images on a canvas.
418 <p>The OGL library was originally written in C++ and provided to
419 wxPython via an extension module wrapper as is most of the rest of
420 wxPython. The code has now been ported to Python (with many thanks to
421 Pierre Hjälm!) in order to make it be more easily maintainable and
422 less likely to get rusty because nobody cares about the C++ lib any
427 if __name__
== '__main__':
430 run
.main(['', os
.path
.basename(sys
.argv
[0])] + sys
.argv
[1:])