qskinny/src/controls/QskMenu.cpp

383 lines
7.5 KiB
C++
Raw Normal View History

2021-12-23 18:36:32 +01:00
#include "QskMenu.h"
#include <QskGraphicProvider.h>
#include <QskTextOptions.h>
#include <QskGraphic.h>
#include <QskColorFilter.h>
2021-12-24 16:50:34 +01:00
#include <QskSkinlet.h>
2021-12-29 15:21:09 +01:00
#include <QskEvent.h>
2021-12-23 18:36:32 +01:00
2021-12-24 16:20:34 +01:00
#include <qvector.h>
2021-12-27 09:50:14 +01:00
#include <qvariant.h>
2021-12-30 11:13:48 +01:00
#include <qeventloop.h>
2021-12-23 18:36:32 +01:00
QSK_SUBCONTROL( QskMenu, Panel )
2021-12-24 16:20:34 +01:00
QSK_SUBCONTROL( QskMenu, Cell )
QSK_SUBCONTROL( QskMenu, Cursor )
2021-12-23 18:36:32 +01:00
QSK_SUBCONTROL( QskMenu, Text )
QSK_SUBCONTROL( QskMenu, Graphic )
2022-01-06 18:36:15 +01:00
QSK_SUBCONTROL( QskMenu, Separator )
2021-12-23 18:36:32 +01:00
QSK_SYSTEM_STATE( QskMenu, Selected, QskAspect::FirstSystemState << 2 )
2021-12-27 09:50:14 +01:00
namespace
{
2022-01-06 18:36:15 +01:00
class Option
2021-12-27 09:50:14 +01:00
{
2022-01-06 18:36:15 +01:00
public:
Option( const QUrl& graphicSource, const QString& text )
: graphicSource( graphicSource )
, text( text )
{
if( !graphicSource.isEmpty() )
graphic = Qsk::loadGraphic( graphicSource );
}
QUrl graphicSource;
QString text;
2022-01-06 18:36:15 +01:00
2021-12-27 09:50:14 +01:00
QskGraphic graphic;
};
}
2021-12-23 18:36:32 +01:00
class QskMenu::PrivateData
{
2021-12-23 19:05:59 +01:00
public:
2022-01-06 18:36:15 +01:00
QVector< Option > options;
QVector< int > separators;
2021-12-23 18:36:32 +01:00
2021-12-23 19:05:59 +01:00
QskTextOptions textOptions;
QPointF origin;
2021-12-23 18:36:32 +01:00
2022-01-01 18:13:33 +01:00
// current/selected are not well defined yet, TODO ...
2021-12-29 16:23:19 +01:00
int currentIndex = -1;
2022-01-01 18:13:33 +01:00
int selectedIndex = -1;
2021-12-30 11:13:48 +01:00
2021-12-23 19:05:59 +01:00
bool isPressed = false;
2021-12-23 18:36:32 +01:00
};
QskMenu::QskMenu( QQuickItem* parent )
: Inherited( parent )
, m_data( new PrivateData )
{
setModal( true );
setOverlay( true );
setFaderAspect( QskMenu::Panel | QskAspect::Position | QskAspect::Metric );
setPopupFlag( QskPopup::CloseOnPressOutside, true );
setPopupFlag( QskPopup::DeleteOnClose, true );
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
}
QskMenu::~QskMenu()
{
}
2021-12-26 12:17:31 +01:00
bool QskMenu::isCascading() const
{
return flagHint( QskMenu::Panel | QskAspect::Style );
}
void QskMenu::setCascading( bool on )
{
if ( setFlagHint( QskMenu::Panel | QskAspect::Style, on ) )
Q_EMIT cascadingChanged( on );
}
void QskMenu::resetCascading()
{
if ( resetFlagHint( QskMenu::Panel | QskAspect::Style ) )
Q_EMIT cascadingChanged( isCascading() );
}
2021-12-23 18:36:32 +01:00
void QskMenu::setOrigin( const QPointF& origin )
2021-12-23 19:05:59 +01:00
{
2021-12-23 18:36:32 +01:00
if ( origin != m_data->origin )
{
m_data->origin = origin;
Q_EMIT originChanged( origin );
}
}
2021-12-23 19:05:59 +01:00
2021-12-23 18:36:32 +01:00
QPointF QskMenu::origin() const
{
return m_data->origin;
}
2022-01-06 18:36:15 +01:00
void QskMenu::addOption( const QUrl& graphicSource, const QString& text )
2021-12-23 18:36:32 +01:00
{
2022-01-06 18:36:15 +01:00
m_data->options += Option( graphicSource, text );
2021-12-23 18:36:32 +01:00
resetImplicitSize();
update();
2021-12-27 09:50:14 +01:00
if ( isComponentComplete() )
countChanged( count() );
2021-12-23 18:36:32 +01:00
}
2022-01-06 18:36:15 +01:00
void QskMenu::addOption( const QString& graphicSource, const QString& text )
2021-12-23 18:36:32 +01:00
{
2022-01-06 18:36:15 +01:00
addOption( QUrl( graphicSource ), text );
}
int QskMenu::count() const
{
return m_data->options.count();
2021-12-23 18:36:32 +01:00
}
void QskMenu::addSeparator()
{
2022-01-06 18:36:15 +01:00
m_data->separators += m_data->options.count();
resetImplicitSize();
update();
2021-12-23 18:36:32 +01:00
}
2022-01-06 18:36:15 +01:00
int QskMenu::separatorPosition( int index ) const
2021-12-23 18:36:32 +01:00
{
2022-01-06 18:36:15 +01:00
return m_data->separators.value( index, -1 );
2021-12-23 18:36:32 +01:00
}
2022-01-06 18:36:15 +01:00
int QskMenu::separatorCount() const
{
return m_data->separators.count();
}
void QskMenu::clear()
2021-12-23 18:36:32 +01:00
{
2022-01-06 18:36:15 +01:00
m_data->options.clear();
m_data->separators.clear();
2021-12-23 18:36:32 +01:00
}
2022-01-06 18:36:15 +01:00
QVariantList QskMenu::optionAt( int index ) const
2021-12-23 18:36:32 +01:00
{
2022-01-06 18:36:15 +01:00
const auto& options = m_data->options;
2021-12-23 18:36:32 +01:00
2022-01-06 18:36:15 +01:00
if( index < 0 || index >= options.count() )
return QVariantList();
2021-12-23 18:36:32 +01:00
2022-01-06 18:36:15 +01:00
const auto& option = options[ index ];
2021-12-27 09:50:14 +01:00
QVariantList list;
2022-01-06 18:36:15 +01:00
list += QVariant::fromValue( option.graphic );
list += QVariant::fromValue( option.text );
2021-12-23 18:36:32 +01:00
2021-12-27 09:50:14 +01:00
return list;
2021-12-23 18:36:32 +01:00
}
void QskMenu::setTextOptions( const QskTextOptions& textOptions )
{
if( textOptions != m_data->textOptions )
{
m_data->textOptions = textOptions;
update();
}
}
QskTextOptions QskMenu::textOptions() const
{
return m_data->textOptions;
}
void QskMenu::setCurrentIndex( int index )
{
2021-12-29 16:23:19 +01:00
if( index < 0 || index >= count() )
index = -1;
if( index != m_data->currentIndex )
2021-12-23 18:36:32 +01:00
{
2021-12-29 16:23:19 +01:00
setPositionHint( Cursor, index );
2021-12-23 18:36:32 +01:00
m_data->currentIndex = index;
update();
Q_EMIT currentIndexChanged( index );
}
}
int QskMenu::currentIndex() const
{
return m_data->currentIndex;
}
void QskMenu::keyPressEvent( QKeyEvent* event )
{
if( m_data->currentIndex < 0 )
{
return;
}
int key = event->key();
switch( key )
{
case Qt::Key_Up:
{
traverse( -1 );
break;
}
case Qt::Key_Down:
{
traverse( 1 );
break;
}
case Qt::Key_Select:
case Qt::Key_Space:
{
m_data->isPressed = true;
return;
}
case Qt::Key_Escape:
case Qt::Key_Cancel:
{
setSelectedIndex( -1 );
return;
}
default:
{
return;
}
}
}
void QskMenu::keyReleaseEvent( QKeyEvent* )
{
if( m_data->isPressed )
{
m_data->isPressed = false;
setSelectedIndex( m_data->currentIndex );
}
}
2022-01-05 11:59:32 +01:00
#ifndef QT_NO_WHEELEVENT
2021-12-23 18:36:32 +01:00
void QskMenu::wheelEvent( QWheelEvent* event )
{
2022-01-05 11:59:32 +01:00
const auto steps = qskWheelSteps( event );
traverse( -steps );
2021-12-23 18:36:32 +01:00
}
2022-01-05 11:59:32 +01:00
#endif
2021-12-23 18:36:32 +01:00
void QskMenu::traverse( int steps )
{
2021-12-29 16:23:19 +01:00
if ( count() == 0 || ( steps % count() == 0 ) )
return;
2021-12-23 18:36:32 +01:00
2021-12-29 16:23:19 +01:00
auto index = m_data->currentIndex + steps;
2021-12-23 18:36:32 +01:00
2021-12-29 16:23:19 +01:00
auto newIndex = index % count();
if ( newIndex < 0 )
newIndex += count();
2021-12-29 17:19:19 +01:00
if ( hasAnimationHint( Cursor | QskAspect::Position | QskAspect::Metric ) )
2021-12-29 16:23:19 +01:00
{
// when cycling we want slide in
if ( index < 0 )
setPositionHint( Cursor, count() );
if ( index >= count() )
setPositionHint( Cursor, -1 );
movePositionHint( Cursor, newIndex );
}
setCurrentIndex( newIndex );
2021-12-23 18:36:32 +01:00
}
void QskMenu::mousePressEvent( QMouseEvent* event )
{
2021-12-29 15:21:09 +01:00
// QGuiApplication::styleHints()->setFocusOnTouchRelease ??
2021-12-23 18:36:32 +01:00
if ( event->button() == Qt::LeftButton )
{
2021-12-29 15:21:09 +01:00
const auto index = indexAtPosition( qskMousePosition( event ) );
2021-12-24 16:20:34 +01:00
if ( index >= 0 )
{
setCurrentIndex( index );
2021-12-23 18:36:32 +01:00
m_data->isPressed = true;
2021-12-24 16:20:34 +01:00
}
2022-01-04 15:54:16 +01:00
return;
2021-12-23 18:36:32 +01:00
}
2022-01-04 15:54:16 +01:00
return Inherited::mousePressEvent( event );
2021-12-23 18:36:32 +01:00
}
void QskMenu::mouseReleaseEvent( QMouseEvent* event )
{
if ( event->button() == Qt::LeftButton )
{
if( m_data->isPressed )
{
m_data->isPressed = false;
2021-12-24 16:20:34 +01:00
2021-12-29 15:21:09 +01:00
const auto index = indexAtPosition( qskMousePosition( event ) );
2021-12-24 16:20:34 +01:00
if ( index == m_data->currentIndex )
setSelectedIndex( index );
2021-12-23 18:36:32 +01:00
}
2022-01-04 15:54:16 +01:00
return;
2021-12-23 18:36:32 +01:00
}
2022-01-04 15:54:16 +01:00
return Inherited::mouseReleaseEvent( event );
2021-12-23 18:36:32 +01:00
}
void QskMenu::aboutToShow()
2021-12-23 19:05:59 +01:00
{
2021-12-23 18:36:32 +01:00
setGeometry( QRectF( m_data->origin, sizeConstraint() ) );
2021-12-29 16:23:19 +01:00
if ( m_data->currentIndex < 0 )
setCurrentIndex( 0 );
2021-12-23 18:36:32 +01:00
Inherited::aboutToShow();
}
QRectF QskMenu::focusIndicatorRect() const
{
// highlighting the item is good enough
return QRectF();
}
void QskMenu::setSelectedIndex( int index )
{
if ( !isOpen() )
return;
if ( index >= 0 )
setCurrentIndex( index );
2021-12-23 19:05:59 +01:00
2022-01-01 18:13:33 +01:00
m_data->selectedIndex = index;
2021-12-23 18:36:32 +01:00
Q_EMIT triggered( index );
2021-12-30 11:13:48 +01:00
2021-12-23 18:36:32 +01:00
close();
}
2021-12-24 16:20:34 +01:00
QRectF QskMenu::cellRect( int index ) const
{
return effectiveSkinlet()->sampleRect(
2021-12-24 16:50:34 +01:00
this, contentsRect(), QskMenu::Cell, index );
2021-12-24 16:20:34 +01:00
}
2021-12-26 09:15:15 +01:00
int QskMenu::indexAtPosition( const QPointF& pos ) const
{
return effectiveSkinlet()->sampleIndexAt(
2021-12-26 09:15:15 +01:00
this, contentsRect(), QskMenu::Cell, pos );
}
2021-12-30 11:13:48 +01:00
int QskMenu::exec()
{
2022-01-01 18:13:33 +01:00
m_data->selectedIndex = -1;
(void) execPopup();
return m_data->selectedIndex;
2021-12-30 11:13:48 +01:00
}
2021-12-23 18:36:32 +01:00
#include "moc_QskMenu.cpp"