qskinny/src/controls/QskQuickItemPrivate.cpp

243 lines
6.2 KiB
C++
Raw Normal View History

2019-09-04 06:59:43 +02:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskQuickItemPrivate.h"
#include "QskSetup.h"
static inline quint16 qskControlFlags()
{
// we are only interested in the first 8 bits
return static_cast< quint16 >( qskSetup->controlFlags() );
}
static inline void qskSendEventTo( QObject* object, QEvent::Type type )
{
QEvent event( type );
QCoreApplication::sendEvent( object, &event );
}
QskQuickItemPrivate::QskQuickItemPrivate()
: controlFlags( qskControlFlags() )
, controlFlagsMask( 0 )
, polishOnResize( false )
, blockedPolish( false )
, blockedImplicitSize( true )
, clearPreviousNodes( false )
, isInitiallyPainted( false )
, blockLayoutRequestEvents( true )
{
if ( controlFlags & QskQuickItem::DeferredLayout )
{
/*
In general the geometry of an item should be the job of
the parent - unfortunatly not done by Qt Quick
probably in the spirit of "making things easier".
To avoid potentially expensive calculations happening
too often and early QskControl blocks updates of
the implicitSize and any auto resizing of the control
according to it.
There should be no strong reason for using concepts
like Positioners, that rely on implicit resizing,
but to make it working: the DeferredLayout flag needs to be disabled.
*/
widthValid = heightValid = true;
}
}
QskQuickItemPrivate::~QskQuickItemPrivate()
{
}
void QskQuickItemPrivate::mirrorChange()
{
Q_Q( QskQuickItem );
qskSendEventTo( q, QEvent::LayoutDirectionChange );
}
void QskQuickItemPrivate::updateControlFlags( QskQuickItem::Flags flags )
{
const auto oldFlags = controlFlags;
const auto newFlags = static_cast< quint16 >( flags );
if ( oldFlags != newFlags )
{
Q_Q( QskQuickItem );
const auto numBits = qCountTrailingZeroBits(
static_cast< quint32 >( QskQuickItem::LastFlag ) );
for ( quint32 i = 0; i <= numBits; ++i )
{
const quint32 flag = ( 1 << i );
q->updateControlFlag( flag, flags & flag );
}
Q_EMIT q->controlFlagsChanged();
}
}
void QskQuickItemPrivate::layoutConstraintChanged()
{
if ( !blockLayoutRequestEvents )
{
Q_Q( QskQuickItem );
if ( auto item = q->parentItem() )
qskSendEventTo( item, QEvent::LayoutRequest );
/*
We don't send further LayoutRequest events until someone
actively requests a layout relevant information
*/
blockLayoutRequestEvents = true;
}
}
void QskQuickItemPrivate::implicitSizeChanged()
{
layoutConstraintChanged();
}
qreal QskQuickItemPrivate::getImplicitWidth() const
{
if ( blockedImplicitSize )
{
auto that = const_cast< QskQuickItemPrivate* >( this );
that->updateImplicitSize( false );
}
return implicitWidth;
}
qreal QskQuickItemPrivate::getImplicitHeight() const
{
if ( blockedImplicitSize )
{
auto that = const_cast< QskQuickItemPrivate* >( this );
that->updateImplicitSize( false );
}
return implicitHeight;
}
void QskQuickItemPrivate::updateImplicitSize( bool doNotify )
{
blockedImplicitSize = false;
const auto hint = implicitSizeHint();
setImplicitSize( hint.width(), hint.height(), doNotify );
}
void QskQuickItemPrivate::setImplicitSize( qreal w, qreal h, bool doNotify )
{
const bool doWidth = ( w != implicitWidth );
const bool doHeight = ( h != implicitHeight );
if ( !( doWidth || doHeight ) )
return; // nothing to do
implicitWidth = w;
implicitHeight = h;
if ( !( widthValid && heightValid ) )
{
// auto adjusting the size
const qreal oldWidth = width;
const qreal oldHeight = height;
if ( doWidth && !widthValid )
width = qMax( w, qreal( 0.0 ) );
if ( doHeight && !heightValid )
height = qMax( h, qreal( 0.0 ) );
if ( ( width != oldWidth ) || ( height != oldHeight ) )
{
dirty( QQuickItemPrivate::Size );
const QRectF oldRect( x, y, oldWidth, oldHeight );
const QRectF newRect( x, y, width, height );
Q_Q( QskQuickItem );
q->geometryChanged( newRect, oldRect );
}
}
if ( doNotify )
{
// calling implicitSizeChanged only once, TODO ...
if ( doWidth )
Inherited::implicitWidthChanged();
if ( doHeight )
Inherited::implicitHeightChanged();
}
}
void QskQuickItemPrivate::implicitWidthChanged()
{
Inherited::implicitWidthChanged();
blockedImplicitSize = false;
implicitSizeChanged();
}
void QskQuickItemPrivate::implicitHeightChanged()
{
Inherited::implicitWidthChanged();
blockedImplicitSize = false;
implicitSizeChanged();
}
void QskQuickItemPrivate::cleanupNodes()
{
if ( itemNodeInstance == nullptr )
return;
// setting the dirty flags, so that nodes will be recreated
// the next time we participate in a scene graph update
if ( !itemNodeInstance->matrix().isIdentity() )
dirtyAttributes |= QQuickItemPrivate::Position;
if ( extra.isAllocated() )
{
if ( extra->clipNode )
dirtyAttributes |= QQuickItemPrivate::Clip;
if ( extra->opacityNode )
dirtyAttributes |= QQuickItemPrivate::OpacityValue;
if ( extra->rootNode )
dirtyAttributes |= QQuickItemPrivate::EffectReference;
}
if ( window )
{
// putting the nodes on the cleanup list of the window to be deleteted
// in the next cycle of the scene graph
QQuickWindowPrivate::get( window )->cleanup( itemNodeInstance );
}
// now we can forget about the nodes
itemNodeInstance = nullptr;
paintNode = nullptr;
if ( extra.isAllocated() )
{
extra->opacityNode = nullptr;
extra->clipNode = nullptr;
extra->rootNode = nullptr;
}
}