/*
  quickoverlaylegend.cpp

  This file is part of GammaRay, the Qt application inspection and manipulation tool.

  SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
  Author: Filipe Azevedo <filipe.azevedo@kdab.com>

  SPDX-License-Identifier: GPL-2.0-or-later

  Contact KDAB at <info@kdab.com> for commercial licensing options.
*/

#include "quickoverlaylegend.h"
#include "quickdecorationsdrawer.h"

#include <ui/uiresources.h>

#include <QAction>
#include <QVBoxLayout>
#include <QListView>
#include <QAbstractListModel>
#include <QPainter>
#include <QLayout>

namespace GammaRay {

class LegendModel : public QAbstractListModel
{
    Q_OBJECT

    struct Item
    {
        enum Mode
        {
            Rect,
            Line,
            Last = Line + 1
        };

        explicit Item(const QBrush &brush = QBrush(), const QPen &pen = QPen(),
                      const QByteArray &label = QByteArray())
            : brush(brush)
            , pen(pen)
            , label(label)
        {
        }

        QBrush brush;
        QPen pen;
        QByteArray label;
        QPixmap pixmap;

        static void createPixmap(Item &item)
        {
            static qreal dpr = 2.0;
            static QSize iconSize(44, 44);
            QPixmap pixmap(iconSize.width() * Last * dpr, iconSize.height() * dpr);
            pixmap.setDevicePixelRatio(dpr);
            pixmap.fill(QColor(Qt::white));

            {
                const int margin(2);

                QPainter painter(&pixmap);
                QPen pen(item.pen);

                pen.setWidth(pen.width() * 2);

                painter.setPen(pen);
                painter.setBrush(item.brush);

                for (int i = Rect; i < Last; i++) {
                    const QRect rect(QPoint(iconSize.width() * i, 0), iconSize);

                    switch (i) {
                    case Rect: {
                        painter.drawRect(rect.adjusted(margin, margin, -margin, -margin));
                        break;
                    }
                    case Line: {
                        painter.drawLine(QLine(QPoint(rect.left() + margin, rect.center().y() - 2),
                                               QPoint(rect.right() - margin, rect.center().y() - 2)));
                        pen.setStyle(Qt::DotLine);
                        painter.setPen(pen);
                        painter.drawLine(QLine(QPoint(rect.left() + margin, rect.center().y() + 2),
                                               QPoint(rect.right() - margin, rect.center().y() + 2)));
                        break;
                    }
                    }
                }
            }

            item.pixmap = std::move(pixmap);
        }
    };

public:
    explicit LegendModel(QObject *parent = nullptr)
        : QAbstractListModel(parent)
    {
    }

    Qt::ItemFlags flags(const QModelIndex &index) const override
    {
        return QAbstractListModel::flags(index) & ~Qt::ItemIsSelectable;
    }

    int rowCount(const QModelIndex &parent = QModelIndex()) const override
    {
        return parent.isValid() ? 0 : m_items.size();
    }

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
    {
        if (hasIndex(index.row(), index.column(), index.parent())) {
            const Item &item(m_items[index.row()]);

            switch (role) {
            // Return a pixmap so the view will draw it at the given size instead of the view icon size
            case Qt::DecorationRole:
                return item.pixmap;
            case Qt::ForegroundRole:
                return item.pen.brush();
            case Qt::DisplayRole:
                return LegendModel::tr(item.label.constData());
            case Qt::SizeHintRole:
                return QSize(-1, (item.pixmap.height() / item.pixmap.devicePixelRatio()) + (2 * 2));
            }
        }

        return QVariant();
    }

    void setSettings(const QuickDecorationsSettings &settings)
    {
        beginResetModel();
        m_items.clear();

        m_items << Item(
            settings.boundingRectBrush,
            settings.boundingRectColor,
            QT_TR_NOOP("Bounding rect"));

        m_items << Item(
            settings.geometryRectBrush,
            settings.geometryRectColor,
            QT_TR_NOOP("Geometry rect"));

        m_items << Item(
            settings.childrenRectBrush,
            settings.childrenRectColor,
            QT_TR_NOOP("Children rect"));

        m_items << Item(
            QBrush(),
            settings.transformOriginColor,
            QT_TR_NOOP("Transform origin"));

        m_items << Item(
            QBrush(),
            settings.coordinatesColor,
            QT_TR_NOOP("Coordinates (x, y...)"));

        m_items << Item(
            QBrush(),
            settings.marginsColor,
            QT_TR_NOOP("Margins/Anchors"));

        m_items << Item(
            QBrush(),
            settings.paddingColor,
            QT_TR_NOOP("Padding"));

        m_items << Item(
            QBrush(),
            settings.gridColor,
            QT_TR_NOOP("Grid"));

        for (int i = 0; i < m_items.size(); ++i) {
            Item::createPixmap(m_items[i]);
        }
        endResetModel();
    }

private:
    QVector<Item> m_items;
};

QuickOverlayLegend::QuickOverlayLegend(QWidget *parent)
    : QWidget(parent, Qt::Tool)
    , m_model(new LegendModel(this))
{
    setWindowTitle(tr("Legend"));

    auto *view = new QListView(this);
    view->setUniformItemSizes(true);
    view->setModel(m_model);

    auto *layout = new QVBoxLayout(this);
    layout->addWidget(view);

    m_visibilityAction = new QAction(UIResources::themedIcon(QLatin1String("legend.png")),
                                     tr("Show Legend"), this);
    m_visibilityAction->setObjectName("aShowLegend");
    m_visibilityAction->setCheckable(true);
    m_visibilityAction->setToolTip(tr("<b>Show Legend</b><br>"
                                      "This shows a legend explaining the various diagnostic decorations."));

    connect(m_visibilityAction, &QAction::triggered, this, [this](bool toggled) {
        setVisible(toggled);
    });
}

QAction *QuickOverlayLegend::visibilityAction() const
{
    return m_visibilityAction;
}

void QuickOverlayLegend::setOverlaySettings(const QuickDecorationsSettings &settings)
{
    m_model->setSettings(settings);

    const int titleBarHeight = style()->pixelMetric(QStyle::PM_TitleBarHeight);
    const QMargins margins(layout()->contentsMargins());
    const int viewHeight = m_model->index(0, 0).data(Qt::SizeHintRole).toSize().height() * m_model->rowCount();
    resize(280, titleBarHeight + margins.top() + margins.bottom() + viewHeight);
}

void QuickOverlayLegend::showEvent(QShowEvent *event)
{
    QWidget::showEvent(event);
    m_visibilityAction->setChecked(true);
}

void QuickOverlayLegend::hideEvent(QHideEvent *event)
{
    QWidget::hideEvent(event);
    m_visibilityAction->setChecked(false);
}

}

#include "quickoverlaylegend.moc"
