1 # -*- coding: iso-8859-1 -*- 
   2 #---------------------------------------------------------------------------- 
   4 # Purpose:      DrawnShape class 
   6 # Author:       Pierre Hjälm (from C++ original by Julian Smart) 
  10 # Copyright:    (c) 2004 Pierre Hjälm - 1998 Julian Smart 
  11 # License:      wxWindows license 
  12 #---------------------------------------------------------------------------- 
  16 from _basic 
import RectangleShape
 
  17 from _oglmisc 
import * 
  20 METAFLAGS_ATTACHMENTS     
= 2 
  31 DRAWOP_SET_TEXT_COLOUR       
= 4 
  32 DRAWOP_SET_BK_COLOUR         
= 5 
  33 DRAWOP_SET_BK_MODE           
= 6 
  34 DRAWOP_SET_CLIPPING_RECT     
= 7 
  35 DRAWOP_DESTROY_CLIPPING_RECT 
= 8 
  38 DRAWOP_DRAW_POLYLINE         
= 21 
  39 DRAWOP_DRAW_POLYGON          
= 22 
  41 DRAWOP_DRAW_ROUNDED_RECT     
= 24 
  42 DRAWOP_DRAW_ELLIPSE          
= 25 
  43 DRAWOP_DRAW_POINT            
= 26 
  46 DRAWOP_DRAW_SPLINE           
= 29 
  47 DRAWOP_DRAW_ELLIPTIC_ARC     
= 30 
  50     def __init__(self
, theOp
): 
  56     def GetPerimeterPoint(self
, x1
, y1
, x2
, y2
, xOffset
, yOffset
, attachmentMode
): 
  59     def Scale(self
,scaleX
, scaleY
): 
  62     def Translate(self
, x
, y
): 
  65     def Rotate(self
, x
, y
, theta
, sinTheta
, cosTheta
): 
  68 class OpSetGDI(DrawOp
): 
  69     """Set font, brush, text colour.""" 
  70     def __init__(self
, theOp
, theImage
, theGdiIndex
, theMode 
= 0): 
  71         DrawOp
.__init
__(self
, theOp
) 
  73         self
._gdiIndex 
= theGdiIndex
 
  74         self
._image 
= theImage
 
  77     def Do(self
, dc
, xoffset 
= 0, yoffset 
= 0): 
  78         if self
._op 
== DRAWOP_SET_PEN
: 
  79             # Check for overriding this operation for outline colour 
  80             if self
._gdiIndex 
in self
._image
._outlineColours
: 
  81                 if self
._image
._outlinePen
: 
  82                     dc
.SetPen(self
._image
._outlinePen
) 
  85                     dc
.SetPen(self
._image
._gdiObjects
[self
._gdiIndex
]) 
  88         elif self
._op 
== DRAWOP_SET_BRUSH
: 
  89             # Check for overriding this operation for outline or fill colour 
  90             if self
._gdiIndex 
in self
._image
._outlineColours
: 
  91                 # Need to construct a brush to match the outline pen's colour 
  92                 if self
._image
._outlinePen
: 
  93                     br 
= wx
.TheBrushList
.FindOrCreateBrush(self
._image
._outlinePen
, wx
.SOLID
) 
  96             elif self
._gdiIndex 
in self
._image
._fillColours
: 
  97                 if self
._image
._fillBrush
: 
  98                     dc
.SetBrush(self
._image
._fillBrush
) 
 100                 brush 
= self
._image
._gdiObjects
[self
._gdiIndex
] 
 103         elif self
._op 
== DRAWOP_SET_FONT
: 
 105                 dc
.SetFont(self
._image
._gdiObjects
[self
._gdiIndex
]) 
 108         elif self
._op 
== DRAWOP_SET_TEXT_COLOUR
: 
 109             dc
.SetTextForeground(wx
.Colour(self
._r
, self
._g
, self
._b
)) 
 110         elif self
._op 
== DRAWOP_SET_BK_COLOUR
: 
 111             dc
.SetTextBackground(wx
.Colour(self
._r
, self
._g
, self
._b
)) 
 112         elif self
._op 
== DRAWOP_SET_BK_MODE
: 
 113             dc
.SetBackgroundMode(self
._mode
) 
 116 class OpSetClipping(DrawOp
): 
 117     """Set/destroy clipping.""" 
 118     def __init__(self
, theOp
, theX1
, theY1
, theX2
, theY2
): 
 119         DrawOp
.__init
__(self
, theOp
) 
 126     def Do(self
, dc
, xoffset
, yoffset
): 
 127         if self
._op 
== DRAWOP_SET_CLIPPING_RECT
: 
 128             dc
