2021-12-23 18:36:32 +01:00
|
|
|
#include "QskMenuSkinlet.h"
|
|
|
|
#include "QskMenu.h"
|
|
|
|
|
|
|
|
#include <QskBoxNode.h>
|
|
|
|
#include <QskGraphic.h>
|
|
|
|
#include <QskColorFilter.h>
|
|
|
|
#include <QskGraphicNode.h>
|
|
|
|
#include <QskTextNode.h>
|
|
|
|
#include <QskTextOptions.h>
|
|
|
|
#include <QskSGNode.h>
|
|
|
|
#include <QskFunctions.h>
|
|
|
|
#include <QskSkinStateChanger.h>
|
|
|
|
#include <QskMargins.h>
|
2021-12-29 16:23:19 +01:00
|
|
|
#include <QskFunctions.h>
|
2021-12-23 18:36:32 +01:00
|
|
|
|
|
|
|
#include <qfontmetrics.h>
|
2021-12-29 16:54:16 +01:00
|
|
|
#include <qmath.h>
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-27 09:50:14 +01:00
|
|
|
template< class T >
|
2021-12-28 16:14:30 +01:00
|
|
|
static inline QVariant qskSampleAt( const QskMenu* menu, int index )
|
2021-12-27 09:50:14 +01:00
|
|
|
{
|
|
|
|
const auto item = menu->itemAt( index );
|
|
|
|
|
|
|
|
if ( item.canConvert< T >() )
|
2021-12-28 15:33:13 +01:00
|
|
|
return item;
|
2021-12-27 09:50:14 +01:00
|
|
|
|
|
|
|
if ( item.canConvert< QVariantList >() )
|
|
|
|
{
|
|
|
|
const auto list = item.value< QVariantList >();
|
|
|
|
for ( const auto& value : list )
|
|
|
|
{
|
|
|
|
if ( value.canConvert< T >() )
|
2021-12-28 15:33:13 +01:00
|
|
|
return value;
|
2021-12-27 09:50:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return QVariant();
|
2021-12-27 09:50:14 +01:00
|
|
|
}
|
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
template< class T >
|
|
|
|
static inline T qskValueAt( const QskMenu* menu, int index )
|
|
|
|
{
|
|
|
|
const auto sample = qskSampleAt< T >( menu, index );
|
|
|
|
return sample.template value< T >();
|
|
|
|
}
|
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
class QskMenuSkinlet::PrivateData
|
2021-12-23 18:36:32 +01:00
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
public:
|
|
|
|
class CacheGuard
|
2021-12-23 18:36:32 +01:00
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
public:
|
|
|
|
CacheGuard( QskMenuSkinlet::PrivateData* data )
|
|
|
|
: m_data( data )
|
2021-12-23 18:36:32 +01:00
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
m_data->enableCache( true );
|
2021-12-23 18:36:32 +01:00
|
|
|
}
|
2021-12-23 19:05:59 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
~CacheGuard()
|
|
|
|
{
|
|
|
|
m_data->enableCache( false );
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
QskMenuSkinlet::PrivateData* m_data;
|
|
|
|
};
|
2021-12-23 19:05:59 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
void enableCache( bool on )
|
2021-12-23 18:36:32 +01:00
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
m_isCaching = on;
|
|
|
|
m_cellHeight = m_cellWidth = m_graphicWidth = m_textWidth = -1.0;
|
2021-12-23 19:05:59 +01:00
|
|
|
}
|
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
inline qreal graphicWidth( const QskMenu* menu ) const
|
|
|
|
{
|
|
|
|
if ( m_isCaching )
|
|
|
|
{
|
|
|
|
if ( m_graphicWidth < 0.0 )
|
|
|
|
m_graphicWidth = graphicWidthInternal( menu );
|
2021-12-24 16:50:34 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return m_graphicWidth;
|
|
|
|
}
|
2021-12-24 16:50:34 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return graphicWidthInternal( menu );
|
|
|
|
}
|
2021-12-24 16:50:34 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
inline qreal textWidth( const QskMenu* menu ) const
|
|
|
|
{
|
|
|
|
if ( m_isCaching )
|
|
|
|
{
|
|
|
|
if ( m_textWidth < 0.0 )
|
|
|
|
m_textWidth = textWidthInternal( menu );
|
2021-12-24 16:50:34 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return m_textWidth;
|
|
|
|
}
|
2021-12-24 16:50:34 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return textWidthInternal( menu );
|
|
|
|
}
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
inline qreal cellWidth( const QskMenu* menu ) const
|
|
|
|
{
|
|
|
|
if ( m_isCaching )
|
|
|
|
{
|
|
|
|
if ( m_cellWidth < 0.0 )
|
|
|
|
m_cellWidth = cellWidthInternal( menu );
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return m_cellWidth;
|
|
|
|
}
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return cellWidthInternal( menu );
|
|
|
|
}
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
inline qreal cellHeight( const QskMenu* menu ) const
|
|
|
|
{
|
|
|
|
if ( m_isCaching )
|
|
|
|
{
|
|
|
|
if ( m_cellHeight < 0.0 )
|
|
|
|
m_cellHeight = cellHeightInternal( menu );
|
2021-12-28 10:08:21 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return m_cellHeight;
|
|
|
|
}
|
2021-12-28 10:08:21 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return cellHeightInternal( menu );
|
|
|
|
}
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
private:
|
|
|
|
qreal graphicWidthInternal( const QskMenu* menu ) const
|
2021-12-23 18:36:32 +01:00
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
const auto skinlet = menu->effectiveSkinlet();
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
const auto hint = menu->strutSizeHint( QskMenu::Graphic );
|
|
|
|
const qreal textHeight = menu->effectiveFontHeight( QskMenu::Text );
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
const auto h = qMax( hint.height(), textHeight );
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
qreal maxW = 0.0;
|
|
|
|
for ( int i = 0; i < menu->count(); i++ )
|
2021-12-24 16:20:34 +01:00
|
|
|
{
|
2021-12-28 16:14:30 +01:00
|
|
|
const auto sample = skinlet->sampleAt( menu, QskMenu::Graphic, i );
|
|
|
|
if ( sample.canConvert< QskGraphic >() )
|
2021-12-24 16:20:34 +01:00
|
|
|
{
|
2021-12-28 16:14:30 +01:00
|
|
|
const auto graphic = sample.value< QskGraphic >();
|
2021-12-28 15:33:13 +01:00
|
|
|
if ( !graphic.isNull() )
|
|
|
|
{
|
|
|
|
const auto w = graphic.widthForHeight( h );
|
|
|
|
if( w > maxW )
|
|
|
|
maxW = w;
|
|
|
|
}
|
2021-12-24 16:20:34 +01:00
|
|
|
}
|
|
|
|
}
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return qMax( hint.width(), maxW );
|
|
|
|
}
|
2021-12-24 16:20:34 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
qreal textWidthInternal( const QskMenu* menu ) const
|
|
|
|
{
|
|
|
|
const auto skinlet = menu->effectiveSkinlet();
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
const QFontMetricsF fm( menu->effectiveFont( QskMenu::Text ) );
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
auto maxWidth = 0.0;
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
for ( int i = 0; i < menu->count(); i++ )
|
|
|
|
{
|
2021-12-28 16:14:30 +01:00
|
|
|
const auto sample = skinlet->sampleAt( menu, QskMenu::Text, i );
|
|
|
|
if ( sample.canConvert< QString >() )
|
2021-12-28 15:33:13 +01:00
|
|
|
{
|
2021-12-28 16:14:30 +01:00
|
|
|
const auto text = sample.value< QString >();
|
2021-12-28 15:33:13 +01:00
|
|
|
if( !text.isEmpty() )
|
|
|
|
{
|
|
|
|
const auto w = qskHorizontalAdvance( fm, text );
|
|
|
|
if( w > maxWidth )
|
|
|
|
maxWidth = w;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return maxWidth;
|
2021-12-23 18:36:32 +01:00
|
|
|
}
|
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
qreal cellWidthInternal( const QskMenu* menu ) const
|
|
|
|
{
|
|
|
|
using Q = QskMenu;
|
2021-12-28 10:08:21 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
const auto spacing = menu->spacingHint( Q::Cell );
|
|
|
|
const auto padding = menu->paddingHint( Q::Cell );
|
2021-12-28 10:08:21 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
auto w = graphicWidth( menu ) + spacing + textWidth( menu );
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
w += padding.left() + padding.right();
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
const auto minWidth = menu->strutSizeHint( Q::Cell ).width();
|
|
|
|
return qMax( w, minWidth );
|
|
|
|
}
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
qreal cellHeightInternal( const QskMenu* menu ) const
|
2021-12-23 18:36:32 +01:00
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
using Q = QskMenu;
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
const auto graphicHeight = menu->strutSizeHint( Q::Graphic ).height();
|
|
|
|
const auto textHeight = menu->effectiveFontHeight( Q::Text );
|
|
|
|
const auto padding = menu->paddingHint( Q::Cell );
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
qreal h = qMax( graphicHeight, textHeight );
|
|
|
|
h += padding.top() + padding.bottom();
|
2021-12-23 19:05:59 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
const auto minHeight = menu->strutSizeHint( Q::Cell ).height();
|
|
|
|
h = qMax( h, minHeight );
|
2021-12-27 09:50:14 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return h;
|
2021-12-23 18:36:32 +01:00
|
|
|
}
|
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
bool m_isCaching;
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
mutable qreal m_graphicWidth = -1.0;
|
|
|
|
mutable qreal m_textWidth = -1.0;
|
|
|
|
mutable qreal m_cellHeight = -1.0;
|
|
|
|
mutable qreal m_cellWidth = -1.0;
|
|
|
|
};
|
2021-12-23 18:36:32 +01:00
|
|
|
|
|
|
|
QskMenuSkinlet::QskMenuSkinlet( QskSkin* skin )
|
|
|
|
: Inherited( skin )
|
2021-12-28 15:33:13 +01:00
|
|
|
, m_data( new PrivateData() )
|
2021-12-23 18:36:32 +01:00
|
|
|
{
|
|
|
|
appendNodeRoles( { PanelRole } );
|
|
|
|
}
|
|
|
|
|
2021-12-29 16:23:19 +01:00
|
|
|
QRectF QskMenuSkinlet::cursorRect(
|
|
|
|
const QskSkinnable* skinnable, const QRectF& contentsRect, int index ) const
|
|
|
|
{
|
|
|
|
const auto count = sampleCount( skinnable, QskMenu::Cell );
|
|
|
|
|
|
|
|
auto rect = sampleRect( skinnable, contentsRect,
|
|
|
|
QskMenu::Cell, qBound( 0, index, count ) );
|
|
|
|
|
|
|
|
if ( index < 0 )
|
|
|
|
rect.setBottom( rect.top() );
|
|
|
|
|
|
|
|
if ( index >= count )
|
|
|
|
rect.setTop( rect.bottom() );
|
|
|
|
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
2021-12-23 18:36:32 +01:00
|
|
|
QRectF QskMenuSkinlet::subControlRect(
|
|
|
|
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
|
|
|
QskAspect::Subcontrol subControl ) const
|
|
|
|
{
|
2021-12-29 16:23:19 +01:00
|
|
|
using Q = QskMenu;
|
|
|
|
|
2021-12-24 16:20:34 +01:00
|
|
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
|
|
|
|
2021-12-29 16:23:19 +01:00
|
|
|
if( subControl == Q::Panel )
|
2021-12-23 18:36:32 +01:00
|
|
|
{
|
|
|
|
return contentsRect;
|
|
|
|
}
|
|
|
|
|
2021-12-29 16:23:19 +01:00
|
|
|
if( subControl == Q::Cursor )
|
2021-12-24 16:20:34 +01:00
|
|
|
{
|
2021-12-29 16:23:19 +01:00
|
|
|
if ( menu->currentIndex() < 0 )
|
|
|
|
return QRectF();
|
|
|
|
|
|
|
|
const qreal pos = menu->positionHint( Q::Cursor );
|
|
|
|
|
|
|
|
const int pos1 = qFloor( pos );
|
|
|
|
const int pos2 = qCeil( pos );
|
|
|
|
|
|
|
|
auto rect = cursorRect( skinnable, contentsRect, pos1 );
|
|
|
|
|
|
|
|
if ( pos1 != pos2 )
|
|
|
|
{
|
|
|
|
const auto r = cursorRect( skinnable, contentsRect, pos2 );
|
|
|
|
|
|
|
|
const qreal ratio = ( pos - pos1 ) / ( pos2 - pos1 );
|
|
|
|
rect = qskInterpolatedRect( rect, r, ratio );
|
|
|
|
}
|
|
|
|
|
|
|
|
return rect;
|
2021-12-24 16:20:34 +01:00
|
|
|
}
|
|
|
|
|
2021-12-23 18:36:32 +01:00
|
|
|
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
|
|
|
}
|
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
QRectF QskMenuSkinlet::sampleRect(
|
2021-12-24 16:50:34 +01:00
|
|
|
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
|
|
|
QskAspect::Subcontrol subControl, int index ) const
|
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
using Q = QskMenu;
|
2021-12-24 16:50:34 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
2021-12-24 16:50:34 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
if ( subControl == Q::Cell )
|
|
|
|
{
|
|
|
|
const auto r = menu->subControlContentsRect( Q::Panel );
|
|
|
|
const auto h = m_data->cellHeight( menu );
|
2021-12-24 16:50:34 +01:00
|
|
|
|
|
|
|
return QRectF( r.x(), r.y() + index * h, r.width(), h );
|
|
|
|
}
|
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
if ( subControl == QskMenu::Graphic || subControl == QskMenu::Text )
|
|
|
|
{
|
2021-12-28 16:14:30 +01:00
|
|
|
const auto r = sampleRect( menu, contentsRect, Q::Cell, index );
|
2021-12-28 15:33:13 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
return Inherited::sampleRect(
|
2021-12-24 16:50:34 +01:00
|
|
|
skinnable, contentsRect, subControl, index );
|
|
|
|
}
|
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
int QskMenuSkinlet::sampleIndexAt(
|
2021-12-28 15:33:13 +01:00
|
|
|
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
|
|
|
QskAspect::Subcontrol subControl, const QPointF& pos ) const
|
|
|
|
{
|
|
|
|
const PrivateData::CacheGuard guard( m_data.get() );
|
2021-12-28 16:14:30 +01:00
|
|
|
return Inherited::sampleIndexAt( skinnable, contentsRect, subControl, pos );
|
2021-12-28 15:33:13 +01:00
|
|
|
}
|
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
int QskMenuSkinlet::sampleCount(
|
2021-12-28 10:08:21 +01:00
|
|
|
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) const
|
2021-12-26 09:15:15 +01:00
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
using Q = QskMenu;
|
|
|
|
|
|
|
|
if ( subControl == Q::Cell || subControl == Q::Graphic || subControl == Q::Text )
|
2021-12-26 09:15:15 +01:00
|
|
|
{
|
|
|
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
2021-12-28 10:08:21 +01:00
|
|
|
return menu->count();
|
|
|
|
}
|
2021-12-26 09:15:15 +01:00
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
return Inherited::sampleCount( skinnable, subControl );
|
2021-12-28 10:08:21 +01:00
|
|
|
}
|
2021-12-26 09:15:15 +01:00
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
QskAspect::States QskMenuSkinlet::sampleStates(
|
2021-12-28 10:08:21 +01:00
|
|
|
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const
|
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
using Q = QskMenu;
|
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
auto states = Inherited::sampleStates( skinnable, subControl, index );
|
2021-12-26 09:15:15 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
if ( subControl == Q::Cell || subControl == Q::Graphic || subControl == Q::Text )
|
2021-12-28 10:08:21 +01:00
|
|
|
{
|
|
|
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
|
|
|
if ( menu->currentIndex() == index )
|
|
|
|
states |= QskMenu::Selected;
|
2021-12-26 09:15:15 +01:00
|
|
|
}
|
|
|
|
|
2021-12-28 10:08:21 +01:00
|
|
|
return states;
|
2021-12-26 09:15:15 +01:00
|
|
|
}
|
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
QVariant QskMenuSkinlet::sampleAt( const QskSkinnable* skinnable,
|
2021-12-28 15:33:13 +01:00
|
|
|
QskAspect::Subcontrol subControl, int index ) const
|
|
|
|
{
|
|
|
|
using Q = QskMenu;
|
|
|
|
|
|
|
|
const auto menu = static_cast< const QskMenu* >( skinnable );
|
|
|
|
|
|
|
|
if ( subControl == Q::Graphic )
|
2021-12-28 16:14:30 +01:00
|
|
|
return qskSampleAt< QskGraphic >( menu, index );
|
2021-12-28 15:33:13 +01:00
|
|
|
|
|
|
|
if ( subControl == Q::Text )
|
2021-12-28 16:14:30 +01:00
|
|
|
return qskSampleAt< QString >( menu, index );
|
2021-12-28 15:33:13 +01:00
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
return Inherited::sampleAt( skinnable, subControl, index );
|
2021-12-28 15:33:13 +01:00
|
|
|
}
|
|
|
|
|
2021-12-23 18:36:32 +01:00
|
|
|
QSGNode* QskMenuSkinlet::updateContentsNode(
|
|
|
|
const QskPopup* popup, QSGNode* contentsNode ) const
|
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
const PrivateData::CacheGuard guard( m_data.get() );
|
|
|
|
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 };
|
2021-12-23 18:36:32 +01:00
|
|
|
|
|
|
|
if ( contentsNode == nullptr )
|
|
|
|
contentsNode = new QSGNode();
|
|
|
|
|
|
|
|
for ( const auto role : roles )
|
|
|
|
{
|
|
|
|
auto oldNode = QskSGNode::findChildNode( contentsNode, role );
|
|
|
|
|
2021-12-24 16:20:34 +01:00
|
|
|
QSGNode* newNode = nullptr;
|
2021-12-23 18:36:32 +01:00
|
|
|
|
|
|
|
switch( role )
|
|
|
|
{
|
|
|
|
case Panel:
|
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
newNode = updateBoxNode( skinnable, oldNode, QskMenu::Panel );
|
2021-12-23 18:36:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2021-12-28 15:33:13 +01:00
|
|
|
case Background:
|
2021-12-23 18:36:32 +01:00
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
newNode = updateSeriesNode( skinnable, QskMenu::Cell, oldNode );
|
2021-12-23 18:36:32 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Cursor:
|
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
newNode = updateBoxNode( skinnable, oldNode, QskMenu::Cursor );
|
2021-12-23 18:36:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2021-12-28 15:33:13 +01:00
|
|
|
case Graphic:
|
2021-12-23 18:36:32 +01:00
|
|
|
{
|
2021-12-28 15:33:13 +01:00
|
|
|
newNode = updateSeriesNode( skinnable, QskMenu::Graphic, oldNode );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Text:
|
|
|
|
{
|
|
|
|
newNode = updateSeriesNode( skinnable, QskMenu::Text, oldNode );
|
2021-12-23 18:36:32 +01:00
|
|
|
break;
|
2021-12-23 19:05:59 +01:00
|
|
|
}
|
2021-12-23 18:36:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QskSGNode::replaceChildNode( roles, role, contentsNode, oldNode, newNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
return contentsNode;
|
|
|
|
}
|
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
QSGNode* QskMenuSkinlet::updateSampleNode( const QskSkinnable* skinnable,
|
2021-12-28 15:33:13 +01:00
|
|
|
QskAspect::Subcontrol subControl, int index, QSGNode* node ) const
|
|
|
|
{
|
|
|
|
using Q = QskMenu;
|
|
|
|
|
|
|
|
auto menu = static_cast< const QskMenu* >( skinnable );
|
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
const auto rect = sampleRect( menu, menu->contentsRect(), subControl, index );
|
2021-12-28 15:33:13 +01:00
|
|
|
|
|
|
|
if ( subControl == Q::Cell )
|
|
|
|
{
|
|
|
|
return updateBoxNode( menu, node, rect, subControl );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( subControl == Q::Graphic )
|
|
|
|
{
|
2021-12-28 16:14:30 +01:00
|
|
|
const auto graphic = qskValueAt< QskGraphic >( menu, index );
|
|
|
|
if ( graphic.isNull() )
|
|
|
|
return nullptr;
|
2021-12-28 15:33:13 +01:00
|
|
|
|
|
|
|
const auto alignment = menu->alignmentHint( subControl, Qt::AlignCenter );
|
|
|
|
const auto filter = menu->effectiveGraphicFilter( subControl );
|
|
|
|
|
|
|
|
return QskSkinlet::updateGraphicNode(
|
2021-12-28 16:14:30 +01:00
|
|
|
menu, node, graphic, filter, rect, alignment );
|
2021-12-28 15:33:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( subControl == Q::Text )
|
|
|
|
{
|
2021-12-28 16:14:30 +01:00
|
|
|
const auto text = qskValueAt< QString >( menu, index );
|
|
|
|
if ( text.isEmpty() )
|
|
|
|
return nullptr;
|
2021-12-28 15:33:13 +01:00
|
|
|
|
|
|
|
const auto alignment = menu->alignmentHint(
|
|
|
|
subControl, Qt::AlignVCenter | Qt::AlignLeft );
|
|
|
|
|
|
|
|
return QskSkinlet::updateTextNode( menu, node, rect, alignment,
|
2021-12-28 16:14:30 +01:00
|
|
|
text, menu->textOptions(), QskMenu::Text );
|
2021-12-28 15:33:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-23 18:36:32 +01:00
|
|
|
QSizeF QskMenuSkinlet::sizeHint( const QskSkinnable* skinnable,
|
|
|
|
Qt::SizeHint which, const QSizeF& ) const
|
|
|
|
{
|
|
|
|
if ( which != Qt::PreferredSize )
|
|
|
|
return QSizeF();
|
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
const PrivateData::CacheGuard guard( m_data.get() );
|
|
|
|
|
2021-12-28 16:14:30 +01:00
|
|
|
const auto count = sampleCount( skinnable, QskMenu::Cell );
|
2021-12-28 15:33:13 +01:00
|
|
|
|
|
|
|
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 );
|
|
|
|
}
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
auto hint = skinnable->outerBoxSize( QskMenu::Panel, QSizeF( w, h ) );
|
|
|
|
hint = hint.expandedTo( skinnable->strutSizeHint( QskMenu::Panel ) );
|
2021-12-23 18:36:32 +01:00
|
|
|
|
2021-12-28 15:33:13 +01:00
|
|
|
return hint;
|
2021-12-23 18:36:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#include "moc_QskMenuSkinlet.cpp"
|