# -*- coding: utf-8 -*-

# Copyright (c) 2004 - 2006 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing an arrow canvas widget.
"""

from math import *

from qt import *
from qtcanvas import *

NormalArrow = 1
WideArrow = 2

class Arrow(QCanvasPolygonalItem):
    """
    Class implementing an arrow canvas widget.
    """
    def __init__(self, canvas, sx, sy, ex, ey, filled = 0, type = NormalArrow, shortinit = 0):
        """
        Constructor
        
        @param canvas canvas containing the arrow (QCanvas)
        @param sx x-coordinate of the start point (integer)
        @param sy y-coordinate of the start point (integer)
        @param ex x-coordinate of the end point (integer)
        @param ey y-coordinate of the end point (integer)
        @param filled flag indicating a filled arrow (boolean)
        @param type type of the arrow. It must be one of
            <ul>
            <li>NormalArrow (default)</li>
            <li>WideArrow</li>
            </ul>
        @param shortinit flag indicating a short initialization.
            If this flag is set, the arraow is not updated after creation.
        """
        QCanvasPolygonalItem.__init__(self, canvas)
        self.start = (sx, sy)
        self.end = (ex, ey)
        self.filled = filled
        self.type = type
        
        self.arrowA = (0, 0)
        self.arrowB = (0, 0)
        
        self.headList = []
        self.headPoints = QPointArray(3)
        self.halfLength = 13
        
        self.createLines()
        if not shortinit:
            self.update()
        
    def calculateHead(self):
        """
        Method to calculate the head of the arrow.
        """
        arrowAngle = self.type * 0.5 * atan(sqrt(3.0) / 3.0);
        slope = atan2(self.end[1] - self.start[1], self.end[0] - self.start[0]) # slope of line
        arrowSlope = slope + arrowAngle;
        
        self.arrowA = (int(self.end[0] - self.halfLength * cos(arrowSlope)),
                       int(self.end[1] - self.halfLength * sin(arrowSlope)))
        arrowSlope = slope - arrowAngle;
        self.arrowB = (int(self.end[0] - self.halfLength * cos(arrowSlope)),
                       int(self.end[1] - self.halfLength * sin(arrowSlope)))
        
        self.headPoints.setPoint(0, self.end[0], self.end[1])
        self.headPoints.setPoint(1, self.arrowA[0], self.arrowA[1])
        self.headPoints.setPoint(2, self.arrowB[0], self.arrowB[1])
        
    def createLines(self):
        """
        Method to create the lines making up the arrow.
        """
        self.headList = []
        canvas = self.canvas()
        
        line = QCanvasLine(canvas)
        line.setZ(0)
        line.setPen(self.pen())
        line.setVisible(1)
        self.headList.append(line)
        
        line = QCanvasLine(canvas)
        line.setZ(0)
        line.setPen(self.pen())
        line.setVisible(1)
        self.headList.append(line)
        
        line = QCanvasLine(canvas)
        line.setZ(0)
        line.setPen(self.pen())
        line.setVisible(1)
        self.headList.append(line)
        
        self.clearPoly = QCanvasPolygon(canvas)
        self.clearPoly.setVisible(1)
        self.clearPoly.setBrush(QBrush(self.filled and self.pen().color() or Qt.white))
        self.clearPoly.setZ(-1)
        
        self.bodyLine = QCanvasLine(canvas)
        self.bodyLine.setZ(-2)
        self.bodyLine.setPen(self.pen())
        self.bodyLine.setVisible(1)
        
    def updateLines(self):
        """
        Method to update the lines.
        """
        self.headList[0].setPoints(self.end[0], self.end[1], self.arrowA[0], self.arrowA[1])
        self.headList[1].setPoints(self.end[0], self.end[1], self.arrowB[0], self.arrowB[1])
        self.headList[2].setPoints(self.arrowA[0], self.arrowA[1], self.arrowB[0], self.arrowB[1])
        self.clearPoly.setPoints(self.headPoints)
        self.bodyLine.setPoints(self.start[0], self.start[1], self.end[0], self.end[1])
        
    def setFilled(self, filled):
        """
        Method to set the filled flag and paint the arrow head.
        
        @param filled flag indicating a filled arrow (boolean)
        """
        self.filled = filled
        self.clearPoly.setBrush(QBrush(self.filled and self.pen().color() or Qt.white))
        
    def setPoints(self, sx, sy, ex, ey):
        """
        Method to set the start and end point of the arrow.
        
        @param sx x-coordinate of the start point (integer)
        @param sy y-coordinate of the start point (integer)
        @param ex x-coordinate of the end point (integer)
        @param ey y-coordinate of the end point (integer)
        """
        self.start = (sx, sy)
        self.end = (ex, ey)
        self.update()
        
    def show(self):
        """
        Overriden method to show the arrow on the canvas.
        """
        self.headList[0].show()
        self.headList[1].show()
        self.headList[2].show()
        self.clearPoly.show()
        self.bodyLine.show()
        
    def hide(self):
        """
        Overriden method to hide the arrow from the canvas.
        """
        self.headList[0].hide()
        self.headList[1].hide()
        self.headList[2].hide()
        self.clearPoly.hide()
        self.bodyLine.hide()
        
    def update(self):
        """
        Overriden method to update the arrow on the canvas.
        """
        self.calculateHead()
        self.updateLines()
