#include "ElaMultiSelectComboBox.h" #include #include #include #include #include #include #include "DeveloperComponents/ElaComboBoxView.h" #include "ElaApplication.h" #include "ElaComboBoxStyle.h" #include "ElaScrollBar.h" #include "ElaTheme.h" #include "private/ElaMultiSelectComboBoxPrivate.h" Q_PROPERTY_CREATE_Q_CPP(ElaMultiSelectComboBox, int, BorderRadius) ElaMultiSelectComboBox::ElaMultiSelectComboBox(QWidget* parent) : QComboBox(parent), d_ptr(new ElaMultiSelectComboBoxPrivate()) { Q_D(ElaMultiSelectComboBox); d->q_ptr = this; d->_pBorderRadius = 3; d->_pExpandIconRotate = 0; d->_pExpandMarkWidth = 0; d->_themeMode = eTheme->getThemeMode(); setFixedHeight(35); d->_comboBoxStyle = new ElaComboBoxStyle(style()); setStyle(d->_comboBoxStyle); //调用view 让container初始化 d->_comboView = new ElaComboBoxView(this); setView(d->_comboView); QAbstractItemView* comboBoxView = this->view(); comboBoxView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); ElaScrollBar* scrollBar = new ElaScrollBar(this); comboBoxView->setVerticalScrollBar(scrollBar); ElaScrollBar* floatVScrollBar = new ElaScrollBar(scrollBar, comboBoxView); floatVScrollBar->setIsAnimation(true); comboBoxView->setAutoScroll(false); comboBoxView->setSelectionMode(QAbstractItemView::NoSelection); comboBoxView->setSelectionBehavior(QAbstractItemView::SelectRows); comboBoxView->setObjectName("ElaComboBoxView"); comboBoxView->setStyleSheet("#ElaComboBoxView{background-color:transparent;}"); comboBoxView->setStyle(d->_comboBoxStyle); QWidget* container = this->findChild(); if (container) { container->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint); container->setAttribute(Qt::WA_TranslucentBackground); container->setObjectName("ElaComboBoxContainer"); container->setStyle(d->_comboBoxStyle); QLayout* layout = container->layout(); while (layout->count()) { layout->takeAt(0); } layout->addWidget(view()); layout->setContentsMargins(6, 0, 6, 6); #ifndef Q_OS_WIN #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) container->setStyleSheet("background-color:transparent;"); #endif #endif } QComboBox::setMaxVisibleItems(5); connect(d->_comboView, &ElaComboBoxView::itemPressed, d, &ElaMultiSelectComboBoxPrivate::onItemPressed); connect(this, QOverload::of(&ElaMultiSelectComboBox::currentIndexChanged), d, &ElaMultiSelectComboBoxPrivate::_refreshCurrentIndexs); d->_itemSelection.resize(32); d->_itemSelection.fill(false); d->_itemSelection[0] = true; QComboBox::setMaxVisibleItems(5); connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { d->_themeMode = themeMode; }); } ElaMultiSelectComboBox::~ElaMultiSelectComboBox() { Q_D(ElaMultiSelectComboBox); delete d->_comboBoxStyle; } void ElaMultiSelectComboBox::setCurrentSelection(QString selection) { Q_D(ElaMultiSelectComboBox); d->_itemSelection.fill(false); d->_comboView->selectionModel()->clearSelection(); for (int i = 0; i < this->count(); i++) { if (selection == itemText(i)) { QModelIndex index = model()->index(i, 0); d->_comboView->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows); d->_itemSelection[index.row()] = true; } } d->_refreshCurrentIndexs(); } void ElaMultiSelectComboBox::setCurrentSelection(QStringList selection) { Q_D(ElaMultiSelectComboBox); d->_comboView->selectionModel()->clearSelection(); d->_itemSelection.fill(false); for (int i = 0; i < this->count(); i++) { if (selection.contains(itemText(i))) { QModelIndex index = model()->index(i, 0); d->_comboView->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows); d->_itemSelection[index.row()] = true; } } d->_refreshCurrentIndexs(); } void ElaMultiSelectComboBox::setCurrentSelection(int index) { Q_D(ElaMultiSelectComboBox); if (index >= this->count() || index < 0) { return; } d->_comboView->selectionModel()->clearSelection(); d->_itemSelection.fill(false); QModelIndex currentIndex = model()->index(index, 0); d->_comboView->selectionModel()->select(currentIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows); d->_itemSelection[index] = true; d->_refreshCurrentIndexs(); } void ElaMultiSelectComboBox::setCurrentSelection(QList selectionIndex) { Q_D(ElaMultiSelectComboBox); d->_itemSelection.fill(false); d->_comboView->selectionModel()->clearSelection(); for (auto index: selectionIndex) { if (index >= this->count() || index < 0) { continue; } QModelIndex currentIndex = model()->index(index, 0); d->_comboView->selectionModel()->select(currentIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows); d->_itemSelection[index] = true; } d->_refreshCurrentIndexs(); } QStringList ElaMultiSelectComboBox::getCurrentSelection() const { return d_ptr->_selectedTextList; } QList ElaMultiSelectComboBox::getCurrentSelectionIndex() const { QList indexList; for (int i = 0; i < d_ptr->_itemSelection.count(); i++) { if (d_ptr->_itemSelection[i]) { indexList.append(i); } } return indexList; } void ElaMultiSelectComboBox::paintEvent(QPaintEvent* e) { Q_D(ElaMultiSelectComboBox); QPainter painter(this); painter.save(); painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing | QPainter::TextAntialiasing); painter.setPen(ElaThemeColor(d->_themeMode, BasicBorder)); painter.setBrush(isEnabled() ? underMouse() ? ElaThemeColor(d->_themeMode, BasicHover) : ElaThemeColor(d->_themeMode, BasicBase) : Qt::transparent); QRect foregroundRect = rect(); foregroundRect.adjust(6, 1, -6, -1); painter.drawRoundedRect(foregroundRect, d->_pBorderRadius, d->_pBorderRadius); // 底边线绘制 painter.setPen(ElaThemeColor(d->_themeMode, BasicBaseLine)); painter.drawLine(foregroundRect.x() + d->_pBorderRadius, foregroundRect.y() + foregroundRect.height(), foregroundRect.x() + foregroundRect.width() - d->_pBorderRadius, foregroundRect.y() + foregroundRect.height()); //文字绘制 painter.setPen(isEnabled() ? ElaThemeColor(d->_themeMode, BasicText) : ElaThemeColor(d->_themeMode, BasicTextDisable)); QString currentText = painter.fontMetrics().elidedText(d->_currentText, Qt::ElideRight, foregroundRect.width() - 27 - width() * 0.05); painter.drawText(15, height() / 2 + painter.fontMetrics().ascent() / 2 - 1, currentText); //展开指示器绘制 painter.setPen(Qt::NoPen); painter.setBrush(d->_themeMode == ElaThemeType::Light ? QColor(0x0E, 0x6F, 0xC3) : QColor(0x4C, 0xA0, 0xE0)); painter.drawRoundedRect(QRectF(width() / 2 - d->_pExpandMarkWidth, height() - 3, d->_pExpandMarkWidth * 2, 3), 2, 2); // 展开图标绘制 if (count() > 0) { QFont iconFont = QFont("ElaAwesome"); iconFont.setPixelSize(17); painter.setFont(iconFont); painter.setPen(isEnabled() ? ElaThemeColor(d->_themeMode, BasicText) : ElaThemeColor(d->_themeMode, BasicTextDisable)); QRectF expandIconRect(width() - 25, 0, 20, height()); painter.translate(expandIconRect.x() + (qreal)expandIconRect.width() / 2 - 2, expandIconRect.y() + (qreal)expandIconRect.height() / 2); painter.rotate(d->_pExpandIconRotate); painter.translate(-expandIconRect.x() - (qreal)expandIconRect.width() / 2 + 2, -expandIconRect.y() - (qreal)expandIconRect.height() / 2); painter.drawText(expandIconRect, Qt::AlignVCenter, QChar((unsigned short)ElaIconType::AngleDown)); painter.restore(); } } void ElaMultiSelectComboBox::showPopup() { Q_D(ElaMultiSelectComboBox); bool oldAnimationEffects = qApp->isEffectEnabled(Qt::UI_AnimateCombo); qApp->setEffectEnabled(Qt::UI_AnimateCombo, false); QComboBox::showPopup(); qApp->setEffectEnabled(Qt::UI_AnimateCombo, oldAnimationEffects); if (count() > 0) { QWidget* container = this->findChild(); if (container) { int containerHeight = 0; if (count() >= maxVisibleItems()) { containerHeight = maxVisibleItems() * 35 + 8; } else { containerHeight = count() * 35 + 8; } view()->resize(view()->width(), containerHeight - 8); container->move(container->x(), container->y() + 3); QLayout* layout = container->layout(); while (layout->count()) { layout->takeAt(0); } QPropertyAnimation* fixedSizeAnimation = new QPropertyAnimation(container, "maximumHeight"); connect(fixedSizeAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) { container->setFixedHeight(value.toUInt()); }); fixedSizeAnimation->setStartValue(1); fixedSizeAnimation->setEndValue(containerHeight); fixedSizeAnimation->setEasingCurve(QEasingCurve::OutCubic); fixedSizeAnimation->setDuration(400); fixedSizeAnimation->start(QAbstractAnimation::DeleteWhenStopped); QPropertyAnimation* viewPosAnimation = new QPropertyAnimation(view(), "pos"); connect(viewPosAnimation, &QPropertyAnimation::finished, this, [=]() { d->_isAllowHidePopup = true; layout->addWidget(view()); }); QPoint viewPos = view()->pos(); viewPosAnimation->setStartValue(QPoint(viewPos.x(), viewPos.y() - view()->height())); viewPosAnimation->setEndValue(viewPos); viewPosAnimation->setEasingCurve(QEasingCurve::OutCubic); viewPosAnimation->setDuration(400); viewPosAnimation->start(QAbstractAnimation::DeleteWhenStopped); } //指示器动画 QPropertyAnimation* rotateAnimation = new QPropertyAnimation(d, "pExpandIconRotate"); connect(rotateAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) { update(); }); rotateAnimation->setDuration(300); rotateAnimation->setEasingCurve(QEasingCurve::InOutSine); rotateAnimation->setStartValue(d->_pExpandIconRotate); rotateAnimation->setEndValue(-180); rotateAnimation->start(QAbstractAnimation::DeleteWhenStopped); QPropertyAnimation* markAnimation = new QPropertyAnimation(d, "pExpandMarkWidth"); markAnimation->setDuration(300); markAnimation->setEasingCurve(QEasingCurve::InOutSine); markAnimation->setStartValue(d->_pExpandMarkWidth); qreal step = (width() / 2 - d->_pBorderRadius) / count(); markAnimation->setEndValue(step * d->_selectedTextList.count()); markAnimation->start(QAbstractAnimation::DeleteWhenStopped); } d->_refreshCurrentIndexs(); } void ElaMultiSelectComboBox::hidePopup() { Q_D(ElaMultiSelectComboBox); if (d->_isFirstPopup && !this->view()->underMouse()) { d->_isFirstPopup = false; return; } if (eApp->containsCursorToItem(d->_comboView)) { return; } else { if (d->_isAllowHidePopup) { QWidget* container = this->findChild(); int containerHeight = container->height(); if (container) { QLayout* layout = container->layout(); while (layout->count()) { layout->takeAt(0); } QPropertyAnimation* viewPosAnimation = new QPropertyAnimation(view(), "pos"); connect(viewPosAnimation, &QPropertyAnimation::finished, this, [=]() { layout->addWidget(view()); QMouseEvent focusEvent(QEvent::MouseButtonPress, QPoint(-1, -1), QPoint(-1, -1), Qt::NoButton, Qt::NoButton, Qt::NoModifier); QApplication::sendEvent(parentWidget(), &focusEvent); QComboBox::hidePopup(); container->setFixedHeight(containerHeight); }); QPoint viewPos = view()->pos(); connect(viewPosAnimation, &QPropertyAnimation::finished, this, [=]() { view()->move(viewPos); }); viewPosAnimation->setStartValue(viewPos); viewPosAnimation->setEndValue(QPoint(viewPos.x(), viewPos.y() - view()->height())); viewPosAnimation->setEasingCurve(QEasingCurve::InCubic); viewPosAnimation->start(QAbstractAnimation::DeleteWhenStopped); QPropertyAnimation* fixedSizeAnimation = new QPropertyAnimation(container, "maximumHeight"); connect(fixedSizeAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) { container->setFixedHeight(value.toUInt()); }); fixedSizeAnimation->setStartValue(container->height()); fixedSizeAnimation->setEndValue(1); fixedSizeAnimation->setEasingCurve(QEasingCurve::InCubic); fixedSizeAnimation->start(QAbstractAnimation::DeleteWhenStopped); d->_isAllowHidePopup = false; } //指示器动画 QPropertyAnimation* rotateAnimation = new QPropertyAnimation(d, "pExpandIconRotate"); connect(rotateAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) { update(); }); rotateAnimation->setDuration(300); rotateAnimation->setEasingCurve(QEasingCurve::InOutSine); rotateAnimation->setStartValue(d->_pExpandIconRotate); rotateAnimation->setEndValue(0); rotateAnimation->start(QAbstractAnimation::DeleteWhenStopped); QPropertyAnimation* markAnimation = new QPropertyAnimation(d, "pExpandMarkWidth"); markAnimation->setDuration(300); markAnimation->setEasingCurve(QEasingCurve::InOutSine); markAnimation->setStartValue(d->_pExpandMarkWidth); markAnimation->setEndValue(0); markAnimation->start(QAbstractAnimation::DeleteWhenStopped); } } }