# Source code for pyqtgraph.graphicsItems.InfiniteLine

    from ..Qt import QtGui, QtCore
    from ..Point import Point
    from .GraphicsObject import GraphicsObject
    from .. import functions as fn
    import numpy as np
    import weakref

    __all__ = ['InfiniteLine']
    class InfiniteLine(GraphicsObject):
        """
        **Bases:** :class:`GraphicsObject <pyqtgraph.GraphicsObject>`

        Displays a line of infinite length.
        This line may be dragged to indicate a position in data coordinates.

        =============================== ===================================================
        **Signals:**
        sigDragged(self)
        sigPositionChangeFinished(self)
        sigPositionChanged(self)
        =============================== ===================================================
        """

        sigDragged = QtCore.Signal(object)
        sigPositionChangeFinished = QtCore.Signal(object)
        sigPositionChanged = QtCore.Signal(object)

        def __init__(self, pos=None, angle=90, pen=None, movable=False, bounds=None):
            """
            =============== ==================================================================
            **Arguments:**
            pos             Position of the line. This can be a QPointF or a single value for
                            vertical/horizontal lines.
            angle           Angle of line in degrees. 0 is horizontal, 90 is vertical.
            pen             Pen to use when drawing line. Can be any arguments that are valid
                            for :func:`mkPen <pyqtgraph.mkPen>`. Default pen is transparent
                            yellow.
            movable         If True, the line can be dragged to a new position by the user.
            bounds          Optional [min, max] bounding values. Bounds are only valid if the
                            line is vertical or horizontal.
            =============== ==================================================================
            """

            GraphicsObject.__init__(self)

            if bounds is None:              ## allowed value boundaries for orthogonal lines
                self.maxRange = [None, None]
            else:
                self.maxRange = bounds
            self.moving = False
            self.setMovable(movable)
            self.mouseHovering = False
            self.p = [0, 0]
            self.setAngle(angle)
            if pos is None:
                pos = Point(0,0)
            self.setPos(pos)

            if pen is None:
                pen = (200, 200, 100)

            self.setPen(pen)
            self.setHoverPen(color=(255,0,0), width=self.pen.width())
            self.currentPen = self.pen
            #self.setFlag(self.ItemSendsScenePositionChanges)

        def setMovable(self, m):
            """Set whether the line is movable by the user."""
            self.movable = m
            self.setAcceptHoverEvents(m)

        def setBounds(self, bounds):
            """Set the (minimum, maximum) allowable values when dragging."""
            self.maxRange = bounds
            self.setValue(self.value())

        def setPen(self, *args, **kwargs):
            """Set the pen for drawing the line. Allowable arguments are any that are valid
            for :func:`mkPen <pyqtgraph.mkPen>`."""
            self.pen = fn.mkPen(*args, **kwargs)
            if not self.mouseHovering:
                self.currentPen = self.pen
                self.update()

        def setHoverPen(self, *args, **kwargs):
            """Set the pen for drawing the line while the mouse hovers over it.
            Allowable arguments are any that are valid
            for :func:`mkPen <pyqtgraph.mkPen>`.

            If the line is not movable, then hovering is also disabled.

            Added in version 0.9.9."""
            self.hoverPen = fn.mkPen(*args, **kwargs)
            if self.mouseHovering:
                self.currentPen = self.hoverPen
                self.update()

        def setAngle(self, angle):
            """
            Takes angle argument in degrees.
            0 is horizontal; 90 is vertical.

            Note that the use of value() and setValue() changes if the line is
            not vertical or horizontal.
            """
            self.angle = ((angle+45) % 180) - 45   ##  -45 <= angle < 135
            self.resetTransform()
            self.rotate(self.angle)
            self.update()

        def setPos(self, pos):

            if type(pos) in [list, tuple]:
                newPos = pos
            elif isinstance(pos, QtCore.QPointF):
                newPos = [pos.x(), pos.y()]
            else:
                if self.angle == 90:
                    newPos = [pos, 0]
                elif self.angle == 0:
                    newPos = [0, pos]
                else:
                    raise Exception("Must specify 2D coordinate for non-orthogonal lines.")

            ## check bounds (only works for orthogonal lines)
            if self.angle == 90:
                if self.maxRange[0] is not None:
                    newPos[0] = max(newPos[0], self.maxRange[0])
                if self.maxRange[1] is not None:
                    newPos[0] = min(newPos[0], self.maxRange[1])
            elif self.angle == 0:
                if self.maxRange[0] is not None:
                    newPos[1] = max(newPos[1], self.maxRange[0])
                if self.maxRange[1] is not None:
                    newPos[1] = min(newPos[1], self.maxRange[1])

            if self.p != newPos:
                self.p = newPos
                GraphicsObject.setPos(self, Point(self.p))
                self.update()
                self.sigPositionChanged.emit(self)

        def getXPos(self):
            return self.p[0]

        def getYPos(self):
            return self.p[1]

        def getPos(self):
            return self.p

        def value(self):
            """Return the value of the line. Will be a single number for horizontal and
            vertical lines, and a list of [x,y] values for diagonal lines."""
            if self.angle%180 == 0:
                return self.getYPos()
            elif self.angle%180 == 90:
                return self.getXPos()
            else:
                return self.getPos()

        def setValue(self, v):
            """Set the position of the line. If line is horizontal or vertical, v can be
            a single value. Otherwise, a 2D coordinate must be specified (list, tuple and
            QPointF are all acceptable)."""
            self.setPos(v)

        ## broken in 4.7
        #def itemChange(self, change, val):
            #if change in [self.ItemScenePositionHasChanged, self.ItemSceneHasChanged]:
                #self.updateLine()
                #print "update", change
                #print self.getBoundingParents()
            #else:
                #print "ignore", change
            #return GraphicsObject.itemChange(self, change, val)

        def boundingRect(self):
            #br = UIGraphicsItem.boundingRect(self)
            br = self.viewRect()
            ## add a 4-pixel radius around the line for mouse interaction.

            px = self.pixelLength(direction=Point(1,0), ortho=True)  ## get pixel length orthogonal to the line
            if px is None:
                px = 0
            w = (max(4, self.pen.width()/2, self.hoverPen.width()/2)+1) * px
            br.setBottom(-w)
            br.setTop(w)
            return br.normalized()

        def paint(self, p, *args):
            br = self.boundingRect()
            p.setPen(self.currentPen)
            p.drawLine(Point(br.right(), 0), Point(br.left(), 0))
            #p.drawRect(self.boundingRect())

        def dataBounds(self, axis, frac=1.0, orthoRange=None):
            if axis == 0:
                return None   ## x axis should never be auto-scaled
            else:
                return (0,0)

        def mouseDragEvent(self, ev):
            if self.movable and ev.button() == QtCore.Qt.LeftButton:
                if ev.isStart():
                    self.moving = True
                    self.cursorOffset = self.pos() - self.mapToParent(ev.buttonDownPos())
                    self.startPosition = self.pos()
                ev.accept()

                if not self.moving:
                    return

                #pressDelta = self.mapToParent(ev.buttonDownPos()) - Point(self.p)
                self.setPos(self.cursorOffset + self.mapToParent(ev.pos()))
                self.sigDragged.emit(self)
                if ev.isFinish():
                    self.moving = False
                    self.sigPositionChangeFinished.emit(self)
            #else:
                #print ev

        def mouseClickEvent(self, ev):
            if self.moving and ev.button() == QtCore.Qt.RightButton:
                ev.accept()
                self.setPos(self.startPosition)
                self.moving = False
                self.sigDragged.emit(self)
                self.sigPositionChangeFinished.emit(self)

        def hoverEvent(self, ev):
            if (not ev.isExit()) and self.movable and ev.acceptDrags(QtCore.Qt.LeftButton):
                self.setMouseHover(True)
            else:
                self.setMouseHover(False)

        def setMouseHover(self, hover):
            ## Inform the item that the mouse is (not) hovering over it
            if self.mouseHovering == hover:
                return
            self.mouseHovering = hover
            if hover:
                self.currentPen = self.hoverPen
            else:
                self.currentPen = self.pen
            self.update()

        #def hoverEnterEvent(self, ev):
            #print "line hover enter"
            #ev.ignore()
            #self.updateHoverPen()

        #def hoverMoveEvent(self, ev):
            #print "line hover move"
            #ev.ignore()
            #self.updateHoverPen()

        #def hoverLeaveEvent(self, ev):
            #print "line hover leave"
            #ev.ignore()
            #self.updateHoverPen(False)

        #def updateHoverPen(self, hover=None):
            #if hover is None:
                #scene = self.scene()
                #hover = scene.claimEvent(self, QtCore.Qt.LeftButton, scene.Drag)

            #if hover:
                #self.currentPen = fn.mkPen(255, 0,0)
            #else:
                #self.currentPen = self.pen
            #self.update()