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
) 
 217             shapeList 
= canvas
.GetDiagram().GetShapeList() 
 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... 
 227             shape
.Select(True, dc
) 
 235         self
.UpdateStatusBar(shape
) 
 238     def OnEndDragLeft(self
, x
, y
, keys
=0, attachment
=0): 
 239         shape 
= self
.GetShape() 
 240         ogl
.ShapeEvtHandler
.OnEndDragLeft(self
, x
, y
, keys
, attachment
) 
 242         if not shape
.Selected(): 
 243             self
.OnLeftClick(x
, y
, keys
, attachment
) 
 245         self
.UpdateStatusBar(shape
) 
 248     def OnSizingEndDragLeft(self
, pt
, x
, y
, keys
, attch
): 
 249         ogl
.ShapeEvtHandler
.OnSizingEndDragLeft(self
, pt
, x
, y
, keys
, attch
) 
 250         self
.UpdateStatusBar(self
.GetShape()) 
 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()) 
 258     def OnRightClick(self
, *dontcare
): 
 259         self
.log
.WriteText("%s\n" % self
.GetShape()) 
 262 #---------------------------------------------------------------------- 
 264 class TestWindow(ogl
.ShapeCanvas
): 
 265     def __init__(self
, parent
, log
, frame
): 
 266         ogl
.ShapeCanvas
.__init
__(self
, parent
) 
 270         self
.SetScrollbars(20, 20, maxWidth
/20, maxHeight
/20) 
 274         self
.SetBackgroundColour("LIGHT BLUE") #wx.WHITE) 
 275         self
.diagram 
= ogl
.Diagram() 
 276         self
.SetDiagram(self
.diagram
) 
 277         self
.diagram
.SetCanvas(self
) 
 281         rRectBrush 
= wx
.Brush("MEDIUM TURQUOISE", wx
.SOLID
) 
 282         dsBrush 
= wx
.Brush("WHEAT", wx
.SOLID
) 
 285             CompositeDivisionShape(self
),  
 286             270, 310, wx
.BLACK_PEN
, wx
.BLUE_BRUSH
, "Division" 
 290             CompositeShape(self
),  
 291             100, 260, wx
.BLACK_PEN
, wx
.RED_BRUSH
, "Composite" 
 296             75, 110, wx
.Pen(wx
.BLUE
, 3), wx
.GREEN_BRUSH
, "Circle" 
 300             ogl
.TextShape(120, 45),  
 301             160, 35, wx
.GREEN_PEN
, wx
.LIGHT_GREY_BRUSH
, "OGL is now a\npure Python lib!" 
 305             ogl
.RectangleShape(85, 50),  
 306             305, 60, wx
.BLACK_PEN
, wx
.LIGHT_GREY_BRUSH
, "Rectangle" 
 311             500, 80, wx
.BLACK_PEN
, wx
.BLACK_BRUSH
, "DrawnShape" 
 314         ds 
= self
.MyAddShape( 
 315             DividedShape(140, 150, self
),  
 316             520, 265, wx
.BLACK_PEN
, dsBrush
, '' 
 320             DiamondShape(90, 90),  
 321             355, 260, wx
.Pen(wx
.BLUE
, 3, wx
.DOT
), wx
.RED_BRUSH
, "Polygon" 
 325             RoundedRectangleShape(95, 70),  
 326             345, 145, wx
.Pen(wx
.RED
, 2), rRectBrush
, "Rounded Rect" 
 329         bmp 
= images
.getTest2Bitmap() 
 330         mask 
= wx
.Mask(bmp
, wx
.BLUE
) 
 333         s 
= ogl
.BitmapShape() 
 335         self
.MyAddShape(s
, 225, 130, None, None, "Bitmap") 
 337         dc 
= wx
.ClientDC(self
) 
 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] 
 345                 toShape 
= self
.shapes
[x
+1] 
 347             line 
= ogl
.LineShape() 
 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
) 
 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
) 
 365             shape
.SetDraggable(True, True) 
 366         shape
.SetCanvas(self
) 
 369         if pen
:    shape
.SetPen(pen
) 
 370         if brush
:  shape
.SetBrush(brush
) 
 372             for line 
in text
.split('\n'): 
 374         #shape.SetShadowMode(ogl.SHADOW_RIGHT) 
 375         self
.diagram
.AddShape(shape
) 
 378         evthandler 
= MyEvtHandler(self
.log
, self
.frame
) 
 379         evthandler
.SetShape(shape
) 
 380         evthandler
.SetPreviousHandler(shape
.GetEventHandler()) 
 381         shape
.SetEventHandler(evthandler
) 
 383         self
.shapes
.append(shape
) 
 387     def OnBeginDragLeft(self
, x
, y
, keys
): 
 388         self
.log
.write("OnBeginDragLeft: %s, %s, %s\n" % (x
, y
, keys
)) 
 390     def OnEndDragLeft(self
, x
, y
, keys
): 
 391         self
.log
.write("OnEndDragLeft: %s, %s, %s\n" % (x
, y
, keys
)) 
 394 #---------------------------------------------------------------------- 
 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. 
 402     win 
= TestWindow(nb
, log
, frame
) 
 405 #---------------------------------------------------------------------- 
 408 overview 
= """<html><body> 
 409 <h2>Object Graphics Library</h2> 
 411 The Object Graphics Library is a library supporting the creation and 
 412 manipulation of simple and complex graphic images on a canvas. 
 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 
 423 if __name__ 
== '__main__': 
 426     run
.main(['', os
.path
.basename(sys
.argv
[0])] + sys
.argv
[1:])