splitting QskControl.cpp
This commit is contained in:
parent
fcd455a545
commit
b80b9b709c
File diff suppressed because it is too large
Load Diff
|
|
@ -4,27 +4,23 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_CONTROL_H
|
||||
#define QSK_CONTROL_H 1
|
||||
#define QSK_CONTROL_H
|
||||
|
||||
#include "QskQuickItem.h"
|
||||
#include "QskSkinnable.h"
|
||||
#include "QskAspect.h"
|
||||
#include "QskGradient.h"
|
||||
#include "QskSizePolicy.h"
|
||||
#include "QskSkinnable.h"
|
||||
|
||||
#include <qlocale.h>
|
||||
#include <qquickitem.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class QskControlPrivate;
|
||||
|
||||
class QskGeometryChangeEvent;
|
||||
class QskWindowChangeEvent;
|
||||
class QskGestureEvent;
|
||||
|
||||
template< typename T > class QVector;
|
||||
|
||||
class QSK_EXPORT QskControl : public QQuickItem, public QskSkinnable
|
||||
class QSK_EXPORT QskControl : public QskQuickItem, public QskSkinnable
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
|
@ -32,16 +28,10 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskSkinnable
|
|||
WRITE setLocale RESET resetLocale NOTIFY localeChanged FINAL )
|
||||
|
||||
Q_PROPERTY( bool autoFillBackground READ autoFillBackground
|
||||
WRITE setAutoFillBackground NOTIFY controlFlagsChanged FINAL )
|
||||
WRITE setAutoFillBackground FINAL )
|
||||
|
||||
Q_PROPERTY( bool autoLayoutChildren READ autoLayoutChildren
|
||||
WRITE setAutoLayoutChildren NOTIFY controlFlagsChanged FINAL )
|
||||
|
||||
Q_PROPERTY( bool polishOnResize READ polishOnResize
|
||||
WRITE setPolishOnResize NOTIFY controlFlagsChanged FINAL )
|
||||
|
||||
Q_PROPERTY( bool transparentForPositioners READ isTransparentForPositioner
|
||||
WRITE setTransparentForPositioner NOTIFY controlFlagsChanged FINAL )
|
||||
WRITE setAutoLayoutChildren FINAL )
|
||||
|
||||
Q_PROPERTY( Qt::FocusPolicy focusPolicy READ focusPolicy
|
||||
WRITE setFocusPolicy NOTIFY focusPolicyChanged FINAL )
|
||||
|
|
@ -49,9 +39,6 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskSkinnable
|
|||
Q_PROPERTY( bool wheelEnabled READ isWheelEnabled
|
||||
WRITE setWheelEnabled NOTIFY wheelEnabledChanged FINAL )
|
||||
|
||||
Q_PROPERTY( bool tabFence READ isTabFence
|
||||
WRITE setTabFence NOTIFY controlFlagsChanged FINAL )
|
||||
|
||||
Q_PROPERTY( QMarginsF margins READ margins
|
||||
WRITE setMargins RESET resetMargins NOTIFY marginsChanged )
|
||||
|
||||
|
|
@ -61,40 +48,17 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskSkinnable
|
|||
Q_PROPERTY( QskSizePolicy sizePolicy READ sizePolicy WRITE setSizePolicy )
|
||||
|
||||
Q_PROPERTY( QSizeF minimumSize READ minimumSize WRITE setMinimumSize )
|
||||
|
||||
Q_PROPERTY( QSizeF maximumSize READ maximumSize WRITE setMaximumSize )
|
||||
|
||||
Q_PROPERTY( QSizeF preferredSize READ preferredSize WRITE setPreferredSize )
|
||||
|
||||
Q_PROPERTY( QRectF geometry READ geometry WRITE setGeometry )
|
||||
|
||||
using Inherited = QQuickItem;
|
||||
using Inherited = QskQuickItem;
|
||||
|
||||
public:
|
||||
QSK_STATES( Disabled, Hovered, Focused )
|
||||
|
||||
enum Flag
|
||||
{
|
||||
DeferredUpdate = 1 << 0,
|
||||
DeferredPolish = 1 << 1,
|
||||
DeferredLayout = 1 << 2,
|
||||
CleanupOnVisibility = 1 << 3,
|
||||
|
||||
PreferRasterForTextures = 1 << 4,
|
||||
|
||||
DebugForceBackground = 1 << 7,
|
||||
|
||||
LastFlag = DebugForceBackground
|
||||
};
|
||||
|
||||
Q_ENUM( Flag )
|
||||
Q_DECLARE_FLAGS( Flags, Flag )
|
||||
|
||||
QskControl( QQuickItem* parent = nullptr );
|
||||
~QskControl() override;
|
||||
|
||||
const char* className() const;
|
||||
|
||||
void setMargins( qreal );
|
||||
void setMargins( const QMarginsF& );
|
||||
void resetMargins();
|
||||
|
|
@ -106,9 +70,6 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskSkinnable
|
|||
void resetBackground();
|
||||
QskGradient background() const;
|
||||
|
||||
QRectF geometry() const;
|
||||
|
||||
QRectF rect() const;
|
||||
QRectF contentsRect() const;
|
||||
QRectF layoutRect() const;
|
||||
|
||||
|
|
@ -122,32 +83,15 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskSkinnable
|
|||
void setAutoFillBackground( bool );
|
||||
bool autoFillBackground() const;
|
||||
|
||||
void setPolishOnResize( bool );
|
||||
bool polishOnResize() const;
|
||||
|
||||
void setAutoLayoutChildren( bool );
|
||||
bool autoLayoutChildren() const;
|
||||
|
||||
void setTransparentForPositioner( bool );
|
||||
bool isTransparentForPositioner() const;
|
||||
|
||||
void setWheelEnabled( bool );
|
||||
bool isWheelEnabled() const;
|
||||
|
||||
void setFocusPolicy( Qt::FocusPolicy );
|
||||
Qt::FocusPolicy focusPolicy() const;
|
||||
|
||||
void setTabFence( bool );
|
||||
bool isTabFence() const;
|
||||
|
||||
void setControlFlags( Flags );
|
||||
void resetControlFlags();
|
||||
Flags controlFlags() const;
|
||||
|
||||
Q_INVOKABLE void setControlFlag( Flag, bool on = true );
|
||||
Q_INVOKABLE void resetControlFlag( Flag );
|
||||
Q_INVOKABLE bool testControlFlag( Flag ) const;
|
||||
|
||||
void setSizePolicy( QskSizePolicy::Policy, QskSizePolicy::Policy );
|
||||
void setSizePolicy( QskSizePolicy );
|
||||
void setSizePolicy( Qt::Orientation, QskSizePolicy::Policy );
|
||||
|
|
@ -195,24 +139,9 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskSkinnable
|
|||
|
||||
virtual QSizeF contentsSizeHint() const;
|
||||
|
||||
bool isVisibleTo( const QQuickItem* ) const;
|
||||
|
||||
QLocale locale() const;
|
||||
void resetLocale();
|
||||
|
||||
void setLayoutMirroring( bool on, bool recursive = false );
|
||||
void resetLayoutMirroring();
|
||||
bool layoutMirroring() const;
|
||||
|
||||
QSizeF size() const;
|
||||
QSizeF implicitSize() const;
|
||||
|
||||
void setGeometry( qreal x, qreal y, qreal width, qreal height );
|
||||
|
||||
bool isPolishScheduled() const;
|
||||
bool isUpdateNodeScheduled() const;
|
||||
bool isInitiallyPainted() const;
|
||||
|
||||
QVector< QskAspect::Subcontrol > subControls() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
|
@ -220,26 +149,15 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskSkinnable
|
|||
void marginsChanged();
|
||||
void focusIndicatorRectChanged();
|
||||
void localeChanged( const QLocale& );
|
||||
void controlFlagsChanged();
|
||||
void focusPolicyChanged();
|
||||
void wheelEnabledChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
void setGeometry( const QRectF& );
|
||||
void setLocale( const QLocale& );
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
void setVisible( bool );
|
||||
|
||||
void resetImplicitSize();
|
||||
|
||||
protected:
|
||||
bool event( QEvent* ) override;
|
||||
|
||||
virtual void changeEvent( QEvent* );
|
||||
virtual void geometryChangeEvent( QskGeometryChangeEvent* );
|
||||
virtual void windowChangeEvent( QskWindowChangeEvent* );
|
||||
virtual void gestureEvent( QskGestureEvent* );
|
||||
|
||||
void hoverEnterEvent( QHoverEvent* ) override;
|
||||
|
|
@ -251,61 +169,26 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskSkinnable
|
|||
void itemChange( ItemChange, const ItemChangeData& ) override;
|
||||
void geometryChanged( const QRectF&, const QRectF& ) override;
|
||||
void windowDeactivateEvent() override;
|
||||
void classBegin() override;
|
||||
void componentComplete() override;
|
||||
void releaseResources() override;
|
||||
|
||||
void initSizePolicy( QskSizePolicy::Policy, QskSizePolicy::Policy );
|
||||
|
||||
void cleanupNodes();
|
||||
|
||||
virtual void aboutToShow(); // called in updatePolish
|
||||
virtual void updateLayout(); // called in updatePolish
|
||||
|
||||
bool maybeUnresized() const;
|
||||
// called from updatePolish
|
||||
virtual void updateResources();
|
||||
virtual void updateLayout();
|
||||
|
||||
private:
|
||||
// don't use boundingRect - it seems to be deprecated
|
||||
QRectF boundingRect() const override final { return rect(); }
|
||||
|
||||
/*
|
||||
childrenRect()/childrenRectChanged does not make much sense
|
||||
in a system, where the parent is responsible for laying out
|
||||
its children.
|
||||
*/
|
||||
void childrenRect() = delete;
|
||||
|
||||
void setActiveFocusOnTab( bool ) = delete; // use setFocusPolicy
|
||||
void updateInputMethod( Qt::InputMethodQueries ) = delete; // use qskUpdateInputMethod
|
||||
|
||||
QSGNode* updatePaintNode( QSGNode*, UpdatePaintNodeData* ) override final;
|
||||
void updatePolish() override final;
|
||||
QSGNode* updateItemPaintNode( QSGNode* ) override final;
|
||||
void updateItemPolish() override final;
|
||||
|
||||
QskControl* owningControl() const override final;
|
||||
|
||||
void layoutConstraintChanged();
|
||||
|
||||
void updateControlFlag( uint flag, bool on );
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE( QskControl )
|
||||
};
|
||||
|
||||
inline void QskControl::setGeometry( const QRectF& rect )
|
||||
{
|
||||
setGeometry( rect.x(), rect.y(), rect.width(), rect.height() );
|
||||
}
|
||||
|
||||
inline QSizeF QskControl::size() const
|
||||
{
|
||||
return QSizeF( width(), height() );
|
||||
}
|
||||
|
||||
inline QSizeF QskControl::implicitSize() const
|
||||
{
|
||||
return QSizeF( implicitWidth(), implicitHeight() );
|
||||
}
|
||||
|
||||
inline QSizeF QskControl::sizeHint() const
|
||||
{
|
||||
return effectiveSizeHint( Qt::PreferredSize );
|
||||
|
|
@ -336,7 +219,4 @@ inline const QskControl* qskControlCast( const QObject* object )
|
|||
return qobject_cast< const QskControl* >( object );
|
||||
}
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QskControl::Flags )
|
||||
Q_DECLARE_METATYPE( QskControl::Flags )
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,184 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskControlPrivate.h"
|
||||
#include "QskSetup.h"
|
||||
#include "QskLayoutConstraint.h"
|
||||
|
||||
static inline void qskSendEventTo( QObject* object, QEvent::Type type )
|
||||
{
|
||||
QEvent event( type );
|
||||
QCoreApplication::sendEvent( object, &event );
|
||||
}
|
||||
|
||||
/*
|
||||
Qt 5.12:
|
||||
sizeof( QQuickItemPrivate::ExtraData ) -> 184
|
||||
sizeof( QQuickItemPrivate ) -> 320
|
||||
|
||||
( these numbers include pointers to optional extra data, but not
|
||||
the size for the extra data. So the effective memory footprint,
|
||||
is often even worse ).
|
||||
|
||||
sizeof( QskControlPrivate ) -> sizeof( QQuickItemPrivate ) + 32
|
||||
sizeof( QskSkinnable::PrivateData ) -> 40
|
||||
|
||||
It might be possible to save some bytes, but in the end QskControl
|
||||
is heavy simply because of deriving from QQuickItem. So without
|
||||
patching Qt the only way to limit the memory footprint of an application
|
||||
substantially is to limit the number of QQuickItems.
|
||||
|
||||
That's why QSkinny builds more complex controls from scene graph nodes
|
||||
instead of doing QQuickItem composition. As this can only be done
|
||||
in C++ it is kind of obvious, why it is often a bad idea to build
|
||||
custom controls in QML.
|
||||
*/
|
||||
|
||||
QskControlPrivate::QskControlPrivate()
|
||||
: explicitSizeHints( nullptr )
|
||||
, sizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Preferred )
|
||||
, explicitLocale( false )
|
||||
, autoFillBackground( false )
|
||||
, autoLayoutChildren( false )
|
||||
, focusPolicy( Qt::NoFocus )
|
||||
, isWheelEnabled( false )
|
||||
{
|
||||
}
|
||||
|
||||
QskControlPrivate::~QskControlPrivate()
|
||||
{
|
||||
delete [] explicitSizeHints;
|
||||
}
|
||||
|
||||
void QskControlPrivate::implicitSizeChanged()
|
||||
{
|
||||
Q_Q( QskControl );
|
||||
if ( !q->explicitSizeHint( Qt::PreferredSize ).isValid() )
|
||||
{
|
||||
// when we have no PreferredSize we fall back
|
||||
// to the implicit size
|
||||
|
||||
layoutConstraintChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QSizeF QskControlPrivate::implicitSizeHint() const
|
||||
{
|
||||
Q_Q( const QskControl );
|
||||
|
||||
const auto m = q->margins();
|
||||
const auto dw = m.left() + m.right();
|
||||
const auto dh = m.top() + m.bottom();
|
||||
|
||||
const auto hint = q->contentsSizeHint();
|
||||
|
||||
const qreal w = ( hint.width() >= 0 ) ? dw + hint.width() : -1.0;
|
||||
const qreal h = ( hint.height() >= 0 ) ? dh + hint.height() : -1.0;
|
||||
|
||||
return QSizeF( w, h );
|
||||
}
|
||||
|
||||
void QskControlPrivate::setExplicitSizeHint(
|
||||
Qt::SizeHint whichHint, const QSizeF& size )
|
||||
{
|
||||
if ( explicitSizeHints == nullptr )
|
||||
{
|
||||
using namespace QskLayoutConstraint;
|
||||
|
||||
explicitSizeHints = new QSizeF[3];
|
||||
explicitSizeHints[0] = defaultSizeHints[0];
|
||||
explicitSizeHints[1] = defaultSizeHints[1];
|
||||
explicitSizeHints[2] = defaultSizeHints[2];
|
||||
}
|
||||
|
||||
explicitSizeHints[ whichHint ] = size;
|
||||
}
|
||||
|
||||
void QskControlPrivate::resetExplicitSizeHint( Qt::SizeHint whichHint )
|
||||
{
|
||||
if ( explicitSizeHints )
|
||||
{
|
||||
using namespace QskLayoutConstraint;
|
||||
explicitSizeHints[ whichHint ] = defaultSizeHints[ whichHint ];
|
||||
}
|
||||
}
|
||||
|
||||
QSizeF QskControlPrivate::explicitSizeHint( Qt::SizeHint whichHint ) const
|
||||
{
|
||||
if ( explicitSizeHints )
|
||||
return explicitSizeHints[ whichHint ];
|
||||
|
||||
return QskLayoutConstraint::defaultSizeHints[ whichHint ];
|
||||
}
|
||||
|
||||
bool QskControlPrivate::maybeGesture( QQuickItem* child, QEvent* event )
|
||||
{
|
||||
Q_Q( QskControl );
|
||||
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
const auto mouseEvent = static_cast< const QMouseEvent* >( event );
|
||||
const QPointF pos = q->mapFromScene( mouseEvent->windowPos() );
|
||||
|
||||
if ( !q->gestureRect().contains( pos ) )
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::UngrabMouse:
|
||||
case QEvent::TouchBegin:
|
||||
case QEvent::TouchCancel:
|
||||
case QEvent::TouchUpdate:
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return q->gestureFilter( child, event );
|
||||
}
|
||||
|
||||
QSGTransformNode* QskControlPrivate::createTransformNode()
|
||||
{
|
||||
return Inherited::createTransformNode();
|
||||
}
|
||||
|
||||
void QskControlPrivate::transformChanged()
|
||||
{
|
||||
Inherited::transformChanged();
|
||||
}
|
||||
|
||||
bool QskControlPrivate::inheritLocale( QskControl* control, const QLocale& locale )
|
||||
{
|
||||
auto d = static_cast< QskControlPrivate* >( QQuickItemPrivate::get( control ) );
|
||||
|
||||
if ( d->explicitLocale || d->locale == locale )
|
||||
return true;
|
||||
|
||||
d->locale = locale;
|
||||
qskSendEventTo( control, QEvent::LocaleChange );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QskControlPrivate::resolveLocale( QskControl* control )
|
||||
{
|
||||
const auto locale = qskSetup->inheritedLocale( control );
|
||||
|
||||
auto d = static_cast< QskControlPrivate* >( QQuickItemPrivate::get( control ) );
|
||||
if ( d->locale != locale )
|
||||
{
|
||||
d->locale = locale;
|
||||
|
||||
qskSendEventTo( control, QEvent::LocaleChange );
|
||||
qskSetup->inheritLocale( control, locale );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_CONTROL_PRIVATE_H
|
||||
#define QSK_CONTROL_PRIVATE_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include "QskControl.h"
|
||||
|
||||
#include "QskQuickItemPrivate.h"
|
||||
|
||||
class QskControlPrivate : public QskQuickItemPrivate
|
||||
{
|
||||
using Inherited = QskQuickItemPrivate;
|
||||
|
||||
public:
|
||||
static bool inheritLocale( QskControl*, const QLocale& );
|
||||
static void resolveLocale( QskControl* );
|
||||
|
||||
protected:
|
||||
QskControlPrivate();
|
||||
~QskControlPrivate() override;
|
||||
|
||||
private:
|
||||
QSGTransformNode* createTransformNode() override;
|
||||
void transformChanged() override;
|
||||
|
||||
void setExplicitSizeHint( Qt::SizeHint, const QSizeF& );
|
||||
void resetExplicitSizeHint( Qt::SizeHint );
|
||||
QSizeF explicitSizeHint( Qt::SizeHint ) const;
|
||||
|
||||
bool maybeGesture( QQuickItem*, QEvent* );
|
||||
|
||||
QSizeF implicitSizeHint() const override final;
|
||||
void implicitSizeChanged() override final;
|
||||
|
||||
private:
|
||||
Q_DECLARE_PUBLIC( QskControl )
|
||||
|
||||
QSizeF* explicitSizeHints;
|
||||
|
||||
QLocale locale;
|
||||
QskSizePolicy sizePolicy;
|
||||
|
||||
bool explicitLocale : 1;
|
||||
|
||||
bool autoFillBackground : 1;
|
||||
bool autoLayoutChildren : 1;
|
||||
|
||||
uint focusPolicy : 4;
|
||||
bool isWheelEnabled : 1;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,842 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskQuickItem.h"
|
||||
#include "QskQuickItemPrivate.h"
|
||||
#include "QskQuick.h"
|
||||
#include "QskEvent.h"
|
||||
#include "QskSetup.h"
|
||||
#include "QskSkin.h"
|
||||
#include "QskDirtyItemFilter.h"
|
||||
|
||||
#include <qglobalstatic.h>
|
||||
#include <qquickwindow.h>
|
||||
|
||||
#if defined( QT_DEBUG )
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qquickpositioners_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
#endif
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
static inline void qskSendEventTo( QObject* object, QEvent::Type type )
|
||||
{
|
||||
QEvent event( type );
|
||||
QCoreApplication::sendEvent( object, &event );
|
||||
}
|
||||
|
||||
static inline void qskUpdateControlFlags(
|
||||
QskQuickItem::Flags flags, QskQuickItem* item )
|
||||
{
|
||||
auto d = static_cast< QskQuickItemPrivate* >( QskQuickItemPrivate::get( item ) );
|
||||
d->updateControlFlags( flags );
|
||||
}
|
||||
|
||||
static inline quint16 qskControlFlags()
|
||||
{
|
||||
// we are only interested in the first 8 bits
|
||||
return static_cast< quint16 >( qskSetup->controlFlags() );
|
||||
}
|
||||
|
||||
static inline void qskFilterWindow( QQuickWindow* window )
|
||||
{
|
||||
if ( window == nullptr )
|
||||
return;
|
||||
|
||||
static QskDirtyItemFilter itemFilter;
|
||||
itemFilter.addWindow( window );
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class QskQuickItemRegistry
|
||||
{
|
||||
public:
|
||||
QskQuickItemRegistry()
|
||||
{
|
||||
/*
|
||||
Its faster and saves some memory to have this registry instead
|
||||
of setting up direct connections between qskSetup and each control
|
||||
*/
|
||||
QObject::connect( qskSetup, &QskSetup::controlFlagsChanged,
|
||||
qskSetup, [ this ] { updateControlFlags(); } );
|
||||
|
||||
QObject::connect( qskSetup, &QskSetup::skinChanged,
|
||||
qskSetup, [ this ] { updateSkin(); } );
|
||||
}
|
||||
|
||||
inline void insert( QskQuickItem* item )
|
||||
{
|
||||
m_items.insert( item );
|
||||
}
|
||||
|
||||
inline void remove( QskQuickItem* item )
|
||||
{
|
||||
m_items.erase( item );
|
||||
}
|
||||
|
||||
void updateControlFlags()
|
||||
{
|
||||
const auto flags = static_cast< QskQuickItem::Flags >( qskControlFlags() );
|
||||
|
||||
for ( auto item : m_items )
|
||||
qskUpdateControlFlags( flags, item );
|
||||
}
|
||||
|
||||
void updateSkin()
|
||||
{
|
||||
QEvent event( QEvent::StyleChange );
|
||||
|
||||
for ( auto item : m_items )
|
||||
{
|
||||
event.setAccepted( true );
|
||||
QCoreApplication::sendEvent( item, &event );
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_set< QskQuickItem* > m_items;
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
/*
|
||||
A helper class to store the released window to be able to
|
||||
put it later into the WindowChange event.
|
||||
*/
|
||||
class QskWindowStore
|
||||
{
|
||||
public:
|
||||
QskWindowStore()
|
||||
: m_refCount( 0 )
|
||||
, m_window( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
void setWindow( QQuickWindow* window )
|
||||
{
|
||||
if ( m_window != window )
|
||||
{
|
||||
m_window = window;
|
||||
m_refCount = 0;
|
||||
}
|
||||
|
||||
if ( m_window )
|
||||
m_refCount++;
|
||||
}
|
||||
|
||||
QQuickWindow* window()
|
||||
{
|
||||
QQuickWindow* w = m_window;
|
||||
|
||||
if ( m_window )
|
||||
{
|
||||
if ( --m_refCount == 0 )
|
||||
m_window = nullptr;
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_refCount;
|
||||
QQuickWindow* m_window;
|
||||
};
|
||||
}
|
||||
|
||||
Q_GLOBAL_STATIC( QskQuickItemRegistry, qskRegistry )
|
||||
Q_GLOBAL_STATIC( QskWindowStore, qskReleasedWindowCounter )
|
||||
|
||||
QskQuickItem::QskQuickItem( QskQuickItemPrivate& dd, QQuickItem* parent )
|
||||
: QQuickItem( dd, parent )
|
||||
{
|
||||
setFlag( QQuickItem::ItemHasContents, true );
|
||||
|
||||
// since Qt 5.10 we have QQuickItem::ItemEnabledHasChanged
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 10, 0 )
|
||||
/*
|
||||
Setting up this connections slows down the time needed
|
||||
for construction by almost 100%. Would be nice to
|
||||
avoid this penalty also for earlier Qt versions.
|
||||
*/
|
||||
connect( this, &QQuickItem::enabledChanged,
|
||||
[ this ] { qskSendEventTo( this, QEvent::EnabledChange ); } );
|
||||
#endif
|
||||
|
||||
Q_D( QskQuickItem );
|
||||
if ( d->controlFlags & QskQuickItem::DeferredUpdate )
|
||||
qskFilterWindow( window() );
|
||||
|
||||
qskRegistry->insert( this );
|
||||
}
|
||||
|
||||
QskQuickItem::~QskQuickItem()
|
||||
{
|
||||
/*
|
||||
We set componentComplete to false, so that operations
|
||||
that are triggered by detaching the item from its parent
|
||||
can be aware of the about-to-delete state.
|
||||
*/
|
||||
d_func()->componentComplete = false;
|
||||
|
||||
if ( qskRegistry )
|
||||
qskRegistry->remove( this );
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 10, 0 )
|
||||
disconnect( this, &QQuickItem::enabledChanged, nullptr, nullptr );
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* QskQuickItem::className() const
|
||||
{
|
||||
return metaObject()->className();
|
||||
}
|
||||
|
||||
void QskQuickItem::classBegin()
|
||||
{
|
||||
Inherited::classBegin();
|
||||
}
|
||||
|
||||
void QskQuickItem::componentComplete()
|
||||
{
|
||||
#if defined( QT_DEBUG )
|
||||
if ( qobject_cast< const QQuickBasePositioner* >( parent() ) )
|
||||
{
|
||||
if ( d_func()->controlFlags & QskQuickItem::DeferredLayout )
|
||||
{
|
||||
qWarning( "QskQuickItem in DeferredLayout mode under control of a positioner" );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Inherited::componentComplete();
|
||||
}
|
||||
|
||||
void QskQuickItem::releaseResources()
|
||||
{
|
||||
Inherited::releaseResources();
|
||||
|
||||
// QQuickItem::derefWindow runs over the children between
|
||||
// calling releaseResources and itemChange. So we need to have
|
||||
// a reference count to know, when we have processed all
|
||||
// sequences to be able to provide the correct "oldWindow"
|
||||
// in the WindowChange event.
|
||||
|
||||
qskReleasedWindowCounter->setWindow( window() );
|
||||
}
|
||||
|
||||
void QskQuickItem::setVisible( bool on )
|
||||
{
|
||||
// QQuickItem::setVisible is no slot
|
||||
Inherited::setVisible( on );
|
||||
}
|
||||
|
||||
void QskQuickItem::show()
|
||||
{
|
||||
Inherited::setVisible( true );
|
||||
}
|
||||
|
||||
void QskQuickItem::hide()
|
||||
{
|
||||
Inherited::setVisible( false );
|
||||
}
|
||||
|
||||
bool QskQuickItem::isVisibleTo( const QQuickItem* ancestor ) const
|
||||
{
|
||||
return qskIsVisibleTo( this, ancestor );
|
||||
}
|
||||
|
||||
void QskQuickItem::setGeometry( qreal x, qreal y, qreal width, qreal height )
|
||||
{
|
||||
// QQuickItem does not even offer changing the geometry
|
||||
// in one call - what leads to 2 calls of the updateGeometry
|
||||
// hook. Grmpf ...
|
||||
|
||||
Q_D( QQuickItem );
|
||||
|
||||
d->heightValid = true;
|
||||
d->widthValid = true;
|
||||
|
||||
const QRectF oldRect( d->x, d->y, d->width, d->height );
|
||||
|
||||
int dirtyType = 0;
|
||||
|
||||
if ( d->x != x || d->y != y )
|
||||
{
|
||||
d->x = x;
|
||||
d->y = y;
|
||||
|
||||
dirtyType |= QQuickItemPrivate::Position;
|
||||
}
|
||||
|
||||
if ( d->width != width || d->height != height )
|
||||
{
|
||||
d->height = height;
|
||||
d->width = width;
|
||||
|
||||
dirtyType |= QQuickItemPrivate::Size;
|
||||
}
|
||||
|
||||
if ( dirtyType )
|
||||
{
|
||||
if ( dirtyType & QQuickItemPrivate::Position )
|
||||
d->dirty( QQuickItemPrivate::Position );
|
||||
|
||||
if ( dirtyType & QQuickItemPrivate::Size )
|
||||
d->dirty( QQuickItemPrivate::Size );
|
||||
|
||||
/*
|
||||
Unfortunately geometryChanged is protected and we can't implement
|
||||
this code as qskSetItemGeometry - further hacking required: TODO ...
|
||||
*/
|
||||
|
||||
geometryChanged( QRectF( d->x, d->y, d->width, d->height ), oldRect );
|
||||
}
|
||||
}
|
||||
|
||||
QRectF QskQuickItem::rect() const
|
||||
{
|
||||
Q_D( const QQuickItem );
|
||||
return QRectF( 0, 0, d->width, d->height );
|
||||
}
|
||||
|
||||
QRectF QskQuickItem::geometry() const
|
||||
{
|
||||
Q_D( const QQuickItem );
|
||||
return QRectF( d->x, d->y, d->width, d->height );
|
||||
}
|
||||
|
||||
void QskQuickItem::setTransparentForPositioner( bool on )
|
||||
{
|
||||
Q_D( QQuickItem );
|
||||
if ( on != d->isTransparentForPositioner() )
|
||||
{
|
||||
d->setTransparentForPositioner( on );
|
||||
Q_EMIT itemFlagsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskQuickItem::isTransparentForPositioner() const
|
||||
{
|
||||
return d_func()->isTransparentForPositioner();
|
||||
}
|
||||
|
||||
void QskQuickItem::setTabFence( bool on )
|
||||
{
|
||||
Q_D( QQuickItem );
|
||||
if ( on != d->isTabFence )
|
||||
{
|
||||
d->isTabFence = on;
|
||||
Q_EMIT itemFlagsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskQuickItem::isTabFence() const
|
||||
{
|
||||
return d_func()->isTabFence;
|
||||
}
|
||||
|
||||
void QskQuickItem::setPolishOnResize( bool on )
|
||||
{
|
||||
Q_D( QskQuickItem );
|
||||
if ( on != d->polishOnResize )
|
||||
{
|
||||
d->polishOnResize = on;
|
||||
polish();
|
||||
|
||||
Q_EMIT itemFlagsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskQuickItem::polishOnResize() const
|
||||
{
|
||||
return d_func()->polishOnResize;
|
||||
}
|
||||
|
||||
bool QskQuickItem::layoutMirroring() const
|
||||
{
|
||||
return d_func()->effectiveLayoutMirror;
|
||||
}
|
||||
|
||||
void QskQuickItem::setLayoutMirroring( bool on, bool recursive )
|
||||
{
|
||||
// Again we have to deal with an existing API made for QML,
|
||||
// that is weired for C++: LayoutMirroring/QQuickLayoutMirroringAttached
|
||||
// Internally it is managed by 5(!) different flags - condolences
|
||||
// to the poor guy who has been sentenced to maintain this.
|
||||
|
||||
// Anyway, the code below might achieve the desired behavior without
|
||||
// breaking the QML path.
|
||||
|
||||
Q_D( QQuickItem );
|
||||
|
||||
if ( recursive != d->inheritMirrorFromItem )
|
||||
{
|
||||
d->inheritMirrorFromItem = recursive;
|
||||
d->resolveLayoutMirror();
|
||||
}
|
||||
|
||||
d->isMirrorImplicit = false;
|
||||
|
||||
if ( on != d->effectiveLayoutMirror )
|
||||
{
|
||||
d->setLayoutMirror( on );
|
||||
if ( recursive )
|
||||
d->resolveLayoutMirror();
|
||||
}
|
||||
}
|
||||
|
||||
void QskQuickItem::resetLayoutMirroring()
|
||||
{
|
||||
Q_D( QQuickItem );
|
||||
|
||||
if ( d && !d->isMirrorImplicit )
|
||||
{
|
||||
d->isMirrorImplicit = true;
|
||||
// d->inheritMirrorFromItem = false;
|
||||
d->resolveLayoutMirror();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskQuickItem::isPolishScheduled() const
|
||||
{
|
||||
return d_func()->polishScheduled;
|
||||
}
|
||||
|
||||
bool QskQuickItem::isUpdateNodeScheduled() const
|
||||
{
|
||||
Q_D( const QskQuickItem );
|
||||
|
||||
return ( d->dirtyAttributes & QQuickItemPrivate::ContentUpdateMask ) &&
|
||||
( d->flags & QQuickItem::ItemHasContents );
|
||||
}
|
||||
|
||||
bool QskQuickItem::isInitiallyPainted() const
|
||||
{
|
||||
return d_func()->isInitiallyPainted;
|
||||
}
|
||||
|
||||
bool QskQuickItem::maybeUnresized() const
|
||||
{
|
||||
Q_D( const QskQuickItem );
|
||||
|
||||
if ( d->width <= 0.0 && d->height <= 0.0 )
|
||||
{
|
||||
/*
|
||||
Unfortunately the list of items to-be-polished is not processed
|
||||
in top/down order and we might run into updatePolish() before
|
||||
having a proper size. But when the parentItem() is waiting
|
||||
for to-be-polished, we assume, that we will be resized then
|
||||
and run into another updatePolish() then.
|
||||
*/
|
||||
if ( d->polishOnResize && qskIsPolishScheduled( parentItem() ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QskQuickItem::Flags QskQuickItem::controlFlags() const
|
||||
{
|
||||
return QskQuickItem::Flags( d_func()->controlFlags );
|
||||
}
|
||||
|
||||
void QskQuickItem::setControlFlags( Flags flags )
|
||||
{
|
||||
Q_D( QskQuickItem );
|
||||
|
||||
// set all bits in the mask
|
||||
d->controlFlagsMask = std::numeric_limits< quint16 >::max();
|
||||
d->updateControlFlags( flags );
|
||||
}
|
||||
|
||||
void QskQuickItem::resetControlFlags()
|
||||
{
|
||||
Q_D( QskQuickItem );
|
||||
|
||||
// clear all bits in the mask
|
||||
d->controlFlagsMask = 0;
|
||||
d->updateControlFlags( static_cast< Flags >( qskControlFlags() ) );
|
||||
}
|
||||
|
||||
void QskQuickItem::setControlFlag( Flag flag, bool on )
|
||||
{
|
||||
Q_D( QskQuickItem );
|
||||
|
||||
d->controlFlagsMask |= flag;
|
||||
|
||||
if ( ( d->controlFlags & flag ) != on )
|
||||
{
|
||||
updateControlFlag( flag, on );
|
||||
Q_EMIT controlFlagsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void QskQuickItem::resetControlFlag( Flag flag )
|
||||
{
|
||||
Q_D( QskQuickItem );
|
||||
|
||||
d->controlFlagsMask &= ~flag;
|
||||
|
||||
const bool on = qskSetup->testControlFlag( static_cast< QskSetup::Flag >( flag ) );
|
||||
|
||||
if ( ( d->controlFlags & flag ) != on )
|
||||
{
|
||||
updateControlFlag( flag, on );
|
||||
Q_EMIT controlFlagsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskQuickItem::testControlFlag( Flag flag ) const
|
||||
{
|
||||
return d_func()->controlFlags & flag;
|
||||
}
|
||||
|
||||
void QskQuickItem::updateControlFlag( uint flag, bool on )
|
||||
{
|
||||
Q_D( QskQuickItem );
|
||||
|
||||
if ( ( flag > std::numeric_limits< quint16 >::max() ) ||
|
||||
( bool( d->controlFlags & flag ) == on ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( on )
|
||||
d->controlFlags |= flag;
|
||||
else
|
||||
d->controlFlags &= ~flag;
|
||||
|
||||
switch ( flag )
|
||||
{
|
||||
case QskQuickItem::DeferredUpdate:
|
||||
{
|
||||
if ( on )
|
||||
{
|
||||
qskFilterWindow( window() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !isVisible() )
|
||||
update();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case QskQuickItem::DeferredPolish:
|
||||
{
|
||||
if ( !on && d->blockedPolish )
|
||||
polish();
|
||||
|
||||
break;
|
||||
}
|
||||
case QskQuickItem::DeferredLayout:
|
||||
{
|
||||
if ( !on )
|
||||
{
|
||||
// Update the implicitSize and rebind the size to it.
|
||||
// Having set the size explicitly gets lost.
|
||||
|
||||
d->widthValid = d->heightValid = false;
|
||||
d->updateImplicitSize( false );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case QskQuickItem::CleanupOnVisibility:
|
||||
{
|
||||
if ( on && !isVisible() )
|
||||
d->cleanupNodes();
|
||||
|
||||
break;
|
||||
}
|
||||
case QskQuickItem::DebugForceBackground:
|
||||
{
|
||||
// no need to mark it dirty
|
||||
if ( flags() & QQuickItem::ItemHasContents )
|
||||
update();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QskQuickItem::resetImplicitSize()
|
||||
{
|
||||
Q_D( QskQuickItem );
|
||||
|
||||
if ( d->controlFlags & QskQuickItem::DeferredLayout )
|
||||
{
|
||||
d->blockedImplicitSize = true;
|
||||
d->layoutConstraintChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
d->updateImplicitSize( true );
|
||||
}
|
||||
}
|
||||
|
||||
bool QskQuickItem::event( QEvent* event )
|
||||
{
|
||||
const int eventType = event->type();
|
||||
|
||||
switch( eventType )
|
||||
{
|
||||
case QEvent::StyleChange:
|
||||
{
|
||||
d_func()->clearPreviousNodes = true;
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
|
||||
if ( flags() & QQuickItem::ItemHasContents )
|
||||
update();
|
||||
|
||||
changeEvent( event );
|
||||
return true;
|
||||
}
|
||||
case QEvent::ContentsRectChange:
|
||||
{
|
||||
if ( polishOnResize() )
|
||||
polish();
|
||||
|
||||
changeEvent( event );
|
||||
return true;
|
||||
}
|
||||
case QEvent::EnabledChange:
|
||||
case QEvent::FontChange:
|
||||
case QEvent::PaletteChange:
|
||||
case QEvent::LocaleChange:
|
||||
case QEvent::ReadOnlyChange:
|
||||
case QEvent::ParentChange:
|
||||
{
|
||||
changeEvent( event );
|
||||
return true;
|
||||
}
|
||||
case QskEvent::GeometryChange:
|
||||
{
|
||||
geometryChangeEvent( static_cast< QskGeometryChangeEvent* >( event ) );
|
||||
return true;
|
||||
}
|
||||
case QskEvent::WindowChange:
|
||||
{
|
||||
windowChangeEvent( static_cast< QskWindowChangeEvent* >( event ) );
|
||||
return true;
|
||||
}
|
||||
case QEvent::LayoutRequest:
|
||||
{
|
||||
if ( d_func()->polishOnResize )
|
||||
polish();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::event( event );
|
||||
}
|
||||
|
||||
void QskQuickItem::windowChangeEvent( QskWindowChangeEvent* )
|
||||
{
|
||||
}
|
||||
|
||||
void QskQuickItem::geometryChangeEvent( QskGeometryChangeEvent* )
|
||||
{
|
||||
}
|
||||
|
||||
void QskQuickItem::changeEvent( QEvent* )
|
||||
{
|
||||
}
|
||||
|
||||
void QskQuickItem::itemChange( QQuickItem::ItemChange change,
|
||||
const QQuickItem::ItemChangeData& value )
|
||||
{
|
||||
switch ( change )
|
||||
{
|
||||
case QQuickItem::ItemSceneChange:
|
||||
{
|
||||
if ( value.window )
|
||||
{
|
||||
Q_D( const QskQuickItem );
|
||||
if ( d->controlFlags & QskQuickItem::DeferredUpdate )
|
||||
qskFilterWindow( value.window );
|
||||
}
|
||||
|
||||
#if 1
|
||||
auto oldWindow = qskReleasedWindowCounter->window();
|
||||
if ( oldWindow && ( oldWindow->activeFocusItem() == this ) )
|
||||
{
|
||||
/*
|
||||
Removing an item from the scene might result in
|
||||
changes of the active focus item. Unfortunately the corresponding
|
||||
FocusIn/Out events are sent, while the item tree is in an
|
||||
invalid state.
|
||||
When having event handlers, that do modifications of the focus
|
||||
( f.e. assigning the local focus, inside of a focus scope )
|
||||
we might end up with having a dangling pointer for
|
||||
oldWindow->activeFocusItem().
|
||||
*/
|
||||
QQuickWindowPrivate::get( oldWindow )->clearFocusInScope(
|
||||
qskNearestFocusScope( this ), this, Qt::OtherFocusReason );
|
||||
}
|
||||
#endif
|
||||
|
||||
QskWindowChangeEvent event( oldWindow, value.window );
|
||||
QCoreApplication::sendEvent( this, &event );
|
||||
|
||||
break;
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
|
||||
case QQuickItem::ItemEnabledHasChanged:
|
||||
{
|
||||
qskSendEventTo( this, QEvent::EnabledChange );
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case QQuickItem::ItemVisibleHasChanged:
|
||||
{
|
||||
Q_D( QskQuickItem );
|
||||
#if 1
|
||||
/*
|
||||
~QQuickItem sends QQuickItem::ItemVisibleHasChanged recursively
|
||||
to all childItems. When being a child ( not only a childItem() )
|
||||
we are short before being destructed too and any updates
|
||||
done here are totally pointless. TODO ...
|
||||
*/
|
||||
#endif
|
||||
if ( value.boolValue )
|
||||
{
|
||||
if ( d->blockedPolish )
|
||||
polish();
|
||||
|
||||
if ( d->controlFlags & QskQuickItem::DeferredUpdate )
|
||||
{
|
||||
if ( d->dirtyAttributes && ( d->flags & QQuickItem::ItemHasContents ) )
|
||||
update();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( d->controlFlags & QskQuickItem::CleanupOnVisibility )
|
||||
d->cleanupNodes();
|
||||
|
||||
d->isInitiallyPainted = false;
|
||||
}
|
||||
|
||||
if ( parentItem() && parentItem()->isVisible() )
|
||||
{
|
||||
/*
|
||||
Layout code might consider the visiblility of the children
|
||||
and therefore needs to be updated. Posting a statement about
|
||||
changed layout constraints has this effect, but is not correct.
|
||||
The right way to go would be to create show/hide events and to
|
||||
handle them, where visibility of the children matters.
|
||||
TODO ...
|
||||
*/
|
||||
|
||||
d->layoutConstraintChanged();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case QQuickItem::ItemParentHasChanged:
|
||||
case QQuickItem::ItemChildAddedChange:
|
||||
case QQuickItem::ItemChildRemovedChange:
|
||||
case ItemOpacityHasChanged:
|
||||
case ItemActiveFocusHasChanged:
|
||||
case ItemRotationHasChanged:
|
||||
case ItemAntialiasingHasChanged:
|
||||
case ItemDevicePixelRatioHasChanged:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Inherited::itemChange( change, value );
|
||||
}
|
||||
|
||||
void QskQuickItem::geometryChanged(
|
||||
const QRectF& newGeometry, const QRectF& oldGeometry )
|
||||
{
|
||||
Inherited::geometryChanged( newGeometry, oldGeometry );
|
||||
|
||||
Q_D( const QskQuickItem );
|
||||
if ( !d->polishScheduled && d->polishOnResize )
|
||||
{
|
||||
if ( newGeometry.size() != oldGeometry.size() )
|
||||
polish();
|
||||
}
|
||||
|
||||
QskGeometryChangeEvent event( newGeometry, oldGeometry );
|
||||
QCoreApplication::sendEvent( this, &event );
|
||||
}
|
||||
|
||||
void QskQuickItem::updatePolish()
|
||||
{
|
||||
Q_D( QskQuickItem );
|
||||
|
||||
if ( d->controlFlags & QskQuickItem::DeferredPolish )
|
||||
{
|
||||
if ( !isVisible() )
|
||||
{
|
||||
d->blockedPolish = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
d->blockedPolish = false;
|
||||
|
||||
if ( !d->isInitiallyPainted )
|
||||
{
|
||||
/*
|
||||
We should find a better way for identifying, when
|
||||
an item is about to be shown, than making it dependend
|
||||
from polishing and the existence of scene graph nodes. TODO ...
|
||||
*/
|
||||
aboutToShow();
|
||||
}
|
||||
|
||||
updateItemPolish();
|
||||
}
|
||||
|
||||
void QskQuickItem::aboutToShow()
|
||||
{
|
||||
}
|
||||
|
||||
void QskQuickItem::updateItemPolish()
|
||||
{
|
||||
}
|
||||
|
||||
QSGNode* QskQuickItem::updatePaintNode( QSGNode* node, UpdatePaintNodeData* data )
|
||||
{
|
||||
Q_UNUSED( data );
|
||||
|
||||
Q_D( QskQuickItem );
|
||||
|
||||
Q_ASSERT( isVisible() || !( d->controlFlags & QskQuickItem::DeferredUpdate ) );
|
||||
|
||||
d->isInitiallyPainted = true;
|
||||
|
||||
if ( d->clearPreviousNodes )
|
||||
{
|
||||
delete node;
|
||||
node = nullptr;
|
||||
|
||||
d->clearPreviousNodes = false;
|
||||
}
|
||||
|
||||
return updateItemPaintNode( node );
|
||||
}
|
||||
|
||||
QSGNode* QskQuickItem::updateItemPaintNode( QSGNode* node )
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
#include "moc_QskQuickItem.cpp"
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_QUICK_ITEM_H
|
||||
#define QSK_QUICK_ITEM_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include <qquickitem.h>
|
||||
|
||||
class QskQuickItemPrivate;
|
||||
class QskGeometryChangeEvent;
|
||||
class QskWindowChangeEvent;
|
||||
|
||||
class QSK_EXPORT QskQuickItem : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( QRectF geometry READ geometry WRITE setGeometry )
|
||||
|
||||
Q_PROPERTY( bool transparentForPositioners READ isTransparentForPositioner
|
||||
WRITE setTransparentForPositioner NOTIFY itemFlagsChanged )
|
||||
|
||||
Q_PROPERTY( bool tabFence READ isTabFence
|
||||
WRITE setTabFence NOTIFY itemFlagsChanged )
|
||||
|
||||
Q_PROPERTY( bool polishOnResize READ polishOnResize
|
||||
WRITE setPolishOnResize NOTIFY itemFlagsChanged FINAL )
|
||||
|
||||
using Inherited = QQuickItem;
|
||||
|
||||
public:
|
||||
enum Flag
|
||||
{
|
||||
DeferredUpdate = 1 << 0,
|
||||
DeferredPolish = 1 << 1,
|
||||
DeferredLayout = 1 << 2,
|
||||
CleanupOnVisibility = 1 << 3,
|
||||
|
||||
PreferRasterForTextures = 1 << 4,
|
||||
|
||||
DebugForceBackground = 1 << 7,
|
||||
|
||||
LastFlag = DebugForceBackground
|
||||
};
|
||||
|
||||
Q_ENUM( Flag )
|
||||
Q_DECLARE_FLAGS( Flags, Flag )
|
||||
|
||||
~QskQuickItem() override;
|
||||
|
||||
const char* className() const;
|
||||
|
||||
bool isVisibleTo( const QQuickItem* ) const;
|
||||
|
||||
QRectF geometry() const;
|
||||
QRectF rect() const;
|
||||
QSizeF size() const;
|
||||
QSizeF implicitSize() const;
|
||||
|
||||
void setGeometry( qreal x, qreal y, qreal width, qreal height );
|
||||
|
||||
void setPolishOnResize( bool );
|
||||
bool polishOnResize() const;
|
||||
|
||||
void setTransparentForPositioner( bool );
|
||||
bool isTransparentForPositioner() const;
|
||||
|
||||
void setTabFence( bool );
|
||||
bool isTabFence() const;
|
||||
|
||||
void setLayoutMirroring( bool on, bool recursive = false );
|
||||
void resetLayoutMirroring();
|
||||
bool layoutMirroring() const;
|
||||
|
||||
void setControlFlags( Flags );
|
||||
void resetControlFlags();
|
||||
Flags controlFlags() const;
|
||||
|
||||
Q_INVOKABLE void setControlFlag( Flag, bool on = true );
|
||||
Q_INVOKABLE void resetControlFlag( Flag );
|
||||
Q_INVOKABLE bool testControlFlag( Flag ) const;
|
||||
|
||||
void classBegin() override;
|
||||
void componentComplete() override;
|
||||
void releaseResources() override;
|
||||
|
||||
bool isPolishScheduled() const;
|
||||
bool isUpdateNodeScheduled() const;
|
||||
bool isInitiallyPainted() const;
|
||||
|
||||
bool maybeUnresized() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void itemFlagsChanged();
|
||||
void controlFlagsChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
void setGeometry( const QRectF& );
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
void setVisible( bool );
|
||||
|
||||
void resetImplicitSize();
|
||||
|
||||
protected:
|
||||
QskQuickItem( QskQuickItemPrivate&, QQuickItem* = nullptr );
|
||||
|
||||
bool event( QEvent* ) override;
|
||||
|
||||
virtual void changeEvent( QEvent* );
|
||||
virtual void geometryChangeEvent( QskGeometryChangeEvent* );
|
||||
virtual void windowChangeEvent( QskWindowChangeEvent* );
|
||||
|
||||
void itemChange( ItemChange, const ItemChangeData& ) override;
|
||||
void geometryChanged( const QRectF&, const QRectF& ) override;
|
||||
|
||||
virtual void aboutToShow(); // called in updatePolish
|
||||
|
||||
private:
|
||||
// don't use boundingRect - it seems to be deprecated
|
||||
QRectF boundingRect() const override final { return rect(); }
|
||||
|
||||
/*
|
||||
childrenRect()/childrenRectChanged does not make much sense
|
||||
in a system, where the parent is responsible for laying out
|
||||
its children.
|
||||
*/
|
||||
void childrenRect() = delete;
|
||||
|
||||
void updateControlFlag( uint flag, bool on );
|
||||
|
||||
QSGNode* updatePaintNode( QSGNode*, UpdatePaintNodeData* ) override final;
|
||||
virtual QSGNode* updateItemPaintNode( QSGNode* );
|
||||
|
||||
void updatePolish() override final;
|
||||
virtual void updateItemPolish();
|
||||
|
||||
Q_DECLARE_PRIVATE( QskQuickItem )
|
||||
};
|
||||
|
||||
inline void QskQuickItem::setGeometry( const QRectF& rect )
|
||||
{
|
||||
setGeometry( rect.x(), rect.y(), rect.width(), rect.height() );
|
||||
}
|
||||
|
||||
inline QSizeF QskQuickItem::size() const
|
||||
{
|
||||
return QSizeF( width(), height() );
|
||||
}
|
||||
|
||||
inline QSizeF QskQuickItem::implicitSize() const
|
||||
{
|
||||
return QSizeF( implicitWidth(), implicitHeight() );
|
||||
}
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QskQuickItem::Flags )
|
||||
Q_DECLARE_METATYPE( QskQuickItem::Flags )
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
/******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_QUICK_ITEM_PRIVATE_H
|
||||
#define QSK_QUICK_ITEM_PRIVATE_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include "QskQuickItem.h"
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qquickitem_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
class QskQuickItemPrivate : public QQuickItemPrivate
|
||||
{
|
||||
using Inherited = QQuickItemPrivate;
|
||||
|
||||
protected:
|
||||
QskQuickItemPrivate();
|
||||
~QskQuickItemPrivate() override;
|
||||
|
||||
public:
|
||||
void updateControlFlags( QskQuickItem::Flags );
|
||||
|
||||
protected:
|
||||
void layoutConstraintChanged();
|
||||
virtual void implicitSizeChanged();
|
||||
virtual QSizeF implicitSizeHint() const = 0;
|
||||
|
||||
private:
|
||||
void cleanupNodes();
|
||||
void mirrorChange() override;
|
||||
|
||||
qreal getImplicitWidth() const override final;
|
||||
qreal getImplicitHeight() const override final;
|
||||
|
||||
void implicitWidthChanged() override final;
|
||||
void implicitHeightChanged() override final;
|
||||
|
||||
void updateImplicitSize( bool doNotify );
|
||||
|
||||
void setImplicitSize( qreal width, qreal height, bool doNotify );
|
||||
|
||||
private:
|
||||
Q_DECLARE_PUBLIC( QskQuickItem )
|
||||
|
||||
quint16 controlFlags;
|
||||
quint16 controlFlagsMask;
|
||||
|
||||
bool polishOnResize : 1;
|
||||
|
||||
bool blockedPolish : 1;
|
||||
bool blockedImplicitSize : 1;
|
||||
bool clearPreviousNodes : 1;
|
||||
|
||||
bool isInitiallyPainted : 1;
|
||||
|
||||
protected:
|
||||
mutable bool blockLayoutRequestEvents : 1;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "QskSetup.h"
|
||||
#include "QskControl.h"
|
||||
#include "QskControlPrivate.h"
|
||||
#include "QskGraphicProviderMap.h"
|
||||
#include "QskObjectTree.h"
|
||||
#include "QskSkin.h"
|
||||
|
|
@ -73,7 +74,6 @@ static void qskApplicationFilter()
|
|||
Q_CONSTRUCTOR_FUNCTION( qskApplicationHook )
|
||||
Q_COREAPP_STARTUP_FUNCTION( qskApplicationFilter )
|
||||
|
||||
extern bool qskInheritLocale( QskControl*, const QLocale& );
|
||||
extern bool qskInheritLocale( QskWindow*, const QLocale& );
|
||||
|
||||
namespace
|
||||
|
|
@ -90,7 +90,7 @@ namespace
|
|||
bool setImplicitValue( QskControl* control,
|
||||
const QLocale& locale ) override
|
||||
{
|
||||
return qskInheritLocale( control, locale );
|
||||
return QskControlPrivate::inheritLocale( control, locale );
|
||||
}
|
||||
|
||||
bool setImplicitValue( QskWindow* window,
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ HEADERS += \
|
|||
controls/QskBox.h \
|
||||
controls/QskBoxSkinlet.h \
|
||||
controls/QskControl.h \
|
||||
controls/QskControlPrivate.h \
|
||||
controls/QskDirtyItemFilter.h \
|
||||
controls/QskEvent.h \
|
||||
controls/QskFlickAnimator.h \
|
||||
|
|
@ -133,6 +134,8 @@ HEADERS += \
|
|||
controls/QskPushButton.h \
|
||||
controls/QskPushButtonSkinlet.h \
|
||||
controls/QskQuick.h \
|
||||
controls/QskQuickItem.h \
|
||||
controls/QskQuickItemPrivate.h \
|
||||
controls/QskRangeControl.h \
|
||||
controls/QskScrollArea.h \
|
||||
controls/QskScrollView.h \
|
||||
|
|
@ -175,6 +178,7 @@ SOURCES += \
|
|||
controls/QskBox.cpp \
|
||||
controls/QskBoxSkinlet.cpp \
|
||||
controls/QskControl.cpp \
|
||||
controls/QskControlPrivate.cpp \
|
||||
controls/QskDirtyItemFilter.cpp \
|
||||
controls/QskEvent.cpp \
|
||||
controls/QskFlickAnimator.cpp \
|
||||
|
|
@ -197,6 +201,8 @@ SOURCES += \
|
|||
controls/QskPushButton.cpp \
|
||||
controls/QskPushButtonSkinlet.cpp \
|
||||
controls/QskQuick.cpp \
|
||||
controls/QskQuickItem.cpp \
|
||||
controls/QskQuickItemPrivate.cpp \
|
||||
controls/QskRangeControl.cpp \
|
||||
controls/QskScrollArea.cpp \
|
||||
controls/QskScrollView.cpp \
|
||||
|
|
|
|||
Loading…
Reference in New Issue