qskinny/src/controls/QskComboBox.cpp
2023-03-03 19:01:40 +01:00

281 lines
5.8 KiB
C++

/******************************************************************************
* QSkinny - Copyright (C) 2023 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskComboBox.h"
#include "QskGraphic.h"
#include "QskMenu.h"
#include "QskTextOptions.h"
QSK_SUBCONTROL( QskComboBox, Panel )
QSK_SUBCONTROL( QskComboBox, Graphic )
QSK_SUBCONTROL( QskComboBox, Text )
QSK_SUBCONTROL( QskComboBox, OpenMenuGraphic )
QSK_SUBCONTROL( QskComboBox, Splash )
QSK_SYSTEM_STATE( QskComboBox, Pressed, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskComboBox, PopupOpen, QskAspect::FirstSystemState << 2 )
class QskComboBox::PrivateData
{
public:
PrivateData( QskComboBox* const box )
: menu( new QskMenu( box ) )
{
menu->setPopupFlag( QskPopup::DeleteOnClose, false );
#if 1
/*
CloseOnPressOutside catches all mouse events in the parent
what is the comboBox in our case. However we need to handle
events for the complete window to make the CloseOnPressOutside
work like expected. TODO ...
*/
#endif
}
QskMenu* menu;
QString placeholderText;
};
QskComboBox::QskComboBox( QQuickItem* parent )
: Inherited( parent )
, m_data( new PrivateData( this ) )
{
initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed );
setPolishOnResize( true );
setAcceptedMouseButtons( Qt::LeftButton );
setWheelEnabled( true );
setFocusPolicy( Qt::StrongFocus );
setAcceptHoverEvents( true );
connect( m_data->menu, &QskMenu::currentIndexChanged,
this, &QskComboBox::currentIndexChanged );
connect( m_data->menu, &QskMenu::currentIndexChanged,
this, &QQuickItem::update );
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 );
}
bool QskComboBox::isPopupOpen() const
{
return hasSkinState( PopupOpen );
}
QskGraphic QskComboBox::graphic() const
{
const int index = currentIndex();
if( index >= 0 )
{
const auto option = m_data->menu->optionAt( index );
return option.at( 0 ).value< QskGraphic >();
}
return QskGraphic();
}
void QskComboBox::setTextOptions( const QskTextOptions& textOptions )
{
setTextOptionsHint( Text, textOptions );
}
QskTextOptions QskComboBox::textOptions() const
{
return textOptionsHint( Text );
}
void QskComboBox::addOption( const QUrl& graphicSource, const QString& text )
{
m_data->menu->addOption( graphicSource, text );
}
QVariantList QskComboBox::optionAt( int index ) const
{
return m_data->menu->optionAt( index );
}
QString QskComboBox::placeholderText() const
{
return m_data->placeholderText;
}
void QskComboBox::setPlaceholderText( const QString& text )
{
if ( m_data->placeholderText == text )
return;
m_data->placeholderText = text;
resetImplicitSize();
if ( currentIndex() < 0 )
update();
Q_EMIT placeholderTextChanged( text );
}
QString QskComboBox::text() const
{
const int index = currentIndex();
if( index >= 0 )
{
const auto option = optionAt( index );
return option.at( 1 ).toString();
}
return placeholderText();
}
void QskComboBox::togglePopup()
{
setPopupOpen( !isPopupOpen() );
}
void QskComboBox::openPopup()
{
m_data->menu->open();
}
void QskComboBox::closePopup()
{
m_data->menu->close();
}
void QskComboBox::updateLayout()
{
Inherited::updateLayout();
auto origin = contentsRect().bottomLeft();
m_data->menu->setOrigin( origin );
m_data->menu->setFixedWidth( contentsRect().width() );
}
void QskComboBox::mousePressEvent( QMouseEvent* )
{
setPressed( true );
}
void QskComboBox::mouseReleaseEvent( QMouseEvent* )
{
releaseButton();
}
void QskComboBox::keyPressEvent( QKeyEvent* event )
{
switch ( event->key() )
{
case Qt::Key_Select:
case Qt::Key_Space:
{
if ( !event->isAutoRepeat() )
{
setPressed( true );
// calling release button here, because
// we will never get the key release event
// when the menu is opened:
releaseButton();
}
// always accepting
return;
}
}
Inherited::keyPressEvent( event );
}
void QskComboBox::keyReleaseEvent( QKeyEvent* event )
{
Inherited::keyReleaseEvent( event );
}
void QskComboBox::clear()
{
m_data->menu->clear();
update();
}
void QskComboBox::setCurrentIndex( int index )
{
m_data->menu->setCurrentIndex( index );
}
int QskComboBox::currentIndex() const
{
return m_data->menu->currentIndex();
}
int QskComboBox::count() const
{
return m_data->menu->count();
}
void QskComboBox::releaseButton()
{
if ( !isPressed() )
return;
setPressed( false );
Q_EMIT clicked();
}
#include "moc_QskComboBox.cpp"