qt-material-widgets/components/qtmaterialselectfield.cpp

384 lines
8.6 KiB
C++

#include "qtmaterialselectfield.h"
#include "qtmaterialselectfield_p.h"
#include <QEvent>
#include <QFontDatabase>
#include <QEasingCurve>
#include <QTimer>
#include <QPainter>
#include "lib/qtmaterialstyle.h"
#include "qtmaterialmenuitem.h"
#include "qtmaterialcollapsiblemenu.h"
#include "lib/qtmaterialoverlaywidget.h"
/*!
* \class QtMaterialSelectFieldPrivate
* \internal
*/
QtMaterialSelectFieldPrivate::QtMaterialSelectFieldPrivate(QtMaterialSelectField *q)
: q_ptr(q)
{
}
QtMaterialSelectFieldPrivate::~QtMaterialSelectFieldPrivate()
{
}
void QtMaterialSelectFieldPrivate::init()
{
Q_Q(QtMaterialSelectField);
menuOverlay = new QtMaterialOverlayWidget(q);
menu = new QtMaterialCollapsibleMenu;
selectedIndex = -1;
useThemeColors = true;
q->setStyle(&QtMaterialStyle::instance());
QFontDatabase db;
QFont font(db.font("Roboto", "Regular", 11));
q->setFont(font);
menuOverlay->setParent(q->parentWidget());
menuOverlay->setAttribute(Qt::WA_TransparentForMouseEvents);
menuOverlay->installEventFilter(q);
menu->setParent(menuOverlay);
menu->setMaximumHeight(300);
menu->setCollapsedXScale(1);
menu->setExpandYDuration(280);
menu->setExpandYEasingCurve(QEasingCurve::OutQuad);
QObject::connect(menu, SIGNAL(aboutToCollapse()), q, SLOT(makeTransparent()));
QObject::connect(menu, SIGNAL(wasExpanded()), q, SLOT(makeOpaque()));
QObject::connect(menu, SIGNAL(aboutToExpand()), menuOverlay, SLOT(raise()));
QObject::connect(menu, SIGNAL(itemClicked(int)), q, SLOT(setSelectedIndex(int)));
QObject::connect(menu, SIGNAL(itemClicked(int)), q, SLOT(collapseDelayed()));
QObject::connect(menu, SIGNAL(itemClicked(int)), q, SIGNAL(itemSelected(int)));
}
/*!
* \class QtMaterialSelectField
*/
QtMaterialSelectField::QtMaterialSelectField(QWidget *parent)
: QWidget(parent),
d_ptr(new QtMaterialSelectFieldPrivate(this))
{
d_func()->init();
}
QtMaterialSelectField::~QtMaterialSelectField()
{
}
/*!
* \reimp
*/
QSize QtMaterialSelectField::sizeHint() const
{
return QSize(300, 30);
}
void QtMaterialSelectField::addItem(const QString &text)
{
Q_D(QtMaterialSelectField);
QtMaterialMenuItem *item = new QtMaterialMenuItem;
item->setText(text);
item->setHaloVisible(false);
d->menu->addMenuItem(item);
}
QtMaterialMenuItem *QtMaterialSelectField::itemAt(int index) const
{
Q_D(const QtMaterialSelectField);
return d->menu->menuItemAt(index);
}
void QtMaterialSelectField::setPlaceholderText(const QString &text)
{
Q_D(QtMaterialSelectField);
d->placeholderText = text;
update();
}
QString QtMaterialSelectField::placeholderText() const
{
Q_D(const QtMaterialSelectField);
return d->placeholderText;
}
void QtMaterialSelectField::setUseThemeColors(bool value)
{
Q_D(QtMaterialSelectField);
if (d->useThemeColors == value) {
return;
}
d->useThemeColors = value;
update();
}
bool QtMaterialSelectField::useThemeColors() const
{
Q_D(const QtMaterialSelectField);
return d->useThemeColors;
}
void QtMaterialSelectField::setUnderlineColor(const QColor &color)
{
Q_D(QtMaterialSelectField);
d->underlineColor = color;
MATERIAL_DISABLE_THEME_COLORS
update();
}
QColor QtMaterialSelectField::underlineColor() const
{
Q_D(const QtMaterialSelectField);
if (d->useThemeColors || !d->underlineColor.isValid()) {
return QtMaterialStyle::instance().themeColor("border");
}
return d->underlineColor;
}
void QtMaterialSelectField::setPlaceholderColor(const QColor &color)
{
Q_D(QtMaterialSelectField);
d->placeholderColor = color;
MATERIAL_DISABLE_THEME_COLORS
update();
}
QColor QtMaterialSelectField::placeholderColor() const
{
Q_D(const QtMaterialSelectField);
if (d->useThemeColors || !d->placeholderColor.isValid()) {
return QtMaterialStyle::instance().themeColor("accent3");
}
return d->placeholderColor;
}
void QtMaterialSelectField::setForegroundColor(const QColor &color)
{
Q_D(QtMaterialSelectField);
d->foregroundColor = color;
MATERIAL_DISABLE_THEME_COLORS
update();
}
QColor QtMaterialSelectField::foregroundColor() const
{
Q_D(const QtMaterialSelectField);
if (d->useThemeColors || !d->foregroundColor.isValid()) {
return QtMaterialStyle::instance().themeColor("text");
}
return d->foregroundColor;
}
void QtMaterialSelectField::setHighlightedColor(const QColor &color)
{
Q_D(QtMaterialSelectField);
d->highlightedColor = color;
MATERIAL_DISABLE_THEME_COLORS
update();
}
QColor QtMaterialSelectField::highlightedColor() const
{
Q_D(const QtMaterialSelectField);
if (d->useThemeColors || !d->highlightedColor.isValid()) {
return QtMaterialStyle::instance().themeColor("primary1");
}
return d->highlightedColor;
}
void QtMaterialSelectField::setDisabledColor(const QColor &color)
{
Q_D(QtMaterialSelectField);
d->disabledColor = color;
MATERIAL_DISABLE_THEME_COLORS
update();
}
QColor QtMaterialSelectField::disabledColor() const
{
Q_D(const QtMaterialSelectField);
if (d->useThemeColors || !d->disabledColor.isValid()) {
return QtMaterialStyle::instance().themeColor("disabled");
}
return d->disabledColor;
}
void QtMaterialSelectField::setSelectedIndex(int index)
{
Q_D(QtMaterialSelectField);
QtMaterialMenuItem *menuItem;
if (d->selectedIndex > -1 && (menuItem = d->menu->menuItemAt(d->selectedIndex))) {
menuItem->setHighlighted(false);
}
if (index > -1 && (menuItem = d->menu->menuItemAt(index))) {
menuItem->setHighlighted(true);
d->selectedText = menuItem->text();
}
d->selectedIndex = index;
update();
}
void QtMaterialSelectField::clearSelection()
{
Q_D(QtMaterialSelectField);
setSelectedIndex(-1);
d->selectedText.clear();
}
void QtMaterialSelectField::makeTransparent()
{
Q_D(QtMaterialSelectField);
d->menuOverlay->setAttribute(Qt::WA_TransparentForMouseEvents, true);
}
void QtMaterialSelectField::makeOpaque()
{
Q_D(QtMaterialSelectField);
d->menuOverlay->setAttribute(Qt::WA_TransparentForMouseEvents, false);
}
void QtMaterialSelectField::collapseDelayed()
{
Q_D(QtMaterialSelectField);
QTimer::singleShot(100, d->menu, SLOT(collapse()));
}
/*!
* \reimp
*/
bool QtMaterialSelectField::event(QEvent *event)
{
Q_D(QtMaterialSelectField);
switch (event->type())
{
case QEvent::Move:
case QEvent::Resize:
{
const QSize sh = d->menu->sizeHint();
d->menu->setGeometry(x(), y(), width(), sh.height());
break;
}
case QEvent::MouseButtonRelease:
{
if (isEnabled()) {
QtMaterialMenuItem *item;
for (int i = 0; i < d->menu->itemCount(); ++i) {
item = d->menu->menuItemAt(i);
if (item->isHighlighted()) {
item->setForegroundColor(highlightedColor());
} else {
item->setForegroundColor(foregroundColor());
}
}
d->menu->expand();
}
break;
}
case QEvent::ParentChange:
{
QWidget *widget;
if ((widget = parentWidget())) {
d->menuOverlay->setParent(widget);
}
break;
}
default:
break;
}
return QWidget::event(event);
}
/*!
* \reimp
*/
bool QtMaterialSelectField::eventFilter(QObject *obj, QEvent *event)
{
Q_D(QtMaterialSelectField);
if (QEvent::MouseButtonPress == event->type()) {
d->menu->collapse();
}
return QWidget::eventFilter(obj, event);
}
/*!
* \reimp
*/
void QtMaterialSelectField::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
Q_D(QtMaterialSelectField);
QPainter painter(this);
const int y = height()-1;
const int wd = width()-5;
if (d->selectedText.isEmpty() && !d->placeholderText.isEmpty()) {
if (isEnabled()) {
painter.setPen(placeholderColor());
} else {
painter.setPen(disabledColor());
}
painter.drawText(2, y-8, d->placeholderText);
} else {
painter.drawText(2, y-8, d->selectedText);
}
QPen pen;
pen.setWidth(1);
pen.setColor(underlineColor());
painter.setPen(pen);
painter.setOpacity(1);
painter.drawLine(2.5, y, wd, y);
if (isEnabled())
{
static const int points[] = { wd-14, 12, wd-4, 12, wd-9, 18 };
QPolygon polygon;
polygon.setPoints(3, points);
painter.setPen(Qt::NoPen);
painter.setBrush(underlineColor());
painter.drawPolygon(polygon);
}
}