# Source code for pyqtgraph.graphicsItems.TextItem

    from math import atan2, degrees

    from .. import functions as fn
    from ..Point import Point
    from ..Qt import QtCore, QtGui, QtWidgets
    from .GraphicsObject import GraphicsObject

    __all__ = ['TextItem']

    class TextItem(GraphicsObject):
        """
        GraphicsItem displaying unscaled text (the text will always appear normal even inside a scaled ViewBox).
        """
        def __init__(self, text='', color=(200,200,200), html=None, anchor=(0,0),
                     border=None, fill=None, angle=0, rotateAxis=None):
            """
            ==============  =================================================================================
            **Arguments:**
            *text*          The text to display
            *color*         The color of the text (any format accepted by pg.mkColor)
            *html*          If specified, this overrides both *text* and *color*
            *anchor*        A QPointF or (x,y) sequence indicating what region of the text box will
                            be anchored to the item's position. A value of (0,0) sets the upper-left corner
                            of the text box to be at the position specified by setPos(), while a value of (1,1)
                            sets the lower-right corner.
            *border*        A pen to use when drawing the border
            *fill*          A brush to use when filling within the border
            *angle*         Angle in degrees to rotate text. Default is 0; text will be displayed upright.
            *rotateAxis*    If None, then a text angle of 0 always points along the +x axis of the scene.
                            If a QPointF or (x,y) sequence is given, then it represents a vector direction
                            in the parent's coordinate system that the 0-degree line will be aligned to. This
                            Allows text to follow both the position and orientation of its parent while still
                            discarding any scale and shear factors.
            ==============  =================================================================================

            The effects of the `rotateAxis` and `angle` arguments are added independently. So for example:

              * rotateAxis=None, angle=0 -> normal horizontal text
              * rotateAxis=None, angle=90 -> normal vertical text
              * rotateAxis=(1, 0), angle=0 -> text aligned with x axis of its parent
              * rotateAxis=(0, 1), angle=0 -> text aligned with y axis of its parent
              * rotateAxis=(1, 0), angle=90 -> text orthogonal to x axis of its parent
            """

            self.anchor = Point(anchor)
            self.rotateAxis = None if rotateAxis is None else Point(rotateAxis)
            #self.angle = 0
            GraphicsObject.__init__(self)
            self.textItem = QtWidgets.QGraphicsTextItem()
            self.textItem.setParentItem(self)
            self._lastTransform = None
            self._lastScene = None
            self._bounds = QtCore.QRectF()
            if html is None:
                self.setColor(color)
                self.setText(text)
            else:
                self.setHtml(html)
            self.fill = fn.mkBrush(fill)
            self.border = fn.mkPen(border)
            self.setAngle(angle)

        def setText(self, text, color=None):
            """
            Set the text of this item.

            This method sets the plain text of the item; see also setHtml().
            """
            if color is not None:
                self.setColor(color)
            self.setPlainText(text)

        def setPlainText(self, text):
            """
            Set the plain text to be rendered by this item.

            See QtWidgets.QGraphicsTextItem.setPlainText().
            """
            if text != self.toPlainText():
                self.textItem.setPlainText(text)
                self.updateTextPos()

        def toPlainText(self):
            return self.textItem.toPlainText()

        def setHtml(self, html):
            """
            Set the HTML code to be rendered by this item.

            See QtWidgets.QGraphicsTextItem.setHtml().
            """
            if self.toHtml() != html:
                self.textItem.setHtml(html)
                self.updateTextPos()

        def toHtml(self):
            return self.textItem.toHtml()

        def setTextWidth(self, *args):
            """
            Set the width of the text.

            If the text requires more space than the width limit, then it will be
            wrapped into multiple lines.

            See QtWidgets.QGraphicsTextItem.setTextWidth().
            """
            self.textItem.setTextWidth(*args)
            self.updateTextPos()

        def setFont(self, *args):
            """
            Set the font for this text.

            See QtWidgets.QGraphicsTextItem.setFont().
            """
            self.textItem.setFont(*args)
            self.updateTextPos()

        def setAngle(self, angle):
            """
            Set the angle of the text in degrees.

            This sets the rotation angle of the text as a whole, measured
            counter-clockwise from the x axis of the parent. Note that this rotation
            angle does not depend on horizontal/vertical scaling of the parent.
            """
            self.angle = angle
            self.updateTransform(force=True)

        def setAnchor(self, anchor):
            self.anchor = Point(anchor)
            self.updateTextPos()

        def setColor(self, color):
            """
            Set the color for this text.

            See QtWidgets.QGraphicsItem.setDefaultTextColor().
            """
            self.color = fn.mkColor(color)
            self.textItem.setDefaultTextColor(self.color)

        def updateTextPos(self):
            # update text position to obey anchor
            r = self.textItem.boundingRect()
            tl = self.textItem.mapToParent(r.topLeft())
            br = self.textItem.mapToParent(r.bottomRight())
            offset = (br - tl) * self.anchor
            self.textItem.setPos(-offset)

        def boundingRect(self):
            return self.textItem.mapRectToParent(self.textItem.boundingRect())

        def viewTransformChanged(self):
            # called whenever view transform has changed.
            # Do this here to avoid double-updates when view changes.
            self.updateTransform()

        def paint(self, p, *args):
            # this is not ideal because it requires the transform to be updated at every draw.
            # ideally, we would have a sceneTransformChanged event to react to..
            s = self.scene()
            ls = self._lastScene
            if s is not ls:
                if ls is not None:
                    ls.sigPrepareForPaint.disconnect(self.updateTransform)
                self._lastScene = s
                if s is not None:
                    s.sigPrepareForPaint.connect(self.updateTransform)
                self.updateTransform()
                p.setTransform(self.sceneTransform())

            if self.border.style() != QtCore.Qt.PenStyle.NoPen or self.fill.style() != QtCore.Qt.BrushStyle.NoBrush:
                p.setPen(self.border)
                p.setBrush(self.fill)
                p.setRenderHint(p.RenderHint.Antialiasing, True)
                p.drawPolygon(self.textItem.mapToParent(self.textItem.boundingRect()))

        def setVisible(self, v):
            GraphicsObject.setVisible(self, v)
            if v:
                self.updateTransform()

        def updateTransform(self, force=False):
            if not self.isVisible():
                return

            # update transform such that this item has the correct orientation
            # and scaling relative to the scene, but inherits its position from its
            # parent.
            # This is similar to setting ItemIgnoresTransformations = True, but
            # does not break mouse interaction and collision detection.
            p = self.parentItem()
            if p is None:
                pt = QtGui.QTransform()
            else:
                pt = p.sceneTransform()

            if not force and pt == self._lastTransform:
                return

            t = pt.inverted()[0]
            # reset translation
            t.setMatrix(t.m11(), t.m12(), t.m13(), t.m21(), t.m22(), t.m23(), 0, 0, t.m33())

            # apply rotation
            angle = -self.angle
            if self.rotateAxis is not None:
                d = pt.map(self.rotateAxis) - pt.map(Point(0, 0))
                a = degrees(atan2(d.y(), d.x()))
                angle += a
            t.rotate(angle)
            self.setTransform(t)
            self._lastTransform = pt
            self.updateTextPos()