# Source code for qwt.legend

    # -*- coding: utf-8 -*-
    #
    # Licensed under the terms of the Qwt License
    # Copyright (c) 2002 Uwe Rathmann, for the original C++ code
    # Copyright (c) 2015 Pierre Raybaut, for the Python translation/optimization
    # (see LICENSE file for more details)

    """
    QwtLegend
    ---------

    .. autoclass:: QwtLegendData
       :members:

    .. autoclass:: QwtLegendLabel
       :members:

    .. autoclass:: QwtLegend
       :members:
    """

    import numpy as np

    from qwt.qt.QtGui import (QFrame, QScrollArea, QWidget, QVBoxLayout, QPalette,
                              QApplication, QStyleOption, QStyle, QPixmap,
                              QPainter, qDrawWinButton)
    from qwt.qt.QtCore import Signal, QEvent, QSize, Qt, QRect, QRectF, QPoint

    from qwt.text import QwtText, QwtTextLabel
    from qwt.dyngrid_layout import QwtDynGridLayout
    from qwt.painter import QwtPainter

    class QwtLegendData(object):
        """
        Attributes of an entry on a legend

        `QwtLegendData` is an abstract container ( like `QAbstractModel` )
        to exchange attributes, that are only known between to
        the plot item and the legend.

        By overloading `QwtPlotItem.legendData()` any other set of attributes
        could be used, that can be handled by a modified ( or completely
        different ) implementation of a legend.

        .. seealso::

            :py:class:`qwt.legend.QwtLegend`

        .. note::

            The stockchart example implements a legend as a tree
            with checkable items
        """

        # enum Mode
        ReadOnly, Clickable, Checkable = list(range(3))

        # enum Role
        ModeRole, TitleRole, IconRole = list(range(3))
        UserRole = 32

        def __init__(self):
            self.__map = {}

        def setValues(self, map_):
            """
            Set the legend attributes

            :param dict map\_: Values

            .. seealso::

                :py:meth:`values()`
            """
            self.__map = map_

        def values(self):
            """
            :return: Legend attributes

            .. seealso::

                :py:meth:`setValues()`
            """
            return self.__map

        def hasRole(self, role):
            """
            :param int role: Attribute role
            :return: True, when the internal map has an entry for role
            """
            return role in self.__map

        def setValue(self, role, data):
            """
            Set an attribute value

            :param int role: Attribute role
            :param QVariant data: Attribute value

            .. seealso::

                :py:meth:`value()`
            """
            self.__map[role] = data

        def value(self, role):
            """
            :param int role: Attribute role
            :return: Attribute value for a specific role

            .. seealso::

                :py:meth:`setValue()`
            """
            return self.__map.get(role)

        def isValid(self):
            """
            :return: True, when the internal map is empty
            """
            return len(self.__map) != 0

        def title(self):
            """
            :return: Value of the TitleRole attribute
            """
            titleValue = self.value(QwtLegendData.TitleRole)
            if isinstance(titleValue, QwtText):
                text = titleValue
            else:
                text.setText(titleValue)
            return text

        def icon(self):
            """
            :return: Value of the IconRole attribute
            """
            return self.value(QwtLegendData.IconRole)

        def mode(self):
            """
            :return: Value of the ModeRole attribute
            """
            modeValue = self.value(QwtLegendData.ModeRole)
            if isinstance(modeValue, int):
                return modeValue
            return QwtLegendData.ReadOnly

    BUTTONFRAME = 2
    MARGIN = 2

    def buttonShift(w):
        option = QStyleOption()
        option.initFrom(w)
        ph = w.style().pixelMetric(QStyle.PM_ButtonShiftHorizontal, option, w)
        pv = w.style().pixelMetric(QStyle.PM_ButtonShiftVertical, option, w)
        return QSize(ph, pv)

    class QwtLegendLabel_PrivateData(object):
        def __init__(self):
            self.itemMode = QwtLegendData.ReadOnly
            self.isDown = False
            self.spacing = MARGIN
            self.legendData = QwtLegendData()
            self.icon = QPixmap()

    class QwtLegendLabel(QwtTextLabel):
        """A widget representing something on a QwtLegend."""

        clicked = Signal()
        pressed = Signal()
        released = Signal()
        checked = Signal(bool)

        def __init__(self, parent=None):
            QwtTextLabel.__init__(self, parent)
            self.__data = QwtLegendLabel_PrivateData()
            self.setMargin(MARGIN)
            self.setIndent(MARGIN)

        def setData(self, legendData):
            """
            Set the attributes of the legend label

            :param QwtLegendData legendData: Attributes of the label

            .. seealso::

                :py:meth:`data()`
            """
            self.__data.legendData = legendData
            doUpdate = self.updatesEnabled()
            self.setUpdatesEnabled(False)
            self.setText(legendData.title())
            icon = legendData.icon()
            if icon is not None:
                self.setIcon(icon.toPixmap())
            if legendData.hasRole(QwtLegendData.ModeRole):
                self.setItemMode(legendData.mode())
            if doUpdate:
                self.setUpdatesEnabled(True)
                self.update()

        def data(self):
            """
            :return: Attributes of the label

            .. seealso::

                :py:meth:`setData()`, :py:meth:`qwt.plot.QwtPlotItem.legendData()`
            """
            return self.__data.legendData

        def setText(self, text):
            """
            Set the text to the legend item

            :param qwt.text.QwtText text: Text label

            .. seealso::

                :py:meth:`text()`
            """
            flags = Qt.AlignLeft|Qt.AlignVCenter|Qt.TextExpandTabs|Qt.TextWordWrap
            txt = text  #TODO: WTF?
            txt.setRenderFlags(flags)
            QwtTextLabel.setText(self, text)

        def setItemMode(self, mode):
            """
            Set the item mode.
            The default is `QwtLegendData.ReadOnly`.

            :param int mode: Item mode

            .. seealso::

                :py:meth:`itemMode()`
            """
            if mode != self.__data.itemMode:
                self.__data.itemMode = mode
                self.__data.isDown = False
                self.setFocusPolicy(Qt.TabFocus if mode != QwtLegendData.ReadOnly
                                    else Qt.NoFocus)
                self.setMargin(BUTTONFRAME+MARGIN)
                self.updateGeometry()

        def itemMode(self):
            """
            :return: Item mode

            .. seealso::

                :py:meth:`setItemMode()`
            """
            return self.__data.itemMode

        def setIcon(self, icon):
            """
            Assign the icon

            :param QPixmap icon: Pixmap representing a plot item

            .. seealso::

                :py:meth:`icon()`, :py:meth:`qwt.plot.QwtPlotItem.legendIcon()`
            """
            self.__data.icon = icon
            indent = self.margin()+self.__data.spacing
            if icon.width() > 0:
                indent += icon.width()+self.__data.spacing
            self.setIndent(indent)

        def icon(self):
            """
            :return: Pixmap representing a plot item

            .. seealso::

                :py:meth:`setIcon()`
            """
            return self.__data.icon

        def setSpacing(self, spacing):
            """
            Change the spacing between icon and text

            :param int spacing: Spacing

            .. seealso::

                :py:meth:`spacing()`, :py:meth:`qwt.text.QwtTextLabel.margin()`
            """
            spacing = max([spacing, 0])
            if spacing != self.__data.spacing:
                self.__data.spacing = spacing
                indent = self.margin()+self.__data.spacing
                if self.__data.icon.width() > 0:
                    indent += self.__data.icon.width()+self.__data.spacing
                self.setIndent(indent)

        def spacing(self):
            """
            :return: Spacing between icon and text

            .. seealso::

                :py:meth:`setSpacing()`
            """
            return self.__data.spacing

        def setChecked(self, on):
            """
            Check/Uncheck a the item

            :param bool on: check/uncheck

            .. seealso::

                :py:meth:`isChecked()`, :py:meth:`setItemMode()`
            """
            if self.__data.itemMode == QwtLegendData.Checkable:
                isBlocked = self.signalsBlocked()
                self.blockSignals(True)
                self.setDown(on)
                self.blockSignals(isBlocked)

        def isChecked(self):
            """
            :return: true, if the item is checked

            .. seealso::

                :py:meth:`setChecked()`
            """
            return self.__data.itemMode == QwtLegendData.Checkable and self.isDown()

        def setDown(self, down):
            """
            Set the item being down

            :param bool on: true, if the item is down

            .. seealso::

                :py:meth:`isDown()`
            """
            if down == self.__data.isDown:
                return
            self.__data.isDown = down
            self.update()
            if self.__data.itemMode == QwtLegendData.Clickable:
                if self.__data.isDown:
                    self.pressed.emit()
                else:
                    self.released.emit()
                    self.clicked.emit()
            if self.__data.itemMode == QwtLegendData.Checkable:
                self.checked.emit(self.__data.isDown)

        def isDown(self):
            """
            :return: true, if the item is down

            .. seealso::

                :py:meth:`setDown()`
            """
            return self.__data.isDown

        def sizeHint(self):
            """
            :return: a size hint
            """
            sz = QwtTextLabel.sizeHint(self)
            sz.setHeight(max([sz.height(), self.__data.icon.height()+4]))
            if self.__data.itemMode != QwtLegendData.ReadOnly:
                sz += buttonShift(self)
                sz = sz.expandedTo(QApplication.globalStrut())
            return sz

        def paintEvent(self, e):
            cr = self.contentsRect()
            painter = QPainter(self)
            painter.setClipRegion(e.region())
            if self.__data.isDown:
                qDrawWinButton(painter, 0, 0, self.width(), self.height(),
                               self.palette(), True)
            painter.save()
            if self.__data.isDown:
                shiftSize = buttonShift(self)
                painter.translate(shiftSize.width(), shiftSize.height())
            painter.setClipRect(cr)
            self.drawContents(painter)
            if not self.__data.icon.isNull():
                iconRect = QRect(cr)
                iconRect.setX(iconRect.x()+self.margin())
                if self.__data.itemMode != QwtLegendData.ReadOnly:
                    iconRect.setX(iconRect.x()+BUTTONFRAME)
                iconRect.setSize(self.__data.icon.size())
                iconRect.moveCenter(QPoint(iconRect.center().x(),
                                           cr.center().y()))
                painter.drawPixmap(iconRect, self.__data.icon)
            painter.restore()

        def mousePressEvent(self, e):
            if e.button() == Qt.LeftButton:
                if self.__data.itemMode == QwtLegendData.Clickable:
                    self.setDown(True)
                    return
                elif self.__data.itemMode == QwtLegendData.Checkable:
                    self.setDown(not self.isDown())
                    return
            QwtTextLabel.mousePressEvent(self, e)

        def mouseReleaseEvent(self, e):
            if e.button() == Qt.LeftButton:
                if self.__data.itemMode == QwtLegendData.Clickable:
                    self.setDown(False)
                    return
                elif self.__data.itemMode == QwtLegendData.Checkable:
                    return
            QwtTextLabel.mouseReleaseEvent(self, e)

        def keyPressEvent(self, e):
            if e.key() == Qt.Key_Space:
                if self.__data.itemMode == QwtLegendData.Clickable:
                    if not e.isAutoRepeat():
                        self.setDown(True)
                    return
                elif self.__data.itemMode == QwtLegendData.Checkable:
                    if not e.isAutoRepeat():
                        self.setDown(not self.isDown())
                    return
            QwtTextLabel.keyPressEvent(self, e)

        def keyReleaseEvent(self, e):
            if e.key() == Qt.Key_Space:
                if self.__data.itemMode == QwtLegendData.Clickable:
                    if not e.isAutoRepeat():
                        self.setDown(False)
                    return
                elif self.__data.itemMode == QwtLegendData.Checkable:
                    return
            QwtTextLabel.keyReleaseEvent(self, e)

    class QwtAbstractLegend(QFrame):
        def __init__(self, parent):
            QFrame.__init__(self, parent)

        def renderLegend(self, painter, rect, fillBackground):
            raise NotImplementedError

        def isEmpty(self):
            return 0

        def scrollExtent(self, orientation):
            return 0

        def updateLegend(self, itemInfo, data):
            raise NotImplementedError

    class Entry(object):
        def __init__(self):
            self.itemInfo = None
            self.widgets = []

    class QwtLegendMap(object):
        def __init__(self):
            self.__entries = []

        def isEmpty(self):
            return len(self.__entries) == 0

        def insert(self, itemInfo, widgets):
            for entry in self.__entries:
                if entry.itemInfo == itemInfo:
                    entry.widgets = widgets
                    return
            newEntry = Entry()
            newEntry.itemInfo = itemInfo
            newEntry.widgets = widgets
            self.__entries += [newEntry]

        def remove(self, itemInfo):
            for entry in self.__entries[:]:
                if entry.itemInfo == itemInfo:
                    self.__entries.remove(entry)
                    return

        def removeWidget(self, widget):
            for entry in self.__entries:
                while widget in entry.widgets:
                    entry.widgets.remove(widget)

        def itemInfo(self, widget):
            if widget is not None:
                for entry in self.__entries:
                    if widget in entry.widgets:
                        return entry.itemInfo

        def legendWidgets(self, itemInfo):
            if itemInfo is not None:
                for entry in self.__entries:
                    if entry.itemInfo == itemInfo:
                        return entry.widgets
            return []

    class LegendView(QScrollArea):
        def __init__(self, parent):
            QScrollArea.__init__(self, parent)
            self.gridLayout = None
            self.contentsWidget = QWidget(self)
            self.contentsWidget.setObjectName("QwtLegendViewContents")
            self.setWidget(self.contentsWidget)
            self.setWidgetResizable(False)
            self.viewport().setObjectName("QwtLegendViewport")
            self.contentsWidget.setAutoFillBackground(False)
            self.viewport().setAutoFillBackground(False)

        def event(self, event):
            if event.type() == QEvent.PolishRequest:
                self.setFocusPolicy(Qt.NoFocus)
            if event.type() == QEvent.Resize:
                cr = self.contentsRect()
                w = cr.width()
                h = self.contentsWidget.heightForWidth(cr.width())
                if h > w:
                    w -= self.verticalScrollBar().sizeHint().width()
                    h = self.contentsWidget.heightForWidth(w)
                self.contentsWidget.resize(w, h)
            return QScrollArea.event(self, event)

        def viewportEvent(self, event):
            ok = QScrollArea.viewportEvent(self, event)
            if event.type() == QEvent.Resize:
                self.layoutContents()
            return ok

        def viewportSize(self, w, h):
            sbHeight = self.horizontalScrollBar().sizeHint().height()
            sbWidth = self.verticalScrollBar().sizeHint().width()
            cw = self.contentsRect().width()
            ch = self.contentsRect().height()
            vw = cw
            vh = ch
            if w > vw:
                vh -= sbHeight
            if h > vh:
                vw -= sbWidth
                if w > vw and vh == ch:
                    vh -= sbHeight
            return QSize(vw, vh)

        def layoutContents(self):
            tl = self.gridLayout
            if tl is None:
                return
            visibleSize = self.viewport().contentsRect().size()
            margins = tl.contentsMargins()
            margin_w = margins.left() + margins.right()
            minW = int(tl.maxItemWidth()+margin_w)
            w = max([visibleSize.width(), minW])
            h = max([tl.heightForWidth(w), visibleSize.height()])
            vpWidth = self.viewportSize(w, h).width()
            if w > vpWidth:
                w = max([vpWidth, minW])
                h = max([tl.heightForWidth(w), visibleSize.height()])
            self.contentsWidget.resize(w, h)

    class QwtLegend_PrivateData(object):
        def __init__(self):
            self.itemMode = QwtLegendData.ReadOnly
            self.view = None
            self.itemMap = QwtLegendMap()

    class QwtLegend(QwtAbstractLegend):
        """
        The legend widget

        The QwtLegend widget is a tabular arrangement of legend items. Legend
        items might be any type of widget, but in general they will be
        a QwtLegendLabel.

        .. seealso ::

            :py:class`qwt.legend.QwtLegendLabel`,
            :py:class`qwt.plot.QwtPlotItem`,
            :py:class`qwt.plot.QwtPlot`

        .. py:class:: QwtLegend([parent=None])

            Constructor

            :param QWidget parent: Parent widget

        .. py:data:: clicked

            A signal which is emitted when the user has clicked on
            a legend label, which is in `QwtLegendData.Clickable` mode.

            :param itemInfo: Info for the item item of the selected legend item
            :param index: Index of the legend label in the list of widgets that are associated with the plot item

            .. note::

                Clicks are disabled as default

        .. py:data:: checked

            A signal which is emitted when the user has clicked on
            a legend label, which is in `QwtLegendData.Checkable` mode

            :param itemInfo: Info for the item of the selected legend label
            :param index: Index of the legend label in the list of widgets that are associated with the plot item
            :param on: True when the legend label is checked

            .. note::

                Clicks are disabled as default
        """

        clicked = Signal("PyQt_PyObject", int)
        checked = Signal("PyQt_PyObject", bool, int)

        def __init__(self, parent=None):
            QwtAbstractLegend.__init__(self, parent)
            self.setFrameStyle(QFrame.NoFrame)
            self.__data = QwtLegend_PrivateData()
            self.__data.view = LegendView(self)
            self.__data.view.setObjectName("QwtLegendView")
            self.__data.view.setFrameStyle(QFrame.NoFrame)
            gridLayout = QwtDynGridLayout(self.__data.view.contentsWidget)
            gridLayout.setAlignment(Qt.AlignHCenter|Qt.AlignTop)
            self.__data.view.gridLayout = gridLayout
            self.__data.view.contentsWidget.installEventFilter(self)
            layout = QVBoxLayout(self)
            layout.setContentsMargins(0, 0, 0, 0)
            layout.addWidget(self.__data.view)

        def setMaxColumns(self, numColumns):
            """
            Set the maximum number of entries in a row

            F.e when the maximum is set to 1 all items are aligned
            vertically. 0 means unlimited

            :param int numColumns: Maximum number of entries in a row

            .. seealso::

                :py:meth:`maxColumns()`,
                :py:meth:`QwtDynGridLayout.setMaxColumns()`
            """
            tl = self.__data.view.gridLayout
            if tl is not None:
                tl.setMaxColumns(numColumns)

        def maxColumns(self):
            """
            :return: Maximum number of entries in a row

            .. seealso::

                :py:meth:`setMaxColumns()`,
                :py:meth:`QwtDynGridLayout.maxColumns()`
            """
            tl = self.__data.view.gridLayout
            if tl is not None:
                return tl.maxColumns()
            return 0

        def setDefaultItemMode(self, mode):
            """
            Set the default mode for legend labels

            Legend labels will be constructed according to the
            attributes in a `QwtLegendData` object. When it doesn't
            contain a value for the `QwtLegendData.ModeRole` the
            label will be initialized with the default mode of the legend.

            :param int mode: Default item mode

            .. seealso::

                :py:meth:`itemMode()`,
                :py:meth:`QwtLegendData.value()`,
                :py:meth:`QwtPlotItem::legendData()`

            ... note::

                Changing the mode doesn't have any effect on existing labels.
            """
            self.__data.itemMode = mode

        def defaultItemMode(self):
            """
            :return: Default item mode

            .. seealso::

                :py:meth:`setDefaultItemMode()`
            """
            return self.__data.itemMode

        def contentsWidget(self):
            """
            The contents widget is the only child of the viewport of
            the internal `QScrollArea` and the parent widget of all legend
            items.

            :return: Container widget of the legend items
            """
            return self.__data.view.contentsWidget

        def horizontalScrollBar(self):
            """
            :return: Horizontal scrollbar

            .. seealso::

                :py:meth:`verticalScrollBar()`
            """
            return self.__data.view.horizontalScrollBar()

        def verticalScrollBar(self):
            """
            :return: Vertical scrollbar

            .. seealso::

                :py:meth:`horizontalScrollBar()`
            """
            return self.__data.view.verticalScrollBar()

        def updateLegend(self, itemInfo, data):
            """
            Update the entries for an item

            :param QVariant itemInfo: Info for an item
            :param list data: Default item mode
            """
            widgetList = self.legendWidgets(itemInfo)
            if len(widgetList) != len(data):
                contentsLayout = self.__data.view.gridLayout
                while len(widgetList) > len(data):
                    w = widgetList.pop(-1)
                    contentsLayout.removeWidget(w)
                    w.hide()
                    w.deleteLater()
                for i in range(len(widgetList), len(data)):
                    widget = self.createWidget(data[i])
                    if contentsLayout is not None:
                        contentsLayout.addWidget(widget)
                    if self.isVisible():
                        widget.setVisible(True)
                    widgetList.append(widget)
                if not widgetList:
                    self.__data.itemMap.remove(itemInfo)
                else:
                    self.__data.itemMap.insert(itemInfo, widgetList)
                self.updateTabOrder()
            for i in range(len(data)):
                self.updateWidget(widgetList[i], data[i])

        def createWidget(self, data):
            """
            Create a widget to be inserted into the legend

            The default implementation returns a `QwtLegendLabel`.

            :param QwtLegendData data: Attributes of the legend entry
            :return: Widget representing data on the legend

            ... note::

                updateWidget() will called soon after createWidget()
                with the same attributes.
            """
            label = QwtLegendLabel()
            label.setItemMode(self.defaultItemMode())
            label.clicked.connect(lambda: self.itemClicked(label))
            label.checked.connect(lambda state: self.itemChecked(state, label))
            return label

        def updateWidget(self, widget, data):
            """
            Update the widget

            :param QWidget widget: Usually a QwtLegendLabel
            :param QwtLegendData data: Attributes to be displayed

            .. seealso::

                :py:meth:`createWidget()`

            ... note::

                When widget is no QwtLegendLabel updateWidget() does nothing.
            """
            label = widget #TODO: cast to QwtLegendLabel!
            if label is not None:
                label.setData(data)
                if data.value(QwtLegendData.ModeRole) is None:
                    label.setItemMode(self.defaultItemMode())

        def updateTabOrder(self):
            contentsLayout = self.__data.view.gridLayout
            if contentsLayout is not None:
                w = None
                for i in range(contentsLayout.count()):
                    item = contentsLayout.itemAt(i)
                    if w is not None and item.widget():
                        QWidget.setTabOrder(w, item.widget())
                    w = item.widget()

        def sizeHint(self):
            """Return a size hint"""
            hint = self.__data.view.contentsWidget.sizeHint()
            hint += QSize(2*self.frameWidth(), 2*self.frameWidth())
            return hint

        def heightForWidth(self, width):
            """
            :param int width: Width
            :return: The preferred height, for a width.
            """
            width -= 2*self.frameWidth()
            h = self.__data.view.contentsWidget.heightForWidth(width)
            if h >= 0:
                h += 2*self.frameWidth()
            return h

        def eventFilter(self, object_, event):
            """
            Handle QEvent.ChildRemoved andQEvent.LayoutRequest events
            for the contentsWidget().

            :param QObject object: Object to be filtered
            :param QEvent event: Event
            :return: Forwarded to QwtAbstractLegend.eventFilter()
            """
            if object_ is self.__data.view.contentsWidget:
                if event.type() == QEvent.ChildRemoved:
                    ce = event  #TODO: cast to QChildEvent
                    if ce.child().isWidgetType():
                        w = ce.child()  #TODO: cast to QWidget
                        self.__data.itemMap.removeWidget(w)
                elif event.type() == QEvent.LayoutRequest:
                    self.__data.view.layoutContents()
                    if self.parentWidget() and self.parentWidget().layout() is None:
                        QApplication.postEvent(self.parentWidget(),
                                               QEvent(QEvent.LayoutRequest))
            return QwtAbstractLegend.eventFilter(self, object_, event)

        def itemClicked(self, widget):
    #        w = self.sender()  #TODO: cast to QWidget
            w = widget
            if w is not None:
                itemInfo = self.__data.itemMap.itemInfo(w)
                if itemInfo is not None:
                    widgetList = self.__data.itemMap.legendWidgets(itemInfo)
                    if w in widgetList:
                        index = widgetList.index(w)
                        self.clicked.emit(itemInfo, index)

        def itemChecked(self, on, widget):
    #        w = self.sender()  #TODO: cast to QWidget
            w = widget
            if w is not None:
                itemInfo = self.__data.itemMap.itemInfo(w)
                if itemInfo is not None:
                    widgetList = self.__data.itemMap.legendWidgets(itemInfo)
                    if w in widgetList:
                        index = widgetList.index(w)
                        self.checked.emit(itemInfo, on, index)

        def renderLegend(self, painter, rect, fillBackground):
            """
            Render the legend into a given rectangle.

            :param QPainter painter: Painter
            :param QRectF rect: Bounding rectangle
            :param bool fillBackground: When true, fill rect with the widget background
            """
            if self.__data.itemMap.isEmpty():
                return
            if fillBackground:
                if self.autoFillBackground() or\
                   self.testAttribute(Qt.WA_StyledBackground):
                    QwtPainter.drawBackground(painter, rect, self)
    #    const QwtDynGridLayout *legendLayout =
    #        qobject_cast<QwtDynGridLayout *>( contentsWidget()->layout() );
            #TODO: not the exact same implementation
            legendLayout = self.__data.view.contentsWidget.layout()
            if legendLayout is None:
                return
            left, right, top, bottom = self.getContentsMargins()
            layoutRect = QRect()
            layoutRect.setLeft(np.ceil(rect.left())+left)
            layoutRect.setTop(np.ceil(rect.top())+top)
            layoutRect.setRight(np.ceil(rect.right())-right)
            layoutRect.setBottom(np.ceil(rect.bottom())-bottom)
            numCols = legendLayout.columnsForWidth(layoutRect.width())
            itemRects = legendLayout.layoutItems(layoutRect, numCols)
            index = 0
            for i in range(legendLayout.count()):
                item = legendLayout.itemAt(i)
                w = item.widget()
                if w is not None:
                    painter.save()
                    painter.setClipRect(itemRects[index], Qt.IntersectClip)
                    self.renderItem(painter, w, itemRects[index], fillBackground)
                    index += 1
                    painter.restore()

        def renderItem(self, painter, widget, rect, fillBackground):
            """
            Render a legend entry into a given rectangle.

            :param QPainter painter: Painter
            :param QWidget widget: Widget representing a legend entry
            :param QRectF rect: Bounding rectangle
            :param bool fillBackground: When true, fill rect with the widget background
            """
            if fillBackground:
                if widget.autoFillBackground() or\
                   widget.testAttribute(Qt.WA_StyledBackground):
                    QwtPainter.drawBackground(painter, rect, widget)
            label = widget  #TODO: cast to QwtLegendLabel
            if label is not None:
                icon = label.data().icon()
                sz = icon.defaultSize()
                iconRect = QRectF(rect.x()+label.margin(),
                                  rect.center().y()-.5*sz.height(),
                                  sz.width(), sz.height())
                icon.render(painter, iconRect, Qt.KeepAspectRatio)
                titleRect = QRectF(rect)
                titleRect.setX(iconRect.right()+2*label.spacing())
                painter.setFont(label.font())
                painter.setPen(label.palette().color(QPalette.Text))
                label.drawText(painter, titleRect)  #TODO: cast label to QwtLegendLabel

        def legendWidgets(self, itemInfo):
            """
            List of widgets associated to a item

            :param QVariant itemInfo: Info about an item
            """
            return self.__data.itemMap.legendWidgets(itemInfo)

        def legendWidget(self, itemInfo):
            """
            First widget in the list of widgets associated to an item

            :param QVariant itemInfo: Info about an item
            """
            list_ = self.__data.itemMap.legendWidgets(itemInfo)
            if list_:
                return list_[0]

        def itemInfo(self, widget):
            """
            Find the item that is associated to a widget

            :param QWidget widget: Widget on the legend
            :return: Associated item info
            """
            return self.__data.itemMap.itemInfo(widget)

        def isEmpty(self):
            return self.__data.itemMap.isEmpty()