.SetClippingRegion(self
._x
1 + xoffset
, self
._y
1 + yoffset
, self
._x
2 + xoffset
, self
._y
2 + yoffset
) 
 129         elif self
._op 
== DRAWOP_DESTROY_CLIPPING_RECT
: 
 130             dc
.DestroyClippingRegion() 
 132     def Scale(self
, scaleX
, scaleY
): 
 138     def Translate(self
, x
, y
): 
 143 class OpDraw(DrawOp
): 
 144     """Draw line, rectangle, rounded rectangle, ellipse, point, arc, text.""" 
 145     def __init__(self
, theOp
, theX1
, theY1
, theX2
, theY2
, theRadius 
= 0.0, s 
= ""): 
 146         DrawOp
.__init
__(self
, theOp
) 
 154         self
._radius 
= theRadius
 
 157     def Do(self
, dc
, xoffset
, yoffset
): 
 158         if self
._op 
== DRAWOP_DRAW_LINE
: 
 159             dc
.DrawLine(self
._x
1 + xoffset
, self
._y
1 + yoffset
, self
._x
2 + xoffset
, self
._y
2 + yoffset
) 
 160         elif self
._op 
== DRAWOP_DRAW_RECT
: 
 161             dc
.DrawRectangle(self
._x
1 + xoffset
, self
._y
1 + yoffset
, self
._x
2, self
._y
2) 
 162         elif self
._op 
== DRAWOP_DRAW_ROUNDED_RECT
: 
 163             dc
.DrawRoundedRectangle(self
._x
1 + xoffset
, self
._y
1 + yoffset
, self
._x
2, self
._y
2, self
._radius
) 
 164         elif self
._op 
== DRAWOP_DRAW_ELLIPSE
: 
 165             dc
.DrawEllipse(self
._x
1 + xoffset
, self
._y
1 + yoffset
, self
._x
2, self
._y
2) 
 166         elif self
._op 
== DRAWOP_DRAW_ARC
: 
 167             dc
.DrawArc(self
._x
2 + xoffset
, self
._y
2 + yoffset
, self
._x
3 + xoffset
, self
._y
3 + yoffset
, self
._x
1 + xoffset
, self
._y
1 + yoffset
) 
 168         elif self
._op 
== DRAWOP_DRAW_ELLIPTIC_ARC
: 
 169             dc
.DrawEllipticArc(self
._x
1 + xoffset
, self
._y
1 + yoffset
, self
._x
2, self
._y
2, self
._x
3 * 360 / (2 * math
.pi
), self
._y
3 * 360 / (2 * math
.pi
)) 
 170         elif self
._op 
== DRAWOP_DRAW_POINT
: 
 171             dc
.DrawPoint(self
._x
1 + xoffset
, self
._y
1 + yoffset
) 
 172         elif self
._op 
== DRAWOP_DRAW_TEXT
: 
 173             dc
.DrawText(self
._textString
, self
._x
1 + xoffset
, self
._y
1 + yoffset
) 
 174     def Scale(self
, scaleX
, scaleY
): 
 180         if self
._op 
!= DRAWOP_DRAW_ELLIPTIC_ARC
: 
 184         self
._radius 
*= scaleX
 
 186     def Translate(self
, x
, y
): 
 190         if self
._op 
== DRAWOP_DRAW_LINE
: 
 193         elif self
._op 
== DRAWOP_DRAW_ARC
: 
 199     def Rotate(self
, x
, y
, theta
, sinTheta
, cosTheta
): 
 200         newX1 
= self
._x
1 * cosTheta 
+ self
._y
1 * sinTheta 
+ x 
* (1 - cosTheta
) + y 
* sinTheta
 
 201         newY1 
= self
._x
1 * sinTheta 
+ self
._y
1 * cosTheta 
+ y 
* (1 - cosTheta
) + x 
* sinTheta
 
 203         if self
._op 
== DRAWOP_DRAW_LINE
: 
 204             newX2 
= self
._x
2 * cosTheta 
- self
._y
2 * sinTheta 
+ x 
* (1 - cosTheta
) + y 
* sinTheta
 
 205             newY2 
= self
._x
2 * sinTheta 
+ self
._y
2 * cosTheta 
+ y 
* (1 - cosTheta
) + x 
* sinTheta
; 
 212         elif self
._op 
in [DRAWOP_DRAW_RECT
, DRAWOP_DRAW_ROUNDED_RECT
, DRAWOP_DRAW_ELLIPTIC_ARC
]: 
 213             # Assume only 0, 90, 180, 270 degree rotations. 
 214             # oldX1, oldY1 represents the top left corner. Find the 
 215             # bottom right, and rotate that. Then the width/height is 
 216             # the difference between x/y values. 
 217             oldBottomRightX 
