]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/ogl/_lines.py
move wxPython to new trunk
[wxWidgets.git] / wxPython / wx / lib / ogl / _lines.py
diff --git a/wxPython/wx/lib/ogl/_lines.py b/wxPython/wx/lib/ogl/_lines.py
deleted file mode 100644 (file)
index 77ce392..0000000
+++ /dev/null
@@ -1,1527 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-#----------------------------------------------------------------------------
-# Name:         lines.py
-# Purpose:      LineShape class
-#
-# Author:       Pierre Hjälm (from C++ original by Julian Smart)
-#
-# Created:      2004-05-08
-# RCS-ID:       $Id$
-# Copyright:    (c) 2004 Pierre Hjälm - 1998 Julian Smart
-# Licence:      wxWindows license
-#----------------------------------------------------------------------------
-
-import sys
-import math
-
-from _basic import Shape, ShapeRegion, ShapeTextLine, ControlPoint, RectangleShape
-from _oglmisc import *
-
-# Line alignment flags
-# Vertical by default
-LINE_ALIGNMENT_HORIZ =              1
-LINE_ALIGNMENT_VERT =               0
-LINE_ALIGNMENT_TO_NEXT_HANDLE =     2
-LINE_ALIGNMENT_NONE =               0
-
-
-
-class LineControlPoint(ControlPoint):
-    def __init__(self, theCanvas = None, object = None, size = 0.0, x = 0.0, y = 0.0, the_type = 0):
-        ControlPoint.__init__(self, theCanvas, object, size, x, y, the_type)
-        self._xpos = x
-        self._ypos = y
-        self._type = the_type
-        self._point = None
-        self._originalPos = None
-
-    def OnDraw(self, dc):
-        RectangleShape.OnDraw(self, dc)
-
-    # Implement movement of Line point
-    def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
-        self._shape.GetEventHandler().OnSizingDragLeft(self, draw, x, y, keys, attachment)
-
-    def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
-        self._shape.GetEventHandler().OnSizingBeginDragLeft(self, x, y, keys, attachment)
-
-    def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
-        self._shape.GetEventHandler().OnSizingEndDragLeft(self, x, y, keys, attachment)
-
-
-
-class ArrowHead(object):
-    def __init__(self, type = 0, end = 0, size = 0.0, dist = 0.0, name = "", mf = None, arrowId = -1):
-        if isinstance(type, ArrowHead):
-            pass
-        else:
-            self._arrowType = type
-            self._arrowEnd = end
-            self._arrowSize = size
-            self._xOffset = dist
-            self._yOffset = 0.0
-            self._spacing = 5.0
-
-            self._arrowName = name
-            self._metaFile = mf
-            self._id = arrowId
-            if self._id == -1:
-                self._id = wx.NewId()
-            
-    def _GetType(self):
-        return self._arrowType
-
-    def GetPosition(self):
-        return self._arrowEnd
-
-    def SetPosition(self, pos):
-        self._arrowEnd = pos
-
-    def GetXOffset(self):
-        return self._xOffset
-
-    def GetYOffset(self):
-        return self._yOffset
-    
-    def GetSpacing(self):
-        return self._spacing
-
-    def GetSize(self):
-        return self._arrowSize
-
-    def SetSize(self, size):
-        self._arrowSize = size
-        if self._arrowType == ARROW_METAFILE and self._metaFile:
-            oldWidth = self._metaFile._width
-            if oldWidth == 0:
-                return
-
-            scale = float(size) / oldWidth
-            if scale != 1:
-                self._metaFile.Scale(scale, scale)
-                
-    def GetName(self):
-        return self._arrowName
-
-    def SetXOffset(self, x):
-        self._xOffset = x
-
-    def SetYOffset(self, y):
-        self._yOffset = y
-
-    def GetMetaFile(self):
-        return self._metaFile
-
-    def GetId(self):
-        return self._id
-
-    def GetArrowEnd(self):
-        return self._arrowEnd
-
-    def GetArrowSize(self):
-        return self._arrowSize
-
-    def SetSpacing(self, sp):
-        self._spacing = sp
-
-
-
-class LabelShape(RectangleShape):
-    def __init__(self, parent, region, w, h):
-        RectangleShape.__init__(self, w, h)
-        self._lineShape = parent
-        self._shapeRegion = region
-        self.SetPen(wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT))
-
-    def OnDraw(self, dc):
-        if self._lineShape and not self._lineShape.GetDrawHandles():
-            return
-
-        x1 = self._xpos - self._width / 2.0
-        y1 = self._ypos - self._height / 2.0
-
-        if self._pen:
-            if self._pen.GetWidth() == 0:
-                dc.SetPen(wx.Pen(wx.WHITE, 1, wx.TRANSPARENT))
-            else:
-                dc.SetPen(self._pen)
-        dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
-        if self._cornerRadius > 0:
-            dc.DrawRoundedRectangle(x1, y1, self._width, self._height, self._cornerRadius)
-        else:
-            dc.DrawRectangle(x1, y1, self._width, self._height)
-
-    def OnDrawContents(self, dc):
-        pass
-
-    def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
-        RectangleShape.OnDragLeft(self, draw, x, y, keys, attachment)
-
-    def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
-        RectangleShape.OnBeginDragLeft(self, x, y, keys, attachment)
-
-    def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
-        RectangleShape.OnEndDragLeft(self, x, y, keys, attachment)
-
-    def OnMovePre(self, dc, x, y, old_x, old_y, display):
-        return self._lineShape.OnLabelMovePre(dc, self, x, y, old_x, old_y, display)
-
-    # Divert left and right clicks to line object
-    def OnLeftClick(self, x, y, keys = 0, attachment = 0):
-        self._lineShape.GetEventHandler().OnLeftClick(x, y, keys, attachment)
-
-    def OnRightClick(self, x, y, keys = 0, attachment = 0):
-        self._lineShape.GetEventHandler().OnRightClick(x, y, keys, attachment)
-        
-
-
-class LineShape(Shape):
-    """LineShape may be attached to two nodes;
-    it may be segmented, in which case a control point is drawn for each joint.
-
-    A wxLineShape may have arrows at the beginning, end and centre.
-
-    Derived from:
-      Shape
-    """
-    def __init__(self):
-        Shape.__init__(self)
-
-        self._sensitivity = OP_CLICK_LEFT | OP_CLICK_RIGHT
-        self._draggable = False
-        self._attachmentTo = 0
-        self._attachmentFrom = 0
-        self._from = None
-        self._to = None
-        self._erasing = False
-        self._arrowSpacing = 5.0
-        self._ignoreArrowOffsets = False
-        self._isSpline = False
-        self._maintainStraightLines = False
-        self._alignmentStart = 0
-        self._alignmentEnd = 0
-
-        self._lineControlPoints = None
-
-        # Clear any existing regions (created in an earlier constructor)
-        # and make the three line regions.
-        self.ClearRegions()
-        for name in ["Middle","Start","End"]:
-            newRegion = ShapeRegion()
-            newRegion.SetName(name)
-            newRegion.SetSize(150, 50)
-            self._regions.append(newRegion)
-
-        self._labelObjects = [None, None, None]
-        self._lineOrientations = []
-        self._lineControlPoints = []
-        self._arcArrows = []
-
-    def GetFrom(self):
-        """Return the 'from' object."""
-        return self._from
-    
-    def GetTo(self):
-        """Return the 'to' object."""
-        return self._to
-
-    def GetAttachmentFrom(self):
-        """Return the attachment point on the 'from' node."""
-        return self._attachmentFrom
-
-    def GetAttachmentTo(self):
-        """Return the attachment point on the 'to' node."""
-        return self._attachmentTo
-
-    def GetLineControlPoints(self):
-        return self._lineControlPoints
-
-    def SetSpline(self, spline):
-        """Specifies whether a spline is to be drawn through the control points."""
-        self._isSpline = spline
-
-    def IsSpline(self):
-        """TRUE if a spline is drawn through the control points."""
-        return self._isSpline
-
-    def SetAttachmentFrom(self, attach):
-        """Set the 'from' shape attachment."""
-        self._attachmentFrom = attach
-
-    def SetAttachmentTo(self, attach):
-        """Set the 'to' shape attachment."""
-        self._attachmentTo = attach
-
-    # This is really to distinguish between lines and other images.
-    # For lines, want to pass drag to canvas, since lines tend to prevent
-    # dragging on a canvas (they get in the way.)
-    def Draggable(self):
-        return False
-
-    def SetIgnoreOffsets(self, ignore):
-        """Set whether to ignore offsets from the end of the line when drawing."""
-        self._ignoreArrowOffsets = ignore
-
-    def GetArrows(self):
-        return self._arcArrows
-
-    def GetAlignmentStart(self):
-        return self._alignmentStart
-
-    def GetAlignmentEnd(self):
-        return self._alignmentEnd
-
-    def IsEnd(self, nodeObject):
-        """TRUE if shape is at the end of the line."""
-        return self._to == nodeObject
-
-    def MakeLineControlPoints(self, n):
-        """Make a given number of control points (minimum of two)."""
-        self._lineControlPoints = []
-        
-        for _ in range(n):
-            point = wx.RealPoint(-999, -999)
-            self._lineControlPoints.append(point)
-
-        # pi: added _initialised to keep track of when we have set
-        # the middle points to something other than (-999, -999)
-        self._initialised = False
-        
-    def InsertLineControlPoint(self, dc = None, point = None):
-        """Insert a control point at an optional given position."""
-        if dc:
-            self.Erase(dc)
-
-        if point:
-            line_x, line_y = point
-        else:
-            last_point = self._lineControlPoints[-1]
-            second_last_point = self._lineControlPoints[-2]
-
-            line_x = (last_point[0] + second_last_point[0]) / 2.0
-            line_y = (last_point[1] + second_last_point[1]) / 2.0
-
-        point = wx.RealPoint(line_x, line_y)
-        self._lineControlPoints.insert(len(self._lineControlPoints)-1, point)
-
-    def DeleteLineControlPoint(self):
-        """Delete an arbitary point on the line."""
-        if len(self._lineControlPoints) < 3:
-            return False
-
-        del self._lineControlPoints[-2]
-        return True
-
-    def Initialise(self):
-        """Initialise the line object."""
-        if self._lineControlPoints:
-            # Just move the first and last control points
-            first_point = self._lineControlPoints[0]
-            last_point = self._lineControlPoints[-1]
-
-            # If any of the line points are at -999, we must
-            # initialize them by placing them half way between the first
-            # and the last.
-
-            for i in range(1,len(self._lineControlPoints)):
-                point = self._lineControlPoints[i]
-                if point[0] == -999:
-                    if first_point[0] < last_point[0]:
-                        x1 = first_point[0]
-                        x2 = last_point[0]
-                    else:
-                        x2 = first_point[0]
-                        x1 = last_point[0]
-                    if first_point[1] < last_point[1]:
-                        y1 = first_point[1]
-                        y2 = last_point[1]
-                    else:
-                        y2 = first_point[1]
-                        y1 = last_point[1]
-                    self._lineControlPoints[i] = wx.RealPoint((x2 - x1) / 2.0 + x1, (y2 - y1) / 2.0 + y1)
-            self._initialised = True
-                    
-    def FormatText(self, dc, s, i):
-        """Format a text string according to the region size, adding
-        strings with positions to region text list.
-        """
-        self.ClearText(i)
-
-        if len(self._regions) == 0 or i >= len(self._regions):
-            return
-
-        region = self._regions[i]
-        region.SetText(s)
-        dc.SetFont(region.GetFont())
-
-        w, h = region.GetSize()
-        # Initialize the size if zero
-        if (w == 0 or h == 0) and s:
-            w, h = 100, 50
-            region.SetSize(w, h)
-
-        string_list = FormatText(dc, s, w - 5, h - 5, region.GetFormatMode())
-        for s in string_list:
-            line = ShapeTextLine(0.0, 0.0, s)
-            region.GetFormattedText().append(line)
-
-        actualW = w
-        actualH = h
-        if region.GetFormatMode() & FORMAT_SIZE_TO_CONTENTS:
-            actualW, actualH = GetCentredTextExtent(dc, region.GetFormattedText(), self._xpos, self._ypos, w, h)
-            if actualW != w or actualH != h:
-                xx, yy = self.GetLabelPosition(i)
-                self.EraseRegion(dc, region, xx, yy)
-                if len(self._labelObjects) < i:
-                    self._labelObjects[i].Select(False, dc)
-                    self._labelObjects[i].Erase(dc)
-                    self._labelObjects[i].SetSize(actualW, actualH)
-
-                region.SetSize(actualW, actualH)
-
-                if len(self._labelObjects) < i:
-                    self._labelObjects[i].Select(True, dc)
-                    self._labelObjects[i].Draw(dc)
-
-        CentreText(dc, region.GetFormattedText(), self._xpos, self._ypos, actualW, actualH, region.GetFormatMode())
-        self._formatted = True
-
-    def DrawRegion(self, dc, region, x, y):
-        """Format one region at this position."""
-        if self.GetDisableLabel():
-            return
-
-        w, h = region.GetSize()
-
-        # Get offset from x, y
-        xx, yy = region.GetPosition()
-
-        xp = xx + x
-        yp = yy + y
-
-        # First, clear a rectangle for the text IF there is any
-        if len(region.GetFormattedText()):
-            dc.SetPen(self.GetBackgroundPen())
-            dc.SetBrush(self.GetBackgroundBrush())
-
-            # Now draw the text
-            if region.GetFont():
-                dc.SetFont(region.GetFont())
-                dc.DrawRectangle(xp - w / 2.0, yp - h / 2.0, w, h)
-
-                if self._pen:
-                    dc.SetPen(self._pen)
-                dc.SetTextForeground(region.GetActualColourObject())
-
-                DrawFormattedText(dc, region.GetFormattedText(), xp, yp, w, h, region.GetFormatMode())
-
-    def EraseRegion(self, dc, region, x, y):
-        """Erase one region at this position."""
-        if self.GetDisableLabel():
-            return
-
-        w, h = region.GetSize()
-
-        # Get offset from x, y
-        xx, yy = region.GetPosition()
-
-        xp = xx + x
-        yp = yy + y
-
-        if region.GetFormattedText():
-            dc.SetPen(self.GetBackgroundPen())
-            dc.SetBrush(self.GetBackgroundBrush())
-
-            dc.DrawRectangle(xp - w / 2.0, yp - h / 2.0, w, h)
-
-    def GetLabelPosition(self, position):
-        """Get the reference point for a label.
-
-        Region x and y are offsets from this.
-        position is 0 (middle), 1 (start), 2 (end).
-        """
-        if position == 0:
-            # Want to take the middle section for the label
-            half_way = int(len(self._lineControlPoints) / 2.0)
-
-            # Find middle of this line
-            point = self._lineControlPoints[half_way - 1]
-            next_point = self._lineControlPoints[half_way]
-
-            dx = next_point[0] - point[0]
-            dy = next_point[1] - point[1]
-
-            return point[0] + dx / 2.0, point[1] + dy / 2.0
-        elif position == 1:
-            return self._lineControlPoints[0][0], self._lineControlPoints[0][1]
-        elif position == 2:
-            return self._lineControlPoints[-1][0], self._lineControlPoints[-1][1]
-
-    def Straighten(self, dc = None):
-        """Straighten verticals and horizontals."""
-        if len(self._lineControlPoints) < 3:
-            return
-
-        if dc:
-            self.Erase(dc)
-
-        GraphicsStraightenLine(self._lineControlPoints[-1], self._lineControlPoints[-2])
-
-        for i in range(len(self._lineControlPoints) - 2):
-            GraphicsStraightenLine(self._lineControlPoints[i], self._lineControlPoints[i + 1])
-                
-        if dc:
-            self.Draw(dc)
-
-    def Unlink(self):
-        """Unlink the line from the nodes at either end."""
-        if self._to:
-            self._to.GetLines().remove(self)
-        if self._from:
-            self._from.GetLines().remove(self)
-        self._to = None
-        self._from = None
-        for i in range(3):
-            if self._labelObjects[i]:
-                self._labelObjects[i].Select(False)
-                self._labelObjects[i].RemoveFromCanvas(self._canvas)
-        self.ClearArrowsAtPosition(-1)
-
-    def SetEnds(self, x1, y1, x2, y2):
-        """Set the end positions of the line."""
-        self._lineControlPoints[0] = wx.RealPoint(x1, y1)
-        self._lineControlPoints[-1] = wx.RealPoint(x2, y2)
-
-        # Find centre point
-        self._xpos = (x1 + x2) / 2.0
-        self._ypos = (y1 + y2) / 2.0
-
-    # Get absolute positions of ends
-    def GetEnds(self):
-        """Get the visible endpoints of the lines for drawing between two objects."""
-        first_point = self._lineControlPoints[0]
-        last_point = self._lineControlPoints[-1]
-
-        return first_point[0], first_point[1], last_point[0], last_point[1]
-
-    def SetAttachments(self, from_attach, to_attach):
-        """Specify which object attachment points should be used at each end
-        of the line.
-        """
-        self._attachmentFrom = from_attach
-        self._attachmentTo = to_attach
-
-    def HitTest(self, x, y):
-        if not self._lineControlPoints:
-            return False
-
-        # Look at label regions in case mouse is over a label
-        inLabelRegion = False
-        for i in range(3):
-            if self._regions[i]:
-                region = self._regions[i]
-                if len(region._formattedText):
-                    xp, yp = self.GetLabelPosition(i)
-                    # Offset region from default label position
-                    cx, cy = region.GetPosition()
-                    cw, ch = region.GetSize() 
-                    cx += xp
-                    cy += yp
-                    
-                    rLeft = cx - cw / 2.0
-                    rTop = cy - ch / 2.0
-                    rRight = cx + cw / 2.0
-                    rBottom = cy + ch / 2.0
-                    if x > rLeft and x < rRight and y > rTop and y < rBottom:
-                        inLabelRegion = True
-                        break
-
-        for i in range(len(self._lineControlPoints) - 1):
-            point1 = self._lineControlPoints[i]
-            point2 = self._lineControlPoints[i + 1]
-
-            # For inaccurate mousing allow 8 pixel corridor
-            extra = 4
-
-            dx = point2[0] - point1[0]
-            dy = point2[1] - point1[1]
-
-            seg_len = math.sqrt(dx * dx + dy * dy)
-            if dy == 0 and dx == 0:
-                continue
-            distance_from_seg = seg_len * float((x - point1[0]) * dy - (y - point1[1]) * dx) / (dy * dy + dx * dx)
-            distance_from_prev = seg_len * float((y - point1[1]) * dy + (x - point1[0]) * dx) / (dy * dy + dx * dx)
-
-            if abs(distance_from_seg) < extra and distance_from_prev >= 0 and distance_from_prev <= seg_len or inLabelRegion:
-                return 0, distance_from_seg
-
-        return False
-
-    def DrawArrows(self, dc):
-        """Draw all arrows."""
-        # Distance along line of each arrow: space them out evenly
-        startArrowPos = 0.0
-        endArrowPos = 0.0
-        middleArrowPos = 0.0
-
-        for arrow in self._arcArrows:
-            ah = arrow.GetArrowEnd()
-            if ah == ARROW_POSITION_START:
-                if arrow.GetXOffset() and not self._ignoreArrowOffsets:
-                    # If specified, x offset is proportional to line length
-                    self.DrawArrow(dc, arrow, arrow.GetXOffset(), True)
-                else:
-                    self.DrawArrow(dc, arrow, startArrowPos, False)
-                    startArrowPos += arrow.GetSize() + arrow.GetSpacing()
-            elif ah == ARROW_POSITION_END:
-                if arrow.GetXOffset() and not self._ignoreArrowOffsets:
-                    self.DrawArrow(dc, arrow, arrow.GetXOffset(), True)
-                else:
-                    self.DrawArrow(dc, arrow, endArrowPos, False)
-                    endArrowPos += arrow.GetSize() + arrow.GetSpacing()
-            elif ah == ARROW_POSITION_MIDDLE:
-                arrow.SetXOffset(middleArrowPos)
-                if arrow.GetXOffset() and not self._ignoreArrowOffsets:
-                    self.DrawArrow(dc, arrow, arrow.GetXOffset(), True)
-                else:
-                    self.DrawArrow(dc, arrow, middleArrowPos, False)
-                    middleArrowPos += arrow.GetSize() + arrow.GetSpacing()
-
-    def DrawArrow(self, dc, arrow, XOffset, proportionalOffset):
-        """Draw the given arrowhead (or annotation)."""
-        first_line_point = self._lineControlPoints[0]
-        second_line_point = self._lineControlPoints[1]
-
-        last_line_point = self._lineControlPoints[-1]
-        second_last_line_point = self._lineControlPoints[-2]
-
-        # Position of start point of line, at the end of which we draw the arrow
-        startPositionX, startPositionY = 0.0, 0.0
-
-        ap = arrow.GetPosition()
-        if ap == ARROW_POSITION_START:
-            # If we're using a proportional offset, calculate just where this
-            # will be on the line.
-            realOffset = XOffset
-            if proportionalOffset:
-                totalLength = math.sqrt((second_line_point[0] - first_line_point[0]) * (second_line_point[0] - first_line_point[0]) + (second_line_point[1] - first_line_point[1]) * (second_line_point[1] - first_line_point[1]))
-                realOffset = XOffset * totalLength
-
-            positionOnLineX, positionOnLineY = GetPointOnLine(second_line_point[0], second_line_point[1], first_line_point[0], first_line_point[1], realOffset)
-            
-            startPositionX = second_line_point[0]
-            startPositionY = second_line_point[1]
-        elif ap == ARROW_POSITION_END:
-            # If we're using a proportional offset, calculate just where this
-            # will be on the line.
-            realOffset = XOffset
-            if proportionalOffset:
-                totalLength = math.sqrt((second_last_line_point[0] - last_line_point[0]) * (second_last_line_point[0] - last_line_point[0]) + (second_last_line_point[1] - last_line_point[1]) * (second_last_line_point[1] - last_line_point[1]));
-                realOffset = XOffset * totalLength
-            
-            positionOnLineX, positionOnLineY = GetPointOnLine(second_last_line_point[0], second_last_line_point[1], last_line_point[0], last_line_point[1], realOffset)
-            
-            startPositionX = second_last_line_point[0]
-            startPositionY = second_last_line_point[1]
-        elif ap == ARROW_POSITION_MIDDLE:
-            # Choose a point half way between the last and penultimate points
-            x = (last_line_point[0] + second_last_line_point[0]) / 2.0
-            y = (last_line_point[1] + second_last_line_point[1]) / 2.0
-
-            # If we're using a proportional offset, calculate just where this
-            # will be on the line.
-            realOffset = XOffset
-            if proportionalOffset:
-                totalLength = math.sqrt((second_last_line_point[0] - x) * (second_last_line_point[0] - x) + (second_last_line_point[1] - y) * (second_last_line_point[1] - y));
-                realOffset = XOffset * totalLength
-
-            positionOnLineX, positionOnLineY = GetPointOnLine(second_last_line_point[0], second_last_line_point[1], x, y, realOffset)
-            startPositionX = second_last_line_point[0]
-            startPositionY = second_last_line_point[1]
-
-        # Add yOffset to arrow, if any
-
-        # The translation that the y offset may give
-        deltaX = 0.0
-        deltaY = 0.0
-        if arrow.GetYOffset and not self._ignoreArrowOffsets:
-            #                             |(x4, y4)
-            #                             |d
-            #                             |
-            #   (x1, y1)--------------(x3, y3)------------------(x2, y2)
-            #   x4 = x3 - d * math.sin(theta)
-            #   y4 = y3 + d * math.cos(theta)
-            #
-            #   Where theta = math.tan(-1) of (y3-y1) / (x3-x1)
-            x1 = startPositionX
-            y1 = startPositionY
-            x3 = float(positionOnLineX)
-            y3 = float(positionOnLineY)
-            d = -arrow.GetYOffset() # Negate so +offset is above line
-
-            if x3 == x1:
-                theta = math.pi / 2.0
-            else:
-                theta = math.atan((y3 - y1) / (x3 - x1))
-
-            x4 = x3 - d * math.sin(theta)
-            y4 = y3 + d * math.cos(theta)
-            
-            deltaX = x4 - positionOnLineX
-            deltaY = y4 - positionOnLineY
-
-        at = arrow._GetType()
-        if at == ARROW_ARROW:
-            arrowLength = arrow.GetSize()
-            arrowWidth = arrowLength / 3.0
-
-            tip_x, tip_y, side1_x, side1_y, side2_x, side2_y = GetArrowPoints(startPositionX + deltaX, startPositionY + deltaY, positionOnLineX + deltaX, positionOnLineY + deltaY, arrowLength, arrowWidth)
-
-            points = [[tip_x, tip_y],
-                    [side1_x, side1_y],
-                    [side2_x, side2_y],
-                    [tip_x, tip_y]]
-
-            dc.SetPen(self._pen)
-            dc.SetBrush(self._brush)
-            dc.DrawPolygon(points)
-        elif at in [ARROW_HOLLOW_CIRCLE, ARROW_FILLED_CIRCLE]:
-            # Find point on line of centre of circle, which is a radius away
-            # from the end position
-            diameter = arrow.GetSize()
-            x, y = GetPointOnLine(startPositionX + deltaX, startPositionY + deltaY,
-                               positionOnLineX + deltaX, positionOnLineY + deltaY,
-                               diameter / 2.0)
-            x1 = x - diameter / 2.0
-            y1 = y - diameter / 2.0
-            dc.SetPen(self._pen)
-            if arrow._GetType() == ARROW_HOLLOW_CIRCLE:
-                dc.SetBrush(self.GetBackgroundBrush())
-            else:
-                dc.SetBrush(self._brush)
-
-            dc.DrawEllipse(x1, y1, diameter, diameter)
-        elif at == ARROW_SINGLE_OBLIQUE:
-            pass
-        elif at == ARROW_METAFILE:
-            if arrow.GetMetaFile():
-                # Find point on line of centre of object, which is a half-width away
-                # from the end position
-                #
-                #                 width
-                #  <-- start pos  <-----><-- positionOnLineX
-                #                 _____
-                #  --------------|  x  | <-- e.g. rectangular arrowhead
-                #                 -----
-                #
-                x, y = GetPointOnLine(startPositionX, startPositionY,
-                                   positionOnLineX, positionOnLineY,
-                                   arrow.GetMetaFile()._width / 2.0)
-                # Calculate theta for rotating the metafile.
-                #
-                # |
-                # |     o(x2, y2)   'o' represents the arrowhead.
-                # |    /
-                # |   /
-                # |  /theta
-                # | /(x1, y1)
-                # |______________________
-                #
-                theta = 0.0
-                x1 = startPositionX
-                y1 = startPositionY
-                x2 = float(positionOnLineX)
-                y2 = float(positionOnLineY)
-
-                if x1 == x2 and y1 == y2:
-                    theta = 0.0
-                elif x1 == x2 and y1 > y2:
-                    theta = 3.0 * math.pi / 2.0
-                elif x1 == x2 and y2 > y1:
-                    theta = math.pi / 2.0
-                elif x2 > x1 and y2 >= y1:
-                    theta = math.atan((y2 - y1) / (x2 - x1))
-                elif x2 < x1:
-                    theta = math.pi + math.atan((y2 - y1) / (x2 - x1))
-                elif x2 > x1 and y2 < y1:
-                    theta = 2 * math.pi + math.atan((y2 - y1) / (x2 - x1))
-                else:
-                    raise "Unknown arrowhead rotation case"
-
-                # Rotate about the centre of the object, then place
-                # the object on the line.
-                if arrow.GetMetaFile().GetRotateable():
-                    arrow.GetMetaFile().Rotate(0.0, 0.0, theta)
-
-                if self._erasing:
-                    # If erasing, just draw a rectangle
-                    minX, minY, maxX, maxY = arrow.GetMetaFile().GetBounds()
-                    # Make erasing rectangle slightly bigger or you get droppings
-                    extraPixels = 4
-                    dc.DrawRectangle(deltaX + x + minX - extraPixels / 2.0, deltaY + y + minY - extraPixels / 2.0, maxX - minX + extraPixels, maxY - minY + extraPixels)
-                else:
-                    arrow.GetMetaFile().Draw(dc, x + deltaX, y + deltaY)
-
-    def OnErase(self, dc):
-        old_pen = self._pen
-        old_brush = self._brush
-
-        bg_pen = self.GetBackgroundPen()
-        bg_brush = self.GetBackgroundBrush()
-        self.SetPen(bg_pen)
-        self.SetBrush(bg_brush)
-
-        bound_x, bound_y = self.GetBoundingBoxMax()
-        if self._font:
-            dc.SetFont(self._font)
-
-        # Undraw text regions
-        for i in range(3):
-            if self._regions[i]:
-                x, y = self.GetLabelPosition(i)
-                self.EraseRegion(dc, self._regions[i], x, y)
-
-        # Undraw line
-        dc.SetPen(self.GetBackgroundPen())
-        dc.SetBrush(self.GetBackgroundBrush())
-
-        # Drawing over the line only seems to work if the line has a thickness
-        # of 1.
-        if old_pen and old_pen.GetWidth() > 1:
-            dc.DrawRectangle(self._xpos - bound_x / 2.0 - 2, self._ypos - bound_y / 2.0 - 2,
-                             bound_x + 4, bound_y + 4)
-        else:
-            self._erasing = True
-            self.GetEventHandler().OnDraw(dc)
-            self.GetEventHandler().OnEraseControlPoints(dc)
-            self._erasing = False
-
-        if old_pen:
-            self.SetPen(old_pen)
-        if old_brush:
-            self.SetBrush(old_brush)
-
-    def GetBoundingBoxMin(self):
-        x1, y1 = 10000, 10000
-        x2, y2 = -10000, -10000
-
-        for point in self._lineControlPoints:
-            if point[0] < x1:
-                x1 = point[0]
-            if point[1] < y1:
-                y1 = point[1]
-            if point[0] > x2:
-                x2 = point[0]
-            if point[1] > y2:
-                y2 = point[1]
-
-        return x2 - x1, y2 - y1
-        
-    # For a node image of interest, finds the position of this arc
-    # amongst all the arcs which are attached to THIS SIDE of the node image,
-    # and the number of same.
-    def FindNth(self, image, incoming):
-        """Find the position of the line on the given object.
-
-        Specify whether incoming or outgoing lines are being considered
-        with incoming.
-        """
-        n = -1
-        num = 0
-        
-        if image == self._to:
-            this_attachment = self._attachmentTo
-        else:
-            this_attachment = self._attachmentFrom
-
-        # Find number of lines going into / out of this particular attachment point
-        for line in image.GetLines():
-            if line._from == image:
-                # This is the nth line attached to 'image'
-                if line == self and not incoming:
-                    n = num
-
-                # Increment num count if this is the same side (attachment number)
-                if line._attachmentFrom == this_attachment:
-                    num += 1
-
-            if line._to == image:
-                # This is the nth line attached to 'image'
-                if line == self and incoming:
-                    n = num
-
-                # Increment num count if this is the same side (attachment number)
-                if line._attachmentTo == this_attachment:
-                    num += 1
-
-        return n, num
-
-    def OnDrawOutline(self, dc, x, y, w, h):
-        old_pen = self._pen
-        old_brush = self._brush
-
-        dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
-        self.SetPen(dottedPen)
-        self.SetBrush(wx.TRANSPARENT_BRUSH)
-
-        self.GetEventHandler().OnDraw(dc)
-
-        if old_pen:
-            self.SetPen(old_pen)
-        else:
-            self.SetPen(None)
-        if old_brush:
-            self.SetBrush(old_brush)
-        else:
-            self.SetBrush(None)
-
-    def OnMovePre(self, dc, x, y, old_x, old_y, display = True):
-        x_offset = x - old_x
-        y_offset = y - old_y
-
-        if self._lineControlPoints and not (x_offset == 0 and y_offset == 0):
-            for point in self._lineControlPoints:
-                point[0] += x_offset
-                point[1] += y_offset
-
-        # Move temporary label rectangles if necessary
-        for i in range(3):
-            if self._labelObjects[i]:
-                self._labelObjects[i].Erase(dc)
-                xp, yp = self.GetLabelPosition(i)
-                if i < len(self._regions):
-                    xr, yr = self._regions[i].GetPosition()
-                else:
-                    xr, yr = 0, 0
-                self._labelObjects[i].Move(dc, xp + xr, yp + yr)
-        return True
-
-    def OnMoveLink(self, dc, moveControlPoints = True):
-        """Called when a connected object has moved, to move the link to
-        correct position
-        """
-        if not self._from or not self._to:
-            return
-
-        # Do each end - nothing in the middle. User has to move other points
-        # manually if necessary
-        end_x, end_y, other_end_x, other_end_y = self.FindLineEndPoints()
-
-        oldX, oldY = self._xpos, self._ypos
-
-        # pi: The first time we go through FindLineEndPoints we can't
-        # use the middle points (since they don't have sane values),
-        # so we just do what we do for a normal line. Then we call
-        # Initialise to set the middle points, and then FindLineEndPoints
-        # again, but this time (and from now on) we use the middle
-        # points to calculate the end points.
-        # This was buggy in the C++ version too.
-        
-        self.SetEnds(end_x, end_y, other_end_x, other_end_y)
-
-        if len(self._lineControlPoints) > 2:
-            self.Initialise()
-
-        # Do a second time, because one may depend on the other
-        end_x, end_y, other_end_x, other_end_y = self.FindLineEndPoints()
-        self.SetEnds(end_x, end_y, other_end_x, other_end_y)
-
-        # Try to move control points with the arc
-        x_offset = self._xpos - oldX
-        y_offset = self._ypos - oldY
-
-        # Only move control points if it's a self link. And only works
-        # if attachment mode is ON
-        if self._from == self._to and self._from.GetAttachmentMode() != ATTACHMENT_MODE_NONE and moveControlPoints and self._lineControlPoints and not (x_offset == 0 and y_offset == 0):
-            for point in self._lineControlPoints[1:-1]:
-                point[0] += x_offset
-                point[1] += y_offset
-
-        self.Move(dc, self._xpos, self._ypos)
-
-    def FindLineEndPoints(self):
-        """Finds the x, y points at the two ends of the line.
-
-        This function can be used by e.g. line-routing routines to
-        get the actual points on the two node images where the lines will be
-        drawn to / from.
-        """
-        if not self._from or not self._to:
-            return
-
-        # Do each end - nothing in the middle. User has to move other points
-        # manually if necessary.
-        second_point = self._lineControlPoints[1]
-        second_last_point = self._lineControlPoints[-2]
-
-        # pi: If we have a segmented line and this is the first time,
-        # do this as a straight line.
-        if len(self._lineControlPoints) > 2 and self._initialised:
-            if self._from.GetAttachmentMode() != ATTACHMENT_MODE_NONE:
-                nth, no_arcs = self.FindNth(self._from, False) # Not incoming
-                end_x, end_y = self._from.GetAttachmentPosition(self._attachmentFrom, nth, no_arcs, self)
-            else:
-                end_x, end_y = self._from.GetPerimeterPoint(self._from.GetX(), self._from.GetY(), second_point[0], second_point[1])
-
-            if self._to.GetAttachmentMode() != ATTACHMENT_MODE_NONE:
-                nth, no_arch = self.FindNth(self._to, True) # Incoming
-                other_end_x, other_end_y = self._to.GetAttachmentPosition(self._attachmentTo, nth, no_arch, self)
-            else:
-                other_end_x, other_end_y = self._to.GetPerimeterPoint(self._to.GetX(), self._to.GetY(), second_last_point[0], second_last_point[1])
-        else:
-            fromX = self._from.GetX()
-            fromY = self._from.GetY()
-            toX = self._to.GetX()
-            toY = self._to.GetY()
-
-            if self._from.GetAttachmentMode() != ATTACHMENT_MODE_NONE:
-                nth, no_arcs = self.FindNth(self._from, False)
-                end_x, end_y = self._from.GetAttachmentPosition(self._attachmentFrom, nth, no_arcs, self)
-                fromX = end_x
-                fromY = end_y
-
-            if self._to.GetAttachmentMode() != ATTACHMENT_MODE_NONE:
-                nth, no_arcs = self.FindNth(self._to, True)
-                other_end_x, other_end_y = self._to.GetAttachmentPosition(self._attachmentTo, nth, no_arcs, self)
-                toX = other_end_x
-                toY = other_end_y
-
-            if self._from.GetAttachmentMode() == ATTACHMENT_MODE_NONE:
-                end_x, end_y = self._from.GetPerimeterPoint(self._from.GetX(), self._from.GetY(), toX, toY)
-
-            if self._to.GetAttachmentMode() == ATTACHMENT_MODE_NONE:
-                other_end_x, other_end_y = self._to.GetPerimeterPoint(self._to.GetX(), self._to.GetY(), fromX, fromY)
-
-        return end_x, end_y, other_end_x, other_end_y
-
-
-    def OnDraw(self, dc):
-        if not self._lineControlPoints:
-            return
-
-        if self._pen:
-            dc.SetPen(self._pen)
-        if self._brush:
-            dc.SetBrush(self._brush)
-
-        points = []
-        for point in self._lineControlPoints:
-            points.append(wx.Point(point[0], point[1]))
-
-        if self._isSpline:
-            dc.DrawSpline(points)
-        else:
-            dc.DrawLines(points)
-
-        if sys.platform[:3] == "win":
-            # For some reason, last point isn't drawn under Windows
-            pt = points[-1]
-            dc.DrawPoint(pt[0], pt[1])
-
-        # Problem with pen - if not a solid pen, does strange things
-        # to the arrowhead. So make (get) a new pen that's solid.
-        if self._pen and self._pen.GetStyle() != wx.SOLID:
-            solid_pen = wx.Pen(self._pen.GetColour(), 1, wx.SOLID)
-            if solid_pen:
-                dc.SetPen(solid_pen)
-
-        self.DrawArrows(dc)
-
-    def OnDrawControlPoints(self, dc):
-        if not self._drawHandles:
-            return
-
-        # Draw temporary label rectangles if necessary
-        for i in range(3):
-            if self._labelObjects[i]:
-                self._labelObjects[i].Draw(dc)
-
-        Shape.OnDrawControlPoints(self, dc)
-
-    def OnEraseControlPoints(self, dc):
-        # Erase temporary label rectangles if necessary
-        
-        for i in range(3):
-            if self._labelObjects[i]:
-                self._labelObjects[i].Erase(dc)
-
-        Shape.OnEraseControlPoints(self, dc)
-
-    def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
-        pass
-
-    def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
-        pass
-
-    def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
-        pass
-
-    def OnDrawContents(self, dc):
-        if self.GetDisableLabel():
-            return
-
-        for i in range(3):
-            if self._regions[i]:
-                x, y = self.GetLabelPosition(i)
-                self.DrawRegion(dc, self._regions[i], x, y)
-
-    def SetTo(self, object):
-        """Set the 'to' object for the line."""
-        self._to = object
-
-    def SetFrom(self, object):
-        """Set the 'from' object for the line."""
-        self._from = object
-
-    def MakeControlPoints(self):
-        """Make handle control points."""
-        if self._canvas and self._lineControlPoints:
-            first = self._lineControlPoints[0]
-            last = self._lineControlPoints[-1]
-
-            control = LineControlPoint(self._canvas, self, CONTROL_POINT_SIZE, first[0], first[1], CONTROL_POINT_ENDPOINT_FROM)
-            control._point = first
-            self._canvas.AddShape(control)
-            self._controlPoints.append(control)
-
-            for point in self._lineControlPoints[1:-1]:
-                control = LineControlPoint(self._canvas, self, CONTROL_POINT_SIZE, point[0], point[1], CONTROL_POINT_LINE)
-                control._point = point
-                self._canvas.AddShape(control)
-                self._controlPoints.append(control)
-
-            control = LineControlPoint(self._canvas, self, CONTROL_POINT_SIZE, last[0], last[1], CONTROL_POINT_ENDPOINT_TO)
-            control._point = last
-            self._canvas.AddShape(control)
-            self._controlPoints.append(control)
-
-    def ResetControlPoints(self):
-        if self._canvas and self._lineControlPoints and self._controlPoints:
-            for i in range(min(len(self._controlPoints), len(self._lineControlPoints))):
-                point = self._lineControlPoints[i]
-                control = self._controlPoints[i]
-                control.SetX(point[0])
-                control.SetY(point[1])
-
-    # Override select, to create / delete temporary label-moving objects
-    def Select(self, select, dc = None):
-        Shape.Select(self, select, dc)
-        if select:
-            for i in range(3):
-                if self._regions[i]:
-                    region = self._regions[i]
-                    if region._formattedText:
-                        w, h = region.GetSize()
-                        x, y = region.GetPosition()
-                        xx, yy = self.GetLabelPosition(i)
-
-                        if self._labelObjects[i]:
-                            self._labelObjects[i].Select(False)
-                            self._labelObjects[i].RemoveFromCanvas(self._canvas)
-
-                        self._labelObjects[i] = self.OnCreateLabelShape(self, region, w, h)
-                        self._labelObjects[i].AddToCanvas(self._canvas)
-                        self._labelObjects[i].Show(True)
-                        if dc:
-                            self._labelObjects[i].Move(dc, x + xx, y + yy)
-                        self._labelObjects[i].Select(True, dc)
-        else:
-            for i in range(3):
-                if self._labelObjects[i]:
-                    self._labelObjects[i].Select(False, dc)
-                    self._labelObjects[i].Erase(dc)
-                    self._labelObjects[i].RemoveFromCanvas(self._canvas)
-                    self._labelObjects[i] = None
-
-    # Control points ('handles') redirect control to the actual shape, to
-    # make it easier to override sizing behaviour.
-    def OnSizingDragLeft(self, pt, draw, x, y, keys = 0, attachment = 0):
-        dc = wx.ClientDC(self.GetCanvas())
-        self.GetCanvas().PrepareDC(dc)
-
-        dc.SetLogicalFunction(OGLRBLF)
-
-        dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
-        dc.SetPen(dottedPen)
-        dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
-        if pt._type == CONTROL_POINT_LINE:
-            x, y = self._canvas.Snap(x, y)
-
-            pt.SetX(x)
-            pt.SetY(y)
-            pt._point[0] = x
-            pt._point[1] = y
-            
-            old_pen = self.GetPen()
-            old_brush = self.GetBrush()
-
-            self.SetPen(dottedPen)
-            self.SetBrush(wx.TRANSPARENT_BRUSH)
-
-            self.GetEventHandler().OnMoveLink(dc, False)
-            
-            self.SetPen(old_pen)
-            self.SetBrush(old_brush)
-
-    def OnSizingBeginDragLeft(self, pt, x, y, keys = 0, attachment = 0):
-        dc = wx.ClientDC(self.GetCanvas())
-        self.GetCanvas().PrepareDC(dc)
-
-        if pt._type == CONTROL_POINT_LINE:
-            pt._originalPos = pt._point
-            x, y = self._canvas.Snap(x, y)
-
-            self.Erase(dc)
-
-            # Redraw start and end objects because we've left holes
-            # when erasing the line
-            self.GetFrom().OnDraw(dc)
-            self.GetFrom().OnDrawContents(dc)
-            self.GetTo().OnDraw(dc)
-            self.GetTo().OnDrawContents(dc)
-
-            self.SetDisableLabel(True)
-            dc.SetLogicalFunction(OGLRBLF)
-
-            pt._xpos = x
-            pt._ypos = y
-            pt._point[0] = x
-            pt._point[1] = y
-
-            old_pen = self.GetPen()
-            old_brush = self.GetBrush()
-
-            dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
-            self.SetPen(dottedPen)
-            self.SetBrush(wx.TRANSPARENT_BRUSH)
-
-            self.GetEventHandler().OnMoveLink(dc, False)
-
-            self.SetPen(old_pen)
-            self.SetBrush(old_brush)
-
-        if pt._type == CONTROL_POINT_ENDPOINT_FROM or pt._type == CONTROL_POINT_ENDPOINT_TO:
-            self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_BULLSEYE))
-            pt._oldCursor = wx.STANDARD_CURSOR
-
-    def OnSizingEndDragLeft(self, pt, x, y, keys = 0, attachment = 0):
-        dc = wx.ClientDC(self.GetCanvas())
-        self.GetCanvas().PrepareDC(dc)
-
-        self.SetDisableLabel(False)
-
-        if pt._type == CONTROL_POINT_LINE:
-            x, y = self._canvas.Snap(x, y)
-
-            rpt = wx.RealPoint(x, y)
-
-            # Move the control point back to where it was;
-            # MoveControlPoint will move it to the new position
-            # if it decides it wants. We only moved the position
-            # during user feedback so we could redraw the line
-            # as it changed shape.
-            pt._xpos = pt._originalPos[0]
-            pt._ypos = pt._originalPos[1]
-            pt._point[0] = pt._originalPos[0]
-            pt._point[1] = pt._originalPos[1]
-
-            self.OnMoveMiddleControlPoint(dc, pt, rpt)
-
-        if pt._type == CONTROL_POINT_ENDPOINT_FROM:
-            if pt._oldCursor:
-                self._canvas.SetCursor(pt._oldCursor)
-
-            if self.GetFrom():
-                self.GetFrom().MoveLineToNewAttachment(dc, self, x, y)
-
-        if pt._type == CONTROL_POINT_ENDPOINT_TO:
-            if pt._oldCursor:
-                self._canvas.SetCursor(pt._oldCursor)
-
-            if self.GetTo():
-                self.GetTo().MoveLineToNewAttachment(dc, self, x, y)
-
-    # This is called only when a non-end control point is moved
-    def OnMoveMiddleControlPoint(self, dc, lpt, pt):
-        lpt._xpos = pt[0]
-        lpt._ypos = pt[1]
-
-        lpt._point[0] = pt[0]
-        lpt._point[1] = pt[1]
-
-        self.GetEventHandler().OnMoveLink(dc)
-
-        return True
-
-    def AddArrow(self, type, end = ARROW_POSITION_END, size = 10.0, xOffset = 0.0, name = "", mf = None, arrowId = -1):
-        """Add an arrow (or annotation) to the line.
-
-        type may currently be one of:
-
-        ARROW_HOLLOW_CIRCLE
-          Hollow circle. 
-        ARROW_FILLED_CIRCLE
-          Filled circle. 
-        ARROW_ARROW
-          Conventional arrowhead. 
-        ARROW_SINGLE_OBLIQUE
-          Single oblique stroke. 
-        ARROW_DOUBLE_OBLIQUE
-          Double oblique stroke. 
-        ARROW_DOUBLE_METAFILE
-          Custom arrowhead. 
-
-        end may currently be one of:
-
-        ARROW_POSITION_END
-          Arrow appears at the end. 
-        ARROW_POSITION_START
-          Arrow appears at the start. 
-
-        arrowSize specifies the length of the arrow.
-
-        xOffset specifies the offset from the end of the line.
-
-        name specifies a name for the arrow.
-
-        mf can be a wxPseduoMetaFile, perhaps loaded from a simple Windows
-        metafile.
-
-        arrowId is the id for the arrow.
-        """
-        arrow = ArrowHead(type, end, size, xOffset, name, mf, arrowId)
-        self._arcArrows.append(arrow)
-        return arrow
-
-    # Add arrowhead at a particular position in the arrowhead list
-    def AddArrowOrdered(self, arrow, referenceList, end):
-        """Add an arrowhead in the position indicated by the reference list
-        of arrowheads, which contains all legal arrowheads for this line, in
-        the correct order. E.g.
-
-        Reference list:      a b c d e
-        Current line list:   a d
-
-        Add c, then line list is: a c d.
-
-        If no legal arrowhead position, return FALSE. Assume reference list
-        is for one end only, since it potentially defines the ordering for
-        any one of the 3 positions. So we don't check the reference list for
-        arrowhead position.
-        """
-        if not referenceList:
-            return False
-
-        targetName = arrow.GetName()
-
-        # First check whether we need to insert in front of list,
-        # because this arrowhead is the first in the reference
-        # list and should therefore be first in the current list.
-        refArrow = referenceList[0]
-        if refArrow.GetName() == targetName:
-            self._arcArrows.insert(0, arrow)
-            return True
-
-        i1 = i2 = 0
-        while i1 < len(referenceList) and i2 < len(self._arcArrows):
-            refArrow = referenceList[i1]
-            currArrow = self._arcArrows[i2]
-
-            # Matching: advance current arrow pointer
-            if currArrow.GetArrowEnd() == end and currArrow.GetName() == refArrow.GetName():
-                i2 += 1
-
-            # Check if we're at the correct position in the
-            # reference list
-            if targetName == refArrow.GetName():
-                if i2 < len(self._arcArrows):
-                    self._arcArrows.insert(i2, arrow)
-                else:
-                    self._arcArrows.append(arrow)
-                return True
-            i1 += 1
-
-        self._arcArrows.append(arrow)
-        return True
-
-    def ClearArrowsAtPosition(self, end):
-        """Delete the arrows at the specified position, or at any position
-        if position is -1.
-        """
-        if end == -1:
-            self._arcArrows = []
-            return
-
-        for arrow in self._arcArrows:
-            if arrow.GetArrowEnd() == end:
-                self._arcArrows.remove(arrow)
-
-    def ClearArrow(self, name):
-        """Delete the arrow with the given name."""
-        for arrow in self._arcArrows:
-            if arrow.GetName() == name:
-                self._arcArrows.remove(arrow)
-                return True
-        return False
-
-    def FindArrowHead(self, position, name):
-        """Find arrowhead by position and name.
-
-        if position is -1, matches any position.
-        """
-        for arrow in self._arcArrows:
-            if (position == -1 or position == arrow.GetArrowEnd()) and arrow.GetName() == name:
-                return arrow
-
-        return None
-
-    def FindArrowHeadId(self, arrowId):
-        """Find arrowhead by id."""
-        for arrow in self._arcArrows:
-            if arrowId == arrow.GetId():
-                return arrow
-
-        return None
-
-    def DeleteArrowHead(self, position, name):
-        """Delete arrowhead by position and name.
-
-        if position is -1, matches any position.
-        """
-        for arrow in self._arcArrows:
-            if (position == -1 or position == arrow.GetArrowEnd()) and arrow.GetName() == name:
-                self._arcArrows.remove(arrow)
-                return True
-        return False
-    
-    def DeleteArrowHeadId(self, id):
-        """Delete arrowhead by id."""
-        for arrow in self._arcArrows:
-            if arrowId == arrow.GetId():
-                self._arcArrows.remove(arrow)
-                return True
-        return False
-
-    # Calculate the minimum width a line
-    # occupies, for the purposes of drawing lines in tools.
-    def FindMinimumWidth(self):
-        """Find the horizontal width for drawing a line with arrows in
-        minimum space. Assume arrows at end only.
-        """
-        minWidth = 0.0
-        for arrowHead in self._arcArrows:
-            minWidth += arrowHead.GetSize()
-            if arrowHead != self._arcArrows[-1]:
-                minWidth += arrowHead + GetSpacing
-
-        # We have ABSOLUTE minimum now. So
-        # scale it to give it reasonable aesthetics
-        # when drawing with line.
-        if minWidth > 0:
-            minWidth = minWidth * 1.4
-        else:
-            minWidth = 20.0
-
-        self.SetEnds(0.0, 0.0, minWidth, 0.0)
-        self.Initialise()
-
-        return minWidth
-
-    def FindLinePosition(self, x, y):
-        """Find which position we're talking about at this x, y.
-
-        Returns ARROW_POSITION_START, ARROW_POSITION_MIDDLE, ARROW_POSITION_END.
-        """
-        startX, startY, endX, endY = self.GetEnds()
-
-        # Find distances from centre, start and end. The smallest wins
-        centreDistance = math.sqrt((x - self._xpos) * (x - self._xpos) + (y - self._ypos) * (y - self._ypos))
-        startDistance = math.sqrt((x - startX) * (x - startX) + (y - startY) * (y - startY))
-        endDistance = math.sqrt((x - endX) * (x - endX) + (y - endY) * (y - endY))
-
-        if centreDistance < startDistance and centreDistance < endDistance:
-            return ARROW_POSITION_MIDDLE
-        elif startDistance < endDistance:
-            return ARROW_POSITION_START
-        else:
-            return ARROW_POSITION_END
-
-    def SetAlignmentOrientation(self, isEnd, isHoriz):
-        if isEnd:
-            if isHoriz and self._alignmentEnd & LINE_ALIGNMENT_HORIZ != LINE_ALIGNMENT_HORIZ:
-                self._alignmentEnd != LINE_ALIGNMENT_HORIZ
-            elif not isHoriz and self._alignmentEnd & LINE_ALIGNMENT_HORIZ == LINE_ALIGNMENT_HORIZ:
-                self._alignmentEnd -= LINE_ALIGNMENT_HORIZ
-        else:
-            if isHoriz and self._alignmentStart & LINE_ALIGNMENT_HORIZ != LINE_ALIGNMENT_HORIZ:
-                self._alignmentStart != LINE_ALIGNMENT_HORIZ
-            elif not isHoriz and self._alignmentStart & LINE_ALIGNMENT_HORIZ == LINE_ALIGNMENT_HORIZ:
-                self._alignmentStart -= LINE_ALIGNMENT_HORIZ
-            
-    def SetAlignmentType(self, isEnd, alignType):
-        if isEnd:
-            if alignType == LINE_ALIGNMENT_TO_NEXT_HANDLE:
-                if self._alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE != LINE_ALIGNMENT_TO_NEXT_HANDLE:
-                    self._alignmentEnd |= LINE_ALIGNMENT_TO_NEXT_HANDLE
-            elif self._alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE == LINE_ALIGNMENT_TO_NEXT_HANDLE:
-                self._alignmentEnd -= LINE_ALIGNMENT_TO_NEXT_HANDLE
-        else:
-            if alignType == LINE_ALIGNMENT_TO_NEXT_HANDLE:
-                if self._alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE != LINE_ALIGNMENT_TO_NEXT_HANDLE:
-                    self._alignmentStart |= LINE_ALIGNMENT_TO_NEXT_HANDLE
-            elif self._alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE == LINE_ALIGNMENT_TO_NEXT_HANDLE:
-                self._alignmentStart -= LINE_ALIGNMENT_TO_NEXT_HANDLE
-            
-    def GetAlignmentOrientation(self, isEnd):
-        if isEnd:
-            return self._alignmentEnd & LINE_ALIGNMENT_HORIZ == LINE_ALIGNMENT_HORIZ
-        else:
-            return self._alignmentStart & LINE_ALIGNMENT_HORIZ == LINE_ALIGNMENT_HORIZ
-
-    def GetAlignmentType(self, isEnd):
-        if isEnd:
-            return self._alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE
-        else:
-            return self._alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE
-
-    def GetNextControlPoint(self, shape):
-        """Find the next control point in the line after the start / end point,
-        depending on whether the shape is at the start or end.
-        """
-        n = len(self._lineControlPoints)
-        if self._to == shape:
-            # Must be END of line, so we want (n - 1)th control point.
-            # But indexing ends at n-1, so subtract 2.
-            nn = n - 2
-        else:
-            nn = 1
-        if nn < len(self._lineControlPoints):
-            return self._lineControlPoints[nn]
-        return None
-
-    def OnCreateLabelShape(self, parent, region, w, h):
-        return LabelShape(parent, region, w, h)
-
-    
-    def OnLabelMovePre(self, dc, labelShape, x, y, old_x, old_y, display):
-        labelShape._shapeRegion.SetSize(labelShape.GetWidth(), labelShape.GetHeight())
-
-        # Find position in line's region list
-        i = self._regions.index(labelShape._shapeRegion)
-                
-        xx, yy = self.GetLabelPosition(i)
-        # Set the region's offset, relative to the default position for
-        # each region.
-        labelShape._shapeRegion.SetPosition(x - xx, y - yy)
-        labelShape.SetX(x)
-        labelShape.SetY(y)
-
-        # Need to reformat to fit region
-        if labelShape._shapeRegion.GetText():
-            s = labelShape._shapeRegion.GetText()
-            labelShape.FormatText(dc, s, i)
-            self.DrawRegion(dc, labelShape._shapeRegion, xx, yy)
-        return True
-