#!/usr/bin/env python
# License: GPLv3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>


from qt.core import QFontMetrics, QHBoxLayout, QIcon, QMenu, QPushButton, QSize, QSizePolicy, QStyle, QStyleOption, QStylePainter, Qt, QWidget

ICON_SZ = 64


class LayoutItem(QWidget):

    mouse_over = False

    def __init__(self, button, parent=None):
        QWidget.__init__(self, parent)
        self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
        self.button = button
        self.text = button.label
        self.setCursor(Qt.CursorShape.PointingHandCursor)
        self.fm = QFontMetrics(self.font())
        self._bi = self._di = None

    def update_tips(self):
        self.setToolTip(self.button.toolTip())
        self.setStatusTip(self.button.statusTip())

    @property
    def bright_icon(self):
        if self._bi is None:
            self._bi = self.button.icon().pixmap(ICON_SZ, ICON_SZ)
        return self._bi

    @property
    def dull_icon(self):
        if self._di is None:
            self._di = self.button.icon().pixmap(ICON_SZ, ICON_SZ, mode=QIcon.Mode.Disabled)
        return self._di

    def enterEvent(self, ev):
        super().enterEvent(ev)
        if not self.mouse_over:
            self.mouse_over = True
            self.update()

    def leaveEvent(self, ev):
        super().leaveEvent(ev)
        if self.mouse_over:
            self.mouse_over = False
            self.update()

    def sizeHint(self):
        br = self.fm.boundingRect(self.text)
        w = max(br.width(), ICON_SZ) + 10
        h = 2 * self.fm.lineSpacing() + ICON_SZ + 8
        return QSize(w, h)

    def paintEvent(self, ev):
        shown = self.button.isChecked()
        ls = self.fm.lineSpacing()
        painter = QStylePainter(self)
        if self.mouse_over:
            tool = QStyleOption()
            tool.initFrom(self)
            tool.rect = self.rect()
            tool.state = QStyle.StateFlag.State_Raised | QStyle.StateFlag.State_Active | QStyle.StateFlag.State_MouseOver
            painter.drawPrimitive(QStyle.PrimitiveElement.PE_PanelButtonTool, tool)
        painter.drawText(
            0, 0,
            self.width(),
            ls, Qt.AlignmentFlag.AlignCenter | Qt.TextFlag.TextSingleLine, self.text)
        text = _('Hide') if shown else _('Show')
        f = self.font()
        f.setBold(True)
        painter.setFont(f)
        painter.drawText(
            0, self.height() - ls,
            self.width(),
            ls, Qt.AlignmentFlag.AlignCenter | Qt.TextFlag.TextSingleLine, text)
        x = (self.width() - ICON_SZ) // 2
        y = ls + (self.height() - ICON_SZ - 2 * ls) // 2
        pmap = self.bright_icon if shown else self.dull_icon
        painter.drawPixmap(x, y, pmap)
        painter.end()


class LayoutMenu(QMenu):

    def __init__(self, parent=None):
        QMenu.__init__(self, parent)
        self.l = l = QHBoxLayout(self)
        l.setSpacing(20)
        self.items = []
        if parent is None:
            buttons = [
                QPushButton(QIcon.ic(i + '.png'), i, self)
                for i in 'search tags cover_flow grid book'.split()]
            for b in buttons:
                b.setVisible(False), b.setCheckable(True), b.setChecked(b.text() in 'tags grid')
                b.label = b.text().capitalize()
        else:
            buttons = parent.layout_buttons
        for b in buttons:
            self.items.append(LayoutItem(b, self))
            l.addWidget(self.items[-1])
            self.aboutToShow.connect(self.about_to_show)
        self.current_item = None

    def about_to_show(self):
        for x in self.items:
            x.update_tips()

    def sizeHint(self):
        return QWidget.sizeHint(self)

    def paintEvent(self, ev):
        return QWidget.paintEvent(self, ev)

    def item_for_ev(self, ev):
        for item in self.items:
            if item.geometry().contains(ev.pos()):
                return item

    def mousePressEvent(self, ev):
        if ev.button() != Qt.MouseButton.LeftButton:
            ev.ignore()
            return
        if (ev.pos().isNull() and not ev.screenPos().isNull()) or not self.rect().contains(ev.pos()):
            self.hide()
        self.current_item = self.item_for_ev(ev)
        if self.current_item is not None:
            ev.accept()
        else:
            ev.ignore()

    def mouseReleaseEvent(self, ev):
        if ev.button() != Qt.MouseButton.LeftButton:
            ev.ignore()
            return
        item = self.item_for_ev(ev)
        if item is not None and item is self.current_item:
            ev.accept()
            self.hide()
            item.button.click()


if __name__ == '__main__':
    from calibre.gui2 import Application
    app = Application([])
    w = LayoutMenu()
    w.show()
    w.exec()
