git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@28825 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			1532 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1532 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# -*- 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, 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.ThePenList.FindOrCreatePen(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 __del__(self):
 | 
						|
        if self._lineControlPoints:
 | 
						|
            self.ClearPointList(self._lineControlPoints)
 | 
						|
            self._lineControlPoints = []
 | 
						|
        for i in range(3):
 | 
						|
            if self._labelObjects[i]:
 | 
						|
                self._labelObjects[i].Select(False)
 | 
						|
                self._labelObjects[i].RemoveFromCanvas(self._canvas)
 | 
						|
        self._labelObjects = []
 | 
						|
        self.ClearArrowsAtPosition(-1)
 | 
						|
 | 
						|
    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)."""
 | 
						|
        if self._lineControlPoints:
 | 
						|
            self.ClearPointList(self._lineControlPoints)
 | 
						|
        self._lineControlPoints = []
 | 
						|
        
 | 
						|
        for _ in range(n):
 | 
						|
            point = wx.RealPoint(-999, -999)
 | 
						|
            self._lineControlPoints.append(point)
 | 
						|
 | 
						|
    def InsertLineControlPoint(self, dc = None):
 | 
						|
        """Insert a control point at an arbitrary position."""
 | 
						|
        if dc:
 | 
						|
            self.Erase(dc)
 | 
						|
 | 
						|
        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), 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 point in self._lineControlPoints[1:]:
 | 
						|
                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]
 | 
						|
                    point[0] = (x2 - x1) / 2.0 + x1
 | 
						|
                    point[1] = (y2 - y1) / 2.0 + y1
 | 
						|
                    
 | 
						|
    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
 | 
						|
 | 
						|
    def SetEnds(self, x1, y1, x2, y2):
 | 
						|
        """Set the end positions of the line."""
 | 
						|
        # Find centre point
 | 
						|
        first_point = self._lineControlPoints[0]
 | 
						|
        last_point = self._lineControlPoints[-1]
 | 
						|
 | 
						|
        first_point[0] = x1
 | 
						|
        first_point[1] = y1
 | 
						|
        last_point[0] = x2
 | 
						|
        last_point[1] = y2
 | 
						|
 | 
						|
        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 or dx == 0:
 | 
						|
                return False
 | 
						|
            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
 | 
						|
 | 
						|
        if len(self._lineControlPoints) > 2:
 | 
						|
            self.Initialise()
 | 
						|
 | 
						|
        # 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()
 | 
						|
 | 
						|
        first = self._lineControlPoints[0]
 | 
						|
        last = self._lineControlPoints[-1]
 | 
						|
 | 
						|
        oldX, oldY = self._xpos, self._ypos
 | 
						|
 | 
						|
        self.SetEnds(end_x, end_y, other_end_x, other_end_y)
 | 
						|
 | 
						|
        # 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.x += x_offset
 | 
						|
                point.y += 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]
 | 
						|
        
 | 
						|
        if len(self._lineControlPoints) > 2:
 | 
						|
            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)
 | 
						|
 | 
						|
            #print type(self._from), type(self._to), end_x, end_y, other_end_x, other_end_y
 | 
						|
            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.x, point.y))
 | 
						|
 | 
						|
        #print points
 | 
						|
        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.x, pt.y)
 | 
						|
 | 
						|
        # 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.ThePenList.FindOrCreatePen(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:
 | 
						|
            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()
 | 
						|
 | 
						|
            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()
 | 
						|
 | 
						|
            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.Cursor(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()
 | 
						|
 | 
						|
            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 arow
 | 
						|
 | 
						|
        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 = 0
 | 
						|
        for region in self.GetRegions():
 | 
						|
            if labelShape._shapeRegion == region:
 | 
						|
                self.GetRegions().remove(region)
 | 
						|
            else:
 | 
						|
                i += 1
 | 
						|
                
 | 
						|
        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
 | 
						|
    
 |