diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index bd48c08b..57cf765e 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -290,9 +290,9 @@ void Editor::setupComboBox() m_pal.surfaceVariant, m_pal.focusOpacity ); setGradient( Q::Panel | Q::Focused, focusColor ); - const auto pressedColor = flattenedColor( m_pal.onSurfaceVariant, + const auto activeColor = flattenedColor( m_pal.onSurfaceVariant, m_pal.surfaceVariant, m_pal.pressedOpacity ); - setGradient( Q::Panel | Q::Pressed, pressedColor ); + setGradient( Q::Panel | Q::PopupOpen, activeColor ); setStrutSize( Q::Graphic, 24_dp, 24_dp ); setGraphicRole( Q::Graphic, QskMaterial3Skin::GraphicRoleOnSurface ); @@ -300,9 +300,9 @@ void Editor::setupComboBox() setColor( Q::Text, m_pal.onSurface ); setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium ); - setStrutSize( Q::OpenMenuGraphic, 12_dp, 12_dp ); - setGraphicRole( Q::OpenMenuGraphic, QskMaterial3Skin::GraphicRoleOnSurface ); - setAlignment( Q::OpenMenuGraphic, Qt::AlignRight | Qt::AlignVCenter ); + setStrutSize( Q::PopupIndicator, 12_dp, 12_dp ); + setGraphicRole( Q::PopupIndicator, QskMaterial3Skin::GraphicRoleOnSurface ); + setAlignment( Q::PopupIndicator, Qt::AlignRight | Qt::AlignVCenter ); const auto disabledPanelColor = QskRgb::toTransparentF( m_pal.onSurface, 0.04 ); @@ -313,10 +313,10 @@ void Editor::setupComboBox() setColor( Q::Text | Q::Disabled, m_pal.onSurface38 ); - setGraphicRole( Q::OpenMenuGraphic, QskMaterial3Skin::GraphicRoleOnSurface38 ); + setGraphicRole( Q::PopupIndicator, QskMaterial3Skin::GraphicRoleOnSurface38 ); - setSymbol( Q::OpenMenuGraphic, symbol( "combo-box-arrow-closed" ) ); - setSymbol( Q::OpenMenuGraphic | Q::PopupOpen, symbol( "combo-box-arrow-open" ) ); + setSymbol( Q::PopupIndicator, symbol( "combo-box-arrow-closed" ) ); + setSymbol( Q::PopupIndicator | Q::PopupOpen, symbol( "combo-box-arrow-open" ) ); } void Editor::setupBox() diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 207577cc..3361ce74 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -382,14 +382,14 @@ void Editor::setupComboBox() setStrutSize( Q::Graphic, 24_dp, 24_dp ); setGraphicRole( Q::Graphic | Q::Disabled, DisabledSymbol ); - setStrutSize( Q::OpenMenuGraphic, 15_dp, 15_dp ); - setGraphicRole( Q::OpenMenuGraphic | Q::Disabled, DisabledSymbol ); + setStrutSize( Q::PopupIndicator, 15_dp, 15_dp ); + setGraphicRole( Q::PopupIndicator | Q::Disabled, DisabledSymbol ); - setAlignment( Q::OpenMenuGraphic, Qt::AlignRight | Qt::AlignVCenter ); + setAlignment( Q::PopupIndicator, Qt::AlignRight | Qt::AlignVCenter ); - setSymbol( Q::OpenMenuGraphic, + setSymbol( Q::PopupIndicator, QskStandardSymbol::graphic( QskStandardSymbol::TriangleDown ) ); - setSymbol( Q::OpenMenuGraphic | Q::PopupOpen, + setSymbol( Q::PopupIndicator | Q::PopupOpen, QskStandardSymbol::graphic( QskStandardSymbol::TriangleUp ) ); } diff --git a/src/controls/QskComboBox.cpp b/src/controls/QskComboBox.cpp index c4b5eddf..5aa79cac 100644 --- a/src/controls/QskComboBox.cpp +++ b/src/controls/QskComboBox.cpp @@ -8,17 +8,45 @@ #include "QskGraphic.h" #include "QskMenu.h" #include "QskTextOptions.h" +#include "QskEvent.h" #include +QSK_QT_PRIVATE_BEGIN +#include +QSK_QT_PRIVATE_END + +#include + QSK_SUBCONTROL( QskComboBox, Panel ) QSK_SUBCONTROL( QskComboBox, Graphic ) QSK_SUBCONTROL( QskComboBox, Text ) -QSK_SUBCONTROL( QskComboBox, OpenMenuGraphic ) +QSK_SUBCONTROL( QskComboBox, PopupIndicator ) QSK_SUBCONTROL( QskComboBox, Splash ) -QSK_SYSTEM_STATE( QskComboBox, Pressed, QskAspect::FirstSystemState << 1 ) -QSK_SYSTEM_STATE( QskComboBox, PopupOpen, QskAspect::FirstSystemState << 2 ) +QSK_SYSTEM_STATE( QskComboBox, PopupOpen, QskAspect::FirstSystemState << 1 ) + +#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) + +static inline QList< Qt::Key > qskButtonPressKeys() +{ + const auto hint = QGuiApplicationPrivate::platformTheme()->themeHint( + QPlatformTheme::ButtonPressKeys ); + + return hint.value< QList< Qt::Key > >(); +} + +#else + +static inline QList< Qt::Key > qskButtonPressKeys() +{ + static const QList< Qt::Key > keys = + { Qt::Key_Space, Qt::Key_Enter, Qt::Key_Return, Qt::Key_Select }; + + return keys; +} + +#endif class QskComboBox::PrivateData { @@ -56,63 +84,34 @@ QskComboBox::QskComboBox( QQuickItem* parent ) setAcceptHoverEvents( true ); - connect( m_data->menu, &QskMenu::currentIndexChanged, - this, &QskComboBox::currentIndexChanged ); + connect( m_data->menu, &QskMenu::triggered, + this, &QskComboBox::activated ); connect( m_data->menu, &QskMenu::currentIndexChanged, - this, &QQuickItem::update ); + this, &QskComboBox::showOption ); connect( m_data->menu, &QskMenu::countChanged, this, &QskComboBox::countChanged ); - connect( this, &QskComboBox::currentIndexChanged, - this, &QskControl::focusIndicatorRectChanged ); - connect( m_data->menu, &QskMenu::closed, this, [ this ]() { setPopupOpen( false ); setFocus( true ); } ); - - connect( this, &QskComboBox::pressed, this, &QskComboBox::togglePopup ); } QskComboBox::~QskComboBox() { } -void QskComboBox::setPressed( bool on ) -{ - if ( on == isPressed() ) - return; - - setSkinStateFlag( Pressed, on ); - Q_EMIT pressedChanged( on ); - - if ( on ) - Q_EMIT pressed(); - else - Q_EMIT released(); -} - -bool QskComboBox::isPressed() const -{ - return hasSkinState( Pressed ); -} - void QskComboBox::setPopupOpen( bool on ) { if ( on == isPopupOpen() ) return; - if( on ) - { - openPopup(); - } - else - { - closePopup(); - } - setSkinStateFlag( PopupOpen, on ); - Q_EMIT popupOpenChanged( on ); + + if( on ) + openPopup(); + else + closePopup(); } bool QskComboBox::isPopupOpen() const @@ -172,7 +171,7 @@ void QskComboBox::setPlaceholderText( const QString& text ) Q_EMIT placeholderTextChanged( text ); } -QString QskComboBox::text() const +QString QskComboBox::currentText() const { const int index = currentIndex(); if( index >= 0 ) @@ -184,11 +183,6 @@ QString QskComboBox::text() const return placeholderText(); } -void QskComboBox::togglePopup() -{ - setPopupOpen( !isPopupOpen() ); -} - void QskComboBox::openPopup() { const auto cr = contentsRect(); @@ -209,39 +203,64 @@ void QskComboBox::closePopup() void QskComboBox::mousePressEvent( QMouseEvent* ) { - setPressed( true ); -} - -void QskComboBox::mouseUngrabEvent() -{ - setPressed( false ); + setPopupOpen( true ); } void QskComboBox::mouseReleaseEvent( QMouseEvent* ) { - releaseButton(); } void QskComboBox::keyPressEvent( QKeyEvent* event ) { - switch ( event->key() ) + if ( qskButtonPressKeys().contains( event->key() ) ) { - case Qt::Key_Select: - case Qt::Key_Space: + if ( !event->isAutoRepeat() ) { - if ( !event->isAutoRepeat() ) - { - setPressed( true ); - // calling release button here, because - // we will never get the key release event - // when the menu is opened: - releaseButton(); - } - + setPopupOpen( true ); return; } } + switch( event->key() ) + { +#if 0 + case Qt::Key_F4: + { + // QComboBox does this ??? + setPopupOpen( true ); + return; + } +#endif + case Qt::Key_Up: + case Qt::Key_PageUp: + { + increment( -1 ); + return; + } + case Qt::Key_Down: + case Qt::Key_PageDown: + { + increment( 1 ); + return; + } + case Qt::Key_Home: + { + if ( count() > 0 ) + setCurrentIndex( 0 ); + return; + } + case Qt::Key_End: + { + if ( count() > 0 ) + setCurrentIndex( count() - 1 ); + return; + } + + default: + // searching option by key TODO ... + break; + } + Inherited::keyPressEvent( event ); } @@ -250,6 +269,11 @@ void QskComboBox::keyReleaseEvent( QKeyEvent* event ) Inherited::keyReleaseEvent( event ); } +void QskComboBox::wheelEvent( QWheelEvent* event ) +{ + increment( -qRound( qskWheelSteps( event ) ) ); +} + void QskComboBox::clear() { m_data->menu->clear(); @@ -271,13 +295,29 @@ int QskComboBox::count() const return m_data->menu->count(); } -void QskComboBox::releaseButton() +void QskComboBox::showOption( int index ) { - if ( !isPressed() ) + update(); + Q_EMIT currentIndexChanged( index ); +} + +void QskComboBox::increment( int steps ) +{ + if ( count() == 0 ) return; - setPressed( false ); - Q_EMIT clicked(); + if ( currentIndex() == -1 && steps < 0 ) + steps++; + + int nextIndex = ( currentIndex() + steps ) % count(); + if ( nextIndex < 0 ) + nextIndex += count(); + + if ( nextIndex != currentIndex() ) + { + m_data->menu->setCurrentIndex( nextIndex ); + Q_EMIT activated( nextIndex ); + } } #include "moc_QskComboBox.cpp" diff --git a/src/controls/QskComboBox.h b/src/controls/QskComboBox.h index ed5fd34d..e86af870 100644 --- a/src/controls/QskComboBox.h +++ b/src/controls/QskComboBox.h @@ -17,6 +17,8 @@ class QSK_EXPORT QskComboBox : public QskControl Q_PROPERTY( int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged ) + Q_PROPERTY( QString currentText READ currentText ) + Q_PROPERTY( int count READ count NOTIFY countChanged ) Q_PROPERTY( QString placeholderText READ placeholderText @@ -25,17 +27,14 @@ class QSK_EXPORT QskComboBox : public QskControl using Inherited = QskControl; public: - QSK_SUBCONTROLS( Panel, Graphic, Text, OpenMenuGraphic, Splash ) - QSK_STATES( Pressed, PopupOpen ) + QSK_SUBCONTROLS( Panel, Graphic, Text, PopupIndicator, Splash ) + QSK_STATES( PopupOpen ) QskComboBox( QQuickItem* parent = nullptr ); ~QskComboBox() override; - void setPressed( bool on ); - bool isPressed() const; - - void setPopupOpen( bool on ); + void setPopupOpen( bool ); bool isPopupOpen() const; QskGraphic graphic() const; @@ -48,46 +47,40 @@ class QSK_EXPORT QskComboBox : public QskControl void clear(); int currentIndex() const; + QString currentText() const; int count() const; - QVariantList optionAt( int ) const; QString placeholderText() const; void setPlaceholderText( const QString& ); - QString text() const; - public Q_SLOTS: - void togglePopup(); - virtual void openPopup(); - virtual void closePopup(); - void setCurrentIndex( int ); Q_SIGNALS: + void activated( int ); void currentIndexChanged( int ); + void countChanged(); - - void pressed(); - void released(); - void clicked(); - - void pressedChanged( bool ); - void popupOpenChanged( bool ); - void placeholderTextChanged( const QString& ); protected: void mousePressEvent( QMouseEvent* ) override; - void mouseUngrabEvent() override; void mouseReleaseEvent( QMouseEvent* ) override; void keyPressEvent( QKeyEvent* ) override; void keyReleaseEvent( QKeyEvent* ) override; + void wheelEvent( QWheelEvent* ) override; + + virtual void openPopup(); + virtual void closePopup(); + private: + void showOption( int ); void releaseButton(); + void increment( int ); class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/src/controls/QskComboBoxSkinlet.cpp b/src/controls/QskComboBoxSkinlet.cpp index 7b192e84..87e160d8 100644 --- a/src/controls/QskComboBoxSkinlet.cpp +++ b/src/controls/QskComboBoxSkinlet.cpp @@ -18,7 +18,7 @@ namespace { if( std::is_same< T, QString >() ) { - return box->text(); + return box->currentText(); } const int index = box->currentIndex(); @@ -56,7 +56,8 @@ namespace QskComboBox::Text, qskValueAt< QString >( box ), QskComboBox::Graphic, qskValueAt< QskGraphic >( box ).defaultSize() ); - const auto alignment = box->alignmentHint( QskComboBox::Panel, Qt::AlignLeft ); + const auto alignment = box->alignmentHint( + QskComboBox::Panel, Qt::AlignLeft ); setFixedContent( QskComboBox::Text, Qt::Horizontal, alignment ); } }; @@ -65,7 +66,8 @@ namespace QskComboBoxSkinlet::QskComboBoxSkinlet( QskSkin* skin ) : Inherited( skin ) { - setNodeRoles( { PanelRole, SplashRole, GraphicRole, TextRole, OpenMenuGraphicRole } ); + setNodeRoles( { PanelRole, SplashRole, + GraphicRole, TextRole, PopupIndicatorRole } ); } QskComboBoxSkinlet::~QskComboBoxSkinlet() = default; @@ -93,10 +95,10 @@ QRectF QskComboBoxSkinlet::subControlRect( const QskSkinnable* skinnable, return layoutEngine.subControlRect( subControl ); } - if( subControl == Q::OpenMenuGraphic ) + if( subControl == Q::PopupIndicator ) { auto rect = box->innerBox( Q::Panel, contentsRect ); - const auto size = box->strutSizeHint( Q::OpenMenuGraphic ); + const auto size = box->strutSizeHint( Q::PopupIndicator ); rect.setLeft( rect.right() - size.width() ); return rect; } @@ -122,8 +124,8 @@ QSGNode* QskComboBoxSkinlet::updateSubNode( case TextRole: return updateTextNode( box, node ); - case OpenMenuGraphicRole: - return updateSymbolNode( box, node, Q::OpenMenuGraphic ); + case PopupIndicatorRole: + return updateSymbolNode( box, node, Q::PopupIndicator ); } return Inherited::updateSubNode( skinnable, nodeRole, node ); @@ -144,7 +146,7 @@ QRectF QskComboBoxSkinlet::splashRect( const auto pos = box->positionHint( Q::Splash ); const qreal w = 2.0 * rect.width() * ratio; - rect.setX( pos - 0.5 * w ); + rect.setX( pos - 0.5 * w ); rect.setWidth( w ); } @@ -165,7 +167,7 @@ QSGNode* QskComboBoxSkinlet::updateTextNode( const auto alignment = box->alignmentHint( Q::Text, Qt::AlignLeft | Qt::AlignVCenter ); return QskSkinlet::updateTextNode( box, node, rect, - alignment, box->text(), Q::Text ); + alignment, box->currentText(), Q::Text ); } QSGNode* QskComboBoxSkinlet::updateSplashNode( @@ -210,7 +212,7 @@ QSizeF QskComboBoxSkinlet::sizeHint( const QskSkinnable* skinnable, auto size = layoutEngine.sizeHint( which, QSizeF() ); const auto spacingHint = box->spacingHint( Q::Panel ); - const auto menuGraphicHint = box->strutSizeHint( Q::OpenMenuGraphic ); + const auto menuGraphicHint = box->strutSizeHint( Q::PopupIndicator ); size.rwidth() += spacingHint + menuGraphicHint.width(); diff --git a/src/controls/QskComboBoxSkinlet.h b/src/controls/QskComboBoxSkinlet.h index efcafa52..5b21d50a 100644 --- a/src/controls/QskComboBoxSkinlet.h +++ b/src/controls/QskComboBoxSkinlet.h @@ -22,7 +22,7 @@ class QSK_EXPORT QskComboBoxSkinlet : public QskSkinlet PanelRole, GraphicRole, TextRole, - OpenMenuGraphicRole, + PopupIndicatorRole, SplashRole, RoleCount