This commit is contained in:
Uwe Rathmann 2023-05-12 14:58:40 +02:00
parent 33b3ddb5e3
commit 2a7a68e915
3 changed files with 82 additions and 63 deletions

View File

@ -28,13 +28,25 @@ QSK_SUBCONTROL( QskMenu, Separator )
QSK_SYSTEM_STATE( QskMenu, Selected, QskAspect::FirstSystemState << 2 ) QSK_SYSTEM_STATE( QskMenu, Selected, QskAspect::FirstSystemState << 2 )
QVector< int > qskSeparators( const QVector< QskLabelData >& options )
{
QVector< int > separators;
for ( int i = 0; i < options.count(); i++ )
{
if ( options[i].isEmpty() )
separators += i;
}
return separators;
}
class QskMenu::PrivateData class QskMenu::PrivateData
{ {
public: public:
QPointF origin; QPointF origin;
QVector< QskLabelData > options; QVector< QskLabelData > options;
// QVector< bool > enabled;
QVector< int > separators; QVector< int > separators;
int triggeredIndex = -1; int triggeredIndex = -1;
@ -128,13 +140,16 @@ int QskMenu::addOption( const QskLabelData& option )
{ {
m_data->options += option; m_data->options += option;
if ( option.isEmpty() )
m_data->separators += m_data->options.count() - 1;
resetImplicitSize(); resetImplicitSize();
update(); update();
if ( isComponentComplete() ) if ( isComponentComplete() )
Q_EMIT optionsChanged(); Q_EMIT optionsChanged();
return count() - 1; return m_data->options.count() - 1;
} }
void QskMenu::setOptions( const QStringList& options ) void QskMenu::setOptions( const QStringList& options )
@ -145,6 +160,7 @@ void QskMenu::setOptions( const QStringList& options )
void QskMenu::setOptions( const QVector< QskLabelData >& options ) void QskMenu::setOptions( const QVector< QskLabelData >& options )
{ {
m_data->options = options; m_data->options = options;
m_data->separators = qskSeparators( options );
if ( m_data->currentIndex >= 0 ) if ( m_data->currentIndex >= 0 )
{ {
@ -163,7 +179,6 @@ void QskMenu::setOptions( const QVector< QskLabelData >& options )
void QskMenu::clear() void QskMenu::clear()
{ {
m_data->separators.clear();
setOptions( QVector< QskLabelData >() ); setOptions( QVector< QskLabelData >() );
} }
@ -177,27 +192,19 @@ QskLabelData QskMenu::optionAt( int index ) const
return m_data->options.value( index ); return m_data->options.value( index );
} }
int QskMenu::count() const int QskMenu::optionsCount() const
{ {
return m_data->options.count(); return m_data->options.count();
} }
void QskMenu::addSeparator() void QskMenu::addSeparator()
{ {
m_data->separators += m_data->options.count(); addOption( QskLabelData() );
resetImplicitSize();
update();
} }
int QskMenu::separatorPosition( int index ) const QVector< int > QskMenu::separators() const
{ {
return m_data->separators.value( index, -1 ); return m_data->separators;
}
int QskMenu::separatorCount() const
{
return m_data->separators.count();
} }
int QskMenu::currentIndex() const int QskMenu::currentIndex() const
@ -207,8 +214,15 @@ int QskMenu::currentIndex() const
void QskMenu::setCurrentIndex( int index ) void QskMenu::setCurrentIndex( int index )
{ {
if( index < 0 || index >= count() ) if( index < 0 || index >= m_data->options.count() )
{
index = -1; index = -1;
}
else
{
if ( m_data->options[index].isEmpty() ) // a seperator
index = -1;
}
if( index != m_data->currentIndex ) if( index != m_data->currentIndex )
{ {
@ -308,22 +322,38 @@ void QskMenu::wheelEvent( QWheelEvent* event )
void QskMenu::traverse( int steps ) void QskMenu::traverse( int steps )
{ {
if ( count() == 0 || ( steps % count() == 0 ) ) const auto count = m_data->options.count();
const auto n = count - m_data->separators.count();
if ( ( n <= 0 ) || ( steps % n == 0 ) )
return; return;
auto index = m_data->currentIndex + steps; auto index = m_data->currentIndex;
for ( auto i : m_data->separators )
{
if ( i < index )
index--;
}
auto newIndex = index % count(); index += steps;
auto newIndex = index % n;
if ( newIndex < 0 ) if ( newIndex < 0 )
newIndex += count(); newIndex += n;
for ( int i = 0; i < newIndex; i++)
{
if ( m_data->options[i].isEmpty() )
newIndex++;
}
// when cycling we want slide in // when cycling we want slide in
int startIndex = m_data->currentIndex; int startIndex = m_data->currentIndex;
if ( index < 0 ) if ( index < 0 )
startIndex = count(); startIndex = count;
else if ( index >= count() ) else if ( index >= n )
startIndex = -1; startIndex = -1;
movePositionHint( Cursor, startIndex, newIndex ); movePositionHint( Cursor, startIndex, newIndex );

View File

@ -26,7 +26,7 @@ class QSK_EXPORT QskMenu : public QskPopup
Q_PROPERTY( QVector< QskLabelData > options READ options Q_PROPERTY( QVector< QskLabelData > options READ options
WRITE setOptions NOTIFY optionsChanged ) WRITE setOptions NOTIFY optionsChanged )
Q_PROPERTY( int count READ count ) Q_PROPERTY( int optionsCount READ optionsCount )
Q_PROPERTY( int currentIndex READ currentIndex Q_PROPERTY( int currentIndex READ currentIndex
WRITE setCurrentIndex NOTIFY currentIndexChanged ) WRITE setCurrentIndex NOTIFY currentIndexChanged )
@ -65,12 +65,10 @@ class QSK_EXPORT QskMenu : public QskPopup
QVector< QskLabelData > options() const; QVector< QskLabelData > options() const;
QskLabelData optionAt( int ) const; QskLabelData optionAt( int ) const;
int count() const; int optionsCount() const;
void addSeparator(); void addSeparator();
QVector< int > separators() const;
int separatorPosition( int ) const;
int separatorCount() const;
void clear(); void clear();

View File

@ -47,10 +47,12 @@ class QskMenuSkinlet::PrivateData
inline int separatorsBefore( const QskMenu* menu, int index ) const inline int separatorsBefore( const QskMenu* menu, int index ) const
{ {
const auto separators = menu->separators();
int i = 0; int i = 0;
for ( ; i < menu->separatorCount(); i++ ) for ( ; i < separators.count(); i++ )
{ {
if ( menu->separatorPosition( i ) > index ) if ( separators[i] >= index )
break; break;
} }
@ -112,26 +114,22 @@ class QskMenuSkinlet::PrivateData
private: private:
qreal graphicWidthInternal( const QskMenu* menu ) const qreal graphicWidthInternal( const QskMenu* menu ) const
{ {
const auto skinlet = menu->effectiveSkinlet();
const auto hint = menu->strutSizeHint( QskMenu::Icon ); const auto hint = menu->strutSizeHint( QskMenu::Icon );
const qreal textHeight = menu->effectiveFontHeight( QskMenu::Text ); const qreal textHeight = menu->effectiveFontHeight( QskMenu::Text );
const auto h = qMax( hint.height(), textHeight ); const auto h = qMax( hint.height(), textHeight );
qreal maxW = 0.0; qreal maxW = 0.0;
for ( int i = 0; i < menu->count(); i++ )
const auto options = menu->options();
for ( auto& option : options )
{ {
const auto sample = skinlet->sampleAt( menu, QskMenu::Icon, i ); const auto graphic = option.icon().graphic();
if ( sample.canConvert< QskGraphic >() ) if ( !graphic.isNull() )
{ {
const auto graphic = sample.value< QskGraphic >(); const auto w = graphic.widthForHeight( h );
if ( !graphic.isNull() ) if( w > maxW )
{ maxW = w;
const auto w = graphic.widthForHeight( h );
if( w > maxW )
maxW = w;
}
} }
} }
@ -140,24 +138,18 @@ class QskMenuSkinlet::PrivateData
qreal textWidthInternal( const QskMenu* menu ) const qreal textWidthInternal( const QskMenu* menu ) const
{ {
const auto skinlet = menu->effectiveSkinlet();
const QFontMetricsF fm( menu->effectiveFont( QskMenu::Text ) ); const QFontMetricsF fm( menu->effectiveFont( QskMenu::Text ) );
auto maxWidth = 0.0; auto maxWidth = 0.0;
for ( int i = 0; i < menu->count(); i++ ) const auto options = menu->options();
for ( auto& option : options )
{ {
const auto sample = skinlet->sampleAt( menu, QskMenu::Text, i ); if( !option.text().isEmpty() )
if ( sample.canConvert< QString >() )
{ {
const auto text = sample.toString(); const auto w = qskHorizontalAdvance( fm, option.text() );
if( !text.isEmpty() ) if( w > maxWidth )
{ maxWidth = w;
const auto w = qskHorizontalAdvance( fm, text );
if( w > maxWidth )
maxWidth = w;
}
} }
} }
@ -324,17 +316,16 @@ QRectF QskMenuSkinlet::sampleRect(
if ( subControl == QskMenu::Separator ) if ( subControl == QskMenu::Separator )
{ {
const int pos = menu->separatorPosition( index ); const auto separators = menu->separators();
if ( pos < 0 ) if ( index >= separators.count() )
return QRectF(); return QRectF();
QRectF r = menu->subControlContentsRect( Q::Panel ); const int pos = separators[ index ];
if ( pos < menu->count() ) auto r = menu->subControlContentsRect( Q::Panel );
{
const auto segmentRect = sampleRect( skinnable, contentsRect, Q::Segment, pos ); const auto segmentRect = sampleRect( skinnable, contentsRect, Q::Segment, pos );
r.setBottom( segmentRect.top() ); // spacing ??? r.setBottom( segmentRect.top() ); // spacing ???
}
const qreal h = menu->metric( Q::Separator | QskAspect::Size ); const qreal h = menu->metric( Q::Separator | QskAspect::Size );
r.setTop( r.bottom() - h ); r.setTop( r.bottom() - h );
@ -362,13 +353,13 @@ int QskMenuSkinlet::sampleCount(
if ( subControl == Q::Segment || subControl == Q::Icon || subControl == Q::Text ) if ( subControl == Q::Segment || subControl == Q::Icon || subControl == Q::Text )
{ {
const auto menu = static_cast< const QskMenu* >( skinnable ); const auto menu = static_cast< const QskMenu* >( skinnable );
return menu->count(); return menu->optionsCount() - menu->separators().count();
} }
if ( subControl == Q::Separator ) if ( subControl == Q::Separator )
{ {
const auto menu = static_cast< const QskMenu* >( skinnable ); const auto menu = static_cast< const QskMenu* >( skinnable );
return menu->separatorCount(); return menu->separators().count();
} }
return Inherited::sampleCount( skinnable, subControl ); return Inherited::sampleCount( skinnable, subControl );