# Source code for taurus.qt.qtgui.display.tauruslcd

    #!/usr/bin/env python

    # ###########################################################################
    #
    # This file is part of Taurus
    #
    # http://taurus-scada.org
    #
    # Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
    #
    # Taurus is free software: you can redistribute it and/or modify
    # it under the terms of the GNU Lesser General Public License as published by
    # the Free Software Foundation, either version 3 of the License, or
    # (at your option) any later version.
    #
    # Taurus is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU Lesser General Public License for more details.
    #
    # You should have received a copy of the GNU Lesser General Public License
    # along with Taurus.  If not, see <http://www.gnu.org/licenses/>.
    #
    # ###########################################################################

    """This module provides a Taurus widget based on QLCDNumber
    """

    from collections.abc import Sequence

    from taurus.core.taurusbasetypes import (
        TaurusElementType,
        TaurusEventType,
        AttrQuality,
        TaurusDevState,
    )
    from taurus.external.qt import Qt
    from taurus.qt.qtgui.base import TaurusBaseWidget
    from taurus.qt.qtgui.base import TaurusBaseController
    from taurus.qt.qtgui.base import TaurusScalarAttributeControllerHelper
    from taurus.qt.qtgui.base import TaurusConfigurationControllerHelper
    from taurus.qt.qtgui.base import updateLabelBackground
    from taurus.qt.qtgui.base import TaurusBgRoleSubscriber

    __docformat__ = "restructuredtext"

    _QT_PLUGIN_INFO = {
        "module": "taurus.qt.qtgui.display",
        "group": "Taurus Display",
        "icon": "designer:lcdnumber.png",
    }

    TaurusModelType = TaurusElementType
    EventType = TaurusEventType

    # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~~-~-
    # Controller classes for LCD
    # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~~-~-

    class TaurusLCDController(TaurusBaseController):
        def _setStyle(self):
            TaurusBaseController._setStyle(self)
            lcd = self.lcd()
            if self.usePalette():
                lcd.setFrameShape(Qt.QFrame.Box)
                lcd.setFrameShadow(Qt.QFrame.Raised)
                lcd.setLineWidth(1)

        def lcd(self):
            """Helper method that returns the LCDNumber widget"""
            return self.widget()

        def _updateForeground(self, lcd):
            value = None
            if lcd.fgRole == "value":
                value = self.getDisplayValue()
            elif lcd.fgRole == "w_value":
                value = self.getDisplayValue(True)
            elif lcd.fgRole in ("", "none"):
                value = ""

            if value is None:
                value = "udef"

            lcd.setNumDigits(len(value))
            lcd.display(value)

        def _needsStateConnection(self):
            lcd = self.lcd()
            return "state" in (lcd.fgRole, lcd.bgRole)

        _updateBackground = updateLabelBackground

    class TaurusLCDControllerAttribute(
        TaurusScalarAttributeControllerHelper, TaurusLCDController
    ):
        def __init__(self, lcd):
            TaurusScalarAttributeControllerHelper.__init__(self)
            TaurusLCDController.__init__(self, lcd)

        def _getDisplayValue(self, widget, valueObj, idx, write):
            try:
                if write:
                    value = valueObj.wvalue.magnitude
                else:
                    value = valueObj.rvalue.magnitude
                if idx is not None and len(idx):
                    for i in idx:
                        value = value[i]
                return widget.displayValue(value)
            except Exception:
                return widget.getNoneValue()

    class TaurusLCDControllerConfiguration(
        TaurusConfigurationControllerHelper, TaurusLCDController
    ):
        def __init__(self, lcd):
            TaurusConfigurationControllerHelper.__init__(self)
            TaurusLCDController.__init__(self, lcd)

    # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~~-~-
    # Design time controllers for LCD
    # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~~-~-

    class TaurusLCDControllerDesignMode(object):
        def _updateLength(self, lcd):
            lcd.setNumDigits(6)

        def getDisplayValue(self, write=False, **kwargs):
            v = self.w_value()
            if not write:
                v = self.value()
            return "%6.2f" % v

        def value(self):
            return 99.99

        def w_value(self):
            return 0.0

        def quality(self):
            return AttrQuality.ATTR_VALID

        def state(self):
            return TaurusDevState.ON

        def _updateToolTip(self, lcd):
            lcd.setToolTip("Some random value for design purposes only")

    class TaurusLCDControllerAttributeDesignMode(
        TaurusLCDControllerDesignMode, TaurusLCDControllerAttribute
    ):
        def __init__(self, label):
            TaurusLCDControllerDesignMode.__init__(self)
            TaurusLCDControllerAttribute.__init__(self, label)

    class TaurusLCDControllerConfigurationDesignMode(
        TaurusLCDControllerDesignMode, TaurusLCDControllerConfiguration
    ):
        def __init__(self, label):
            TaurusLCDControllerDesignMode.__init__(self)
            TaurusLCDControllerConfiguration.__init__(self, label)

        def getDisplayValue(self, write=False, **kwargs):
            return "%6.2f" % -99.99

        def _updateToolTip(self, lcd):
            lcd.setToolTip(
                "Some random configuration value for design purposes only"
            )

    _CONTROLLER_MAP = {
        None: TaurusLCDController,
        TaurusModelType.Unknown: TaurusLCDController,
        TaurusModelType.Attribute: TaurusLCDControllerAttribute,
        TaurusModelType.Configuration: TaurusLCDControllerConfiguration,
    }

    _DESIGNER_CONTROLLER_MAP = {
        None: TaurusLCDControllerAttributeDesignMode,
        TaurusModelType.Unknown: TaurusLCDControllerAttributeDesignMode,
        TaurusModelType.Attribute: TaurusLCDControllerAttributeDesignMode,
        TaurusModelType.Configuration: TaurusLCDControllerConfigurationDesignMode,
    }

    def Controller(lcd):
        ctrl_map = _CONTROLLER_MAP
        if lcd._designMode:
            ctrl_map = _DESIGNER_CONTROLLER_MAP

        model_type = lcd.getModelType()
        ctrl_klass = ctrl_map.get(model_type, TaurusLCDController)
        return ctrl_klass(lcd)

    class TaurusLCD(Qt.QLCDNumber, TaurusBaseWidget):
        """A Taurus-enabled :class:`Qt.QLCDNumber` widget. Its text can represent
        either the rvalue or wvalue *magnitude* (or nothing), and the background
        can colour-code the attribute quality or the device state (or nothing)
        """

        DefaultBgRole = "quality"
        DefaultFgRole = "value"
        DefaultShowText = True
        DefaultModelIndex = None

        def __init__(self, parent=None, designMode=False):
            self._bgRole = self.DefaultBgRole
            self._fgRole = self.DefaultFgRole
            self._modelIndex = self.DefaultModelIndex
            self._modelIndexStr = ""
            self._controller = None
            name = self.__class__.__name__
            self.call__init__wo_kw(Qt.QLCDNumber, parent)
            self.call__init__(TaurusBaseWidget, name, designMode=designMode)

            # if we are in design mode there will be no events so we force the
            # creation of a controller object
            if self._designMode:
                self.controller().update()

        def _calculate_controller_class(self):
            ctrl_map = _CONTROLLER_MAP
            if self._designMode:
                ctrl_map = _DESIGNER_CONTROLLER_MAP

            model_type = self.getModelType()
            ctrl_klass = ctrl_map.get(model_type, TaurusLCDController)
            return ctrl_klass

        def controller(self):
            ctrl = self._controller
            # if there is a controller object and it is not the base controller...
            if ctrl is not None and not ctrl.__class__ == TaurusLCDController:
                return ctrl

            # if there is a controller object and it is still the same class...
            ctrl_klass = self._calculate_controller_class()
            if ctrl is not None and ctrl.__class__ == ctrl_klass:
                return ctrl

            self._controller = ctrl = ctrl_klass(self)
            return ctrl

        # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
        # TaurusBaseWidget overwriting
        # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~

        def handleEvent(self, evt_src, evt_type, evt_value):
            if evt_type in (TaurusEventType.Change, TaurusEventType.Periodic):
                self.emitValueChanged()
            ctrl = self.controller()
            if ctrl is not None:
                ctrl.handleEvent(evt_src, evt_type, evt_value)

        def isReadOnly(self):
            return True

        def setModel(self, m, **kwargs):
            # force to build another controller
            self._controller = None
            TaurusBaseWidget.setModel(self, m, **kwargs)

        # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
        # QT property definition
        # -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~

        def getModelIndexValue(self):
            return self._modelIndex

        def getModelIndex(self):
            return self._modelIndexStr

        def setModelIndex(self, modelIndex):
            mi = str(modelIndex)
            if len(mi) == 0:
                self._modelIndex = None
            else:
                try:
                    mi_value = eval(str(mi))
                except Exception:
                    return
                if type(mi_value) == int:
                    mi_value = (mi_value,)
                if not isinstance(mi_value, Sequence):
                    return
                self._modelIndex = mi_value
            self._modelIndexStr = mi
            self.controller().update()

        def resetModelIndex(self):
            self.setModelIndex(self.DefaultModelIndex)

        def getBgRole(self):
            return self._bgRole

        def setBgRole(self, bgRole):
            self._bgRole = str(bgRole)
            if self._bgRole in ["tango_state"]:
                _bgRoleSubscriber = TaurusBgRoleSubscriber(self)
                _bgRoleSubscriber.setModel(f"{self.modelObj.parentObj.name}/state")
            elif "parentObj." in self._bgRole:
                _attr = self._bgRole.split(".")[1]
                if "Obj" in _attr:
                    _attr = _attr.strip("Obj")
                _bgRoleSubscriber = TaurusBgRoleSubscriber(self)
                _bgRoleSubscriber.setModel(
                    f"{self.modelObj.parentObj.name}/{_attr}"
                )

            self.controllerUpdate()

        def resetBgRole(self):
            self.setBgRole(self.DefaultBgRole)

        def getFgRole(self):
            return self._fgRole

        def setFgRole(self, fgRole):
            self._fgRole = str(fgRole).lower()
            self.controller().update()

        def resetFgRole(self):
            self.setFgRole(self.DefaultFgRole)

        @classmethod
        def getQtDesignerPluginInfo(cls):
            d = TaurusBaseWidget.getQtDesignerPluginInfo()
            d.update(_QT_PLUGIN_INFO)
            return d

        #: This property holds the unique URI string representing the model name
        #: with which this widget will get its data from. The convention used for
        #: the string can be found :ref:`here <model-concept>`.
        #:
        #: **Access functions:**
        #:
        #:     * :meth:`TaurusBaseWidget.getModel`
        #:     * :meth:`TaurusLCD.setModel`
        #:     * :meth:`TaurusBaseWidget.resetModel`
        #:
        #: .. seealso:: :ref:`model-concept`
        model = Qt.pyqtProperty(
            "QString",
            TaurusBaseWidget.getModel,
            setModel,
            TaurusBaseWidget.resetModel,
        )

        #: (deprecated))
        useParentModel = Qt.pyqtProperty(
            "bool",
            TaurusBaseWidget.getUseParentModel,
            TaurusBaseWidget.setUseParentModel,
            TaurusBaseWidget.resetUseParentModel,
        )

        #: This property holds the index inside the model value that should be
        #: displayed
        #:
        #: **Access functions:**
        #:
        #:     * :meth:`TaurusLCD.getModelIndex`
        #:     * :meth:`TaurusLCD.setModelIndex`
        #:     * :meth:`TaurusLCD.resetModelIndex`
        #:
        #: .. seealso:: :ref:`model-concept`
        modelIndex = Qt.pyqtProperty(
            "QString", getModelIndex, setModelIndex, resetModelIndex
        )

        #: This property holds the foreground role.
        #: Valid values are:
        #:
        #:     #. ''/'None' - no value is displayed
        #:     #. 'value' - the value is displayed
        #:     #. 'w_value' - the write value is displayed
        #:
        #: **Access functions:**
        #:
        #:     * :meth:`TaurusLCD.getFgRole`
        #:     * :meth:`TaurusLCD.setFgRole`
        #:     * :meth:`TaurusLCD.resetFgRole`
        fgRole = Qt.pyqtProperty(
            "QString", getFgRole, setFgRole, resetFgRole, doc="foreground role"
        )

        #: This property holds the background role.
        #: Valid values are ''/'None', 'quality', 'state'
        #:
        #: **Access functions:**
        #:
        #:     * :meth:`TaurusLCD.getBgRole`
        #:     * :meth:`TaurusLCD.setBgRole`
        #:     * :meth:`TaurusLCD.resetBgRole`
        bgRole = Qt.pyqtProperty(
            "QString", getBgRole, setBgRole, resetBgRole, doc="background role"
        )

    def demo():
        "LCD"
        from .demo import tauruslcddemo

        return tauruslcddemo.main()

    def main():
        import sys
        import taurus.qt.qtgui.application

        Application = taurus.qt.qtgui.application.TaurusApplication

        app = Application.instance()
        owns_app = app is None

        if owns_app:
            import taurus.core.util.argparse

            parser = taurus.core.util.argparse.get_taurus_parser()
            parser.usage = "%prog [options] <full_attribute_name(s)>"
            app = Application(
                sys.argv,
                cmd_line_parser=parser,
                app_name="Taurus LCD demo",
                app_version="1.0",
                org_domain="Taurus",
                org_name="Tango community",
            )

        args = app.get_command_line_args()

        if len(args) == 0:
            w = demo()
        else:
            models = map(str.lower, args)

            w = Qt.QWidget()
            layout = Qt.QGridLayout()
            w.setLayout(layout)
            for model in models:
                label = TaurusLCD()
                label.model = model
                layout.addWidget(label)
        w.show()

        if owns_app:
            sys.exit(app.exec_())
        else:
            return w

    if __name__ == "__main__":
        main()