/*
 * Cantata
 *
 * Copyright (c) 2011-2022 Craig Drummond <craig.p.drummond@gmail.com>
 *
 * ----
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "selectorlabel.h"
#include "support/osxstyle.h"
#include "support/utils.h"
#include <QAction>
#include <QApplication>
#include <QCursor>
#include <QEvent>
#include <QMouseEvent>

SelectorLabel::SelectorLabel(QWidget* p)
	: QLabel(p), current(0), useArrow(false), bold(true), menu(nullptr)
{
	textColor = palette().text().color();
	setAttribute(Qt::WA_Hover, true);
	menu = new QMenu(this);
#ifdef Q_OS_MAC
	// Mac text seems to be 2px too high. margin-top fixes this
	setStyleSheet(QLatin1String("QLabel { margin-top: 2px} "));
#endif
}

static QString addMarkup(const QString& s, bool arrow, bool bold)
{
	return QLatin1String(bold ? "<b>" : "<p>") + s + (arrow ? QLatin1String("&nbsp;") + QChar(0x25BE) : QString()) + QLatin1String(bold ? "</b>" : "</p>");
}

void SelectorLabel::addItem(const QString& text, const QString& data, const QString& tt)
{
	QAction* act = menu->addAction(text, this, SLOT(itemSelected()));
	act->setData(data);
	if (!tt.isEmpty()) {
		act->setToolTip(tt);
	}
	setText(addMarkup(text, useArrow, bold));
	current = menu->actions().count();
}

void SelectorLabel::itemSelected()
{
	QAction* act = qobject_cast<QAction*>(sender());
	if (act) {
		setCurrentIndex(menu->actions().indexOf(act));
	}
}

bool SelectorLabel::event(QEvent* e)
{
	switch (e->type()) {
	case QEvent::MouseButtonPress:
		if (menu && Qt::NoModifier == static_cast<QMouseEvent*>(e)->modifiers() && Qt::LeftButton == static_cast<QMouseEvent*>(e)->button()) {
			menu->exec(mapToGlobal(QPoint(0, 0)));
			update();
			if (this != QApplication::widgetAt(QCursor::pos())) {
				setStyleSheet(QString("QLabel{color:%1;}").arg(textColor.name()));
			}
		}
		break;
	case QEvent::Wheel:
		if (menu) {
			QList<QAction*> actions = menu->actions();
			int numDegrees = static_cast<QWheelEvent*>(e)->angleDelta().y() / 8;
			int numSteps = numDegrees / 15;
			int newIndex = current;
			if (numSteps > 0) {
				for (int i = 0; i < numSteps; ++i) {
					newIndex++;
					if (newIndex >= actions.count()) {
						newIndex = 0;
					}
				}
			}
			else {
				for (int i = 0; i > numSteps; --i) {
					newIndex--;
					if (newIndex < 0) {
						newIndex = actions.count() - 1;
					}
				}
			}
			setCurrentIndex(newIndex);
		}
		break;
	case QEvent::HoverEnter:
		if (isEnabled()) {
#ifdef Q_OS_MAC
			setStyleSheet(QString("QLabel{color:%1;}").arg(OSXStyle::self()->viewPalette().highlight().color().name()));
#else
			setStyleSheet(QLatin1String("QLabel{color:palette(highlight);}"));
#endif
		}
		break;
	case QEvent::HoverLeave:
		if (isEnabled()) {
			setStyleSheet(QString("QLabel{color:%1;}").arg(textColor.name()));
		}
	default:
		break;
	}
	return QLabel::event(e);
}

void SelectorLabel::setCurrentIndex(int v)
{
	if (!menu || v < 0 || v == current) {
		return;
	}

	QList<QAction*> actions = menu->actions();

	if (v >= actions.count()) {
		return;
	}
	current = v;
	setText(addMarkup(Utils::strippedText(actions.at(current)->text()), useArrow, bold));
	emit activated(current);
}

QString SelectorLabel::itemData(int index) const
{
	QAction* act = action(index);
	return act ? act->data().toString() : QString();
}

QAction* SelectorLabel::action(int index) const
{
	if (!menu) {
		return nullptr;
	}

	QList<QAction*> actions = menu->actions();

	if (index >= actions.count()) {
		return nullptr;
	}
	return actions.at(index);
}

#include "moc_selectorlabel.cpp"