= self
._x
1 + self
._x
2 
 218             oldBottomRightY 
= self
._y
1 + self
._y
2 
 219             newBottomRightX 
= oldBottomRightX 
* cosTheta 
- oldBottomRightY 
* sinTheta 
+ x 
* (1 - cosTheta
) + y 
* sinTheta
 
 220             newBottomRightY 
= oldBottomRightX 
* sinTheta 
+ oldBottomRightY 
* cosTheta 
+ y 
* (1 - cosTheta
) + x 
* sinTheta
 
 222             # Now find the new top-left, bottom-right coordinates. 
 223             minX 
= min(newX1
, newBottomRightX
) 
 224             minY 
= min(newY1
, newBottomRightY
) 
 225             maxX 
= max(newX1
, newBottomRightX
) 
 226             maxY 
= max(newY1
, newBottomRightY
) 
 230             self
._x
2 = maxX 
- minX 
# width 
 231             self
._y
2 = maxY 
- minY 
# height 
 233             if self
._op 
== DRAWOP_DRAW_ELLIPTIC_ARC
: 
 234                 # Add rotation to angles 
 237         elif self
._op 
== DRAWOP_DRAW_ARC
: 
 238             newX2 
= self
._x
2 * cosTheta 
- self
._y
2 * sinTheta 
+ x 
* (1 - cosTheta
) + y 
* sinTheta
 
 239             newY2 
= self
._x
2 * sinTheta 
+ self
._y
2 * cosTheta 
+ y 
* (1 - cosTheta
) + x 
* sinTheta
 
 240             newX3 
= self
._x
3 * cosTheta 
- self
._y
3 * sinTheta 
+ x 
* (1 - cosTheta
) + y 
* sinTheta
 
 241             newY3 
= self
._x
3 * sinTheta 
+ self
._y
3 * cosTheta 
+ y 
* (1 - cosTheta
) + x 
* sinTheta
 
 251 class OpPolyDraw(DrawOp
): 
 252     """Draw polygon, polyline, spline.""" 
 253     def __init__(self
, theOp
, thePoints
): 
 254         DrawOp
.__init
__(self
, theOp
) 
 256         self
._noPoints 
= len(thePoints
) 
 257         self
._points 
= thePoints
 
 259     def Do(self
, dc
, xoffset
, yoffset
): 
 260         if self
._op 
== DRAWOP_DRAW_POLYLINE
: 
 261             dc
.DrawLines(self
._points
, xoffset
, yoffset
) 
 262         elif self
._op 
== DRAWOP_DRAW_POLYGON
: 
 263             dc
.DrawPolygon(self
._points
, xoffset
, yoffset
) 
 264         elif self
._op 
== DRAWOP_DRAW_SPLINE
: 
 265             dc
.DrawSpline(self
._points
) # no offsets in DrawSpline 
 267     def Scale(self
, scaleX
, scaleY
): 
 268         for i 
in range(self
._noPoints
): 
 269             self
._points
[i
] = wx
.Point(self
._points
[i
][0] * scaleX
, self
._points
[i
][1] * scaleY
) 
 271     def Translate(self
, x
, y
): 
 272         for i 
in range(self
._noPoints
): 
 273             self
._points
[i
][0] += x
 
 274             self
._points
[i
][1] += y
 
 276     def Rotate(self
, x
, y
, theta
, sinTheta
, cosTheta
): 
 277         for i 
in range(self
._noPoints
): 
 278             x1 
= self
._points
[i
][0] 
 279             y1 
= self
._points
[i
][1] 
 281             self
._points
[i
] = x1 
* cosTheta 
- y1 
* sinTheta 
+ x 
* (1 - cosTheta
) + y 
* sinTheta
, x1 
* sinTheta 
+ y1 
* cosTheta 
+ y 
* (1 - cosTheta
) + x 
* sinTheta
 
 283     def OnDrawOutline(self
, dc
, x
, y
, w
, h
, oldW
, oldH
): 
 284         dc
.SetBrush(wx
.TRANSPARENT_BRUSH
) 
 286         # Multiply all points by proportion of new size to old size 
 287         x_proportion 
= abs(w 
/ oldW
) 
 288         y_proportion 
= abs(h 
/ oldH
) 
 290         dc
