From fa998a9496163102d86de5879806ba59818937d4 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 7 Mar 2023 13:26:36 +0100 Subject: [PATCH] QskComboBox is creating its menu only temporary now --- examples/gallery/selector/SelectorPage.cpp | 16 +-- src/controls/QskComboBox.cpp | 150 ++++++++++++++++----- src/controls/QskComboBox.h | 7 +- 3 files changed, 126 insertions(+), 47 deletions(-) diff --git a/examples/gallery/selector/SelectorPage.cpp b/examples/gallery/selector/SelectorPage.cpp index c5a6a4a7..d797e486 100644 --- a/examples/gallery/selector/SelectorPage.cpp +++ b/examples/gallery/selector/SelectorPage.cpp @@ -73,16 +73,16 @@ void SelectorPage::populate() auto* comboBox1 = new QskComboBox( comboBoxBox ); comboBox1->setPlaceholderText( "< options >" ); - comboBox1->addOption( {}, "airport" ); - comboBox1->addOption( {}, "flight" ); - comboBox1->addOption( {}, "pizza" ); - comboBox1->addOption( {}, "soccer" ); + comboBox1->addOption( "airport" ); + comboBox1->addOption( "flight" ); + comboBox1->addOption( "pizza" ); + comboBox1->addOption( "soccer" ); auto* comboBox2 = new QskComboBox( comboBoxBox ); - comboBox2->addOption( { "airport_shuttle" }, "airport" ); - comboBox2->addOption( { "flight" }, "flight" ); - comboBox2->addOption( { "local_pizza" }, "pizza" ); - comboBox2->addOption( { "sports_soccer" }, "soccer" ); + comboBox2->addOption( "airport_shuttle", "airport" ); + comboBox2->addOption( "flight", "flight" ); + comboBox2->addOption( "local_pizza", "pizza" ); + comboBox2->addOption( "sports_soccer", "soccer" ); comboBox2->setCurrentIndex( 2 ); setStretchFactor( 0, 0 ); diff --git a/src/controls/QskComboBox.cpp b/src/controls/QskComboBox.cpp index 95c7b7ca..17da7071 100644 --- a/src/controls/QskComboBox.cpp +++ b/src/controls/QskComboBox.cpp @@ -5,11 +5,13 @@ #include "QskComboBox.h" +#include "QskGraphicProvider.h" #include "QskGraphic.h" #include "QskMenu.h" #include "QskTextOptions.h" #include "QskEvent.h" +#include #include QSK_SUBCONTROL( QskComboBox, Panel ) @@ -19,7 +21,7 @@ QSK_SUBCONTROL( QskComboBox, PopupIndicator ) QSK_SYSTEM_STATE( QskComboBox, PopupOpen, QskAspect::FirstSystemState << 1 ) -static inline void qskIncrement( QskComboBox* comboBox, int steps ) +static inline void qskTraverseOptions( QskComboBox* comboBox, int steps ) { const auto count = comboBox->count(); if ( count == 0 ) @@ -33,29 +35,46 @@ static inline void qskIncrement( QskComboBox* comboBox, int steps ) int nextIndex = ( index + steps ) % count; if ( nextIndex < 0 ) nextIndex += count; - + if ( nextIndex != index ) - comboBox->setCurrentIndex( nextIndex ); + comboBox->setCurrentIndex( nextIndex ); +} + +namespace +{ + class Option + { + public: + Option( const QskGraphic& graphic, const QString& text ) + : text( text ) + , graphic( graphic ) + { + } + + Option( const QUrl& graphicSource, const QString& text ) + : graphicSource( graphicSource ) + , text( text ) + { +#if 1 + // lazy loading TODO ... + if( !graphicSource.isEmpty() ) + graphic = Qsk::loadGraphic( graphicSource ); +#endif + } + + QUrl graphicSource; + QString text; + + QskGraphic graphic; + }; } class QskComboBox::PrivateData { public: - PrivateData( QskComboBox* comboBox ) - { - menu = new QskMenu(); + QPointer < QskPopup > menu; - /* - The popup menu is supposed to be modal for the window and - therefore needs the root item of the window as parent item. - So we set the box as QObject parent only, so that it gets - destroyed properly. - */ - menu->setParent( comboBox ); - menu->setPopupFlag( QskPopup::DeleteOnClose, false ); - } - - QskMenu* menu; + QVector< Option > options; QString placeholderText; int currentIndex = -1; @@ -63,7 +82,7 @@ class QskComboBox::PrivateData QskComboBox::QskComboBox( QQuickItem* parent ) : Inherited( parent ) - , m_data( new PrivateData( this ) ) + , m_data( new PrivateData() ) { initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed ); @@ -75,14 +94,6 @@ QskComboBox::QskComboBox( QQuickItem* parent ) setAcceptHoverEvents( true ); - connect( m_data->menu, &QskMenu::triggered, - this, &QskComboBox::setCurrentIndex ); - - connect( m_data->menu, &QskMenu::countChanged, - this, &QskComboBox::countChanged ); - - connect( m_data->menu, &QskMenu::closed, this, - [ this ]() { setPopupOpen( false ); setFocus( true ); } ); } QskComboBox::~QskComboBox() @@ -128,14 +139,52 @@ QskTextOptions QskComboBox::textOptions() const return textOptionsHint( Text ); } +void QskComboBox::addOption( const QString& text ) +{ + addOption( QUrl(), text ); +} + +void QskComboBox::addOption( const QskGraphic& graphic, const QString& text ) +{ + m_data->options += Option( graphic, text ); + + resetImplicitSize(); + update(); + + if ( isComponentComplete() ) + Q_EMIT countChanged( count() ); +} + +void QskComboBox::addOption( const QString& graphicSource, const QString& text ) +{ + addOption( QUrl( graphicSource ), text ); +} + void QskComboBox::addOption( const QUrl& graphicSource, const QString& text ) { - m_data->menu->addOption( graphicSource, text ); + m_data->options += Option( graphicSource, text ); + + resetImplicitSize(); + update(); + + if ( isComponentComplete() ) + Q_EMIT countChanged( count() ); } QVariantList QskComboBox::optionAt( int index ) const { - return m_data->menu->optionAt( index ); + const auto& options = m_data->options; + + if( index < 0 || index >= options.count() ) + return QVariantList(); + + const auto& option = options[ index ]; + + QVariantList list; + list += QVariant::fromValue( option.graphic ); + list += QVariant::fromValue( option.text ); + + return list; } QString QskComboBox::placeholderText() const @@ -170,20 +219,37 @@ QString QskComboBox::currentText() const void QskComboBox::openPopup() { + if ( m_data->menu ) + return; + const auto cr = contentsRect(); - auto menu = m_data->menu; + auto menu = new QskMenu(); + menu->setParent( this ); menu->setParentItem( window()->contentItem() ); + menu->setPopupFlag( QskPopup::DeleteOnClose, true ); + menu->setOrigin( mapToScene( cr.bottomLeft() ) ); menu->setFixedWidth( cr.width() ); + for ( const auto& option : m_data->options ) + menu->addOption( option.graphic, option.text ); + + connect( menu, &QskMenu::triggered, + this, &QskComboBox::setCurrentIndex ); + + connect( menu, &QskMenu::closed, this, + [ this ]() { setPopupOpen( false ); setFocus( true ); } ); + + m_data->menu = menu; menu->open(); } void QskComboBox::closePopup() { - m_data->menu->close(); + if ( m_data->menu ) + m_data->menu->close(); } void QskComboBox::mousePressEvent( QMouseEvent* ) @@ -219,13 +285,13 @@ void QskComboBox::keyPressEvent( QKeyEvent* event ) case Qt::Key_Up: case Qt::Key_PageUp: { - qskIncrement( this, -1 ); + qskTraverseOptions( this, -1 ); return; } case Qt::Key_Down: case Qt::Key_PageDown: { - qskIncrement( this, 1 ); + qskTraverseOptions( this, 1 ); return; } case Qt::Key_Home: @@ -256,17 +322,27 @@ void QskComboBox::keyReleaseEvent( QKeyEvent* event ) void QskComboBox::wheelEvent( QWheelEvent* event ) { - if ( !isPopupOpen() ) + if ( isPopupOpen() ) + { + if ( m_data->menu ) + QCoreApplication::postEvent( m_data->menu, event->clone() ); + } + else { const auto steps = -qRound( qskWheelSteps( event ) ); - qskIncrement( this, steps ); + qskTraverseOptions( this, steps ); } } void QskComboBox::clear() { - m_data->menu->clear(); - setCurrentIndex( -1 ); + if ( !m_data->options.isEmpty() ) + { + m_data->options.clear(); + + if ( isComponentComplete() ) + Q_EMIT countChanged( count() ); + } } void QskComboBox::setCurrentIndex( int index ) @@ -287,7 +363,7 @@ int QskComboBox::currentIndex() const int QskComboBox::count() const { - return m_data->menu->count(); + return m_data->options.count(); } #include "moc_QskComboBox.cpp" diff --git a/src/controls/QskComboBox.h b/src/controls/QskComboBox.h index 3eb74ce9..fdda5036 100644 --- a/src/controls/QskComboBox.h +++ b/src/controls/QskComboBox.h @@ -42,7 +42,10 @@ class QSK_EXPORT QskComboBox : public QskControl void setTextOptions( const QskTextOptions& ); QskTextOptions textOptions() const; - void addOption( const QUrl&, const QString& ); + void addOption( const QString& text ); + void addOption( const QUrl& graphicSource, const QString& text ); + void addOption( const QString& graphicSource, const QString& text ); + void addOption( const QskGraphic&, const QString& text ); void clear(); @@ -61,7 +64,7 @@ class QSK_EXPORT QskComboBox : public QskControl Q_SIGNALS: void currentIndexChanged( int ); - void countChanged(); + void countChanged( int ); void placeholderTextChanged( const QString& ); protected: