# !/usr/bin/python
# coding=utf-8
from PySide2 import QtCore, QtGui, QtWidgets


class RichText:
    """Rich text support for widgets.
    TextMixin with rich text formatting will be set as rich text, otherwise it will be handled as usual.

    ex. <font style="color: rgb(80,180,100)">Operation successful.</font>
    ex. <hl style="color:red;">Error:</hl>
    ex. '<p style="color:white;">'
    ex. '<b style="font-weight: bold;">'
    ex. '<strong style="font-weight: bold;">'
    ex. '<mark style="background-color: grey">'
    escape: '<' replace with &lt;
    escape: '>' replace with &gt;
    """

    has_rich_text = False

    @property
    def richTextLabelDict(self):
        """Returns a list containing any rich text labels that have been created.
        Item indices are used the keys to retrieve the label values.

        Returns:
                (list)
        """
        try:
            return self._richTextLabelDict

        except AttributeError as error:
            self._richTextLabelDict = {}
            return self._richTextLabelDict

    @property
    def richTextSizeHintDict(self):
        """Returns a list containing the sizeHint any rich text labels that have been created.
        Item indices are used the keys to retrieve the size values.

        Returns:
                (list)
        """
        try:
            return self._richTextSizeHintDict

        except AttributeError as error:
            self._richTextSizeHintDict = {}
            return self._richTextSizeHintDict

    def richTextSizeHint(self, index=0):
        """The richTextSizeHint is the sizeHint of the actual widget if it were containing the text.

        Returns:
                (str) the widget's or the label's sizeHint.
        """
        if self.has_rich_text:
            return self._richTextSizeHintDict[index]

        else:
            return self.__class__.__base__.sizeHint(
                self
            )  # return standard widget sizeHint

    def _createRichTextLabel(self, index):
        """Return a QLabel and inside a QHBoxLayout."""
        layout = QtWidgets.QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        # layout.setSpacing(0)

        label = QtWidgets.QLabel(self)
        label.setTextFormat(QtCore.Qt.RichText)
        self.richTextLabelDict[index] = label

        label.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        label.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
        # label.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
        layout.addWidget(label)

        self.set_rich_text_style(index)

        self.has_rich_text = True

        return label

    def set_rich_text_style(self, index=0, textColor="white"):
        """Set the stylesheet for a QLabel.

        Parameters:

        """
        label = self.getRichTextLabel(index)
        label.setStyleSheet(
            """
            QLabel {{
                color: {0};
                margin: 3px 0px 0px 0px; /* top, right, bottom, left */
                padding: 0px 5px 0px 5px; /* top, right, bottom, left */
            }}
        """.format(
                textColor
            )
        )

    def getRichTextLabel(self, index=0):
        """ """
        try:
            label = self.richTextLabelDict[index]
        except KeyError as error:
            label = self._createRichTextLabel(index)

        return label

    def _text(self, index=None):
        """Gets the text for the widget or widget item.

        Parameters:
                item (str)(int): item text or item index
        """
        try:
            return self.__class__.__base__.text(self)

        except AttributeError as error:
            if index is not None:
                return self.__class__.__base__.itemText(self, index)
            else:
                return self.__class__.__base__.currentText(self)

    def richText(self, index=None):
        """
        Returns:
                (str) the widget's or the label's text.
        """
        try:
            index = index if index else 0
            label = self.richTextLabelDict[index]
            return label.text()
        except KeyError as error:  # no rich text at that index. return standard text.
            pass

        return self._text(index)  # return standard widget text

    def _setText(self, text, index=0):
        """Sets the text for the widget or widget item.

        Parameters:
                item (str)(int): item text or item index
        """
        try:
            self.__class__.__base__.setText(self, text)

        except AttributeError as error:
            self.__class__.__base__.setItemText(self, index, text)

    def setRichText(self, text, index=0):
        """If the text string contains rich text formatting:
                Set the rich text label text.
                Add whitespace to the actual widget text until it matches the sizeHint of what it would containing the label's text.

        Parameters:
                text (str): The desired widget's display text.
                index (int): For setting text requires an index. ie. comboBox
        """
        if text and all(
            i in text for i in ("<", ">")
        ):  # check the text string for rich text formatting.
            label = self.getRichTextLabel(index)

            label.setText(text)
            self.updateGeometry()

            self._setText(
                text, index
            )  # temporarily set the text to get the sizeHint value.
            sizeHint = self.richTextSizeHintDict[
                index
            ] = self.__class__.__base__.sizeHint(self)

            self._setText(
                None, index
            )  # clear the text, and add whitespaces until the sizeHint is the correct size.
            whiteSpace = " "
            while sizeHint.width() > self.__class__.__base__.sizeHint(self).width():
                self._setText(whiteSpace, index)
                whiteSpace += " "

        else:
            self._setText(text, index)  # set standard widget text

    def setAlignment(self, alignment="AlignLeft", index=0):
        """Override setAlignment to accept string alignment arguments as well as QtCore.Qt.AlignmentFlags.

        Parameters:
                alignment (str/obj): TextMixin alignment. valid values are: 'AlignLeft', 'AlignCenter', 'AlignRight' or QtCore.Qt.AlignLeft etc.
        """
        if isinstance(alignment, str):
            alignment = getattr(QtCore.Qt, alignment)

        label = self.getRichTextLabel(index)
        label.setAlignment(alignment)


