QskMenu improved
This commit is contained in:
parent
1beec5e599
commit
452ff3a07b
@ -317,12 +317,11 @@ void Editor::setupMenu()
|
||||
setVGradient( Q::Separator, c2, c1 );
|
||||
#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 ) );
|
||||
setSpacing( Q::Cell, 5 );
|
||||
setGradient( Q::Cell, Qt::transparent );
|
||||
|
||||
setHGradient( Q::Cursor, c2, c2.lighter( 2 ) );
|
||||
|
||||
setColor( Q::Text, QColor( 255, 255, 255 ) );
|
||||
setFontRole( Q::Text, QskSkin::SmallFont );
|
||||
|
@ -5,13 +5,13 @@
|
||||
#include <QskGraphic.h>
|
||||
#include <QskColorFilter.h>
|
||||
|
||||
#include <QFontMetricsF>
|
||||
#include <QVector>
|
||||
#include <qvector.h>
|
||||
|
||||
QSK_SUBCONTROL( QskMenu, Panel )
|
||||
QSK_SUBCONTROL( QskMenu, Cell )
|
||||
QSK_SUBCONTROL( QskMenu, Cursor )
|
||||
QSK_SUBCONTROL( QskMenu, Text )
|
||||
QSK_SUBCONTROL( QskMenu, Graphic )
|
||||
QSK_SUBCONTROL( QskMenu, Cell )
|
||||
|
||||
QSK_SYSTEM_STATE( QskMenu, Selected, QskAspect::FirstSystemState << 2 )
|
||||
|
||||
@ -239,10 +239,12 @@ void QskMenu::traverse( int steps )
|
||||
|
||||
int QskMenu::indexAtPosition( const QPointF& pos ) const
|
||||
{
|
||||
const auto r = contentsRect();
|
||||
|
||||
if( count() > 0 && r.contains( pos ) )
|
||||
return ( pos.y() - r.y() ) / ( r.height() / count() );
|
||||
for ( int i = 0; i < count(); i++ )
|
||||
{
|
||||
// A menu never has many cells and we can simply iterate
|
||||
if ( cellRect( i ).contains( pos ) )
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -257,8 +259,12 @@ void QskMenu::mousePressEvent( QMouseEvent* event )
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,8 +274,11 @@ void QskMenu::mouseReleaseEvent( QMouseEvent* event )
|
||||
{
|
||||
if( m_data->isPressed )
|
||||
{
|
||||
setSelectedIndex( indexAtPosition( event->localPos() ) );
|
||||
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();
|
||||
}
|
||||
|
||||
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"
|
||||
|
@ -35,7 +35,7 @@ class QSK_EXPORT QskMenu : public QskPopup
|
||||
QString text;
|
||||
};
|
||||
|
||||
QSK_SUBCONTROLS( Panel, Cell, Text, Graphic )
|
||||
QSK_SUBCONTROLS( Panel, Cell, Cursor, Text, Graphic )
|
||||
QSK_STATES( Selected )
|
||||
|
||||
QskMenu( QQuickItem* parentItem = nullptr );
|
||||
@ -64,6 +64,9 @@ class QSK_EXPORT QskMenu : public QskPopup
|
||||
virtual QskColorFilter graphicFilterAt( int index ) const;
|
||||
QRectF focusIndicatorRect() const override;
|
||||
|
||||
QRectF cellRect( int index ) const;
|
||||
qreal cellHeight() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void triggered( int index );
|
||||
void currentIndexChanged( int index );
|
||||
|
@ -47,11 +47,10 @@ static qreal qskMaxTextWidth( const QskMenu* menu )
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
static QSizeF qskIconSize( const QskMenu* menu )
|
||||
static qreal qskGraphicWidth( const QskMenu* menu )
|
||||
{
|
||||
const auto hint = menu->strutSizeHint( QskMenu::Graphic );
|
||||
const qreal textHeight = QFontMetrics(
|
||||
menu->effectiveFont( QskMenu::Text ) ).height();
|
||||
const qreal textHeight = menu->effectiveFontHeight( QskMenu::Text );
|
||||
|
||||
const auto h = qMax( hint.height(), textHeight );
|
||||
|
||||
@ -63,22 +62,23 @@ static QSizeF qskIconSize( const QskMenu* menu )
|
||||
maxW = w;
|
||||
}
|
||||
|
||||
const auto w = qMax( hint.width(), maxW );
|
||||
|
||||
return QSizeF( w, h );
|
||||
return qMax( hint.width(), maxW );
|
||||
}
|
||||
|
||||
static QSizeF qskItemSize( const QskMenu* menu )
|
||||
static qreal qskCellWidth( const QskMenu* menu )
|
||||
{
|
||||
const auto spacing = menu->spacingHint( QskMenu::Cell );
|
||||
const QskMargins padding = menu->paddingHint( QskMenu::Cell );
|
||||
using Q = QskMenu;
|
||||
|
||||
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();
|
||||
const qreal w = sz.width() + spacing + qskMaxTextWidth( menu ) + padding.width();
|
||||
auto w = qskGraphicWidth( menu )
|
||||
+ 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,
|
||||
@ -101,41 +101,46 @@ static QSGNode* qskUpdateTextNode( const QskMenu* menu,
|
||||
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 )
|
||||
{
|
||||
if ( index >= 0 )
|
||||
for( int i = 0; i < menu->count(); i++ )
|
||||
{
|
||||
auto r = menu->subControlRect( QskMenu::Panel );
|
||||
r = menu->innerBox( QskMenu::Panel, r );
|
||||
QSGNode* newNode = nullptr;
|
||||
|
||||
const auto sz = qskItemSize( menu );
|
||||
{
|
||||
const StateChanger stateChanger( menu, menu->currentIndex() == i );
|
||||
|
||||
const auto y = r.y() + index * sz.height();
|
||||
return QRectF( r.x(), y, r.width(), sz.height() );
|
||||
newNode = QskSkinlet::updateBoxNode(
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
static void qskUpdateItemNode(
|
||||
@ -161,32 +166,14 @@ static void qskUpdateItemNode(
|
||||
|
||||
static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
|
||||
{
|
||||
const auto padding = menu->paddingHint( QskMenu::Cell );
|
||||
const auto spacing = menu->spacingHint( QskMenu::Cell );
|
||||
const auto iconSize = qskIconSize( 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 ) );
|
||||
const auto graphicWidth = qskGraphicWidth( menu );
|
||||
|
||||
if ( rootNode == nullptr )
|
||||
rootNode = new QSGNode();
|
||||
|
||||
QSGNode* node = nullptr;
|
||||
|
||||
qreal y = boundingRect.y();
|
||||
|
||||
for( int i = 0; i < menu->count(); i++ )
|
||||
{
|
||||
if ( node == nullptr )
|
||||
@ -203,13 +190,10 @@ static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
|
||||
{
|
||||
const StateChanger stateChanger( menu, menu->currentIndex() == i );
|
||||
|
||||
QRectF cellRect( boundingRect.x(), y,
|
||||
boundingRect.width(), itemSize.height() );
|
||||
|
||||
cellRect = cellRect.marginsRemoved( padding );
|
||||
const auto cellRect = menu->cellRect( i );
|
||||
|
||||
auto graphicRect = cellRect;
|
||||
graphicRect.setWidth( iconSize.width() );
|
||||
graphicRect.setWidth( graphicWidth );
|
||||
|
||||
auto textRect = cellRect;
|
||||
textRect.setX( graphicRect.right() + spacing );
|
||||
@ -217,12 +201,8 @@ static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
|
||||
qskUpdateItemNode( menu, graphicRect, menu->graphicAt( i ),
|
||||
textRect, menu->entryAt( i ).text, node );
|
||||
}
|
||||
|
||||
y += itemSize.height();
|
||||
|
||||
}
|
||||
|
||||
// Remove trailing nodes
|
||||
QskSGNode::removeAllChildNodesAfter( rootNode, node );
|
||||
|
||||
return rootNode;
|
||||
@ -238,11 +218,18 @@ QRectF QskMenuSkinlet::subControlRect(
|
||||
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
||||
QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
const auto menu = static_cast< const QskMenu* >( skinnable );
|
||||
|
||||
if( subControl == QskMenu::Panel )
|
||||
{
|
||||
return contentsRect;
|
||||
}
|
||||
|
||||
if( subControl == QskMenu::Cursor )
|
||||
{
|
||||
return menu->cellRect( menu->currentIndex() );
|
||||
}
|
||||
|
||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||
}
|
||||
|
||||
@ -261,7 +248,7 @@ QSGNode* QskMenuSkinlet::updateContentsNode(
|
||||
{
|
||||
auto oldNode = QskSGNode::findChildNode( contentsNode, role );
|
||||
|
||||
QSGNode* newNode;
|
||||
QSGNode* newNode = nullptr;
|
||||
|
||||
switch( role )
|
||||
{
|
||||
@ -277,7 +264,7 @@ QSGNode* QskMenuSkinlet::updateContentsNode(
|
||||
}
|
||||
case Cursor:
|
||||
{
|
||||
newNode = qskUpdateCursorNode( menu, oldNode );
|
||||
newNode = updateBoxNode( menu, oldNode, QskMenu::Cursor );
|
||||
break;
|
||||
}
|
||||
case Items:
|
||||
@ -296,18 +283,15 @@ QSGNode* QskMenuSkinlet::updateContentsNode(
|
||||
QSizeF QskMenuSkinlet::sizeHint( const QskSkinnable* skinnable,
|
||||
Qt::SizeHint which, const QSizeF& ) const
|
||||
{
|
||||
using Q = QskMenu;
|
||||
|
||||
if ( which != Qt::PreferredSize )
|
||||
return QSizeF();
|
||||
|
||||
const auto menu = static_cast< const QskMenu* >( skinnable );
|
||||
|
||||
const auto itemSize = qskItemSize( menu );
|
||||
const auto count = menu->count();
|
||||
const qreal w = qskCellWidth( menu );
|
||||
const auto h = menu->count() * menu->cellHeight();
|
||||
|
||||
const qreal h = count * itemSize.height();
|
||||
return menu->outerBoxSize( Q::Panel, QSizeF( itemSize.width(), h ) );
|
||||
return menu->outerBoxSize( QskMenu::Panel, QSizeF( w, h ) );
|
||||
}
|
||||
|
||||
#include "moc_QskMenuSkinlet.cpp"
|
||||
|
Loading…
x
Reference in New Issue
Block a user