.DrawPolygon([(x_proportion 
* x
, y_proportion 
* y
) for x
, y 
in self
._points
], x
, y
) 
 292     def GetPerimeterPoint(self
, x1
, y1
, x2
, y2
, xOffset
, yOffset
, attachmentMode
): 
 293         # First check for situation where the line is vertical, 
 294         # and we would want to connect to a point on that vertical -- 
 295         # oglFindEndForPolyline can't cope with this (the arrow 
 296         # gets drawn to the wrong place). 
 297         if attachmentMode 
== ATTACHMENT_MODE_NONE 
and x1 
== x2
: 
 298             # Look for the point we'd be connecting to. This is 
 300             for point 
in self
._points
: 
 302                     if y2 
> y1 
and point
[1] > 0: 
 303                         return point
[0]+xOffset
, point
[1]+yOffset
 
 304                     elif y2 
< y1 
and point
[1] < 0: 
 305                         return point
[0]+xOffset
, point
[1]+yOffset
 
 307         return FindEndForPolyline([ p
[0] + xOffset 
for p 
in self
._points 
], 
 308                                   [ p
[1] + yOffset 
for p 
in self
._points 
], 
 312 class PseudoMetaFile(object): 
 314     A simple metafile-like class which can load data from a Windows 
 315     metafile on all platforms. 
 318         self
._currentRotation 
= 0 
 319         self
._rotateable 
= True 
 322         self
._outlinePen 
= None 
 323         self
._fillBrush 
= None 
 327         self
._gdiObjects 
= [] 
 329         self
._outlineColours 
= [] 
 330         self
._fillColours 
= [] 
 334         self
._gdiObjects 
= [] 
 335         self
._outlineColours 
= [] 
 336         self
._fillColours 
= [] 
 337         self
._outlineColours 
= -1 
 340         return self
._ops 
!= [] 
 345     def SetOutlineOp(self
, op
): 
 348     def GetOutlineOp(self
): 
 349         return self
._outlineOp
 
 351     def SetOutlinePen(self
, pen
): 
 352         self
._outlinePen 
= pen
 
 354     def GetOutlinePen(self
, pen
): 
 355         return self
._outlinePen
 
 357     def SetFillBrush(self
, brush
): 
 358         self
._fillBrush 
= brush
 
 360     def GetFillBrush(self
): 
 361         return self
._fillBrush
 
 363     def SetSize(self
, w
, h
): 
 367     def SetRotateable(self
, rot
): 
 368         self
._rotateable 
= rot
 
 370     def GetRotateable(self
): 
 371         return self
._rotateable
 
 373     def GetFillColours(self
): 
 374         return self
._fillColours
 
 376     def GetOutlineColours(self
): 
 377         return self
._outlineColours
 
 379     def Draw(self
, dc
, xoffset
, yoffset
): 
 381             op
.Do(dc
, xoffset
, yoffset
) 
 383     def Scale(self
, sx
, sy
): 
 390     def Translate(self
, x
, y
): 
 394     def Rotate(self
, x
, y
, theta
): 
 395         theta1 
= theta 
- self
._currentRotation
 
 399         cosTheta 
= math
.cos(theta1
) 
 400         sinTheta 
= math
.sin(theta1
) 
 403             op
.Rotate(x
, y
, theta
, sinTheta
, cosTheta
) 
 405         self
._currentRotation 
= theta
 
 407     def LoadFromMetaFile(self
, filename
, rwidth
, rheight
): 
 408         if not os
.path
.exist(filename
): 
 411         print "LoadFromMetaFile not implemented yet." 
 415     def ScaleTo(self
, w
, h
): 
 416         scaleX 
= w 
/ self
._width
 
 417         scaleY 
= h 
/ self
._height
 
 419         self
.Scale(scaleX
, scaleY
) 
 422         maxX
, maxY
, minX
, minY 
= -99999.9, -99999.9, 99999.9, 99999.9 
 425             if op
.GetOp() in [DRAWOP_DRAW_LINE
, DRAWOP_DRAW_RECT
, DRAWOP_DRAW_ROUNDED_RECT
, DRAWOP_DRAW_ELLIPSE
, DRAWOP_DRAW_POINT
, DRAWOP_DRAW_TEXT
]: 
 434                 if op
.GetOp() == DRAWOP_DRAW_LINE
: 
 443                 elif op
.GetOp() in [ DRAWOP_DRAW_RECT
, DRAWOP_DRAW_ROUNDED_RECT
, DRAWOP_DRAW_ELLIPSE
]: 
 444                     if op
._x
1 + op
._x
2 < minX
: 
 445                         minX 
= op
._x
1 + op
._x
2 
 446                     if op
._x
1 + op
._x
2 > maxX
: 
 447                         maxX 
= op
._x
1 + op
._x
2 
 448                     if op
._y
1 + op
._y
2 < minY
: 
 449                         minY 
= op
._y
1 + op
._y
2 
 450                     if op
._y
1 + op
._y
2 > maxX
: 
 451                         maxY 
= op
._y
1 + op
._y
2 
 452             elif op
.GetOp() == DRAWOP_DRAW_ARC
: 
 453                 # TODO: don't yet know how to calculate the bounding box 
 454                 # for an arc. So pretend it's a line; to get a correct 
 455                 # bounding box, draw a blank rectangle first, of the  
 473             elif op
.GetOp() in [DRAWOP_DRAW_POLYLINE
, DRAWOP_DRAW_POLYGON
, DRAWOP_DRAW_SPLINE
]: 
 474                 for point 
in op
._points
: 
 484         return [minX
, minY
, maxX
, maxY
] 
 486     # Calculate size from current operations 
 487     def CalculateSize(self
, shape
): 
 488         boundMinX
, boundMinY
, boundMaxX
, boundMaxY 
= self
.GetBounds() 
 490         # By Pierre Hjälm: This is NOT in the old version, which 
 491         # gets this totally wrong. Since the drawing is centered, we 
 492         # cannot get the width by measuring from left to right, we 
 493         # must instead make enough room to handle the largest 
 495         #self.SetSize(boundMaxX - boundMinX, boundMaxY - boundMinY) 
 497         w 
= max(abs(boundMinX
), abs(boundMaxX
)) * 2 
 498         h 
= max(abs(boundMinY
), abs(boundMaxY
)) * 2 
 503             shape
.SetWidth(self
._width
) 
 504             shape
.SetHeight(self
._height
) 
 506     # Set of functions for drawing into a pseudo metafile 
 507     def DrawLine(self
, pt1
, pt2
): 
 508         op 
= OpDraw(DRAWOP_DRAW_LINE
, pt1
[0], pt1
[1], pt2
[0], pt2
[1]) 
 511     def DrawRectangle(self
, rect
): 
 512         op 
= OpDraw(DRAWOP_DRAW_RECT
, rect
[0], rect
[1], rect
[2], rect
[3]) 
 515     def DrawRoundedRectangle(self
, rect
, radius
): 
 516         op 
= OpDraw(DRAWOP_DRAW_ROUNDED_RECT
, rect
[0], rect
[1], rect
[2], rect
[3]) 
 520     def DrawEllipse(self
, rect
): 
 521         op 
= OpDraw(DRAWOP_DRAW_ELLIPSE
, rect
[0], rect
[1], rect
[2], rect
[3]) 
 524     def DrawArc(self
, centrePt
, startPt
, endPt
): 
 525         op 
= OpDraw(DRAWOP_DRAW_ARC
, centrePt
[0], centrePt
[1], startPt
[0], startPt
[1]) 
 526         op
._x
3, op
._y
3 = endPt
 
 530     def DrawEllipticArc(self
, rect
, startAngle
, endAngle
): 
 531         startAngleRadians 
= startAngle 
* math
.pi 
* 2 / 360 
 532         endAngleRadians 
= endAngle 
* math
.pi 
* 2 / 360 
 534         op 
= OpDraw(DRAWOP_DRAW_ELLIPTIC_ARC
, rect
[0], rect
[1], rect
[2], rect
[3]) 
 535         op
._x
3 = startAngleRadians
 
 536         op
._y
3 = endAngleRadians
 
 540     def DrawPoint(self
, pt
): 
 541         op 
= OpDraw(DRAWOP_DRAW_POINT
, pt
[0], pt
[1], 0, 0) 
 544     def DrawText(self
, text
, pt
): 
 545         op 
= OpDraw(DRAWOP_DRAW_TEXT
, pt
[0], pt
[1], 0, 0) 
 546         op
._textString 
= text
 
 549     def DrawLines(self
, pts
): 
 550         op 
= OpPolyDraw(DRAWOP_DRAW_POLYLINE
, pts
) 
 554     # oglMETAFLAGS_OUTLINE: will be used for drawing the outline and 
 555     #                       also drawing lines/arrows at the circumference. 
 556     # oglMETAFLAGS_ATTACHMENTS: will be used for initialising attachment 
 557     #                       points at the vertices (perhaps a rare case...) 
 558     def DrawPolygon(self
, pts
, flags 
= 0): 
 559         op 
= OpPolyDraw(DRAWOP_DRAW_POLYGON
, pts
) 
 562         if flags 
& METAFLAGS_OUTLINE
: 
 563             self
._outlineOp 
= len(self
._ops
) - 1 
 565     def DrawSpline(self
, pts
): 
 566         op 
= OpPolyDraw(DRAWOP_DRAW_SPLINE
, pts
) 
 569     def SetClippingRect(self
, rect
): 
 570         OpSetClipping(DRAWOP_SET_CLIPPING_RECT
, rect
[0], rect
[1], rect
[2], rect
[3]) 
 572     def DestroyClippingRect(self
): 
 573         op 
= OpSetClipping(DRAWOP_DESTROY_CLIPPING_RECT
, 0, 0, 0, 0) 
 576     def SetPen(self
, pen
, isOutline 
= False): 
 577         self
._gdiObjects
.append(pen
) 
 578         op 
= OpSetGDI(DRAWOP_SET_PEN
, self
, len(self
._gdiObjects
) - 1) 
 582             self
._outlineColours
.append(len(self
._gdiObjects
) - 1) 
 584     def SetBrush(self
, brush
, isFill 
= False): 
 585         self
._gdiObjects
.append(brush
) 
 586         op 
= OpSetGDI(DRAWOP_SET_BRUSH
, self
, len(self
._gdiObjects
) - 1) 
 590             self
._fillColours
.append(len(self
._gdiObjects
) - 1) 
 592     def SetFont(self
, font
): 
 593         self
._gdiObjects
.append(font
) 
 594         op 
= OpSetGDI(DRAWOP_SET_FONT
, self
, len(self
._gdiObjects
) - 1) 
 597     def SetTextColour(self
, colour
): 
 598         op 
= OpSetGDI(DRAWOP_SET_TEXT_COLOUR
, self
, 0) 
 599         op
._r
, op
._g
, op
._b 
= colour
.Red(), colour
.Green(), colour
.Blue() 
 603     def SetBackgroundColour(self
, colour
): 
 604         op 
= OpSetGDI(DRAWOP_SET_BK_COLOUR
, self
, 0) 
 605         op
._r
, op
._g
, op
._b 
= colour
.Red(), colour
.Green(), colour
.Blue() 
 609     def SetBackgroundMode(self
, mode
): 
 610         op 
= OpSetGDI(DRAWOP_SET_BK_MODE
, self
, 0) 
 613 class DrawnShape(RectangleShape
): 
 615     Draws a pseudo-metafile shape, which can be loaded from a simple 
 618     wxDrawnShape allows you to specify a different shape for each of four 
 619     orientations (North, West, South and East). It also provides a set of 
 620     drawing functions for programmatic drawing of a shape, so that during 
 621     construction of the shape you can draw into it as if it were a device 
 628         RectangleShape
.__init
__(self
, 100, 50) 
 629         self
._saveToFile 
= True 
 630         self
._currentAngle 
= DRAWN_ANGLE_0
 
 632         self
._metafiles
=PseudoMetaFile(), PseudoMetaFile(), PseudoMetaFile(), PseudoMetaFile() 
 634     def OnDraw(self
, dc
): 
 635         # Pass pen and brush in case we have force outline 
 637         if self
._shadowMode 
!= SHADOW_NONE
: 
 638             if self
._shadowBrush
: 
 639                 self
._metafiles
[self
._currentAngle
]._fillBrush 
= self
._shadowBrush
 
 640             self
._metafiles
[self
._currentAngle
]._outlinePen 
= wx
.Pen(wx
.WHITE
, 1, wx
.TRANSPARENT
) 
 641             self
._metafiles
[self
._currentAngle
].Draw(dc
, self
._xpos 
+ self
._shadowOffsetX
, self
._ypos 
+ self
._shadowOffsetY
) 
 643         self
._metafiles
[self
._currentAngle
]._outlinePen 
= self
._pen
 
 644         self
._metafiles
[self
._currentAngle
]._fillBrush 
= self
._brush
 
 645         self
._metafiles
[self
._currentAngle
].Draw(dc
, self
._xpos
, self
._ypos
) 
 647     def SetSize(self
, w
, h
, recursive 
= True): 
 648         self
.SetAttachmentSize(w
, h
) 
 650         if self
.GetWidth() == 0.0: 
 653             scaleX 
= w 
/ self
.GetWidth() 
 655         if self
.GetHeight() == 0.0: 
 658             scaleY 
= h 
/ self
.GetHeight() 
 661             if self
._metafiles
[i
].IsValid(): 
 662                 self
._metafiles
[i
].Scale(scaleX
, scaleY
) 
 666         self
.SetDefaultRegionSize() 
 668     def Scale(self
, sx
, sy
): 
 669         """Scale the shape by the given amount.""" 
 671             if self
._metafiles
[i
].IsValid(): 
 672                 self
._metafiles
[i
].Scale(sx
, sy
) 
 673                 self
._metafiles
[i
].CalculateSize(self
) 
 675     def Translate(self
, x
, y
): 
 676         """Translate the shape by the given amount.""" 
 678             if self
._metafiles
[i
].IsValid(): 
 679                 self
._metafiles
[i
].Translate(x
, y
) 
 680                 self
._metafiles
[i
].CalculateSize(self
) 
 682     # theta is absolute rotation from the zero position 
 683     def Rotate(self
, x
, y
, theta
): 
 684         """Rotate about the given axis by the given amount in radians.""" 
 685         self
._currentAngle 
= self
.DetermineMetaFile(theta
) 
 687         if self
._currentAngle 
== 0: 
 689             if not self
._metafiles
[0].GetRotateable(): 
 692             self
._metafiles
[0].Rotate(x
, y
, theta
) 
 694         actualTheta 
= theta 
- self
._rotation
 
 696         # Rotate attachment points 
 697         sinTheta 
= math
.sin(actualTheta
) 
 698         cosTheta 
= math
.cos(actualTheta
) 
 700         for point 
in self
._attachmentPoints
: 
 704             point
._x 
= x1 
* cosTheta 
- y1 
* sinTheta 
+ x 
* (1.0 - cosTheta
) + y 
* sinTheta
 
 705             point
._y 
= x1 
* sinTheta 
+ y1 
* cosTheta 
+ y 
* (1.0 - cosTheta
) + x 
* sinTheta
 
 707         self
._rotation 
= theta
 
 709         self
._metafiles
[self
._currentAngle
].CalculateSize(self
) 
 711     # Which metafile do we use now? Based on current rotation and validity 
 713     def DetermineMetaFile(self
, rotation
): 
 715         angles 
= [0.0, math
.pi 
/ 2, math
.pi
, 3 * math
.pi 
/ 2] 
 720             if RoughlyEqual(rotation
, angles
[i
], tolerance
): 
 724         if whichMetaFile 
> 0 and not self
._metafiles
[whichMetaFile
].IsValid(): 
 729     def OnDrawOutline(self
, dc
, x
, y
, w
, h
): 
 730         if self
._metafiles
[self
._currentAngle
].GetOutlineOp() != -1: 
 731             op 
= self
._metafiles
[self
._currentAngle
].GetOps()[self
._metafiles
[self
._currentAngle
].GetOutlineOp()] 
 732             if op
.OnDrawOutline(dc
, x
, y
, w
, h
, self
._width
, self
._height
): 
 735         # Default... just use a rectangle 
 736         RectangleShape
.OnDrawOutline(self
, dc
, x
, y
, w
, h
) 
 738     # Get the perimeter point using the special outline op, if there is one, 
 739     # otherwise use default wxRectangleShape scheme 
 740     def GetPerimeterPoint(self
, x1
, y1
, x2
, y2
): 
 741         if self
._metafiles
[self
._currentAngle
].GetOutlineOp() != -1: 
 742             op 
= self
._metafiles
[self
._currentAngle
].GetOps()[self
._metafiles
[self
._currentAngle
].GetOutlineOp()] 
 743             p 
= op
.GetPerimeterPoint(x1
, y1
, x2
, y2
, self
.GetX(), self
.GetY(), self
.GetAttachmentMode()) 
 747         return RectangleShape
.GetPerimeterPoint(self
, x1
, y1
, x2
, y2
) 
 749     def LoadFromMetaFile(self
, filename
): 
 750         """Load a (very simple) Windows metafile, created for example by 
 751         Top Draw, the Windows shareware graphics package.""" 
 752         return self
._metafiles
[0].LoadFromMetaFile(filename
) 
 754     # Set of functions for drawing into a pseudo metafile. 
 755     # They use integers, but doubles are used internally for accuracy 
 757     def DrawLine(self
, pt1
, pt2
): 
 758         self
._metafiles
[self
._currentAngle
].DrawLine(pt1
, pt2
) 
 760     def DrawRectangle(self
, rect
): 
 761         self
._metafiles
[self
._currentAngle
].DrawRectangle(rect
) 
 763     def DrawRoundedRectangle(self
, rect
, radius
): 
 764         """Draw a rounded rectangle. 
 766         radius is the corner radius. If radius is negative, it expresses 
 767         the radius as a proportion of the smallest dimension of the rectangle. 
 769         self
._metafiles
[self
._currentAngle
].DrawRoundedRectangle(rect
, radius
) 
 771     def DrawEllipse(self
, rect
): 
 772         self
._metafiles
[self
._currentAngle
].DrawEllipse(rect
) 
 774     def DrawArc(self
, centrePt
, startPt
, endPt
): 
 776         self
._metafiles
[self
._currentAngle
].DrawArc(centrePt
, startPt
, endPt
) 
 778     def DrawEllipticArc(self
, rect
, startAngle
, endAngle
): 
 779         """Draw an elliptic arc.""" 
 780         self
._metafiles
[self
._currentAngle
].DrawEllipticArc(rect
, startAngle
, endAngle
) 
 782     def DrawPoint(self
, pt
): 
 783         self
._metafiles
[self
._currentAngle
].DrawPoint(pt
) 
 785     def DrawText(self
, text
, pt
): 
 786         self
._metafiles
[self
._currentAngle
].DrawText(text
, pt
) 
 788     def DrawLines(self
, pts
): 
 789         self
._metafiles
[self
._currentAngle
].DrawLines(pts
) 
 791     def DrawPolygon(self
, pts
, flags 
= 0): 
 794         flags can be one or more of: 
 795         METAFLAGS_OUTLINE (use this polygon for the drag outline) and 
 796         METAFLAGS_ATTACHMENTS (use the vertices of this polygon for attachments). 
 798         if flags 
and METAFLAGS_ATTACHMENTS
: 
 799             self
.ClearAttachments() 
 800             for i 
in range(len(pts
)): 
 801                 self
._attachmentPoints
.append(AttachmentPoint(i
,pts
[i
][0],pts
[i
][1])) 
 802         self
._metafiles
[self
._currentAngle
].DrawPolygon(pts
, flags
) 
 804     def DrawSpline(self
, pts
): 
 805         self
._metafiles
[self
._currentAngle
].DrawSpline(pts
) 
 807     def SetClippingRect(self
, rect
): 
 808         """Set the clipping rectangle.""" 
 809         self
._metafiles
[self
._currentAngle
].SetClippingRect(rect
) 
 811     def DestroyClippingRect(self
): 
 812         """Destroy the clipping rectangle.""" 
 813         self
._metafiles
[self
._currentAngle
].DestroyClippingRect() 
 815     def SetDrawnPen(self
, pen
, isOutline 
= False): 
 816         """Set the pen for this metafile. 
 818         If isOutline is True, this pen is taken to indicate the outline 
 819         (and if the outline pen is changed for the whole shape, the pen 
 820         will be replaced with the outline pen). 
 822         self
._metafiles
[self
._currentAngle
].SetPen(pen
, isOutline
) 
 824     def SetDrawnBrush(self
, brush
, isFill 
= False): 
 825         """Set the brush for this metafile. 
 827         If isFill is True, the brush is used as the fill brush. 
 829         self
._metafiles
[self
._currentAngle
].SetBrush(brush
, isFill
) 
 831     def SetDrawnFont(self
, font
): 
 832         self
._metafiles
[self
._currentAngle
].SetFont(font
) 
 834     def SetDrawnTextColour(self
, colour
): 
 835         """Set the current text colour for the current metafile.""" 
 836         self
._metafiles
[self
._currentAngle
].SetTextColour(colour
) 
 838     def SetDrawnBackgroundColour(self
, colour
): 
 839         """Set the current background colour for the current metafile.""" 
 840         self
._metafiles
[self
._currentAngle
].SetBackgroundColour(colour
) 
 842     def SetDrawnBackgroundMode(self
, mode
): 
 843         """Set the current background mode for the current metafile.""" 
 844         self
._metafiles
[self
._currentAngle
].SetBackgroundMode(mode
) 
 846     def CalculateSize(self
): 
 847         """Calculate the wxDrawnShape size from the current metafile. 
 849         Call this after you have drawn into the shape. 
 851         self
._metafiles
[self
._currentAngle
].CalculateSize(self
) 
 853     def DrawAtAngle(self
, angle
): 
 854         """Set the metafile for the given orientation, which can be one of: 
 861         self
._currentAngle 
= angle
 
 864         """Return the current orientation, which can be one of: 
 871         return self
._currentAngle
 
 873     def GetRotation(self
): 
 874         """Return the current rotation of the shape in radians.""" 
 875         return self
._rotation
 
 877     def SetSaveToFile(self
, save
): 
 878         """If save is True, the image will be saved along with the shape's 
 879         other attributes. The reason why this might not be desirable is that 
 880         if there are many shapes with the same image, it would be more 
 881         efficient for the application to save one copy, and not duplicate 
 882         the information for every shape. The default is True. 
 884         self
._saveToFile 
= save
 
 886     def GetMetaFile(self
, which 
= 0): 
 887         """Return a reference to the internal 'pseudo-metafile'.""" 
 888         return self
._metafiles
[which
]