QskMenuSkinlet improved
This commit is contained in:
parent
f1a324b216
commit
9fff09144a
@ -15,12 +15,12 @@
|
|||||||
#include <qfontmetrics.h>
|
#include <qfontmetrics.h>
|
||||||
|
|
||||||
template< class T >
|
template< class T >
|
||||||
static T qskValueAt( const QskMenu* menu, int index )
|
static inline QVariant qskValueAt( const QskMenu* menu, int index )
|
||||||
{
|
{
|
||||||
const auto item = menu->itemAt( index );
|
const auto item = menu->itemAt( index );
|
||||||
|
|
||||||
if ( item.canConvert< T >() )
|
if ( item.canConvert< T >() )
|
||||||
return item.value< T >();
|
return item;
|
||||||
|
|
||||||
if ( item.canConvert< QVariantList >() )
|
if ( item.canConvert< QVariantList >() )
|
||||||
{
|
{
|
||||||
@ -28,234 +28,189 @@ static T qskValueAt( const QskMenu* menu, int index )
|
|||||||
for ( const auto& value : list )
|
for ( const auto& value : list )
|
||||||
{
|
{
|
||||||
if ( value.canConvert< T >() )
|
if ( value.canConvert< T >() )
|
||||||
return value.value< T >();
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return T();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
static qreal qskMaxTextWidth( const QskMenu* menu )
|
class QskMenuSkinlet::PrivateData
|
||||||
{
|
{
|
||||||
const QFontMetricsF fm( menu->effectiveFont( QskMenu::Text ) );
|
public:
|
||||||
|
class CacheGuard
|
||||||
auto maxWidth = 0.0;
|
|
||||||
|
|
||||||
for ( int i = 0; i < menu->count(); i++ )
|
|
||||||
{
|
{
|
||||||
const auto value = menu->itemAt( i );
|
public:
|
||||||
|
CacheGuard( QskMenuSkinlet::PrivateData* data )
|
||||||
const auto text = qskValueAt< QString >( menu, i );
|
: m_data( data )
|
||||||
if( !text.isEmpty() )
|
|
||||||
{
|
{
|
||||||
const auto w = qskHorizontalAdvance( fm, text );
|
m_data->enableCache( true );
|
||||||
if( w > maxWidth )
|
|
||||||
maxWidth = w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return maxWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qreal qskGraphicWidth( const QskMenu* menu )
|
|
||||||
{
|
|
||||||
const auto hint = menu->strutSizeHint( QskMenu::Graphic );
|
|
||||||
const qreal textHeight = menu->effectiveFontHeight( QskMenu::Text );
|
|
||||||
|
|
||||||
const auto h = qMax( hint.height(), textHeight );
|
|
||||||
|
|
||||||
qreal maxW = 0.0;
|
|
||||||
for ( int i = 0; i < menu->count(); i++ )
|
|
||||||
{
|
|
||||||
const auto graphic = qskValueAt< QskGraphic >( menu, i );
|
|
||||||
const auto w = graphic.widthForHeight( h );
|
|
||||||
if( w > maxW )
|
|
||||||
maxW = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
return qMax( hint.width(), maxW );
|
|
||||||
}
|
|
||||||
|
|
||||||
static qreal qskCellWidth( const QskMenu* menu )
|
|
||||||
{
|
|
||||||
using Q = QskMenu;
|
|
||||||
|
|
||||||
const auto spacing = menu->spacingHint( Q::Cell );
|
|
||||||
const auto padding = menu->paddingHint( Q::Cell );
|
|
||||||
|
|
||||||
auto w = qskGraphicWidth( menu )
|
|
||||||
+ spacing + qskMaxTextWidth( menu );
|
|
||||||
|
|
||||||
w += padding.left() + padding.right();
|
|
||||||
|
|
||||||
const auto minWidth = menu->strutSizeHint( Q::Cell ).width();
|
|
||||||
return qMax( w, minWidth );
|
|
||||||
}
|
|
||||||
|
|
||||||
static qreal qskCellHeight( const QskMenu* menu )
|
|
||||||
{
|
|
||||||
using Q = QskMenu;
|
|
||||||
|
|
||||||
const auto graphicHeight = menu->strutSizeHint( Q::Graphic ).height();
|
|
||||||
const auto textHeight = menu->effectiveFontHeight( Q::Text );
|
|
||||||
const auto padding = menu->paddingHint( Q::Cell );
|
|
||||||
|
|
||||||
qreal h = qMax( graphicHeight, textHeight );
|
|
||||||
h += padding.top() + padding.bottom();
|
|
||||||
|
|
||||||
const auto minHeight = menu->strutSizeHint( Q::Cell ).height();
|
|
||||||
h = qMax( h, minHeight );
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QSGNode* qskUpdateGraphicNode( const QskMenu* menu,
|
|
||||||
const QRectF& rect, const QskGraphic& graphic, QSGNode* node )
|
|
||||||
{
|
|
||||||
const auto alignment = menu->alignmentHint( QskMenu::Graphic, Qt::AlignCenter );
|
|
||||||
const auto colorFilter = menu->effectiveGraphicFilter( QskMenu::Graphic );
|
|
||||||
|
|
||||||
return QskSkinlet::updateGraphicNode(
|
|
||||||
menu, node, graphic, colorFilter, rect, alignment );
|
|
||||||
}
|
|
||||||
|
|
||||||
static QSGNode* qskUpdateTextNode( const QskMenu* menu,
|
|
||||||
const QRectF& rect, const QString& text, QSGNode* node )
|
|
||||||
{
|
|
||||||
const auto alignment = menu->alignmentHint(
|
|
||||||
QskMenu::Text, Qt::AlignVCenter | Qt::AlignLeft );
|
|
||||||
|
|
||||||
return QskSkinlet::updateTextNode( menu, node, rect, alignment,
|
|
||||||
text, menu->textOptions(), QskMenu::Text );
|
|
||||||
}
|
|
||||||
|
|
||||||
static QSGNode* qskUpdateBackgroundNode( const QskMenu* menu, QSGNode* rootNode )
|
|
||||||
{
|
|
||||||
using Q = QskMenu;
|
|
||||||
|
|
||||||
const auto skinlet = menu->effectiveSkinlet();
|
|
||||||
|
|
||||||
auto node = rootNode ? rootNode->firstChild() : nullptr;
|
|
||||||
QSGNode* lastNode = nullptr;
|
|
||||||
|
|
||||||
for( int i = 0; i < menu->count(); i++ )
|
|
||||||
{
|
|
||||||
QSGNode* newNode = nullptr;
|
|
||||||
|
|
||||||
{
|
|
||||||
QskSkinStateChanger stateChanger( menu );
|
|
||||||
stateChanger.setStates(
|
|
||||||
skinlet->subControlCellStates( menu, Q::Cell, i ) );
|
|
||||||
|
|
||||||
newNode = QskSkinlet::updateBoxNode(
|
|
||||||
menu, node, menu->cellRect( i ), Q::Cell );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( newNode )
|
~CacheGuard()
|
||||||
{
|
{
|
||||||
if ( newNode == node )
|
m_data->enableCache( false );
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
QskMenuSkinlet::PrivateData* m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void enableCache( bool on )
|
||||||
|
{
|
||||||
|
m_isCaching = on;
|
||||||
|
m_cellHeight = m_cellWidth = m_graphicWidth = m_textWidth = -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline qreal graphicWidth( const QskMenu* menu ) const
|
||||||
|
{
|
||||||
|
if ( m_isCaching )
|
||||||
|
{
|
||||||
|
if ( m_graphicWidth < 0.0 )
|
||||||
|
m_graphicWidth = graphicWidthInternal( menu );
|
||||||
|
|
||||||
|
return m_graphicWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return graphicWidthInternal( menu );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline qreal textWidth( const QskMenu* menu ) const
|
||||||
|
{
|
||||||
|
if ( m_isCaching )
|
||||||
|
{
|
||||||
|
if ( m_textWidth < 0.0 )
|
||||||
|
m_textWidth = textWidthInternal( menu );
|
||||||
|
|
||||||
|
return m_textWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return textWidthInternal( menu );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline qreal cellWidth( const QskMenu* menu ) const
|
||||||
|
{
|
||||||
|
if ( m_isCaching )
|
||||||
|
{
|
||||||
|
if ( m_cellWidth < 0.0 )
|
||||||
|
m_cellWidth = cellWidthInternal( menu );
|
||||||
|
|
||||||
|
return m_cellWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cellWidthInternal( menu );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline qreal cellHeight( const QskMenu* menu ) const
|
||||||
|
{
|
||||||
|
if ( m_isCaching )
|
||||||
|
{
|
||||||
|
if ( m_cellHeight < 0.0 )
|
||||||
|
m_cellHeight = cellHeightInternal( menu );
|
||||||
|
|
||||||
|
return m_cellHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cellHeightInternal( menu );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
qreal graphicWidthInternal( const QskMenu* menu ) const
|
||||||
|
{
|
||||||
|
const auto skinlet = menu->effectiveSkinlet();
|
||||||
|
|
||||||
|
const auto hint = menu->strutSizeHint( QskMenu::Graphic );
|
||||||
|
const qreal textHeight = menu->effectiveFontHeight( QskMenu::Text );
|
||||||
|
|
||||||
|
const auto h = qMax( hint.height(), textHeight );
|
||||||
|
|
||||||
|
qreal maxW = 0.0;
|
||||||
|
for ( int i = 0; i < menu->count(); i++ )
|
||||||
|
{
|
||||||
|
const auto value = skinlet->valueAt( menu, QskMenu::Graphic, i );
|
||||||
|
if ( value.canConvert< QskGraphic >() )
|
||||||
{
|
{
|
||||||
node = node->nextSibling();
|
const auto graphic = value.value< QskGraphic >();
|
||||||
|
if ( !graphic.isNull() )
|
||||||
|
{
|
||||||
|
const auto w = graphic.widthForHeight( h );
|
||||||
|
if( w > maxW )
|
||||||
|
maxW = w;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
return qMax( hint.width(), maxW );
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal textWidthInternal( const QskMenu* menu ) const
|
||||||
|
{
|
||||||
|
const auto skinlet = menu->effectiveSkinlet();
|
||||||
|
|
||||||
|
const QFontMetricsF fm( menu->effectiveFont( QskMenu::Text ) );
|
||||||
|
|
||||||
|
auto maxWidth = 0.0;
|
||||||
|
|
||||||
|
for ( int i = 0; i < menu->count(); i++ )
|
||||||
|
{
|
||||||
|
const auto value = skinlet->valueAt( menu, QskMenu::Text, i );
|
||||||
|
if ( value.canConvert< QString >() )
|
||||||
{
|
{
|
||||||
if ( rootNode == nullptr )
|
const auto text = value.value< QString >();
|
||||||
rootNode = new QSGNode();
|
if( !text.isEmpty() )
|
||||||
|
{
|
||||||
if ( node )
|
const auto w = qskHorizontalAdvance( fm, text );
|
||||||
rootNode->insertChildNodeBefore( newNode, node );
|
if( w > maxWidth )
|
||||||
else
|
maxWidth = w;
|
||||||
rootNode->appendChildNode( newNode );
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lastNode = newNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return maxWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
QskSGNode::removeAllChildNodesAfter( rootNode, lastNode );
|
qreal cellWidthInternal( const QskMenu* menu ) const
|
||||||
|
|
||||||
return rootNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qskUpdateItemNode(
|
|
||||||
const QskMenu* menu, const QRectF& graphicRect, const QskGraphic& graphic,
|
|
||||||
const QRectF& textRect, const QString& text, QSGNode* itemNode )
|
|
||||||
{
|
|
||||||
enum { GraphicRole, TextRole };
|
|
||||||
static QVector< quint8 > roles = { GraphicRole, TextRole };
|
|
||||||
|
|
||||||
for ( const auto role : roles )
|
|
||||||
{
|
{
|
||||||
auto oldNode = QskSGNode::findChildNode( itemNode, role );
|
using Q = QskMenu;
|
||||||
QSGNode* newNode = nullptr;
|
|
||||||
|
|
||||||
if( role == GraphicRole )
|
const auto spacing = menu->spacingHint( Q::Cell );
|
||||||
newNode = qskUpdateGraphicNode( menu, graphicRect, graphic, oldNode );
|
const auto padding = menu->paddingHint( Q::Cell );
|
||||||
else
|
|
||||||
newNode = qskUpdateTextNode( menu, textRect, text, oldNode );
|
|
||||||
|
|
||||||
QskSGNode::replaceChildNode( roles, role, itemNode, oldNode, newNode );
|
auto w = graphicWidth( menu ) + spacing + textWidth( menu );
|
||||||
|
|
||||||
|
w += padding.left() + padding.right();
|
||||||
|
|
||||||
|
const auto minWidth = menu->strutSizeHint( Q::Cell ).width();
|
||||||
|
return qMax( w, minWidth );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
|
qreal cellHeightInternal( const QskMenu* menu ) const
|
||||||
{
|
|
||||||
using Q = QskMenu;
|
|
||||||
|
|
||||||
const auto skinlet = menu->effectiveSkinlet();
|
|
||||||
|
|
||||||
const auto spacing = menu->spacingHint( Q::Cell );
|
|
||||||
const auto graphicWidth = qskGraphicWidth( menu );
|
|
||||||
const auto contentsRect = menu->contentsRect();
|
|
||||||
|
|
||||||
if ( rootNode == nullptr )
|
|
||||||
rootNode = new QSGNode();
|
|
||||||
|
|
||||||
QSGNode* node = nullptr;
|
|
||||||
|
|
||||||
const auto count = skinlet->subControlCellCount( menu, Q::Cell );
|
|
||||||
for( int i = 0; i < count; i++ )
|
|
||||||
{
|
{
|
||||||
if ( node == nullptr )
|
using Q = QskMenu;
|
||||||
node = rootNode->firstChild();
|
|
||||||
else
|
|
||||||
node = node->nextSibling();
|
|
||||||
|
|
||||||
if ( node == nullptr )
|
const auto graphicHeight = menu->strutSizeHint( Q::Graphic ).height();
|
||||||
{
|
const auto textHeight = menu->effectiveFontHeight( Q::Text );
|
||||||
node = new QSGNode();
|
const auto padding = menu->paddingHint( Q::Cell );
|
||||||
rootNode->appendChildNode( node );
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
qreal h = qMax( graphicHeight, textHeight );
|
||||||
QskSkinStateChanger stateChanger( menu );
|
h += padding.top() + padding.bottom();
|
||||||
stateChanger.setStates(
|
|
||||||
skinlet->subControlCellStates( menu, Q::Cell, i ) );
|
|
||||||
|
|
||||||
const auto cellRect = skinlet->subControlCell(
|
const auto minHeight = menu->strutSizeHint( Q::Cell ).height();
|
||||||
menu, contentsRect, Q::Cell, i );
|
h = qMax( h, minHeight );
|
||||||
|
|
||||||
auto graphicRect = cellRect;
|
return h;
|
||||||
graphicRect.setWidth( graphicWidth );
|
|
||||||
|
|
||||||
auto textRect = cellRect;
|
|
||||||
textRect.setX( graphicRect.right() + spacing );
|
|
||||||
|
|
||||||
const auto graphic = qskValueAt< QskGraphic >( menu, i );
|
|
||||||
const auto text = qskValueAt< QString >( menu, i );
|
|
||||||
|
|
||||||
qskUpdateItemNode( menu, graphicRect, graphic,
|
|
||||||
textRect, text, node );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QskSGNode::removeAllChildNodesAfter( rootNode, node );
|
bool m_isCaching;
|
||||||
|
|
||||||
return rootNode;
|
mutable qreal m_graphicWidth = -1.0;
|
||||||
}
|
mutable qreal m_textWidth = -1.0;
|
||||||
|
mutable qreal m_cellHeight = -1.0;
|
||||||
|
mutable qreal m_cellWidth = -1.0;
|
||||||
|
};
|
||||||
|
|
||||||
QskMenuSkinlet::QskMenuSkinlet( QskSkin* skin )
|
QskMenuSkinlet::QskMenuSkinlet( QskSkin* skin )
|
||||||
: Inherited( skin )
|
: Inherited( skin )
|
||||||
|
, m_data( new PrivateData() )
|
||||||
{
|
{
|
||||||
appendNodeRoles( { PanelRole } );
|
appendNodeRoles( { PanelRole } );
|
||||||
}
|
}
|
||||||
@ -283,29 +238,62 @@ QRectF QskMenuSkinlet::subControlCell(
|
|||||||
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
||||||
QskAspect::Subcontrol subControl, int index ) const
|
QskAspect::Subcontrol subControl, int index ) const
|
||||||
{
|
{
|
||||||
// QskMenu::Text, QskMenu::Graphic ???
|
using Q = QskMenu;
|
||||||
if ( subControl == QskMenu::Cell )
|
|
||||||
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
||||||
|
|
||||||
|
if ( subControl == Q::Cell )
|
||||||
{
|
{
|
||||||
const auto menu = static_cast< const QskMenu* >( skinnable );
|
const auto r = menu->subControlContentsRect( Q::Panel );
|
||||||
|
const auto h = m_data->cellHeight( menu );
|
||||||
if ( index < 0 || index >= menu->count() )
|
|
||||||
return QRectF();
|
|
||||||
|
|
||||||
const auto r = menu->subControlContentsRect( QskMenu::Panel );
|
|
||||||
const auto h = qskCellHeight( menu );
|
|
||||||
|
|
||||||
return QRectF( r.x(), r.y() + index * h, r.width(), h );
|
return QRectF( r.x(), r.y() + index * h, r.width(), h );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( subControl == QskMenu::Graphic || subControl == QskMenu::Text )
|
||||||
|
{
|
||||||
|
const auto r = subControlCell( menu, contentsRect, Q::Cell, index );
|
||||||
|
const auto graphicWidth = m_data->graphicWidth( menu );
|
||||||
|
|
||||||
|
if ( subControl == QskMenu::Graphic )
|
||||||
|
{
|
||||||
|
auto graphicRect = r;
|
||||||
|
graphicRect.setWidth( graphicWidth );
|
||||||
|
|
||||||
|
return QRectF( r.x(), r.y(), graphicWidth, r.height() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto textRect = r;
|
||||||
|
|
||||||
|
if ( graphicWidth > 0.0 )
|
||||||
|
{
|
||||||
|
const auto spacing = skinnable->spacingHint( Q::Cell );
|
||||||
|
textRect.setX( r.x() + graphicWidth + spacing );
|
||||||
|
}
|
||||||
|
|
||||||
|
return textRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Inherited::subControlCell(
|
return Inherited::subControlCell(
|
||||||
skinnable, contentsRect, subControl, index );
|
skinnable, contentsRect, subControl, index );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int QskMenuSkinlet::subControlCellIndexAt(
|
||||||
|
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
||||||
|
QskAspect::Subcontrol subControl, const QPointF& pos ) const
|
||||||
|
{
|
||||||
|
const PrivateData::CacheGuard guard( m_data.get() );
|
||||||
|
return Inherited::subControlCellIndexAt( skinnable, contentsRect, subControl, pos );
|
||||||
|
}
|
||||||
|
|
||||||
int QskMenuSkinlet::subControlCellCount(
|
int QskMenuSkinlet::subControlCellCount(
|
||||||
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) const
|
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) const
|
||||||
{
|
{
|
||||||
// QskMenu::Text, QskMenu::Graphic ???
|
using Q = QskMenu;
|
||||||
if ( subControl == QskMenu::Cell )
|
|
||||||
|
if ( subControl == Q::Cell || subControl == Q::Graphic || subControl == Q::Text )
|
||||||
{
|
{
|
||||||
const auto menu = static_cast< const QskMenu* >( skinnable );
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
||||||
return menu->count();
|
return menu->count();
|
||||||
@ -317,10 +305,11 @@ int QskMenuSkinlet::subControlCellCount(
|
|||||||
QskAspect::States QskMenuSkinlet::subControlCellStates(
|
QskAspect::States QskMenuSkinlet::subControlCellStates(
|
||||||
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const
|
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const
|
||||||
{
|
{
|
||||||
|
using Q = QskMenu;
|
||||||
|
|
||||||
auto states = Inherited::subControlCellStates( skinnable, subControl, index );
|
auto states = Inherited::subControlCellStates( skinnable, subControl, index );
|
||||||
|
|
||||||
// QskMenu::Text, QskMenu::Graphic ???
|
if ( subControl == Q::Cell || subControl == Q::Graphic || subControl == Q::Text )
|
||||||
if ( subControl == QskMenu::Cell )
|
|
||||||
{
|
{
|
||||||
const auto menu = static_cast< const QskMenu* >( skinnable );
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
||||||
if ( menu->currentIndex() == index )
|
if ( menu->currentIndex() == index )
|
||||||
@ -330,17 +319,38 @@ QskAspect::States QskMenuSkinlet::subControlCellStates(
|
|||||||
return states;
|
return states;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant QskMenuSkinlet::valueAt( const QskSkinnable* skinnable,
|
||||||
|
QskAspect::Subcontrol subControl, int index ) const
|
||||||
|
{
|
||||||
|
using Q = QskMenu;
|
||||||
|
|
||||||
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
||||||
|
|
||||||
|
if ( subControl == Q::Graphic )
|
||||||
|
return qskValueAt< QskGraphic >( menu, index );
|
||||||
|
|
||||||
|
if ( subControl == Q::Text )
|
||||||
|
return qskValueAt< QString >( menu, index );
|
||||||
|
|
||||||
|
return Inherited::valueAt( skinnable, subControl, index );
|
||||||
|
}
|
||||||
|
|
||||||
QSGNode* QskMenuSkinlet::updateContentsNode(
|
QSGNode* QskMenuSkinlet::updateContentsNode(
|
||||||
const QskPopup* popup, QSGNode* contentsNode ) const
|
const QskPopup* popup, QSGNode* contentsNode ) const
|
||||||
{
|
{
|
||||||
enum { Panel, Backgrounds, Cursor, Items };
|
const PrivateData::CacheGuard guard( m_data.get() );
|
||||||
static QVector< quint8 > roles = { Panel, Backgrounds, Cursor, Items };
|
return updateMenuNode( popup, contentsNode );
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGNode* QskMenuSkinlet::updateMenuNode(
|
||||||
|
const QskSkinnable* skinnable, QSGNode* contentsNode ) const
|
||||||
|
{
|
||||||
|
enum { Panel, Background, Cursor, Graphic, Text };
|
||||||
|
static QVector< quint8 > roles = { Panel, Background, Cursor, Graphic, Text };
|
||||||
|
|
||||||
if ( contentsNode == nullptr )
|
if ( contentsNode == nullptr )
|
||||||
contentsNode = new QSGNode();
|
contentsNode = new QSGNode();
|
||||||
|
|
||||||
const auto menu = static_cast< const QskMenu* >( popup );
|
|
||||||
|
|
||||||
for ( const auto role : roles )
|
for ( const auto role : roles )
|
||||||
{
|
{
|
||||||
auto oldNode = QskSGNode::findChildNode( contentsNode, role );
|
auto oldNode = QskSGNode::findChildNode( contentsNode, role );
|
||||||
@ -351,22 +361,27 @@ QSGNode* QskMenuSkinlet::updateContentsNode(
|
|||||||
{
|
{
|
||||||
case Panel:
|
case Panel:
|
||||||
{
|
{
|
||||||
newNode = updateBoxNode( menu, oldNode, QskMenu::Panel );
|
newNode = updateBoxNode( skinnable, oldNode, QskMenu::Panel );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Backgrounds:
|
case Background:
|
||||||
{
|
{
|
||||||
newNode = qskUpdateBackgroundNode( menu, oldNode );
|
newNode = updateSeriesNode( skinnable, QskMenu::Cell, oldNode );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Cursor:
|
case Cursor:
|
||||||
{
|
{
|
||||||
newNode = updateBoxNode( menu, oldNode, QskMenu::Cursor );
|
newNode = updateBoxNode( skinnable, oldNode, QskMenu::Cursor );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Items:
|
case Graphic:
|
||||||
{
|
{
|
||||||
newNode = qskUpdateItemsNode( menu, oldNode );
|
newNode = updateSeriesNode( skinnable, QskMenu::Graphic, oldNode );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Text:
|
||||||
|
{
|
||||||
|
newNode = updateSeriesNode( skinnable, QskMenu::Text, oldNode );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,18 +392,71 @@ QSGNode* QskMenuSkinlet::updateContentsNode(
|
|||||||
return contentsNode;
|
return contentsNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSGNode* QskMenuSkinlet::updateSeriesSubNode( const QskSkinnable* skinnable,
|
||||||
|
QskAspect::Subcontrol subControl, int index, QSGNode* node ) const
|
||||||
|
{
|
||||||
|
using Q = QskMenu;
|
||||||
|
|
||||||
|
auto menu = static_cast< const QskMenu* >( skinnable );
|
||||||
|
|
||||||
|
const auto rect = subControlCell( menu, menu->contentsRect(), subControl, index );
|
||||||
|
|
||||||
|
if ( subControl == Q::Cell )
|
||||||
|
{
|
||||||
|
return updateBoxNode( menu, node, rect, subControl );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( subControl == Q::Graphic )
|
||||||
|
{
|
||||||
|
const auto v = qskValueAt< QskGraphic >( menu, index );
|
||||||
|
|
||||||
|
const auto alignment = menu->alignmentHint( subControl, Qt::AlignCenter );
|
||||||
|
const auto filter = menu->effectiveGraphicFilter( subControl );
|
||||||
|
|
||||||
|
return QskSkinlet::updateGraphicNode(
|
||||||
|
menu, node, v.value< QskGraphic >(), filter, rect, alignment );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( subControl == Q::Text )
|
||||||
|
{
|
||||||
|
const auto v = qskValueAt< QString >( menu, index );
|
||||||
|
|
||||||
|
const auto alignment = menu->alignmentHint(
|
||||||
|
subControl, Qt::AlignVCenter | Qt::AlignLeft );
|
||||||
|
|
||||||
|
return QskSkinlet::updateTextNode( menu, node, rect, alignment,
|
||||||
|
v.value< QString>(), menu->textOptions(), QskMenu::Text );
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QSizeF QskMenuSkinlet::sizeHint( const QskSkinnable* skinnable,
|
QSizeF QskMenuSkinlet::sizeHint( const QskSkinnable* skinnable,
|
||||||
Qt::SizeHint which, const QSizeF& ) const
|
Qt::SizeHint which, const QSizeF& ) const
|
||||||
{
|
{
|
||||||
if ( which != Qt::PreferredSize )
|
if ( which != Qt::PreferredSize )
|
||||||
return QSizeF();
|
return QSizeF();
|
||||||
|
|
||||||
const auto menu = static_cast< const QskMenu* >( skinnable );
|
const PrivateData::CacheGuard guard( m_data.get() );
|
||||||
|
|
||||||
const qreal w = qskCellWidth( menu );
|
const auto count = subControlCellCount( skinnable, QskMenu::Cell );
|
||||||
const auto h = menu->count() * qskCellHeight( menu );
|
|
||||||
|
|
||||||
return menu->outerBoxSize( QskMenu::Panel, QSizeF( w, h ) );
|
qreal w = 0.0;
|
||||||
|
qreal h = 0.0;
|
||||||
|
|
||||||
|
if ( count > 0 )
|
||||||
|
{
|
||||||
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
||||||
|
|
||||||
|
w = m_data->cellWidth( menu );
|
||||||
|
h = count * m_data->cellHeight( menu );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hint = skinnable->outerBoxSize( QskMenu::Panel, QSizeF( w, h ) );
|
||||||
|
hint = hint.expandedTo( skinnable->strutSizeHint( QskMenu::Panel ) );
|
||||||
|
|
||||||
|
return hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_QskMenuSkinlet.cpp"
|
#include "moc_QskMenuSkinlet.cpp"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QskPopupSkinlet.h>
|
#include <QskPopupSkinlet.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class QskMenu;
|
class QskMenu;
|
||||||
|
|
||||||
@ -26,14 +27,28 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet
|
|||||||
QRectF subControlCell( const QskSkinnable*,
|
QRectF subControlCell( const QskSkinnable*,
|
||||||
const QRectF&, QskAspect::Subcontrol, int index ) const override;
|
const QRectF&, QskAspect::Subcontrol, int index ) const override;
|
||||||
|
|
||||||
|
int subControlCellIndexAt( const QskSkinnable*,
|
||||||
|
const QRectF&, QskAspect::Subcontrol, const QPointF& ) const override;
|
||||||
|
|
||||||
int subControlCellCount( const QskSkinnable*, QskAspect::Subcontrol ) const override;
|
int subControlCellCount( const QskSkinnable*, QskAspect::Subcontrol ) const override;
|
||||||
|
|
||||||
QskAspect::States subControlCellStates( const QskSkinnable*,
|
QskAspect::States subControlCellStates( const QskSkinnable*,
|
||||||
QskAspect::Subcontrol, int index ) const override;
|
QskAspect::Subcontrol, int index ) const override;
|
||||||
|
|
||||||
|
QVariant valueAt( const QskSkinnable*,
|
||||||
|
QskAspect::Subcontrol, int index ) const override;
|
||||||
|
|
||||||
QSizeF sizeHint( const QskSkinnable*,
|
QSizeF sizeHint( const QskSkinnable*,
|
||||||
Qt::SizeHint, const QSizeF& ) const override;
|
Qt::SizeHint, const QSizeF& ) const override;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const override;
|
QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const override;
|
||||||
|
QSGNode* updateMenuNode( const QskSkinnable*, QSGNode* ) const;
|
||||||
|
|
||||||
|
QSGNode* updateSeriesSubNode( const QskSkinnable*,
|
||||||
|
QskAspect::Subcontrol, int index, QSGNode* ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
std::unique_ptr< PrivateData > m_data;
|
||||||
};
|
};
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "QskTextColors.h"
|
#include "QskTextColors.h"
|
||||||
#include "QskTextNode.h"
|
#include "QskTextNode.h"
|
||||||
#include "QskTextOptions.h"
|
#include "QskTextOptions.h"
|
||||||
|
#include "QskSkinStateChanger.h"
|
||||||
|
|
||||||
#include <qquickwindow.h>
|
#include <qquickwindow.h>
|
||||||
#include <qsgsimplerectnode.h>
|
#include <qsgsimplerectnode.h>
|
||||||
@ -563,24 +564,6 @@ QSGNode* QskSkinlet::updateGraphicNode(
|
|||||||
return qskUpdateGraphicNode( skinnable, node, graphic, colorFilter, rect, mirrored );
|
return qskUpdateGraphicNode( skinnable, node, graphic, colorFilter, rect, mirrored );
|
||||||
}
|
}
|
||||||
|
|
||||||
QSizeF QskSkinlet::hintWithoutConstraint(
|
|
||||||
const QSizeF& hint, const QSizeF& constraint ) const
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
This method is useful in situations, where a hint has been calculated
|
|
||||||
from a constraint and we want to return the calculated part only
|
|
||||||
*/
|
|
||||||
QSizeF h;
|
|
||||||
|
|
||||||
if ( constraint.width() < 0.0 )
|
|
||||||
h.setWidth( hint.width() );
|
|
||||||
|
|
||||||
if ( constraint.height() < 0.0 )
|
|
||||||
h.setHeight( hint.height() );
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QskSkinlet::subControlCellIndexAt( const QskSkinnable* skinnable,
|
int QskSkinlet::subControlCellIndexAt( const QskSkinnable* skinnable,
|
||||||
const QRectF& rect, QskAspect::Subcontrol subControl, const QPointF& pos ) const
|
const QRectF& rect, QskAspect::Subcontrol subControl, const QPointF& pos ) const
|
||||||
{
|
{
|
||||||
@ -601,6 +584,60 @@ int QskSkinlet::subControlCellIndexAt( const QskSkinnable* skinnable,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSGNode* QskSkinlet::updateSeriesNode( const QskSkinnable* skinnable,
|
||||||
|
QskAspect::Subcontrol subControl, QSGNode* rootNode ) const
|
||||||
|
{
|
||||||
|
auto node = rootNode ? rootNode->firstChild() : nullptr;
|
||||||
|
QSGNode* lastNode = nullptr;
|
||||||
|
|
||||||
|
const auto count = subControlCellCount( skinnable, subControl );
|
||||||
|
|
||||||
|
for( int i = 0; i < count; i++ )
|
||||||
|
{
|
||||||
|
QSGNode* newNode = nullptr;
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto newStates = subControlCellStates( skinnable, subControl, i );
|
||||||
|
|
||||||
|
QskSkinStateChanger stateChanger( skinnable );
|
||||||
|
stateChanger.setStates( newStates );
|
||||||
|
|
||||||
|
newNode = updateSeriesSubNode( skinnable, subControl, i, node );
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QskSGNode::removeAllChildNodesAfter( rootNode, lastNode );
|
||||||
|
|
||||||
|
return rootNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGNode* QskSkinlet::updateSeriesSubNode( const QskSkinnable*,
|
||||||
|
QskAspect::Subcontrol, int index, QSGNode* ) const
|
||||||
|
{
|
||||||
|
Q_UNUSED( index )
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
QskAspect::States QskSkinlet::subControlCellStates(
|
QskAspect::States QskSkinlet::subControlCellStates(
|
||||||
const QskSkinnable* skinnable, QskAspect::Subcontrol, int index ) const
|
const QskSkinnable* skinnable, QskAspect::Subcontrol, int index ) const
|
||||||
{
|
{
|
||||||
@ -608,4 +645,29 @@ QskAspect::States QskSkinlet::subControlCellStates(
|
|||||||
return skinnable->skinStates();
|
return skinnable->skinStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant QskSkinlet::valueAt( const QskSkinnable*,
|
||||||
|
QskAspect::Subcontrol, int index ) const
|
||||||
|
{
|
||||||
|
Q_UNUSED( index )
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSizeF QskSkinlet::hintWithoutConstraint(
|
||||||
|
const QSizeF& hint, const QSizeF& constraint ) const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
This method is useful in situations, where a hint has been calculated
|
||||||
|
from a constraint and we want to return the calculated part only
|
||||||
|
*/
|
||||||
|
QSizeF h;
|
||||||
|
|
||||||
|
if ( constraint.width() < 0.0 )
|
||||||
|
h.setWidth( hint.width() );
|
||||||
|
|
||||||
|
if ( constraint.height() < 0.0 )
|
||||||
|
h.setHeight( hint.height() );
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_QskSkinlet.cpp"
|
#include "moc_QskSkinlet.cpp"
|
||||||
|
@ -53,6 +53,9 @@ class QSK_EXPORT QskSkinlet
|
|||||||
virtual QskAspect::States subControlCellStates( const QskSkinnable*,
|
virtual QskAspect::States subControlCellStates( const QskSkinnable*,
|
||||||
QskAspect::Subcontrol, int index ) const;
|
QskAspect::Subcontrol, int index ) const;
|
||||||
|
|
||||||
|
virtual QVariant valueAt( const QskSkinnable*,
|
||||||
|
QskAspect::Subcontrol, int index ) const;
|
||||||
|
|
||||||
const QVector< quint8 >& nodeRoles() const;
|
const QVector< quint8 >& nodeRoles() const;
|
||||||
|
|
||||||
void setOwnedBySkinnable( bool on );
|
void setOwnedBySkinnable( bool on );
|
||||||
@ -130,6 +133,12 @@ class QSK_EXPORT QskSkinlet
|
|||||||
const QskGraphic&, QskAspect::Subcontrol,
|
const QskGraphic&, QskAspect::Subcontrol,
|
||||||
Qt::Orientations mirrored = Qt::Orientations() ) const;
|
Qt::Orientations mirrored = Qt::Orientations() ) const;
|
||||||
|
|
||||||
|
QSGNode* updateSeriesNode( const QskSkinnable*,
|
||||||
|
QskAspect::Subcontrol, QSGNode* ) const;
|
||||||
|
|
||||||
|
virtual QSGNode* updateSeriesSubNode( const QskSkinnable*,
|
||||||
|
QskAspect::Subcontrol, int index, QSGNode* ) const;
|
||||||
|
|
||||||
void replaceChildNode( quint8 nodeRole, QSGNode* parentNode,
|
void replaceChildNode( quint8 nodeRole, QSGNode* parentNode,
|
||||||
QSGNode* oldNode, QSGNode* newNode ) const;
|
QSGNode* oldNode, QSGNode* newNode ) const;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user