2017-07-21 18:21:34 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskControl.h"
|
|
|
|
#include "QskAspect.h"
|
2019-04-24 08:39:13 +02:00
|
|
|
#include "QskFunctions.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
#include "QskDirtyItemFilter.h"
|
2018-08-03 08:15:28 +02:00
|
|
|
#include "QskEvent.h"
|
|
|
|
#include "QskQuick.h"
|
|
|
|
#include "QskSetup.h"
|
2018-07-19 14:10:48 +02:00
|
|
|
#include "QskSkin.h"
|
2019-04-25 14:23:39 +02:00
|
|
|
#include "QskSkinlet.h"
|
2018-08-03 08:15:28 +02:00
|
|
|
#include "QskSkinHintTable.h"
|
2019-04-26 18:09:59 +02:00
|
|
|
#include "QskLayoutConstraint.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
#include <qglobalstatic.h>
|
2018-07-19 14:10:48 +02:00
|
|
|
#include <qlocale.h>
|
|
|
|
#include <qvector.h>
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
QSK_QT_PRIVATE_BEGIN
|
|
|
|
#include <private/qquickitem_p.h>
|
|
|
|
#if defined( QT_DEBUG )
|
|
|
|
#include <private/qquickpositioners_p.h>
|
|
|
|
#endif
|
|
|
|
QSK_QT_PRIVATE_END
|
|
|
|
|
|
|
|
#include <limits>
|
2017-12-14 09:41:10 +01:00
|
|
|
#include <unordered_set>
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2019-04-02 17:50:08 +02:00
|
|
|
QSK_SYSTEM_STATE( QskControl, Disabled, QskAspect::FirstSystemState )
|
|
|
|
QSK_SYSTEM_STATE( QskControl, Hovered, QskAspect::LastSystemState >> 1 )
|
|
|
|
QSK_SYSTEM_STATE( QskControl, Focused, QskAspect::LastSystemState )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2018-05-08 10:34:00 +02:00
|
|
|
// QGridLayoutEngine internally uses FLT_MAX
|
|
|
|
static constexpr qreal qskSizeHintMax = std::numeric_limits< float >::max();
|
2018-08-03 08:15:28 +02:00
|
|
|
static QSizeF qskDefaultSizeHints[ 3 ] =
|
2018-05-08 10:34:00 +02:00
|
|
|
{ { 0, 0 }, { -1, -1 }, { qskSizeHintMax, qskSizeHintMax } };
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
typedef quint16 controlFlags_t;
|
|
|
|
|
2017-12-14 09:41:10 +01:00
|
|
|
void qskResolveLocale( QskControl* ); // not static as being used from outside !
|
|
|
|
static void qskUpdateControlFlags( QskControl::Flags, QskControl* );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-12-12 20:02:48 +01:00
|
|
|
static inline void qskSendEventTo( QObject* object, QEvent::Type type )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
QEvent event( type );
|
|
|
|
QCoreApplication::sendEvent( object, &event );
|
|
|
|
}
|
|
|
|
|
2017-12-12 20:02:48 +01:00
|
|
|
static inline controlFlags_t qskControlFlags()
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
// we are only interested in the first 8 bits
|
|
|
|
return static_cast< controlFlags_t >( qskSetup->controlFlags() );
|
|
|
|
}
|
|
|
|
|
2017-12-12 20:02:48 +01:00
|
|
|
static inline void qskFilterWindow( QQuickWindow* window )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
if ( window == nullptr )
|
|
|
|
return;
|
|
|
|
|
|
|
|
static QskDirtyItemFilter itemFilter;
|
|
|
|
itemFilter.addWindow( window );
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
A helper class to store the released window to be able to
|
|
|
|
put it later into the WindowChange event.
|
|
|
|
*/
|
|
|
|
class QskWindowStore
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
|
|
|
QskWindowStore()
|
|
|
|
: m_refCount( 0 )
|
|
|
|
, m_window( nullptr )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
private:
|
2017-07-21 18:21:34 +02:00
|
|
|
int m_refCount;
|
|
|
|
QQuickWindow* m_window;
|
|
|
|
};
|
2017-12-14 09:41:10 +01:00
|
|
|
|
|
|
|
class QskControlRegistry
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
2017-12-14 09:41:10 +01:00
|
|
|
QskControlRegistry()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
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,
|
2018-08-03 11:11:42 +02:00
|
|
|
qskSetup, [ this ] { updateControlFlags(); } );
|
2017-12-14 09:41:10 +01:00
|
|
|
|
|
|
|
QObject::connect( qskSetup, &QskSetup::skinChanged,
|
2018-08-03 11:11:42 +02:00
|
|
|
qskSetup, [ this ] { updateSkin(); } );
|
2017-12-14 09:41:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void insert( QskControl* control )
|
|
|
|
{
|
|
|
|
m_controls.insert( control );
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void remove( QskControl* control )
|
|
|
|
{
|
|
|
|
m_controls.erase( control );
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateControlFlags()
|
|
|
|
{
|
|
|
|
const auto flags = static_cast< QskControl::Flags >( qskControlFlags() );
|
|
|
|
|
|
|
|
for ( auto control : m_controls )
|
|
|
|
qskUpdateControlFlags( flags, control );
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateSkin()
|
|
|
|
{
|
|
|
|
QEvent event( QEvent::StyleChange );
|
|
|
|
|
|
|
|
for ( auto control : m_controls )
|
|
|
|
{
|
|
|
|
event.setAccepted( true );
|
|
|
|
QCoreApplication::sendEvent( control, &event );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
private:
|
2017-12-14 09:41:10 +01:00
|
|
|
std::unordered_set< QskControl* > m_controls;
|
|
|
|
};
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2017-10-30 14:38:30 +01:00
|
|
|
Q_GLOBAL_STATIC( QskWindowStore, qskReleasedWindowCounter )
|
2017-12-14 09:41:10 +01:00
|
|
|
Q_GLOBAL_STATIC( QskControlRegistry, qskRegistry )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2018-10-18 15:50:09 +02:00
|
|
|
/*
|
|
|
|
QQuickItemPrivate somehow implies, that it is about private data,
|
|
|
|
but it is only the part of the public API, that does not fall
|
|
|
|
under the Qt binary compatibility rules.
|
|
|
|
|
|
|
|
Actually QQuickItemPrivate puts everything into its public section
|
|
|
|
and classes - even from totally different modules like QC2 -
|
|
|
|
are manipulating its members in a totally unguarded way
|
|
|
|
|
|
|
|
While hacking internals of QQuickItemPrivate can't be considered
|
|
|
|
being acceptable for any standards of software engineering
|
|
|
|
we need to do the same to convince QQuickItem/QuickWindow to do what we
|
|
|
|
need.
|
|
|
|
|
|
|
|
This is not the way how we want to create APIs in QSkinny, but that
|
|
|
|
does not mean, that the D-Pointer concept is bad in general:
|
|
|
|
it allows to allocate private data of base and derived class
|
|
|
|
together.
|
|
|
|
|
|
|
|
At the moment QSkinny uses D-Pointer only, when deriving from
|
|
|
|
Qt classes, but does not expose these private data to the public.
|
|
|
|
Once QSkinny is in a stable state this might be changed - but
|
|
|
|
without compromising the privacy of its members.
|
|
|
|
*/
|
2017-12-07 17:04:05 +01:00
|
|
|
class QskControlPrivate final : public QQuickItemPrivate
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2018-03-24 18:05:57 +01:00
|
|
|
Q_DECLARE_PUBLIC( QskControl )
|
2017-10-25 14:53:49 +02:00
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
2018-05-08 10:34:00 +02:00
|
|
|
class ExplicitSizeData
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
|
|
|
QSizeF sizeHints[ 3 ] =
|
|
|
|
{ qskDefaultSizeHints[ 0 ], qskDefaultSizeHints[ 1 ], qskDefaultSizeHints[ 2 ] };
|
2018-05-08 10:34:00 +02:00
|
|
|
};
|
|
|
|
|
2018-11-25 12:52:37 +01:00
|
|
|
QskControlPrivate();
|
|
|
|
~QskControlPrivate() override;
|
2017-12-12 20:02:48 +01:00
|
|
|
|
2018-11-25 12:52:37 +01:00
|
|
|
void mirrorChange() override;
|
2017-12-12 20:02:48 +01:00
|
|
|
|
2018-07-31 17:32:25 +02:00
|
|
|
qreal getImplicitWidth() const override;
|
|
|
|
qreal getImplicitHeight() const override;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2018-11-26 08:50:44 +01:00
|
|
|
void updateImplicitSize( bool doNotify );
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// can we do something useful with overloading ???
|
2018-07-31 17:32:25 +02:00
|
|
|
QSGTransformNode* createTransformNode() override;
|
2017-07-21 18:21:34 +02:00
|
|
|
#endif
|
|
|
|
|
2018-11-25 12:52:37 +01:00
|
|
|
void implicitWidthChanged() override;
|
|
|
|
void implicitHeightChanged() override;
|
2017-12-12 20:02:48 +01:00
|
|
|
|
2018-11-25 16:35:06 +01:00
|
|
|
void setExplicitSizeHint( Qt::SizeHint, const QSizeF& );
|
|
|
|
QSizeF explicitSizeHint( Qt::SizeHint ) const;
|
2017-12-12 20:02:48 +01:00
|
|
|
|
2018-11-26 08:50:44 +01:00
|
|
|
bool maybeGesture( QQuickItem*, QEvent* );
|
2018-11-25 16:35:06 +01:00
|
|
|
void updateControlFlags( QskControl::Flags );
|
2017-12-14 09:41:10 +01:00
|
|
|
|
2018-10-18 15:50:09 +02:00
|
|
|
/*
|
|
|
|
Qt 5.11:
|
|
|
|
sizeof( QQuickItemPrivate::ExtraData ) -> 184
|
|
|
|
sizeof( QQuickItemPrivate ) -> 320
|
|
|
|
|
|
|
|
sizeof( QskControlPrivate ) -> sizeof( QQuickItemPrivate ) + 32
|
|
|
|
sizeof( QskSkinnable::PrivateData ) -> 40
|
|
|
|
|
|
|
|
( these numbers include pointers to optional extra data, that might
|
|
|
|
increase the effective memory footprint, when being accurate ).
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
private:
|
2018-11-25 12:52:37 +01:00
|
|
|
void implicitSizeChanged();
|
2018-11-26 08:50:44 +01:00
|
|
|
void setImplicitSize( qreal width, qreal height, bool doNotify );
|
2018-11-25 12:52:37 +01:00
|
|
|
|
2018-05-08 10:34:00 +02:00
|
|
|
ExplicitSizeData* explicitSizeData;
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
2017-10-25 14:53:49 +02:00
|
|
|
QLocale locale;
|
2017-12-05 13:10:17 +01:00
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
quint16 controlFlags;
|
|
|
|
quint16 controlFlagsMask;
|
|
|
|
|
2019-06-20 11:45:32 +02:00
|
|
|
QskSizePolicy sizePolicy;
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
bool explicitLocale : 1;
|
2017-12-05 13:10:17 +01:00
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
bool autoFillBackground : 1;
|
|
|
|
bool autoLayoutChildren : 1;
|
2019-05-12 12:26:34 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
This one is about calling updateLayout whenever layoutRect()
|
|
|
|
has changed -> whe should find a better name: TODO
|
|
|
|
*/
|
2017-10-25 14:53:49 +02:00
|
|
|
bool polishOnResize : 1;
|
2017-12-05 13:10:17 +01:00
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
bool blockedPolish : 1;
|
|
|
|
bool blockedImplicitSize : 1;
|
|
|
|
bool clearPreviousNodes : 1;
|
2017-12-05 13:10:17 +01:00
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
bool isInitiallyPainted : 1;
|
|
|
|
|
|
|
|
uint focusPolicy : 4;
|
2017-12-05 13:10:17 +01:00
|
|
|
bool isWheelEnabled : 1;
|
2017-10-25 14:53:49 +02:00
|
|
|
};
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2018-11-26 08:50:44 +01:00
|
|
|
static inline void qskUpdateControlFlags( QskControl::Flags flags, QskControl* control )
|
2018-01-24 10:14:50 +01:00
|
|
|
{
|
|
|
|
auto d = static_cast< QskControlPrivate* >( QQuickItemPrivate::get( control ) );
|
|
|
|
d->updateControlFlags( flags );
|
|
|
|
}
|
|
|
|
|
2018-11-25 12:52:37 +01:00
|
|
|
QskControlPrivate::QskControlPrivate()
|
|
|
|
: explicitSizeData( nullptr )
|
|
|
|
, controlFlags( qskControlFlags() )
|
|
|
|
, controlFlagsMask( 0 )
|
2019-06-20 11:45:32 +02:00
|
|
|
, sizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Preferred )
|
2018-11-25 12:52:37 +01:00
|
|
|
, explicitLocale( false )
|
|
|
|
, autoFillBackground( false )
|
|
|
|
, autoLayoutChildren( false )
|
|
|
|
, polishOnResize( false )
|
|
|
|
, blockedPolish( false )
|
|
|
|
, blockedImplicitSize( true )
|
|
|
|
, clearPreviousNodes( false )
|
|
|
|
, isInitiallyPainted( false )
|
|
|
|
, focusPolicy( Qt::NoFocus )
|
|
|
|
, isWheelEnabled( false )
|
|
|
|
{
|
|
|
|
if ( controlFlags & QskControl::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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskControlPrivate::~QskControlPrivate()
|
|
|
|
{
|
|
|
|
delete explicitSizeData;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControlPrivate::mirrorChange()
|
|
|
|
{
|
|
|
|
Q_Q( QskControl );
|
|
|
|
qskSendEventTo( q, QEvent::LayoutDirectionChange );
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void QskControlPrivate::implicitSizeChanged()
|
|
|
|
{
|
2018-11-26 08:50:44 +01:00
|
|
|
blockedImplicitSize = false;
|
|
|
|
|
2018-11-25 12:52:37 +01:00
|
|
|
Q_Q( QskControl );
|
|
|
|
if ( !q->explicitSizeHint( Qt::PreferredSize ).isValid() )
|
|
|
|
{
|
|
|
|
// when we have no PreferredSize we fall back
|
|
|
|
// to the implicit size
|
|
|
|
|
|
|
|
q->layoutConstraintChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-26 08:50:44 +01:00
|
|
|
qreal QskControlPrivate::getImplicitWidth() const
|
|
|
|
{
|
|
|
|
if ( blockedImplicitSize )
|
|
|
|
{
|
|
|
|
auto that = const_cast< QskControlPrivate* >( this );
|
|
|
|
that->updateImplicitSize( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
return implicitWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal QskControlPrivate::getImplicitHeight() const
|
|
|
|
{
|
|
|
|
if ( blockedImplicitSize )
|
|
|
|
{
|
|
|
|
auto that = const_cast< QskControlPrivate* >( this );
|
|
|
|
that->updateImplicitSize( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
return implicitHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControlPrivate::updateImplicitSize( bool doNotify )
|
|
|
|
{
|
|
|
|
Q_Q( const QskControl );
|
|
|
|
|
|
|
|
blockedImplicitSize = false;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
setImplicitSize( w, h, doNotify );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControlPrivate::setImplicitSize( qreal w, qreal h, bool doNotify )
|
|
|
|
{
|
|
|
|
const bool doWidth = ( w != implicitWidth );
|
2019-03-21 14:07:00 +01:00
|
|
|
const bool doHeight = ( h != implicitHeight );
|
2018-11-26 08:50:44 +01:00
|
|
|
|
|
|
|
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( QskControl );
|
|
|
|
q->geometryChanged( newRect, oldRect );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( doNotify )
|
|
|
|
{
|
|
|
|
if ( doWidth )
|
|
|
|
QQuickItemPrivate::implicitWidthChanged();
|
|
|
|
|
|
|
|
if ( doHeight )
|
|
|
|
QQuickItemPrivate::implicitHeightChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-25 12:52:37 +01:00
|
|
|
void QskControlPrivate::implicitWidthChanged()
|
|
|
|
{
|
|
|
|
QQuickItemPrivate::implicitWidthChanged();
|
2018-11-26 08:50:44 +01:00
|
|
|
implicitSizeChanged();
|
2018-11-25 12:52:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControlPrivate::implicitHeightChanged()
|
|
|
|
{
|
|
|
|
QQuickItemPrivate::implicitWidthChanged();
|
2018-11-26 08:50:44 +01:00
|
|
|
implicitSizeChanged();
|
2018-11-25 12:52:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void QskControlPrivate::setExplicitSizeHint(
|
|
|
|
Qt::SizeHint whichHint, const QSizeF& size )
|
|
|
|
{
|
|
|
|
if ( explicitSizeData == nullptr )
|
|
|
|
explicitSizeData = new ExplicitSizeData;
|
|
|
|
|
|
|
|
explicitSizeData->sizeHints[ whichHint ] = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline QSizeF QskControlPrivate::explicitSizeHint( Qt::SizeHint whichHint ) const
|
|
|
|
{
|
|
|
|
if ( explicitSizeData )
|
|
|
|
return explicitSizeData->sizeHints[ whichHint ];
|
|
|
|
|
|
|
|
return qskDefaultSizeHints[ 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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControlPrivate::updateControlFlags( QskControl::Flags flags )
|
|
|
|
{
|
|
|
|
Q_Q( QskControl );
|
|
|
|
|
|
|
|
const auto oldFlags = controlFlags;
|
|
|
|
const auto newFlags = static_cast< controlFlags_t >( flags );
|
|
|
|
|
|
|
|
if ( oldFlags != newFlags )
|
|
|
|
{
|
|
|
|
const auto numBits = qCountTrailingZeroBits(
|
|
|
|
static_cast< quint32 >( QskControl::LastFlag ) );
|
|
|
|
|
|
|
|
for ( quint32 i = 0; i <= numBits; ++i )
|
|
|
|
{
|
|
|
|
const quint32 flag = ( 1 << i );
|
|
|
|
q->updateControlFlag( flag, flags & flag );
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_EMIT q->controlFlagsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
QskControl::QskControl( QQuickItem* parent )
|
|
|
|
: Inherited( *( new QskControlPrivate() ), parent )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
setFlag( QQuickItem::ItemHasContents, true );
|
2017-10-24 19:32:54 +02:00
|
|
|
QQuickItem::setActiveFocusOnTab( false );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
if ( parent )
|
|
|
|
{
|
|
|
|
// inheriting attributes from parent
|
|
|
|
qskResolveLocale( this );
|
|
|
|
}
|
|
|
|
|
2017-12-14 09:41:10 +01:00
|
|
|
// since Qt 5.10 we have QQuickItem::ItemEnabledHasChanged
|
2018-05-01 12:26:59 +02:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK( 5, 10, 0 )
|
2017-12-12 20:02:48 +01:00
|
|
|
/*
|
2017-12-14 09:41:10 +01:00
|
|
|
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.
|
2017-12-12 20:02:48 +01:00
|
|
|
*/
|
2017-12-14 09:41:10 +01:00
|
|
|
connect( this, &QQuickItem::enabledChanged,
|
2018-08-03 08:15:28 +02:00
|
|
|
[ this ] { setSkinStateFlag( Disabled, !isEnabled() ); } );
|
2017-12-12 20:02:48 +01:00
|
|
|
#endif
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-12-12 20:02:48 +01:00
|
|
|
Q_D( QskControl );
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( d->controlFlags & QskControl::DeferredUpdate )
|
2017-07-21 18:21:34 +02:00
|
|
|
qskFilterWindow( window() );
|
2017-12-14 09:41:10 +01:00
|
|
|
|
|
|
|
qskRegistry->insert( this );
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
QskControl::~QskControl()
|
|
|
|
{
|
2019-04-18 16:12:33 +02:00
|
|
|
#if defined( QT_DEBUG )
|
|
|
|
if ( auto w = window() )
|
|
|
|
{
|
|
|
|
// to catch suicide situations as a result of mouse clicks
|
|
|
|
Q_ASSERT( this != w->mouseGrabberItem() );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-12-14 09:41:10 +01:00
|
|
|
if ( qskRegistry )
|
|
|
|
qskRegistry->remove( this );
|
2018-01-24 10:14:50 +01:00
|
|
|
|
2019-01-09 10:08:31 +01:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK( 5, 10, 0 )
|
|
|
|
disconnect( this, &QQuickItem::enabledChanged, nullptr, nullptr );
|
|
|
|
#endif
|
|
|
|
|
2018-01-24 10:14:50 +01:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
Q_D( QskControl );
|
|
|
|
d->componentComplete = false;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* QskControl::className() const
|
|
|
|
{
|
|
|
|
return metaObject()->className();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setVisible( bool on )
|
|
|
|
{
|
|
|
|
// QQuickItem::setVisible is no slot
|
|
|
|
Inherited::setVisible( on );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::show()
|
|
|
|
{
|
|
|
|
Inherited::setVisible( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::hide()
|
|
|
|
{
|
|
|
|
Inherited::setVisible( false );
|
|
|
|
}
|
|
|
|
|
2018-06-26 11:10:44 +02:00
|
|
|
bool QskControl::isVisibleTo( const QQuickItem* ancestor ) const
|
|
|
|
{
|
|
|
|
return qskIsVisibleTo( this, ancestor );
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
void QskControl::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 );
|
|
|
|
|
2018-03-24 18:05:57 +01:00
|
|
|
/*
|
|
|
|
Unfortunately geometryChanged is protected and we can't implement
|
|
|
|
this code as qskSetItemGeometry - further hacking required: TODO ...
|
|
|
|
*/
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
geometryChanged( QRectF( d->x, d->y, d->width, d->height ), oldRect );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-07 19:30:34 +01:00
|
|
|
QRectF QskControl::rect() const
|
|
|
|
{
|
|
|
|
Q_D( const QskControl );
|
|
|
|
return QRectF( 0, 0, d->width, d->height );
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
QRectF QskControl::geometry() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( const QskControl );
|
2017-07-21 18:21:34 +02:00
|
|
|
return QRectF( d->x, d->y, d->width, d->height );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setAutoFillBackground( bool on )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
if ( on != d->autoFillBackground )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
d->autoFillBackground = on;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
update();
|
|
|
|
Q_EMIT controlFlagsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::autoFillBackground() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->autoFillBackground;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setAutoLayoutChildren( bool on )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
if ( on != d->autoLayoutChildren )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
d->autoLayoutChildren = on;
|
2017-07-21 18:21:34 +02:00
|
|
|
if ( on )
|
|
|
|
polish();
|
|
|
|
|
|
|
|
Q_EMIT controlFlagsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::autoLayoutChildren() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->autoLayoutChildren;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setTransparentForPositioner( bool on )
|
|
|
|
{
|
|
|
|
Q_D( QskControl );
|
|
|
|
if ( on != d->isTransparentForPositioner() )
|
|
|
|
{
|
|
|
|
d->setTransparentForPositioner( on );
|
|
|
|
Q_EMIT controlFlagsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::isTransparentForPositioner() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->isTransparentForPositioner();
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setPolishOnResize( bool on )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
if ( on != d->polishOnResize )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
d->polishOnResize = on;
|
2017-07-21 18:21:34 +02:00
|
|
|
polish();
|
|
|
|
|
|
|
|
Q_EMIT controlFlagsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::polishOnResize() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->polishOnResize;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2017-10-24 19:32:54 +02:00
|
|
|
void QskControl::setWheelEnabled( bool on )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
if ( on != d->isWheelEnabled )
|
2017-10-24 19:32:54 +02:00
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
d->isWheelEnabled = on;
|
|
|
|
Q_EMIT wheelEnabledChanged();
|
2017-10-24 19:32:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::isWheelEnabled() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->isWheelEnabled;
|
2017-10-24 19:32:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setFocusPolicy( Qt::FocusPolicy policy )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
if ( policy != d->focusPolicy )
|
2017-10-24 19:32:54 +02:00
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
d->focusPolicy = policy & ~Qt::TabFocus;
|
2017-10-24 19:32:54 +02:00
|
|
|
QQuickItem::setActiveFocusOnTab( policy & Qt::TabFocus );
|
|
|
|
|
2017-10-30 08:33:43 +01:00
|
|
|
Q_EMIT focusPolicyChanged();
|
2017-10-24 19:32:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::FocusPolicy QskControl::focusPolicy() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
uint policy = d_func()->focusPolicy;
|
2017-10-24 19:32:54 +02:00
|
|
|
if ( activeFocusOnTab() )
|
|
|
|
policy |= Qt::TabFocus;
|
|
|
|
|
|
|
|
return static_cast< Qt::FocusPolicy >( policy );
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
void QskControl::setTabFence( bool on )
|
|
|
|
{
|
|
|
|
Q_D( QskControl );
|
|
|
|
if ( on != d->isTabFence )
|
|
|
|
{
|
|
|
|
d->isTabFence = on;
|
|
|
|
Q_EMIT controlFlagsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::isTabFence() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->isTabFence;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QskControl::Flags QskControl::controlFlags() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return QskControl::Flags( d_func()->controlFlags );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setControlFlags( Flags flags )
|
|
|
|
{
|
2017-12-14 09:41:10 +01:00
|
|
|
Q_D( QskControl );
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
// set all bits in the mask
|
2017-12-14 09:41:10 +01:00
|
|
|
d->controlFlagsMask = std::numeric_limits< controlFlags_t >::max();
|
|
|
|
d->updateControlFlags( flags );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::resetControlFlags()
|
|
|
|
{
|
2017-12-14 09:41:10 +01:00
|
|
|
Q_D( QskControl );
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
// clear all bits in the mask
|
2017-12-14 09:41:10 +01:00
|
|
|
d->controlFlagsMask = 0;
|
|
|
|
d->updateControlFlags( static_cast< Flags >( qskControlFlags() ) );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setControlFlag( Flag flag, bool on )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
d->controlFlagsMask |= flag;
|
|
|
|
|
|
|
|
if ( ( d->controlFlags & flag ) != on )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
updateControlFlag( flag, on );
|
|
|
|
Q_EMIT controlFlagsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::resetControlFlag( Flag flag )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
d->controlFlagsMask &= ~flag;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
const bool on = qskSetup->testControlFlag( static_cast< QskSetup::Flag >( flag ) );
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( ( d->controlFlags & flag ) != on )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
updateControlFlag( flag, on );
|
|
|
|
Q_EMIT controlFlagsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::testControlFlag( Flag flag ) const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->controlFlags & flag;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::updateControlFlag( uint flag, bool on )
|
|
|
|
{
|
|
|
|
Q_D( QskControl );
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
if ( ( flag > std::numeric_limits< controlFlags_t >::max() ) ||
|
2019-01-07 09:13:53 +01:00
|
|
|
( bool( d->controlFlags & flag ) == on ) )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( on )
|
2017-10-25 14:53:49 +02:00
|
|
|
d->controlFlags |= flag;
|
2017-07-21 18:21:34 +02:00
|
|
|
else
|
2017-10-25 14:53:49 +02:00
|
|
|
d->controlFlags &= ~flag;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
switch ( flag )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
case QskControl::DeferredUpdate:
|
|
|
|
{
|
|
|
|
if ( on )
|
|
|
|
{
|
|
|
|
qskFilterWindow( window() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( !isVisible() )
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QskControl::DeferredPolish:
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( !on && d->blockedPolish )
|
2017-07-21 18:21:34 +02:00
|
|
|
polish();
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QskControl::DeferredLayout:
|
|
|
|
{
|
|
|
|
if ( !on )
|
|
|
|
{
|
|
|
|
// Update the implicitSize and rebind the size to it.
|
|
|
|
// Having set the size explicitly gets lost.
|
|
|
|
|
|
|
|
d->widthValid = d->heightValid = false;
|
2018-11-26 08:50:44 +01:00
|
|
|
d->updateImplicitSize( false );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QskControl::CleanupOnVisibility:
|
|
|
|
{
|
|
|
|
if ( on && !isVisible() )
|
|
|
|
cleanupNodes();
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QskControl::DebugForceBackground:
|
|
|
|
{
|
|
|
|
// no need to mark it dirty
|
2018-07-13 08:37:44 +02:00
|
|
|
if ( flags() & QQuickItem::ItemHasContents )
|
|
|
|
update();
|
2017-07-21 18:21:34 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setBackgroundColor( const QColor& color )
|
|
|
|
{
|
|
|
|
setAutoFillBackground( true );
|
2017-10-17 17:34:00 +02:00
|
|
|
setBackground( QskGradient( color ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setBackground( const QskGradient& gradient )
|
|
|
|
{
|
|
|
|
using namespace QskAspect;
|
|
|
|
const Aspect aspect = Control | Color;
|
|
|
|
|
2017-10-30 12:06:19 +01:00
|
|
|
if ( hintTable().gradient( aspect ) != gradient )
|
2017-10-17 17:34:00 +02:00
|
|
|
{
|
|
|
|
setGradientHint( aspect, gradient );
|
2017-10-30 12:06:19 +01:00
|
|
|
if ( autoFillBackground() )
|
|
|
|
update();
|
|
|
|
|
|
|
|
Q_EMIT backgroundChanged();
|
2017-10-17 17:34:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::resetBackground()
|
|
|
|
{
|
|
|
|
using namespace QskAspect;
|
|
|
|
const Aspect aspect = Control | Color;
|
|
|
|
|
|
|
|
auto& table = hintTable();
|
|
|
|
|
2017-10-30 12:06:19 +01:00
|
|
|
if ( table.hint( aspect ).isValid() )
|
2017-10-17 17:34:00 +02:00
|
|
|
{
|
|
|
|
table.removeHint( aspect );
|
2017-10-30 12:06:19 +01:00
|
|
|
|
|
|
|
update();
|
|
|
|
Q_EMIT backgroundChanged();
|
2017-10-17 17:34:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskGradient QskControl::background() const
|
|
|
|
{
|
|
|
|
using namespace QskAspect;
|
|
|
|
return gradientHint( Control );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setMargins( qreal margin )
|
|
|
|
{
|
|
|
|
setMargins( QMarginsF( margin, margin, margin, margin ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setMargins( const QMarginsF& margins )
|
|
|
|
{
|
|
|
|
using namespace QskAspect;
|
|
|
|
|
|
|
|
const Subcontrol subControl = effectiveSubcontrol( QskAspect::Control );
|
|
|
|
|
|
|
|
const QMarginsF m(
|
|
|
|
qMax( qreal( margins.left() ), qreal( 0.0 ) ),
|
|
|
|
qMax( qreal( margins.top() ), qreal( 0.0 ) ),
|
|
|
|
qMax( qreal( margins.right() ), qreal( 0.0 ) ),
|
|
|
|
qMax( qreal( margins.bottom() ), qreal( 0.0 ) ) );
|
|
|
|
|
|
|
|
if ( m != this->margins() )
|
|
|
|
{
|
2017-08-23 14:53:29 +02:00
|
|
|
setMarginsHint( subControl | Margin, m );
|
2017-07-21 18:21:34 +02:00
|
|
|
resetImplicitSize();
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( const QskControl );
|
|
|
|
if ( d->polishOnResize || d->autoLayoutChildren )
|
2017-07-21 18:21:34 +02:00
|
|
|
polish();
|
|
|
|
|
|
|
|
qskSendEventTo( this, QEvent::ContentsRectChange );
|
2017-10-30 08:48:49 +01:00
|
|
|
Q_EMIT marginsChanged();
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::resetMargins()
|
|
|
|
{
|
2017-10-17 17:34:00 +02:00
|
|
|
using namespace QskAspect;
|
|
|
|
const Aspect aspect = Control | Metric | Margin;
|
|
|
|
|
|
|
|
const auto oldMargin = marginsHint( aspect );
|
|
|
|
|
|
|
|
auto& table = hintTable();
|
|
|
|
if ( table.hint( aspect ).isValid() )
|
|
|
|
{
|
|
|
|
table.removeHint( aspect );
|
|
|
|
if ( marginsHint( aspect ) != oldMargin )
|
|
|
|
{
|
|
|
|
resetImplicitSize();
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( const QskControl );
|
|
|
|
if ( d->polishOnResize || d->autoLayoutChildren )
|
2017-10-17 17:34:00 +02:00
|
|
|
polish();
|
|
|
|
|
|
|
|
qskSendEventTo( this, QEvent::ContentsRectChange );
|
2017-10-30 08:48:49 +01:00
|
|
|
Q_EMIT marginsChanged();
|
2017-10-17 17:34:00 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QMarginsF QskControl::margins() const
|
|
|
|
{
|
2017-08-23 14:53:29 +02:00
|
|
|
return marginsHint( QskAspect::Control | QskAspect::Margin );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QRectF QskControl::contentsRect() const
|
|
|
|
{
|
2019-04-24 08:39:13 +02:00
|
|
|
return qskValidOrEmptyInnerRect( rect(), margins() );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2019-04-25 14:23:39 +02:00
|
|
|
QRectF QskControl::subControlRect( QskAspect::Subcontrol subControl ) const
|
|
|
|
{
|
|
|
|
return effectiveSkinlet()->subControlRect( this, contentsRect(), subControl );
|
|
|
|
}
|
|
|
|
|
2019-04-26 18:09:59 +02:00
|
|
|
QRectF QskControl::subControlRect(
|
|
|
|
const QSizeF& size, QskAspect::Subcontrol subControl ) const
|
|
|
|
{
|
|
|
|
QRectF rect( 0.0, 0.0, size.width(), size.height() );
|
|
|
|
rect = qskValidOrEmptyInnerRect( rect, margins() );
|
|
|
|
|
|
|
|
return effectiveSkinlet()->subControlRect( this, rect, subControl );
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
bool QskControl::layoutMirroring() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->effectiveLayoutMirror;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::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( QskControl );
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
if ( recursive != d->inheritMirrorFromItem )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
d->inheritMirrorFromItem = recursive;
|
|
|
|
d->resolveLayoutMirror();
|
|
|
|
}
|
|
|
|
|
|
|
|
d->isMirrorImplicit = false;
|
|
|
|
|
|
|
|
if ( on != d->effectiveLayoutMirror )
|
|
|
|
{
|
|
|
|
d->setLayoutMirror( on );
|
|
|
|
if ( recursive )
|
|
|
|
d->resolveLayoutMirror();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::resetLayoutMirroring()
|
|
|
|
{
|
|
|
|
Q_D( QskControl );
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
if ( d && !d->isMirrorImplicit )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
d->isMirrorImplicit = true;
|
2018-08-03 08:15:28 +02:00
|
|
|
// d->inheritMirrorFromItem = false;
|
2017-07-21 18:21:34 +02:00
|
|
|
d->resolveLayoutMirror();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QLocale QskControl::locale() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->locale;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setLocale( const QLocale& locale )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
d->explicitLocale = true;
|
|
|
|
|
|
|
|
if ( d->locale != locale )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
d->locale = locale;
|
2017-07-21 18:21:34 +02:00
|
|
|
qskSendEventTo( this, QEvent::LocaleChange );
|
|
|
|
qskSetup->inheritLocale( this, locale );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::resetLocale()
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
if ( d->explicitLocale )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
d->explicitLocale = false;
|
2017-07-21 18:21:34 +02:00
|
|
|
qskResolveLocale( this );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// not static as being called from QskSetup.cpp
|
|
|
|
bool qskInheritLocale( QskControl* control, const QLocale& locale )
|
|
|
|
{
|
2017-12-05 13:10:17 +01:00
|
|
|
auto d = static_cast< QskControlPrivate* >( QQuickItemPrivate::get( control ) );
|
2017-10-25 14:53:49 +02:00
|
|
|
|
|
|
|
if ( d->explicitLocale || d->locale == locale )
|
2018-04-12 13:07:58 +02:00
|
|
|
return true;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
d->locale = locale;
|
2017-07-21 18:21:34 +02:00
|
|
|
qskSendEventTo( control, QEvent::LocaleChange );
|
|
|
|
|
2018-04-12 13:07:58 +02:00
|
|
|
return false;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void qskResolveLocale( QskControl* control )
|
|
|
|
{
|
|
|
|
const QLocale locale = qskSetup->inheritedLocale( control );
|
|
|
|
|
2017-12-05 13:10:17 +01:00
|
|
|
auto d = static_cast< QskControlPrivate* >( QQuickItemPrivate::get( control ) );
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( d->locale != locale )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
d->locale = locale;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
qskSendEventTo( control, QEvent::LocaleChange );
|
2017-07-21 18:21:34 +02:00
|
|
|
qskSetup->inheritLocale( control, locale );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-08 10:34:00 +02:00
|
|
|
void QskControl::initSizePolicy(
|
|
|
|
QskSizePolicy::Policy horizontalPolicy,
|
|
|
|
QskSizePolicy::Policy verticalPolicy )
|
|
|
|
{
|
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
/*
|
|
|
|
In constructors of derived classes you don't need
|
|
|
|
to propagate changes by layoutConstraintChanged.
|
|
|
|
Sometimes it is even worse as the parent might not be
|
|
|
|
even prepared to handle the LayouRequest event.
|
|
|
|
*/
|
2018-08-03 08:15:28 +02:00
|
|
|
|
2018-05-08 10:34:00 +02:00
|
|
|
d->sizePolicy.setHorizontalPolicy( horizontalPolicy );
|
|
|
|
d->sizePolicy.setVerticalPolicy( verticalPolicy );
|
2019-06-19 13:25:29 +02:00
|
|
|
|
|
|
|
if ( horizontalPolicy == QskSizePolicy::Constrained
|
|
|
|
&& verticalPolicy == QskSizePolicy::Constrained )
|
|
|
|
{
|
|
|
|
qWarning( "QskControl::initSizePolicy: conflicting constraints");
|
|
|
|
}
|
2018-05-08 10:34:00 +02:00
|
|
|
}
|
|
|
|
|
2019-06-20 11:45:32 +02:00
|
|
|
void QskControl::setSizePolicy( QskSizePolicy policy )
|
2018-05-08 10:34:00 +02:00
|
|
|
{
|
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
if ( policy != d->sizePolicy )
|
|
|
|
{
|
|
|
|
d->sizePolicy = policy;
|
|
|
|
layoutConstraintChanged();
|
2019-06-19 13:25:29 +02:00
|
|
|
|
|
|
|
if ( policy.policy( Qt::Horizontal ) == QskSizePolicy::Constrained
|
|
|
|
&& policy.policy( Qt::Vertical ) == QskSizePolicy::Constrained )
|
|
|
|
{
|
|
|
|
qWarning( "QskControl::setSizePolicy: conflicting constraints");
|
|
|
|
}
|
2018-05-08 10:34:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setSizePolicy(
|
|
|
|
QskSizePolicy::Policy horizontalPolicy,
|
|
|
|
QskSizePolicy::Policy verticalPolicy )
|
|
|
|
{
|
|
|
|
setSizePolicy( QskSizePolicy( horizontalPolicy, verticalPolicy ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setSizePolicy(
|
|
|
|
Qt::Orientation orientation, QskSizePolicy::Policy policy )
|
|
|
|
{
|
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
if ( d->sizePolicy.policy( orientation ) != policy )
|
|
|
|
{
|
|
|
|
d->sizePolicy.setPolicy( orientation, policy );
|
|
|
|
layoutConstraintChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-20 11:45:32 +02:00
|
|
|
QskSizePolicy QskControl::sizePolicy() const
|
2018-05-08 10:34:00 +02:00
|
|
|
{
|
|
|
|
return d_func()->sizePolicy;
|
|
|
|
}
|
|
|
|
|
|
|
|
QskSizePolicy::Policy QskControl::sizePolicy( Qt::Orientation orientation ) const
|
|
|
|
{
|
|
|
|
return d_func()->sizePolicy.policy( orientation );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setPreferredSize( const QSizeF& size )
|
|
|
|
{
|
|
|
|
setExplicitSizeHint( Qt::PreferredSize, size );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setPreferredSize( qreal width, qreal height )
|
|
|
|
{
|
|
|
|
setPreferredSize( QSizeF( width, height ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setPreferredWidth( qreal width )
|
|
|
|
{
|
|
|
|
setPreferredSize( QSizeF( width, preferredSize().height() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setPreferredHeight( qreal height )
|
|
|
|
{
|
|
|
|
setPreferredSize( QSizeF( preferredSize().width(), height ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setMinimumSize( const QSizeF& size )
|
|
|
|
{
|
|
|
|
setExplicitSizeHint( Qt::MinimumSize, size );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setMinimumSize( qreal width, qreal height )
|
|
|
|
{
|
|
|
|
setMinimumSize( QSizeF( width, height ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setMinimumWidth( qreal width )
|
|
|
|
{
|
|
|
|
setMinimumSize( QSizeF( width, minimumSize().height() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setMinimumHeight( qreal height )
|
|
|
|
{
|
|
|
|
setMinimumSize( QSizeF( minimumSize().width(), height ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setMaximumSize( const QSizeF& size )
|
|
|
|
{
|
|
|
|
setExplicitSizeHint( Qt::MaximumSize, size );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setMaximumSize( qreal width, qreal height )
|
|
|
|
{
|
|
|
|
setMaximumSize( QSizeF( width, height ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setMaximumWidth( qreal width )
|
|
|
|
{
|
|
|
|
setMaximumSize( QSizeF( width, maximumSize().height() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setMaximumHeight( qreal height )
|
|
|
|
{
|
|
|
|
setMaximumSize( QSizeF( maximumSize().width(), height ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setFixedSize( const QSizeF& size )
|
|
|
|
{
|
|
|
|
const QSizeF newSize = size.expandedTo( QSizeF( 0, 0 ) );
|
|
|
|
|
|
|
|
const QskSizePolicy policy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
|
|
|
|
|
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
if ( policy != d->sizePolicy ||
|
|
|
|
d->explicitSizeHint( Qt::PreferredSize ) != newSize )
|
|
|
|
{
|
|
|
|
d->sizePolicy = policy;
|
|
|
|
d->setExplicitSizeHint( Qt::PreferredSize, newSize );
|
|
|
|
|
|
|
|
layoutConstraintChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setFixedSize( qreal width, qreal height )
|
|
|
|
{
|
|
|
|
setFixedSize( QSizeF( width, height ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setFixedWidth( qreal width )
|
|
|
|
{
|
|
|
|
if ( width < 0 )
|
|
|
|
width = 0;
|
|
|
|
|
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
auto size = d->explicitSizeHint( Qt::PreferredSize );
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
if ( ( d->sizePolicy.horizontalPolicy() != QskSizePolicy::Fixed ) ||
|
2019-01-04 13:42:16 +01:00
|
|
|
( size.width() != width ) )
|
2018-05-08 10:34:00 +02:00
|
|
|
{
|
|
|
|
size.setWidth( width );
|
|
|
|
|
|
|
|
d->sizePolicy.setHorizontalPolicy( QskSizePolicy::Fixed );
|
|
|
|
d->setExplicitSizeHint( Qt::PreferredSize, size );
|
|
|
|
|
|
|
|
layoutConstraintChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setFixedHeight( qreal height )
|
|
|
|
{
|
|
|
|
if ( height < 0 )
|
|
|
|
height = 0;
|
|
|
|
|
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
auto size = d->explicitSizeHint( Qt::PreferredSize );
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
if ( ( d->sizePolicy.verticalPolicy() != QskSizePolicy::Fixed ) ||
|
2019-01-04 13:42:16 +01:00
|
|
|
( size.height() != height ) )
|
2018-05-08 10:34:00 +02:00
|
|
|
{
|
|
|
|
size.setHeight( height );
|
|
|
|
|
|
|
|
d->sizePolicy.setVerticalPolicy( QskSizePolicy::Fixed );
|
|
|
|
d->setExplicitSizeHint( Qt::PreferredSize, size );
|
|
|
|
|
|
|
|
layoutConstraintChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::resetExplicitSizeHint( Qt::SizeHint whichHint )
|
|
|
|
{
|
|
|
|
if ( whichHint >= Qt::MinimumSize && whichHint <= Qt::MaximumSize )
|
|
|
|
setExplicitSizeHint( whichHint, qskDefaultSizeHints[ whichHint ] );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setExplicitSizeHint( Qt::SizeHint whichHint, const QSizeF& size )
|
|
|
|
{
|
|
|
|
if ( whichHint >= Qt::MinimumSize && whichHint <= Qt::MaximumSize )
|
|
|
|
{
|
|
|
|
const QSizeF newSize( ( size.width() < 0 ) ? -1.0 : size.width(),
|
2018-05-09 14:13:26 +02:00
|
|
|
( size.height() < 0 ) ? -1.0 : size.height() );
|
2018-05-08 10:34:00 +02:00
|
|
|
|
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
if ( newSize != d->explicitSizeHint( whichHint ) )
|
|
|
|
{
|
|
|
|
d->setExplicitSizeHint( whichHint, newSize );
|
|
|
|
layoutConstraintChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::setExplicitSizeHint( Qt::SizeHint whichHint, qreal width, qreal height )
|
|
|
|
{
|
|
|
|
setExplicitSizeHint( whichHint, QSizeF( width, height ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
QSizeF QskControl::explicitSizeHint( Qt::SizeHint whichHint ) const
|
|
|
|
{
|
|
|
|
if ( whichHint >= Qt::MinimumSize && whichHint <= Qt::MaximumSize )
|
|
|
|
return d_func()->explicitSizeHint( whichHint );
|
|
|
|
|
|
|
|
return QSizeF( -1, -1 );
|
|
|
|
}
|
|
|
|
|
2018-05-01 13:55:26 +02:00
|
|
|
QSizeF QskControl::effectiveSizeHint( Qt::SizeHint whichHint ) const
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize )
|
|
|
|
return QSizeF( 0, 0 );
|
|
|
|
|
2018-05-01 13:55:26 +02:00
|
|
|
QSizeF size = explicitSizeHint( whichHint );
|
|
|
|
|
|
|
|
if ( whichHint == Qt::PreferredSize && !size.isValid() )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2018-05-01 13:55:26 +02:00
|
|
|
// in most cases we don't have a preferred width/height
|
2017-07-21 18:21:34 +02:00
|
|
|
// and fall back to the implicit size.
|
|
|
|
|
2018-05-01 13:55:26 +02:00
|
|
|
if ( size.width() < 0 )
|
|
|
|
size.setWidth( implicitWidth() );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2018-05-01 13:55:26 +02:00
|
|
|
if ( size.height() < 0 )
|
|
|
|
size.setHeight( implicitHeight() );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2018-05-01 13:55:26 +02:00
|
|
|
return size;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::resetImplicitSize()
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
if ( d->controlFlags & QskControl::DeferredLayout )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2018-12-11 14:58:48 +01:00
|
|
|
/*
|
2019-01-04 13:42:16 +01:00
|
|
|
Is there a way to block consecutive calls ?
|
2018-12-11 14:58:48 +01:00
|
|
|
When the parent is requesting the preferred size, we could use
|
|
|
|
d->blockedImplicitSize, but in case of dynamic constraints we don't
|
|
|
|
have an indication when the event has been processed. TODO ...
|
|
|
|
*/
|
|
|
|
d->blockedImplicitSize = true;
|
|
|
|
layoutConstraintChanged();
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-26 08:50:44 +01:00
|
|
|
d->updateImplicitSize( true );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 13:55:26 +02:00
|
|
|
qreal QskControl::heightForWidth( qreal width ) const
|
|
|
|
{
|
2019-04-26 18:09:59 +02:00
|
|
|
if ( !d_func()->autoLayoutChildren )
|
|
|
|
return -1.0;
|
2018-06-12 08:19:28 +02:00
|
|
|
|
2019-04-26 18:09:59 +02:00
|
|
|
using namespace QskLayoutConstraint;
|
2018-06-12 08:19:28 +02:00
|
|
|
|
2019-04-26 18:09:59 +02:00
|
|
|
return constrainedMetric(
|
|
|
|
HeightForWidth, this, width, constrainedChildrenMetric );
|
2018-05-01 13:55:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
qreal QskControl::widthForHeight( qreal height ) const
|
|
|
|
{
|
2019-04-26 18:09:59 +02:00
|
|
|
if ( !d_func()->autoLayoutChildren )
|
|
|
|
return -1.0;
|
2018-08-03 08:15:28 +02:00
|
|
|
|
2019-04-26 18:09:59 +02:00
|
|
|
using namespace QskLayoutConstraint;
|
2018-08-03 08:15:28 +02:00
|
|
|
|
2019-04-26 18:09:59 +02:00
|
|
|
return constrainedMetric(
|
|
|
|
WidthForHeight, this, height, constrainedChildrenMetric );
|
2018-05-01 13:55:26 +02:00
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
bool QskControl::event( QEvent* event )
|
|
|
|
{
|
|
|
|
const int eventType = event->type();
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
switch ( eventType )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
case QEvent::PolishRequest:
|
|
|
|
{
|
|
|
|
d->polishScheduled = false;
|
|
|
|
updatePolish();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
case QEvent::EnabledChange:
|
|
|
|
{
|
|
|
|
setSkinStateFlag( Disabled, !isEnabled() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QEvent::LocaleChange:
|
|
|
|
{
|
|
|
|
Q_EMIT localeChanged( locale() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QEvent::LayoutRequest:
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( d_func()->autoLayoutChildren )
|
2017-07-21 18:21:34 +02:00
|
|
|
resetImplicitSize();
|
|
|
|
|
2019-05-12 12:26:34 +02:00
|
|
|
if ( d_func()->polishOnResize )
|
|
|
|
polish();
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QEvent::ContentsRectChange:
|
|
|
|
{
|
|
|
|
if ( d_func()->polishOnResize )
|
|
|
|
polish();
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
switch ( eventType )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-12-14 09:41:10 +01:00
|
|
|
case QEvent::StyleChange:
|
|
|
|
{
|
|
|
|
// The skin has changed
|
|
|
|
|
|
|
|
if ( skinlet() == nullptr )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
When we don't have a local skinlet, the skinlet
|
2018-04-05 14:18:15 +02:00
|
|
|
from the previous skin might be cached.
|
2017-12-14 09:41:10 +01:00
|
|
|
*/
|
2018-04-05 14:18:15 +02:00
|
|
|
|
2017-12-14 09:41:10 +01:00
|
|
|
setSkinlet( nullptr );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
We might have a totally different skinlet,
|
|
|
|
that can't deal with nodes created from other skinlets
|
2018-04-05 14:18:15 +02:00
|
|
|
*/
|
2017-12-14 09:41:10 +01:00
|
|
|
d_func()->clearPreviousNodes = true;
|
|
|
|
|
|
|
|
resetImplicitSize();
|
|
|
|
polish();
|
2018-07-13 08:37:44 +02:00
|
|
|
|
|
|
|
if ( flags() & QQuickItem::ItemHasContents )
|
|
|
|
update();
|
2017-12-14 09:41:10 +01:00
|
|
|
|
|
|
|
changeEvent( event );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
case QEvent::EnabledChange:
|
|
|
|
case QEvent::FontChange:
|
|
|
|
case QEvent::PaletteChange:
|
|
|
|
case QEvent::LocaleChange:
|
|
|
|
case QEvent::ReadOnlyChange:
|
|
|
|
case QEvent::ParentChange:
|
|
|
|
case QEvent::ContentsRectChange:
|
|
|
|
{
|
|
|
|
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 QskEvent::Gesture:
|
|
|
|
{
|
|
|
|
gestureEvent( static_cast< QskGestureEvent* >( event ) );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
if ( d_func()->maybeGesture( this, event ) )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Inherited::event( event );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::childMouseEventFilter( QQuickItem* item, QEvent* event )
|
|
|
|
{
|
2019-03-07 13:20:48 +01:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK( 5, 10, 0 )
|
|
|
|
|
|
|
|
if ( event->type() == QEvent::MouseButtonPress )
|
|
|
|
{
|
2019-04-04 17:59:17 +02:00
|
|
|
auto me = static_cast< QMouseEvent* >( event );
|
2019-03-07 13:20:48 +01:00
|
|
|
|
|
|
|
if ( me->source() == Qt::MouseEventSynthesizedByQt )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Unhandled touch events result in creating synthetic
|
|
|
|
mouse events. For all versions < 5.10 those events are
|
|
|
|
passed through childMouseEventFilter without doing the
|
|
|
|
extra checks, that are done for real mouse events.
|
2019-04-04 17:59:17 +02:00
|
|
|
Furthermore the coordinates are relative
|
|
|
|
to this - not to item.
|
|
|
|
|
2019-03-07 13:20:48 +01:00
|
|
|
To avoid having a different behavior between using
|
|
|
|
mouse and touch, we do those checks here.
|
|
|
|
*/
|
|
|
|
|
2019-04-04 17:59:17 +02:00
|
|
|
auto itm = item;
|
|
|
|
auto pos = item->mapFromScene( me->windowPos() );
|
|
|
|
|
|
|
|
for ( itm = item; itm != this; itm = itm->parentItem() )
|
|
|
|
{
|
|
|
|
if ( itm->acceptedMouseButtons() & me->button() )
|
|
|
|
{
|
|
|
|
if ( itm->contains( pos ) )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos += QPointF( itm->x(), itm->y() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( itm != item )
|
|
|
|
{
|
|
|
|
if ( itm == this )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QScopedPointer<QMouseEvent> clonedEvent(
|
|
|
|
QQuickWindowPrivate::cloneMouseEvent( me, &pos ) );
|
|
|
|
|
|
|
|
return d_func()->maybeGesture( itm, clonedEvent.data() );
|
|
|
|
}
|
2019-03-07 13:20:48 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
return d_func()->maybeGesture( item, event );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::gestureFilter( QQuickItem* item, QEvent* event )
|
|
|
|
{
|
|
|
|
Q_UNUSED( item )
|
|
|
|
Q_UNUSED( event )
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::windowChangeEvent( QskWindowChangeEvent* )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::geometryChangeEvent( QskGeometryChangeEvent* )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::hoverEnterEvent( QHoverEvent* event )
|
|
|
|
{
|
|
|
|
Inherited::hoverEnterEvent( event );
|
|
|
|
setSkinStateFlag( Hovered );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::hoverLeaveEvent( QHoverEvent* event )
|
|
|
|
{
|
|
|
|
Inherited::hoverLeaveEvent( event );
|
|
|
|
setSkinStateFlag( Hovered, false );
|
|
|
|
}
|
|
|
|
|
2018-11-03 17:48:34 +01:00
|
|
|
void QskControl::changeEvent( QEvent* )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::gestureEvent( QskGestureEvent* )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::classBegin()
|
|
|
|
{
|
|
|
|
Inherited::classBegin();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::componentComplete()
|
|
|
|
{
|
|
|
|
#if defined( QT_DEBUG )
|
|
|
|
if ( qobject_cast< const QQuickBasePositioner* >( parent() ) )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( d_func()->controlFlags & QskControl::DeferredLayout )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
qWarning( "QskControl in DeferredLayout mode under control of a positioner" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
Inherited::componentComplete();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::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.
|
|
|
|
|
2017-10-30 14:38:30 +01:00
|
|
|
qskReleasedWindowCounter->setWindow( window() );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::itemChange( QQuickItem::ItemChange change,
|
|
|
|
const QQuickItem::ItemChangeData& value )
|
|
|
|
{
|
|
|
|
Inherited::itemChange( change, value );
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
switch ( change )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
case QQuickItem::ItemParentHasChanged:
|
|
|
|
{
|
2017-12-08 13:56:35 +01:00
|
|
|
if ( value.item )
|
|
|
|
{
|
|
|
|
if ( !d->explicitLocale )
|
|
|
|
qskResolveLocale( this );
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
// not necessarily correct, when parent != parentItem ???
|
|
|
|
qskSendEventTo( this, QEvent::ParentChange );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2017-11-18 13:52:48 +01:00
|
|
|
case QQuickItem::ItemChildAddedChange:
|
|
|
|
{
|
2018-01-19 10:07:05 +01:00
|
|
|
if ( d->autoLayoutChildren && !qskIsTransparentForPositioner( value.item ) )
|
2017-11-18 13:52:48 +01:00
|
|
|
polish();
|
2017-12-05 13:10:17 +01:00
|
|
|
|
2017-11-18 13:52:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2018-10-29 20:13:02 +01:00
|
|
|
#if 0
|
|
|
|
case QQuickItem::ItemChildRemovedChange:
|
|
|
|
{
|
|
|
|
// TODO ...
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2017-07-21 18:21:34 +02:00
|
|
|
case QQuickItem::ItemVisibleHasChanged:
|
|
|
|
{
|
2018-03-23 09:55:48 +01:00
|
|
|
#if 1
|
2018-04-05 14:18:15 +02:00
|
|
|
/*
|
2018-03-23 09:55:48 +01:00
|
|
|
~QQuickItem sends QQuickItem::ItemVisibleHasChanged recursively
|
|
|
|
to all childItems. When being a child ( not only a childItem() )
|
2018-04-05 14:18:15 +02:00
|
|
|
we are short before being destructed too and any updates
|
2018-03-23 09:55:48 +01:00
|
|
|
done here are totally pointless. TODO ...
|
2018-04-05 14:18:15 +02:00
|
|
|
*/
|
2018-03-23 09:55:48 +01:00
|
|
|
#endif
|
2017-07-21 18:21:34 +02:00
|
|
|
if ( value.boolValue )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( d->blockedPolish )
|
2017-07-21 18:21:34 +02:00
|
|
|
polish();
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( d->controlFlags & QskControl::DeferredUpdate )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-02-05 10:11:29 +01:00
|
|
|
if ( d->dirtyAttributes && ( d->flags & QQuickItem::ItemHasContents ) )
|
2017-07-21 18:21:34 +02:00
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( d->controlFlags & QskControl::CleanupOnVisibility )
|
2017-07-21 18:21:34 +02:00
|
|
|
cleanupNodes();
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
d->isInitiallyPainted = false;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2018-03-23 09:55:48 +01:00
|
|
|
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 ...
|
|
|
|
*/
|
|
|
|
|
|
|
|
layoutConstraintChanged();
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QQuickItem::ItemSceneChange:
|
|
|
|
{
|
|
|
|
if ( value.window )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( d->controlFlags & QskControl::DeferredUpdate )
|
2017-07-21 18:21:34 +02:00
|
|
|
qskFilterWindow( value.window );
|
|
|
|
}
|
|
|
|
|
2019-01-08 17:08:50 +01:00
|
|
|
#if 1
|
|
|
|
auto oldWindow = qskReleasedWindowCounter->window();
|
|
|
|
if ( oldWindow && ( oldWindow->activeFocusItem() == this ) )
|
|
|
|
{
|
|
|
|
/*
|
2019-01-10 20:07:55 +01:00
|
|
|
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().
|
2019-01-08 17:08:50 +01:00
|
|
|
*/
|
|
|
|
QQuickWindowPrivate::get( oldWindow )->clearFocusInScope(
|
|
|
|
qskNearestFocusScope( this ), this, Qt::OtherFocusReason );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
QskWindowChangeEvent event( oldWindow, value.window );
|
2017-07-21 18:21:34 +02:00
|
|
|
QCoreApplication::sendEvent( this, &event );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QQuickItem::ItemActiveFocusHasChanged:
|
|
|
|
{
|
|
|
|
setSkinStateFlag( Focused, hasActiveFocus() );
|
|
|
|
break;
|
|
|
|
}
|
2018-08-03 08:15:28 +02:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
|
2017-12-14 09:41:10 +01:00
|
|
|
case QQuickItem::ItemEnabledHasChanged:
|
2017-12-12 20:02:48 +01:00
|
|
|
{
|
|
|
|
setSkinStateFlag( Disabled, !value.boolValue );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2017-07-21 18:21:34 +02:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::geometryChanged(
|
|
|
|
const QRectF& newGeometry, const QRectF& oldGeometry )
|
|
|
|
{
|
|
|
|
Inherited::geometryChanged( newGeometry, oldGeometry );
|
|
|
|
|
|
|
|
if ( newGeometry.size() != oldGeometry.size() )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( const QskControl );
|
|
|
|
if ( d->polishOnResize || d->autoLayoutChildren )
|
2017-07-21 18:21:34 +02:00
|
|
|
polish();
|
|
|
|
}
|
|
|
|
|
|
|
|
QskGeometryChangeEvent event( newGeometry, oldGeometry );
|
|
|
|
QCoreApplication::sendEvent( this, &event );
|
|
|
|
}
|
|
|
|
|
2018-10-05 14:20:46 +02:00
|
|
|
void QskControl::windowDeactivateEvent()
|
|
|
|
{
|
|
|
|
// stopping gesture recognition ???
|
|
|
|
Inherited::windowDeactivateEvent();
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
void QskControl::layoutConstraintChanged()
|
|
|
|
{
|
2018-12-11 14:58:48 +01:00
|
|
|
if ( auto item = parentItem() )
|
2017-07-21 18:21:34 +02:00
|
|
|
qskSendEventTo( item, QEvent::LayoutRequest );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::updatePolish()
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
if ( d->controlFlags & QskControl::DeferredPolish )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
if ( !isVisible() )
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
d->blockedPolish = true;
|
2017-07-21 18:21:34 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
d->blockedPolish = false;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( d->autoLayoutChildren )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
const QRectF rect = layoutRect();
|
|
|
|
|
2017-10-30 12:06:19 +01:00
|
|
|
const auto children = childItems();
|
|
|
|
for ( auto child : children )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
if ( !QQuickItemPrivate::get( child )->isTransparentForPositioner() )
|
2019-06-20 11:45:32 +02:00
|
|
|
{
|
|
|
|
// rect = QskLayoutConstraint::itemRect( info.item, rect, ... );
|
2018-03-24 18:05:57 +01:00
|
|
|
qskSetItemGeometry( child, rect );
|
2019-06-20 11:45:32 +02:00
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-26 11:10:44 +02:00
|
|
|
if ( !d->isInitiallyPainted )
|
2018-07-13 08:37:44 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
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 ...
|
|
|
|
*/
|
2018-06-26 11:10:44 +02:00
|
|
|
aboutToShow();
|
2018-07-13 08:37:44 +02:00
|
|
|
}
|
2018-06-26 11:10:44 +02:00
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
updateLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
QSGNode* QskControl::updatePaintNode( QSGNode* node, UpdatePaintNodeData* data )
|
|
|
|
{
|
|
|
|
Q_UNUSED( data );
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
Q_D( QskControl );
|
|
|
|
|
|
|
|
Q_ASSERT( isVisible() || !( d->controlFlags & QskControl::DeferredUpdate ) );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( !d->isInitiallyPainted )
|
|
|
|
d->isInitiallyPainted = true;
|
|
|
|
|
|
|
|
if ( d->clearPreviousNodes )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
delete node;
|
|
|
|
node = nullptr;
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
d->clearPreviousNodes = false;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( node == nullptr )
|
|
|
|
node = new QSGNode;
|
|
|
|
|
|
|
|
updateNode( node );
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskControl::cleanupNodes()
|
|
|
|
{
|
|
|
|
Q_D( QskControl );
|
|
|
|
if ( d->itemNodeInstance == nullptr )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// setting the dirty flags, so that nodes will be recreated
|
|
|
|
// the next time we participate in a scene graph update
|
|
|
|
|
|
|
|
if ( !d->itemNodeInstance->matrix().isIdentity() )
|
|
|
|
d->dirtyAttributes |= QQuickItemPrivate::Position;
|
|
|
|
|
|
|
|
if ( d->extra.isAllocated() )
|
|
|
|
{
|
|
|
|
if ( d->extra->clipNode )
|
|
|
|
d->dirtyAttributes |= QQuickItemPrivate::Clip;
|
|
|
|
|
|
|
|
if ( d->extra->opacityNode )
|
|
|
|
d->dirtyAttributes |= QQuickItemPrivate::OpacityValue;
|
|
|
|
|
|
|
|
if ( d->extra->rootNode )
|
|
|
|
d->dirtyAttributes |= QQuickItemPrivate::EffectReference;
|
|
|
|
}
|
|
|
|
|
2018-04-11 17:33:43 +02:00
|
|
|
if ( d->window )
|
|
|
|
{
|
|
|
|
// putting the nodes on the cleanup list of the window to be deleteted
|
|
|
|
// in the next cycle of the scene graph
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2018-04-11 17:33:43 +02:00
|
|
|
QQuickWindowPrivate::get( d->window )->cleanup( d->itemNodeInstance );
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
// now we can forget about the nodes
|
|
|
|
|
|
|
|
d->itemNodeInstance = nullptr;
|
|
|
|
d->paintNode = nullptr;
|
|
|
|
|
|
|
|
if ( d->extra.isAllocated() )
|
|
|
|
{
|
|
|
|
d->extra->opacityNode = nullptr;
|
|
|
|
d->extra->clipNode = nullptr;
|
|
|
|
d->extra->rootNode = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskControl* QskControl::owningControl() const
|
|
|
|
{
|
|
|
|
return const_cast< QskControl* >( this );
|
|
|
|
}
|
|
|
|
|
2019-04-26 18:09:59 +02:00
|
|
|
QRectF QskControl::layoutRectForSize( const QSizeF& size ) const
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-04-26 18:09:59 +02:00
|
|
|
const QRectF r( 0.0, 0.0, size.width(), size.height() );
|
|
|
|
return qskValidOrEmptyInnerRect( r, margins() );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QRectF QskControl::gestureRect() const
|
|
|
|
{
|
2018-02-07 19:30:34 +01:00
|
|
|
return rect();
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2018-01-19 10:15:29 +01:00
|
|
|
QRectF QskControl::focusIndicatorRect() const
|
|
|
|
{
|
2018-02-01 09:28:47 +01:00
|
|
|
return contentsRect();
|
2018-01-19 10:15:29 +01:00
|
|
|
}
|
|
|
|
|
2018-06-26 11:10:44 +02:00
|
|
|
void QskControl::aboutToShow()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
void QskControl::updateLayout()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QSizeF QskControl::contentsSizeHint() const
|
|
|
|
{
|
|
|
|
qreal w = -1; // no hint
|
|
|
|
qreal h = -1;
|
|
|
|
|
2017-10-25 14:53:49 +02:00
|
|
|
if ( d_func()->autoLayoutChildren )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-30 12:06:19 +01:00
|
|
|
const auto children = childItems();
|
|
|
|
for ( const auto child : children )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-04-26 11:56:09 +02:00
|
|
|
if ( auto control = qskControlCast( child ) )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-04-26 11:56:09 +02:00
|
|
|
if ( !control->isTransparentForPositioner() )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
const QSizeF hint = control->sizeHint();
|
|
|
|
|
|
|
|
w = qMax( w, hint.width() );
|
|
|
|
h = qMax( h, hint.height() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return QSizeF( w, h );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::isPolishScheduled() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->polishScheduled;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::isUpdateNodeScheduled() const
|
|
|
|
{
|
|
|
|
Q_D( const QskControl );
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
return ( d->dirtyAttributes & QQuickItemPrivate::ContentUpdateMask ) &&
|
|
|
|
( d->flags & QQuickItem::ItemHasContents );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool QskControl::isInitiallyPainted() const
|
|
|
|
{
|
2017-10-25 14:53:49 +02:00
|
|
|
return d_func()->isInitiallyPainted;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QVector< QskAspect::Subcontrol > QskControl::subControls() const
|
|
|
|
{
|
|
|
|
using namespace QskAspect;
|
|
|
|
|
|
|
|
QVector< Subcontrol > subControls;
|
|
|
|
|
|
|
|
for ( auto mo = metaObject(); mo != nullptr; mo = mo->superClass() )
|
|
|
|
{
|
|
|
|
const auto moSubControls = QskAspect::subControls( mo );
|
|
|
|
|
|
|
|
for ( auto subControl : moSubControls )
|
|
|
|
{
|
|
|
|
const auto subControlEffective = effectiveSubcontrol( subControl );
|
|
|
|
|
|
|
|
if ( subControlEffective == subControl )
|
|
|
|
{
|
|
|
|
subControls += subControlEffective;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// when subControlEffective differs it usually has
|
|
|
|
// been mapped to a subcontrol of an inherited class
|
|
|
|
// that is already in the list.
|
|
|
|
|
|
|
|
if ( !subControls.contains( subControlEffective ) )
|
|
|
|
{
|
|
|
|
subControls += subControlEffective;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return subControls;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "moc_QskControl.cpp"
|