/*
 * 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 "combobox.h"
#include "lineedit.h"
#include "utils.h"
#include <QAbstractItemView>
#include <QApplication>
#include <QScreen>
#include <QStyleOptionComboBox>

// Max number of items before we try to force a scrollbar in popup menu...
Q_DECL_UNUSED static int maxPopupItemCount = -1;

ComboBox::ComboBox(QWidget* p)
	: QComboBox(p), toggleState(false)
{
#if !defined Q_OS_WIN && !defined Q_OS_MAC
	if (-1 == maxPopupItemCount) {
		if (QApplication::primaryScreen()) {
			maxPopupItemCount = ((QApplication::primaryScreen()->availableGeometry().height() / (QFontMetricsF(QApplication::font()).height() * 1.5)) * 0.75) + 0.5;
		}
		else {
			maxPopupItemCount = 32;
		}
	}
#endif
	connect(this, SIGNAL(editTextChanged(QString)), this, SIGNAL(textChanged(QString)));
}

void ComboBox::setEditable(bool editable)
{
	QComboBox::setEditable(editable);
	if (editable) {
		LineEdit* edit = new LineEdit(this);
		setLineEdit(edit);
	}
}

#if !defined Q_OS_WIN && !defined Q_OS_MAC
void ComboBox::showPopup()
{
	QStyleOptionComboBox opt;
	initStyleOption(&opt);
	toggleState = false;
	bool hack = 0 != style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this, nullptr);
	if (hack && count() > (maxPopupItemCount - 2)) {
		toggleState = !isEditable();

		// Hacky, but if we set the combobox as editable - the style gives the
		// popup a scrollbar. This is more convenient if we have lots of items!
		if (toggleState) {
			setMaxVisibleItems(maxPopupItemCount);
			QComboBox::setEditable(true);
			lineEdit()->setReadOnly(true);
		}
	}
	QComboBox::showPopup();

	if (hack && view()->parentWidget() && count() > maxPopupItemCount) {
		// Also, if the size of the popup is more than required for 32 items, then
		// restrict its height...
		int maxHeight = maxPopupItemCount * view()->sizeHintForRow(0);
		QRect geo(view()->parentWidget()->geometry());
		QRect r(view()->parentWidget()->rect());
		if (geo.height() > maxHeight) {
			geo = QRect(geo.x(), geo.y() + (geo.height() - maxHeight), geo.width(), maxHeight);
			r = QRect(r.x(), r.y() + (r.height() - maxHeight), r.width(), maxHeight);
		}
		QPoint popupBot = view()->parentWidget()->mapToGlobal(r.bottomLeft());
		QPoint bot = mapToGlobal(rect().bottomLeft());

		if (popupBot.y() < bot.y()) {
			geo = QRect(geo.x(), geo.y() + (bot.y() - popupBot.y()), geo.width(), geo.height());
		}
		else {
			QPoint popupTop = view()->parentWidget()->mapToGlobal(r.topLeft());
			QPoint top = mapToGlobal(rect().topLeft());
			if (popupTop.y() > top.y()) {
				geo = QRect(geo.x(), geo.y() - (popupTop.y() - top.y()), geo.width(), geo.height());
			}
		}
		view()->parentWidget()->setGeometry(geo);

		// Hide scrollers - these look ugly...
		for (QObject* c : view()->parentWidget()->children()) {
			if (0 == qstrcmp("QComboBoxPrivateScroller", c->metaObject()->className())) {
				static_cast<QWidget*>(c)->setMaximumHeight(0);
			}
		}
	}
}

void ComboBox::hidePopup()
{
	if (toggleState) {
		QComboBox::setEditable(false);
		toggleState = false;
	}
	QComboBox::hidePopup();
}
#endif

#include "moc_combobox.cpp"
