QskMenu improved
This commit is contained in:
parent
1beec5e599
commit
452ff3a07b
@ -317,12 +317,11 @@ void Editor::setupMenu()
|
|||||||
setVGradient( Q::Separator, c2, c1 );
|
setVGradient( Q::Separator, c2, c1 );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// while fading out we are in Q::Closed state
|
|
||||||
for ( auto state : { QskAspect::NoState, Q::Closed } )
|
|
||||||
setHGradient( Q::Cell | Q::Selected | state, c2, c2.lighter( 2 ) );
|
|
||||||
|
|
||||||
setPadding( Q::Cell, QskMargins( 2, 10, 2, 10 ) );
|
setPadding( Q::Cell, QskMargins( 2, 10, 2, 10 ) );
|
||||||
setSpacing( Q::Cell, 5 );
|
setSpacing( Q::Cell, 5 );
|
||||||
|
setGradient( Q::Cell, Qt::transparent );
|
||||||
|
|
||||||
|
setHGradient( Q::Cursor, c2, c2.lighter( 2 ) );
|
||||||
|
|
||||||
setColor( Q::Text, QColor( 255, 255, 255 ) );
|
setColor( Q::Text, QColor( 255, 255, 255 ) );
|
||||||
setFontRole( Q::Text, QskSkin::SmallFont );
|
setFontRole( Q::Text, QskSkin::SmallFont );
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
#include <QskGraphic.h>
|
#include <QskGraphic.h>
|
||||||
#include <QskColorFilter.h>
|
#include <QskColorFilter.h>
|
||||||
|
|
||||||
#include <QFontMetricsF>
|
#include <qvector.h>
|
||||||
#include <QVector>
|
|
||||||
|
|
||||||
QSK_SUBCONTROL( QskMenu, Panel )
|
QSK_SUBCONTROL( QskMenu, Panel )
|
||||||
|
QSK_SUBCONTROL( QskMenu, Cell )
|
||||||
|
QSK_SUBCONTROL( QskMenu, Cursor )
|
||||||
QSK_SUBCONTROL( QskMenu, Text )
|
QSK_SUBCONTROL( QskMenu, Text )
|
||||||
QSK_SUBCONTROL( QskMenu, Graphic )
|
QSK_SUBCONTROL( QskMenu, Graphic )
|
||||||
QSK_SUBCONTROL( QskMenu, Cell )
|
|
||||||
|
|
||||||
QSK_SYSTEM_STATE( QskMenu, Selected, QskAspect::FirstSystemState << 2 )
|
QSK_SYSTEM_STATE( QskMenu, Selected, QskAspect::FirstSystemState << 2 )
|
||||||
|
|
||||||
@ -239,10 +239,12 @@ void QskMenu::traverse( int steps )
|
|||||||
|
|
||||||
int QskMenu::indexAtPosition( const QPointF& pos ) const
|
int QskMenu::indexAtPosition( const QPointF& pos ) const
|
||||||
{
|
{
|
||||||
const auto r = contentsRect();
|
for ( int i = 0; i < count(); i++ )
|
||||||
|
{
|
||||||
if( count() > 0 && r.contains( pos ) )
|
// A menu never has many cells and we can simply iterate
|
||||||
return ( pos.y() - r.y() ) / ( r.height() / count() );
|
if ( cellRect( i ).contains( pos ) )
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -257,8 +259,12 @@ void QskMenu::mousePressEvent( QMouseEvent* event )
|
|||||||
{
|
{
|
||||||
if ( event->button() == Qt::LeftButton )
|
if ( event->button() == Qt::LeftButton )
|
||||||
{
|
{
|
||||||
if ( contentsRect().contains( event->localPos() ) )
|
const auto index = indexAtPosition( event->localPos() );
|
||||||
|
if ( index >= 0 )
|
||||||
|
{
|
||||||
|
setCurrentIndex( index );
|
||||||
m_data->isPressed = true;
|
m_data->isPressed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,8 +274,11 @@ void QskMenu::mouseReleaseEvent( QMouseEvent* event )
|
|||||||
{
|
{
|
||||||
if( m_data->isPressed )
|
if( m_data->isPressed )
|
||||||
{
|
{
|
||||||
setSelectedIndex( indexAtPosition( event->localPos() ) );
|
|
||||||
m_data->isPressed = false;
|
m_data->isPressed = false;
|
||||||
|
|
||||||
|
const auto index = indexAtPosition( event->localPos() );
|
||||||
|
if ( index == m_data->currentIndex )
|
||||||
|
setSelectedIndex( index );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,4 +307,39 @@ void QskMenu::setSelectedIndex( int index )
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRectF QskMenu::cellRect( int index ) const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Calculations like this one should be done in the skinlet.
|
||||||
|
We need an API like subControlRect( int index, ... ) TODO ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( index < 0 || index >= count() )
|
||||||
|
return QRectF();
|
||||||
|
|
||||||
|
const auto r = subControlContentsRect( QskMenu::Panel );
|
||||||
|
const auto h = cellHeight();
|
||||||
|
|
||||||
|
return QRectF( r.x(), r.y() + index * h, r.width(), h );
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal QskMenu::cellHeight() const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Calculations like this one should be done in the skinlet.
|
||||||
|
We need an API like subControlRect( int index, ... ) TODO ...
|
||||||
|
*/
|
||||||
|
const auto graphicHeight = strutSizeHint( Graphic ).height();
|
||||||
|
const auto textHeight = effectiveFontHeight( Text );
|
||||||
|
const auto padding = paddingHint( Cell );
|
||||||
|
|
||||||
|
qreal h = qMax( graphicHeight, textHeight );
|
||||||
|
h += padding.top() + padding.bottom();
|
||||||
|
|
||||||
|
const auto minHeight = strutSizeHint( Cell ).height();
|
||||||
|
h = qMax( h, minHeight );
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_QskMenu.cpp"
|
#include "moc_QskMenu.cpp"
|
||||||
|
@ -35,7 +35,7 @@ class QSK_EXPORT QskMenu : public QskPopup
|
|||||||
QString text;
|
QString text;
|
||||||
};
|
};
|
||||||
|
|
||||||
QSK_SUBCONTROLS( Panel, Cell, Text, Graphic )
|
QSK_SUBCONTROLS( Panel, Cell, Cursor, Text, Graphic )
|
||||||
QSK_STATES( Selected )
|
QSK_STATES( Selected )
|
||||||
|
|
||||||
QskMenu( QQuickItem* parentItem = nullptr );
|
QskMenu( QQuickItem* parentItem = nullptr );
|
||||||
@ -64,6 +64,9 @@ class QSK_EXPORT QskMenu : public QskPopup
|
|||||||
virtual QskColorFilter graphicFilterAt( int index ) const;
|
virtual QskColorFilter graphicFilterAt( int index ) const;
|
||||||
QRectF focusIndicatorRect() const override;
|
QRectF focusIndicatorRect() const override;
|
||||||
|
|
||||||
|
QRectF cellRect( int index ) const;
|
||||||
|
qreal cellHeight() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void triggered( int index );
|
void triggered( int index );
|
||||||
void currentIndexChanged( int index );
|
void currentIndexChanged( int index );
|
||||||
|
@ -47,11 +47,10 @@ static qreal qskMaxTextWidth( const QskMenu* menu )
|
|||||||
return maxWidth;
|
return maxWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSizeF qskIconSize( const QskMenu* menu )
|
static qreal qskGraphicWidth( const QskMenu* menu )
|
||||||
{
|
{
|
||||||
const auto hint = menu->strutSizeHint( QskMenu::Graphic );
|
const auto hint = menu->strutSizeHint( QskMenu::Graphic );
|
||||||
const qreal textHeight = QFontMetrics(
|
const qreal textHeight = menu->effectiveFontHeight( QskMenu::Text );
|
||||||
menu->effectiveFont( QskMenu::Text ) ).height();
|
|
||||||
|
|
||||||
const auto h = qMax( hint.height(), textHeight );
|
const auto h = qMax( hint.height(), textHeight );
|
||||||
|
|
||||||
@ -63,22 +62,23 @@ static QSizeF qskIconSize( const QskMenu* menu )
|
|||||||
maxW = w;
|
maxW = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto w = qMax( hint.width(), maxW );
|
return qMax( hint.width(), maxW );
|
||||||
|
|
||||||
return QSizeF( w, h );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSizeF qskItemSize( const QskMenu* menu )
|
static qreal qskCellWidth( const QskMenu* menu )
|
||||||
{
|
{
|
||||||
const auto spacing = menu->spacingHint( QskMenu::Cell );
|
using Q = QskMenu;
|
||||||
const QskMargins padding = menu->paddingHint( QskMenu::Cell );
|
|
||||||
|
|
||||||
const auto sz = qskIconSize( menu );
|
const auto spacing = menu->spacingHint( Q::Cell );
|
||||||
|
const auto padding = menu->paddingHint( Q::Cell );
|
||||||
|
|
||||||
const qreal h = sz.height() + padding.height();
|
auto w = qskGraphicWidth( menu )
|
||||||
const qreal w = sz.width() + spacing + qskMaxTextWidth( menu ) + padding.width();
|
+ spacing + qskMaxTextWidth( menu );
|
||||||
|
|
||||||
return QSizeF( w, h );
|
w += padding.left() + padding.right();
|
||||||
|
|
||||||
|
const auto minWidth = menu->strutSizeHint( Q::Cell ).width();
|
||||||
|
return qMax( w, minWidth );
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSGNode* qskUpdateGraphicNode( const QskMenu* menu,
|
static QSGNode* qskUpdateGraphicNode( const QskMenu* menu,
|
||||||
@ -101,41 +101,46 @@ static QSGNode* qskUpdateTextNode( const QskMenu* menu,
|
|||||||
text, menu->textOptions(), QskMenu::Text );
|
text, menu->textOptions(), QskMenu::Text );
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSGNode* qskUpdateBackgroundNode( const QskMenu*, QSGNode* )
|
static QSGNode* qskUpdateBackgroundNode( const QskMenu* menu, QSGNode* rootNode )
|
||||||
{
|
{
|
||||||
return nullptr; // TODO
|
auto node = rootNode ? rootNode->firstChild() : nullptr;
|
||||||
}
|
QSGNode* lastNode = nullptr;
|
||||||
|
|
||||||
static QRectF qskCellRect( const QskMenu* menu, int index )
|
for( int i = 0; i < menu->count(); i++ )
|
||||||
{
|
|
||||||
if ( index >= 0 )
|
|
||||||
{
|
{
|
||||||
auto r = menu->subControlRect( QskMenu::Panel );
|
QSGNode* newNode = nullptr;
|
||||||
r = menu->innerBox( QskMenu::Panel, r );
|
|
||||||
|
|
||||||
const auto sz = qskItemSize( menu );
|
{
|
||||||
|
const StateChanger stateChanger( menu, menu->currentIndex() == i );
|
||||||
|
|
||||||
const auto y = r.y() + index * sz.height();
|
newNode = QskSkinlet::updateBoxNode(
|
||||||
return QRectF( r.x(), y, r.width(), sz.height() );
|
menu, node, menu->cellRect( i ), QskMenu::Cell );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( newNode )
|
||||||
|
{
|
||||||
|
if ( newNode == node )
|
||||||
|
{
|
||||||
|
node = node->nextSibling();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( rootNode == nullptr )
|
||||||
|
rootNode = new QSGNode();
|
||||||
|
|
||||||
|
if ( node )
|
||||||
|
rootNode->insertChildNodeBefore( newNode, node );
|
||||||
|
else
|
||||||
|
rootNode->appendChildNode( newNode );
|
||||||
|
}
|
||||||
|
|
||||||
|
lastNode = newNode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QRectF();
|
QskSGNode::removeAllChildNodesAfter( rootNode, lastNode );
|
||||||
}
|
|
||||||
|
|
||||||
static QSGNode* qskUpdateCursorNode( const QskMenu* menu, QSGNode* node )
|
return rootNode;
|
||||||
{
|
|
||||||
const auto r = qskCellRect( menu, menu->currentIndex() );
|
|
||||||
if ( !r.isEmpty() )
|
|
||||||
{
|
|
||||||
const StateChanger stateChanger( menu, true );
|
|
||||||
|
|
||||||
auto cursorNode = QskSGNode::ensureNode< QskBoxNode >( node );
|
|
||||||
cursorNode->setBoxData( r, menu->gradientHint( QskMenu::Cell ) );
|
|
||||||
|
|
||||||
return cursorNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qskUpdateItemNode(
|
static void qskUpdateItemNode(
|
||||||
@ -161,32 +166,14 @@ static void qskUpdateItemNode(
|
|||||||
|
|
||||||
static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
|
static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
|
||||||
{
|
{
|
||||||
const auto padding = menu->paddingHint( QskMenu::Cell );
|
|
||||||
const auto spacing = menu->spacingHint( QskMenu::Cell );
|
const auto spacing = menu->spacingHint( QskMenu::Cell );
|
||||||
const auto iconSize = qskIconSize( menu );
|
const auto graphicWidth = qskGraphicWidth( menu );
|
||||||
|
|
||||||
auto boundingRect = menu->subControlRect( QskMenu::Panel );
|
|
||||||
boundingRect = menu->innerBox( QskMenu::Panel, boundingRect );
|
|
||||||
|
|
||||||
auto itemSize = iconSize;
|
|
||||||
itemSize.rwidth() += spacing + qskMaxTextWidth( menu );
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 5, 14, 0 )
|
|
||||||
itemSize = itemSize.grownBy( padding );
|
|
||||||
#else
|
|
||||||
itemSize.rwidth() += padding.left() + padding.right();
|
|
||||||
itemSize.rheight() += padding.top() + padding.bottom();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
itemSize = itemSize.expandedTo( menu->strutSizeHint( QskMenu::Graphic ) );
|
|
||||||
|
|
||||||
if ( rootNode == nullptr )
|
if ( rootNode == nullptr )
|
||||||
rootNode = new QSGNode();
|
rootNode = new QSGNode();
|
||||||
|
|
||||||
QSGNode* node = nullptr;
|
QSGNode* node = nullptr;
|
||||||
|
|
||||||
qreal y = boundingRect.y();
|
|
||||||
|
|
||||||
for( int i = 0; i < menu->count(); i++ )
|
for( int i = 0; i < menu->count(); i++ )
|
||||||
{
|
{
|
||||||
if ( node == nullptr )
|
if ( node == nullptr )
|
||||||
@ -203,13 +190,10 @@ static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
|
|||||||
{
|
{
|
||||||
const StateChanger stateChanger( menu, menu->currentIndex() == i );
|
const StateChanger stateChanger( menu, menu->currentIndex() == i );
|
||||||
|
|
||||||
QRectF cellRect( boundingRect.x(), y,
|
const auto cellRect = menu->cellRect( i );
|
||||||
boundingRect.width(), itemSize.height() );
|
|
||||||
|
|
||||||
cellRect = cellRect.marginsRemoved( padding );
|
|
||||||
|
|
||||||
auto graphicRect = cellRect;
|
auto graphicRect = cellRect;
|
||||||
graphicRect.setWidth( iconSize.width() );
|
graphicRect.setWidth( graphicWidth );
|
||||||
|
|
||||||
auto textRect = cellRect;
|
auto textRect = cellRect;
|
||||||
textRect.setX( graphicRect.right() + spacing );
|
textRect.setX( graphicRect.right() + spacing );
|
||||||
@ -217,12 +201,8 @@ static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
|
|||||||
qskUpdateItemNode( menu, graphicRect, menu->graphicAt( i ),
|
qskUpdateItemNode( menu, graphicRect, menu->graphicAt( i ),
|
||||||
textRect, menu->entryAt( i ).text, node );
|
textRect, menu->entryAt( i ).text, node );
|
||||||
}
|
}
|
||||||
|
|
||||||
y += itemSize.height();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove trailing nodes
|
|
||||||
QskSGNode::removeAllChildNodesAfter( rootNode, node );
|
QskSGNode::removeAllChildNodesAfter( rootNode, node );
|
||||||
|
|
||||||
return rootNode;
|
return rootNode;
|
||||||
@ -238,11 +218,18 @@ QRectF QskMenuSkinlet::subControlRect(
|
|||||||
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
||||||
QskAspect::Subcontrol subControl ) const
|
QskAspect::Subcontrol subControl ) const
|
||||||
{
|
{
|
||||||
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
||||||
|
|
||||||
if( subControl == QskMenu::Panel )
|
if( subControl == QskMenu::Panel )
|
||||||
{
|
{
|
||||||
return contentsRect;
|
return contentsRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( subControl == QskMenu::Cursor )
|
||||||
|
{
|
||||||
|
return menu->cellRect( menu->currentIndex() );
|
||||||
|
}
|
||||||
|
|
||||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +248,7 @@ QSGNode* QskMenuSkinlet::updateContentsNode(
|
|||||||
{
|
{
|
||||||
auto oldNode = QskSGNode::findChildNode( contentsNode, role );
|
auto oldNode = QskSGNode::findChildNode( contentsNode, role );
|
||||||
|
|
||||||
QSGNode* newNode;
|
QSGNode* newNode = nullptr;
|
||||||
|
|
||||||
switch( role )
|
switch( role )
|
||||||
{
|
{
|
||||||
@ -277,7 +264,7 @@ QSGNode* QskMenuSkinlet::updateContentsNode(
|
|||||||
}
|
}
|
||||||
case Cursor:
|
case Cursor:
|
||||||
{
|
{
|
||||||
newNode = qskUpdateCursorNode( menu, oldNode );
|
newNode = updateBoxNode( menu, oldNode, QskMenu::Cursor );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Items:
|
case Items:
|
||||||
@ -296,18 +283,15 @@ QSGNode* QskMenuSkinlet::updateContentsNode(
|
|||||||
QSizeF QskMenuSkinlet::sizeHint( const QskSkinnable* skinnable,
|
QSizeF QskMenuSkinlet::sizeHint( const QskSkinnable* skinnable,
|
||||||
Qt::SizeHint which, const QSizeF& ) const
|
Qt::SizeHint which, const QSizeF& ) const
|
||||||
{
|
{
|
||||||
using Q = QskMenu;
|
|
||||||
|
|
||||||
if ( which != Qt::PreferredSize )
|
if ( which != Qt::PreferredSize )
|
||||||
return QSizeF();
|
return QSizeF();
|
||||||
|
|
||||||
const auto menu = static_cast< const QskMenu* >( skinnable );
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
||||||
|
|
||||||
const auto itemSize = qskItemSize( menu );
|
const qreal w = qskCellWidth( menu );
|
||||||
const auto count = menu->count();
|
const auto h = menu->count() * menu->cellHeight();
|
||||||
|
|
||||||
const qreal h = count * itemSize.height();
|
return menu->outerBoxSize( QskMenu::Panel, QSizeF( w, h ) );
|
||||||
return menu->outerBoxSize( Q::Panel, QSizeF( itemSize.width(), h ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_QskMenuSkinlet.cpp"
|
#include "moc_QskMenuSkinlet.cpp"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user