class TextOverlay:
    """ """

    hasTextOverlay = False

    @property
    def textOverlayLabel(self):
        """Return a QLabel inside a QHBoxLayout."""
        try:
            return self._textOverlayLabel

        except AttributeError as error:
            layout = QtWidgets.QHBoxLayout(self)
            layout.setContentsMargins(0, 0, 0, 0)

            self._textOverlayLabel = QtWidgets.QLabel(self)
            self._textOverlayLabel.setTextFormat(QtCore.Qt.RichText)

            self._textOverlayLabel.setAttribute(QtCore.Qt.WA_TranslucentBackground)
            self._textOverlayLabel.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
            layout.addWidget(self._textOverlayLabel)

            self._textOverlayLabel.setStyleSheet(
                """
                    QLabel {
                        margin: 3px 0px 0px 0px; /* top, right, bottom, left */
                        padding: 0px 2px 0px 2px; /* top, right, bottom, left */
                    }"""
            )

            self.hasTextOverlay = True

            return self._textOverlayLabel

    def setTextOverlay(self, text, color=None, alignment=None):
        """If the text string contains rich text formatting:
                Set the rich text label text.
                Add whitespace to the actual widget text until it matches the sizeHint of what it would containing the label's text.

        Parameters:
                text (str): The desired widget's display text.
                index (int): For setting text requires an index. ie. comboBox
                color (str):  The desired text color.
                alignment (str/obj): TextMixin alignment. valid values are: 'AlignLeft', 'AlignCenter', 'AlignRight' or QtCore.Qt.AlignLeft etc.
        """
        self.textOverlayLabel.setText(text)

        if color is not None:
            self.setTextOverlayColor(color)

        if alignment is not None:
            self.setTextOverlayAlignment(alignment)

    def setTextOverlayAlignment(self, alignment="AlignLeft"):
        """Override setAlignment to accept string alignment arguments as well as QtCore.Qt.AlignmentFlags.

        Parameters:
                alignment (str/obj): TextMixin alignment. valid values are: 'AlignLeft', 'AlignCenter', 'AlignRight' or QtCore.Qt.AlignLeft etc.
        """
        if isinstance(alignment, str):
            alignment = getattr(QtCore.Qt, alignment)

        self.textOverlayLabel.setAlignment(alignment)

    def setTextOverlayColor(self, color):
        """Set the stylesheet for a QLabel.

        Parameters:
                color (str):  The desired text color.

        Example: setTextOverlayColor('rgb(185,185,185)')
        """
        label.setStyleSheet(
            """
                QLabel {{
                    color: {0};
                }}
            """.format(
                color
            )
        )


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication.instance() or QtWidgets.QApplication(
        sys.argv
    )  # return the existing QApplication object, or create a new one if none exists.

    sys.exit(app.exec_())


# -----------------------------------------------------------------------------
# Notes
# -----------------------------------------------------------------------------

"""
Promoting a widget in designer to use a custom class:
>   In Qt Designer, select all the widgets you want to replace, 
        then right-click them and select 'Promote to...'. 

>   In the dialog:
        Base Class:     Class from which you inherit. ie. QWidget
        Promoted Class: Name of the class. ie. "MyWidget"
        Header File:    Path of the file (changing the extension .py to .h)  ie. myfolder.mymodule.mywidget.h

>   Then click "Add", "Promote", 
        and you will see the class change from "QWidget" to "MyWidget" in the Object Inspector pane.
"""

# depricated ------------------------------------------------------------------------


# --------------------------------------------------------------------------------------------
# Notes
# --------------------------------------------------------------------------------------------
