qskinny/src/controls/QskControl.cpp

1046 lines
26 KiB
C++
Raw Normal View History

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"
2019-09-04 06:59:43 +02:00
#include "QskControlPrivate.h"
2017-07-21 18:21:34 +02:00
#include "QskAspect.h"
2019-04-24 08:39:13 +02:00
#include "QskFunctions.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"
#include "QskSkinlet.h"
2018-08-03 08:15:28 +02:00
#include "QskSkinHintTable.h"
2017-07-21 18:21:34 +02:00
2018-07-19 14:10:48 +02:00
#include <qlocale.h>
#include <qvector.h>
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
static inline void qskSendEventTo( QObject* object, QEvent::Type type )
2017-07-21 18:21:34 +02:00
{
QEvent event( type );
QCoreApplication::sendEvent( object, &event );
}
2018-08-03 08:15:28 +02:00
QskControl::QskControl( QQuickItem* parent )
2019-09-04 06:59:43 +02:00
: QskQuickItem( *( new QskControlPrivate() ), parent )
2017-07-21 18:21:34 +02:00
{
2019-09-04 06:59:43 +02:00
Inherited::setActiveFocusOnTab( false );
2017-07-21 18:21:34 +02:00
if ( parent )
{
// inheriting attributes from parent
2019-09-04 06:59:43 +02:00
QskControlPrivate::resolveLocale( this );
2017-07-21 18:21:34 +02:00
}
}
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-07-21 18:21:34 +02:00
}
void QskControl::setAutoFillBackground( bool on )
{
Q_D( QskControl );
if ( on != d->autoFillBackground )
2017-07-21 18:21:34 +02:00
{
d->autoFillBackground = on;
2017-07-21 18:21:34 +02:00
update();
}
}
bool QskControl::autoFillBackground() const
{
return d_func()->autoFillBackground;
2017-07-21 18:21:34 +02:00
}
void QskControl::setAutoLayoutChildren( bool on )
{
Q_D( QskControl );
if ( on != d->autoLayoutChildren )
2017-07-21 18:21:34 +02:00
{
d->autoLayoutChildren = on;
2017-07-21 18:21:34 +02:00
if ( on )
polish();
}
}
bool QskControl::autoLayoutChildren() const
{
return d_func()->autoLayoutChildren;
2017-07-21 18:21:34 +02:00
}
void QskControl::setWheelEnabled( bool on )
{
Q_D( QskControl );
if ( on != d->isWheelEnabled )
{
d->isWheelEnabled = on;
Q_EMIT wheelEnabledChanged();
}
}
bool QskControl::isWheelEnabled() const
{
return d_func()->isWheelEnabled;
}
void QskControl::setFocusPolicy( Qt::FocusPolicy policy )
{
Q_D( QskControl );
if ( policy != d->focusPolicy )
{
2019-09-04 06:59:43 +02:00
d->focusPolicy = ( policy & ~Qt::TabFocus );
Inherited::setActiveFocusOnTab( policy & Qt::TabFocus );
2017-10-30 08:33:43 +01:00
Q_EMIT focusPolicyChanged();
}
}
Qt::FocusPolicy QskControl::focusPolicy() const
{
uint policy = d_func()->focusPolicy;
2019-09-04 06:59:43 +02:00
if ( Inherited::activeFocusOnTab() )
policy |= Qt::TabFocus;
return static_cast< Qt::FocusPolicy >( policy );
}
2017-07-21 18:21:34 +02:00
void QskControl::setBackgroundColor( const QColor& color )
{
setAutoFillBackground( true );
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 )
{
setGradientHint( aspect, gradient );
2017-10-30 12:06:19 +01:00
if ( autoFillBackground() )
update();
Q_EMIT backgroundChanged();
}
}
void QskControl::resetBackground()
{
using namespace QskAspect;
2019-12-14 16:40:18 +01:00
if ( resetHint( Control | Color ) )
{
2017-10-30 12:06:19 +01:00
update();
Q_EMIT backgroundChanged();
}
}
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 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() )
{
const auto subControl = effectiveSubcontrol( QskAspect::Control );
setMarginsHint( subControl | Margin, m );
2017-07-21 18:21:34 +02:00
resetImplicitSize();
Q_D( const QskControl );
2019-09-04 06:59:43 +02:00
if ( 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()
{
using namespace QskAspect;
2019-12-14 16:40:18 +01:00
if ( resetHint( Control | Metric | Margin ) )
{
2019-12-14 16:40:18 +01:00
resetImplicitSize();
Q_D( const QskControl );
if ( polishOnResize() || d->autoLayoutChildren )
polish();
qskSendEventTo( this, QEvent::ContentsRectChange );
Q_EMIT marginsChanged();
}
2017-07-21 18:21:34 +02:00
}
QMarginsF QskControl::margins() const
{
return marginsHint( QskAspect::Control | QskAspect::Margin );
2017-07-21 18:21:34 +02:00
}
QRectF QskControl::contentsRect() const
{
2019-09-04 06:59:43 +02:00
return qskValidOrEmptyInnerRect( rect(), margins() );
2017-07-21 18:21:34 +02:00
}
2019-09-04 06:59:43 +02:00
QRectF QskControl::subControlRect( QskAspect::Subcontrol subControl ) const
2017-07-21 18:21:34 +02:00
{
2019-09-04 06:59:43 +02:00
return effectiveSkinlet()->subControlRect( this, contentsRect(), subControl );
2017-07-21 18:21:34 +02:00
}
2019-09-04 06:59:43 +02:00
QRectF QskControl::subControlRect(
const QSizeF& size, QskAspect::Subcontrol subControl ) const
2017-07-21 18:21:34 +02:00
{
2019-09-04 06:59:43 +02:00
QRectF rect( 0.0, 0.0, size.width(), size.height() );
rect = qskValidOrEmptyInnerRect( rect, margins() );
2017-07-21 18:21:34 +02:00
2019-09-04 06:59:43 +02:00
return effectiveSkinlet()->subControlRect( this, rect, subControl );
2017-07-21 18:21:34 +02:00
}
QLocale QskControl::locale() const
{
return d_func()->locale;
2017-07-21 18:21:34 +02:00
}
void QskControl::setLocale( const QLocale& locale )
{
Q_D( QskControl );
2017-07-21 18:21:34 +02:00
d->explicitLocale = true;
if ( d->locale != locale )
2017-07-21 18:21:34 +02:00
{
d->locale = locale;
2017-07-21 18:21:34 +02:00
qskSendEventTo( this, QEvent::LocaleChange );
qskSetup->inheritLocale( this, locale );
}
}
void QskControl::resetLocale()
{
Q_D( QskControl );
if ( d->explicitLocale )
2017-07-21 18:21:34 +02:00
{
d->explicitLocale = false;
2019-09-04 06:59:43 +02:00
QskControlPrivate::resolveLocale( this );
2017-07-21 18:21:34 +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
d->sizePolicy.setHorizontalPolicy( horizontalPolicy );
d->sizePolicy.setVerticalPolicy( verticalPolicy );
if ( horizontalPolicy == QskSizePolicy::Constrained
&& verticalPolicy == QskSizePolicy::Constrained )
{
qWarning( "QskControl::initSizePolicy: conflicting constraints");
}
}
void QskControl::setSizePolicy( QskSizePolicy policy )
{
Q_D( QskControl );
if ( policy != d->sizePolicy )
{
d->sizePolicy = policy;
2019-09-04 06:59:43 +02:00
d->layoutConstraintChanged();
if ( policy.policy( Qt::Horizontal ) == QskSizePolicy::Constrained
&& policy.policy( Qt::Vertical ) == QskSizePolicy::Constrained )
{
qWarning( "QskControl::setSizePolicy: conflicting constraints");
2019-09-04 06:59:43 +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 );
2019-09-04 06:59:43 +02:00
d->layoutConstraintChanged();
}
}
QskSizePolicy QskControl::sizePolicy() const
{
return d_func()->sizePolicy;
}
QskSizePolicy::Policy QskControl::sizePolicy( Qt::Orientation orientation ) const
{
return d_func()->sizePolicy.policy( orientation );
}
/*
Layout attributes belong more to the layout code, than
being parameters of the control. So storing them here is kind of a
design flaw ( similar to QWidget/QSizePolicy ).
But this way we don't need to add the attributes to all type of
layout engines + we can make use of them when doing layouts
manually ( f.e autoLayoutChildren ).
*/
void QskControl::setLayoutAlignmentHint( Qt::Alignment alignment )
{
Q_D( QskControl );
2019-09-13 06:55:28 +02:00
if ( layoutAlignmentHint() != alignment )
{
d->layoutAlignmentHint = alignment;
d->layoutConstraintChanged();
}
}
Qt::Alignment QskControl::layoutAlignmentHint() const
{
return static_cast< Qt::Alignment >( d_func()->layoutAlignmentHint );
}
void QskControl::setLayoutHint( LayoutHint flag, bool on )
{
Q_D( QskControl );
if ( ( d->layoutHints & flag ) != on )
{
if ( on )
d->layoutHints |= flag;
else
d->layoutHints &= ~flag;
d->layoutConstraintChanged();
}
}
bool QskControl::testLayoutHint( LayoutHint hint ) const
{
return d_func()->layoutHints & hint;
}
void QskControl::setLayoutHints( LayoutHints hints )
{
Q_D( QskControl );
if ( hints != layoutHints() )
{
d->layoutHints = hints;
d->layoutConstraintChanged();
}
}
QskControl::LayoutHints QskControl::layoutHints() const
{
return static_cast< LayoutHints >( d_func()->layoutHints );
}
2019-09-06 19:57:25 +02:00
bool QskControl::isVisibleToLayout() const
{
return !isTransparentForPositioner()
&& ( isVisibleToParent() || ( layoutHints() & RetainSizeWhenHidden ) );
}
void QskControl::setPreferredSize( const QSizeF& size )
{
setExplicitSizeHint( Qt::PreferredSize, size );
}
void QskControl::setPreferredSize( qreal width, qreal height )
{
2019-09-13 06:57:48 +02:00
setExplicitSizeHint( Qt::PreferredSize, QSizeF( width, height ) );
}
void QskControl::setPreferredWidth( qreal width )
{
2019-09-13 06:57:48 +02:00
const qreal height = explicitSizeHint( Qt::PreferredSize ).height();
setExplicitSizeHint( Qt::PreferredSize, QSizeF( width, height ) );
}
void QskControl::setPreferredHeight( qreal height )
{
2019-09-13 06:57:48 +02:00
const qreal width = explicitSizeHint( Qt::PreferredSize ).width();
setExplicitSizeHint( Qt::PreferredSize, QSizeF( width, height ) );
}
void QskControl::setMinimumSize( const QSizeF& size )
{
setExplicitSizeHint( Qt::MinimumSize, size );
}
void QskControl::setMinimumSize( qreal width, qreal height )
{
2019-09-13 06:57:48 +02:00
setExplicitSizeHint( Qt::MinimumSize, QSizeF( width, height ) );
}
void QskControl::setMinimumWidth( qreal width )
{
2019-09-13 06:57:48 +02:00
const qreal height = explicitSizeHint( Qt::MinimumSize ).height();
setExplicitSizeHint( Qt::MinimumSize, QSizeF( width, height ) );
}
void QskControl::setMinimumHeight( qreal height )
{
2019-09-13 06:57:48 +02:00
const qreal width = explicitSizeHint( Qt::MinimumSize ).width();
setExplicitSizeHint( Qt::MinimumSize, QSizeF( width, height ) );
}
void QskControl::setMaximumSize( const QSizeF& size )
{
setExplicitSizeHint( Qt::MaximumSize, size );
}
void QskControl::setMaximumSize( qreal width, qreal height )
{
2019-09-13 06:57:48 +02:00
setExplicitSizeHint( Qt::MaximumSize, QSizeF( width, height ) );
}
void QskControl::setMaximumWidth( qreal width )
{
2019-09-13 06:57:48 +02:00
const qreal height = explicitSizeHint( Qt::MaximumSize ).height();
setExplicitSizeHint( Qt::MaximumSize, QSizeF( width, height ) );
}
void QskControl::setMaximumHeight( qreal height )
{
2019-09-13 06:57:48 +02:00
const qreal width = explicitSizeHint( Qt::MaximumSize ).width();
setExplicitSizeHint( Qt::MaximumSize, QSizeF( 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 );
2019-09-04 06:59:43 +02:00
d->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 ) )
{
size.setWidth( width );
d->sizePolicy.setHorizontalPolicy( QskSizePolicy::Fixed );
d->setExplicitSizeHint( Qt::PreferredSize, size );
2019-09-04 06:59:43 +02:00
d->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 ) )
{
size.setHeight( height );
d->sizePolicy.setVerticalPolicy( QskSizePolicy::Fixed );
d->setExplicitSizeHint( Qt::PreferredSize, size );
2019-09-04 06:59:43 +02:00
d->layoutConstraintChanged();
}
}
void QskControl::resetExplicitSizeHint( Qt::SizeHint whichHint )
{
if ( whichHint >= Qt::MinimumSize && whichHint <= Qt::MaximumSize )
2019-09-01 15:33:36 +02:00
{
Q_D( QskControl );
const auto oldHint = d->explicitSizeHint( whichHint );
d->resetExplicitSizeHint( whichHint );
if ( oldHint != d->explicitSizeHint( whichHint ) )
2019-09-04 06:59:43 +02:00
d->layoutConstraintChanged();
2019-09-01 15:33:36 +02:00
}
}
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() );
Q_D( QskControl );
if ( newSize != d->explicitSizeHint( whichHint ) )
{
d->setExplicitSizeHint( whichHint, newSize );
2019-09-04 06:59:43 +02:00
d->layoutConstraintChanged();
}
}
}
2019-07-17 17:52:15 +02:00
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 QSizeF();
return d_func()->explicitSizeHint( whichHint );
}
2019-07-17 17:52:15 +02:00
QSizeF QskControl::implicitSizeHint(
Qt::SizeHint whichHint, const QSizeF& constraint ) const
{
if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize )
return QSizeF();
2019-07-17 17:52:15 +02:00
if ( constraint.isValid() )
{
// having constraints in both directions does not make sense
return constraint;
}
QSizeF hint;
2019-07-17 17:52:15 +02:00
if ( whichHint == Qt::PreferredSize
&& constraint.width() < 0.0 && constraint.height() < 0.0 )
2019-07-17 17:52:15 +02:00
{
// this one might be cached
hint = implicitSize();
2019-07-17 17:52:15 +02:00
}
else
{
hint = d_func()->implicitSizeHint( whichHint, constraint );
2019-07-17 17:52:15 +02:00
}
return hint;
}
QSizeF QskControl::effectiveSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
2017-07-21 18:21:34 +02:00
{
if ( which < Qt::MinimumSize || which > Qt::MaximumSize )
2017-07-21 18:21:34 +02:00
return QSizeF( 0, 0 );
if ( constraint.isValid() )
return constraint;
const bool isConstrained =
constraint.width() >= 0 || constraint.height() >= 0;
2019-07-25 18:38:09 +02:00
Q_D( const QskControl );
d->blockLayoutRequestEvents = false;
QSizeF hint;
2019-09-04 06:59:43 +02:00
/*
The explicit size has always precedence over the implicit size,
and will kill the effect of the constraint
2019-07-25 18:38:09 +02:00
*/
hint = d->explicitSizeHint( which );
2019-07-25 18:38:09 +02:00
if ( !hint.isValid() )
2017-07-21 18:21:34 +02:00
{
const auto implicitHint = implicitSizeHint( which, constraint );
2017-07-21 18:21:34 +02:00
2019-07-25 18:38:09 +02:00
if ( hint.width() < 0 )
hint.setWidth( implicitHint.width() );
2019-07-25 18:38:09 +02:00
if ( hint.height() < 0 )
hint.setHeight( implicitHint.height() );
2019-07-17 17:52:15 +02:00
}
2019-07-25 18:38:09 +02:00
if ( !isConstrained && ( hint.width() >= 0 || hint.height() >= 0 ) )
2019-07-17 17:52:15 +02:00
{
2019-07-25 18:38:09 +02:00
/*
We normalize the unconstrained hints by the explicit hints, so that
2019-07-25 18:38:09 +02:00
we always have: minimum <= preferred <= maximum.
*/
if ( which == Qt::MaximumSize )
2019-07-25 18:38:09 +02:00
{
const auto minimumHint = d->explicitSizeHint( Qt::MinimumSize );
if ( hint.width() >= 0 )
hint.rwidth() = qMax( hint.width(), minimumHint.width() );
2019-09-04 06:59:43 +02:00
2019-07-25 18:38:09 +02:00
if ( hint.height() >= 0 )
hint.rheight() = qMax( hint.height(), minimumHint.height() );
2019-07-25 18:38:09 +02:00
}
else if ( which == Qt::PreferredSize )
2019-07-25 18:38:09 +02:00
{
const auto minimumHint = d->explicitSizeHint( Qt::MinimumSize );
const auto maximumHint = d->explicitSizeHint( Qt::MaximumSize );
if ( hint.width() >= 0 )
{
if ( maximumHint.width() >= 0 )
hint.rwidth() = qMin( hint.width(), maximumHint.width() );
2019-07-25 18:38:09 +02:00
hint.rwidth() = qMax( hint.width(), minimumHint.width() );
2019-07-25 18:38:09 +02:00
}
if ( hint.height() >= 0 )
{
if ( maximumHint.height() >= 0 )
hint.rheight() = qMin( hint.height(), maximumHint.height() );
2019-09-04 06:59:43 +02:00
hint.rheight() = qMax( hint.height(), minimumHint.height() );
2019-07-25 18:38:09 +02:00
}
}
2017-07-21 18:21:34 +02:00
}
2019-07-17 17:52:15 +02:00
return hint;
2017-07-21 18:21:34 +02:00
}
qreal QskControl::heightForWidth( qreal width ) const
{
const auto hint = effectiveSizeHint(
Qt::PreferredSize, QSizeF( width, -1.0 ) );
return hint.height();
}
qreal QskControl::widthForHeight( qreal height ) const
{
const auto hint = effectiveSizeHint(
Qt::PreferredSize, QSizeF( -1.0, height ) );
2018-08-03 08:15:28 +02:00
return hint.width();
}
2019-09-13 06:54:55 +02:00
QSizeF QskControl::sizeConstraint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
return qskSizeConstraint( this, which, constraint );
}
2017-07-21 18:21:34 +02:00
bool QskControl::event( QEvent* event )
{
2019-09-04 06:59:43 +02:00
switch ( static_cast< int >( event->type() ) )
2017-07-21 18:21:34 +02:00
{
case QEvent::EnabledChange:
{
setSkinStateFlag( Disabled, !isEnabled() );
break;
}
case QEvent::LocaleChange:
{
Q_EMIT localeChanged( locale() );
break;
}
2019-09-20 07:43:16 +02:00
case QEvent::ContentsRectChange:
{
resetImplicitSize();
if ( d_func()->autoLayoutChildren )
polish();
break;
}
2017-07-21 18:21:34 +02:00
case QEvent::LayoutRequest:
{
if ( d_func()->autoLayoutChildren )
2017-07-21 18:21:34 +02:00
resetImplicitSize();
break;
}
case QEvent::StyleChange:
{
// The skin has changed
if ( skinlet() == nullptr )
{
/*
When we don't have a local skinlet, the skinlet
from the previous skin might be cached.
*/
setSkinlet( nullptr );
}
2019-09-04 06:59:43 +02:00
break;
2017-07-21 18:21:34 +02:00
}
case QskEvent::Gesture:
{
gestureEvent( static_cast< QskGestureEvent* >( event ) );
return true;
}
}
2019-09-04 06:59:43 +02:00
if ( d_func()->maybeGesture( this, event ) )
return true;
2017-07-21 18:21:34 +02:00
return Inherited::event( event );
}
bool QskControl::childMouseEventFilter( QQuickItem* item, QEvent* event )
{
#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 );
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.
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;
2019-09-04 06:59:43 +02:00
QScopedPointer< QMouseEvent > clonedEvent(
2019-04-04 17:59:17 +02:00
QQuickWindowPrivate::cloneMouseEvent( me, &pos ) );
return d_func()->maybeGesture( itm, clonedEvent.data() );
}
}
}
#endif
2017-07-21 18:21:34 +02:00
return d_func()->maybeGesture( item, event );
}
2019-09-04 06:59:43 +02:00
bool QskControl::gestureFilter( QQuickItem*, QEvent* )
2017-07-21 18:21:34 +02:00
{
return false;
}
2019-09-04 06:59:43 +02:00
void QskControl::gestureEvent( QskGestureEvent* )
2017-07-21 18:21:34 +02:00
{
}
void QskControl::hoverEnterEvent( QHoverEvent* event )
{
Inherited::hoverEnterEvent( event );
setSkinStateFlag( Hovered );
}
void QskControl::hoverLeaveEvent( QHoverEvent* event )
{
Inherited::hoverLeaveEvent( event );
setSkinStateFlag( Hovered, false );
}
void QskControl::itemChange( QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData& value )
{
2019-09-04 06:59:43 +02:00
switch ( static_cast< int >( change ) )
2017-07-21 18:21:34 +02:00
{
case QQuickItem::ItemParentHasChanged:
{
2017-12-08 13:56:35 +01:00
if ( value.item )
{
2019-09-04 06:59:43 +02:00
if ( !d_func()->explicitLocale )
QskControlPrivate::resolveLocale( this );
2017-12-08 13:56:35 +01:00
}
2017-07-21 18:21:34 +02:00
2019-09-04 06:59:43 +02:00
#if 1
2017-07-21 18:21:34 +02:00
// not necessarily correct, when parent != parentItem ???
qskSendEventTo( this, QEvent::ParentChange );
2019-09-04 06:59:43 +02:00
#endif
2017-07-21 18:21:34 +02:00
break;
}
case QQuickItem::ItemChildAddedChange:
{
2019-09-04 06:59:43 +02:00
if ( autoLayoutChildren() && !qskIsTransparentForPositioner( value.item ) )
polish();
2017-12-05 13:10:17 +01:00
2017-07-21 18:21:34 +02:00
break;
}
case QQuickItem::ItemActiveFocusHasChanged:
{
setSkinStateFlag( Focused, hasActiveFocus() );
break;
}
}
2019-09-04 06:59:43 +02:00
Inherited::itemChange( change, value );
2017-07-21 18:21:34 +02:00
}
void QskControl::geometryChanged(
const QRectF& newGeometry, const QRectF& oldGeometry )
{
2019-09-04 06:59:43 +02:00
if ( d_func()->autoLayoutChildren )
2017-07-21 18:21:34 +02:00
{
2019-09-04 06:59:43 +02:00
if ( newGeometry.size() != oldGeometry.size() )
2017-07-21 18:21:34 +02:00
polish();
}
2019-09-04 06:59:43 +02:00
Inherited::geometryChanged( newGeometry, oldGeometry );
2017-07-21 18:21:34 +02:00
}
void QskControl::windowDeactivateEvent()
{
// stopping gesture recognition ???
Inherited::windowDeactivateEvent();
}
2019-09-04 06:59:43 +02:00
void QskControl::updateItemPolish()
2017-07-21 18:21:34 +02:00
{
updateResources(); // an extra dirty bit for this ???
2017-07-21 18:21:34 +02:00
if ( width() >= 0.0 || height() >= 0.0 )
{
if ( d_func()->autoLayoutChildren && !maybeUnresized() )
2017-07-21 18:21:34 +02:00
{
const auto rect = layoutRect();
const auto children = childItems();
for ( auto child : children )
{
/*
We don't want to resize invisible children, but then
we would need to set up connections to know when a child
becomes visible. So we don't use qskIsVisibleToLayout here.
*/
if ( !qskIsTransparentForPositioner( child ) )
{
const auto r = qskConstrainedItemRect( child, rect );
qskSetItemGeometry( child, r );
}
}
2017-07-21 18:21:34 +02:00
}
updateLayout();
}
2017-07-21 18:21:34 +02:00
}
2019-09-04 06:59:43 +02:00
QSGNode* QskControl::updateItemPaintNode( QSGNode* node )
2017-07-21 18:21:34 +02:00
{
if ( node == nullptr )
node = new QSGNode;
2019-09-05 07:05:28 +02:00
updateNode( node );
2017-07-21 18:21:34 +02:00
return node;
}
QskControl* QskControl::owningControl() const
{
return const_cast< QskControl* >( this );
}
2019-06-23 12:53:38 +02:00
QRectF QskControl::layoutRect() const
{
Q_D( const QskControl );
if ( d->width <= 0.0 && d->height <= 0.0 )
return QRectF();
return layoutRectForSize( size() );
}
QRectF QskControl::layoutRectForSize( const QSizeF& size ) const
2017-07-21 18:21:34 +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
{
return rect();
2017-07-21 18:21:34 +02:00
}
QRectF QskControl::focusIndicatorRect() const
{
return contentsRect();
}
2019-09-04 06:59:43 +02:00
void QskControl::updateLayout()
2018-06-26 11:10:44 +02:00
{
}
2019-09-04 06:59:43 +02:00
void QskControl::updateResources()
2017-07-21 18:21:34 +02:00
{
}
QSizeF QskControl::contentsSizeHint( Qt::SizeHint, const QSizeF& ) const
2017-07-21 18:21:34 +02:00
{
return QSizeF();
}
2017-07-21 18:21:34 +02:00
QSizeF QskControl::layoutSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( which == Qt::MaximumSize || !d_func()->autoLayoutChildren )
return QSizeF();
2019-09-18 08:57:08 +02:00
qreal w = -1.0;
qreal h = -1.0;
const auto children = childItems();
for ( const auto child : children )
2017-07-21 18:21:34 +02:00
{
if ( !qskIsVisibleToLayout( child ) )
continue;
const auto policy = qskSizePolicy( child );
if ( constraint.width() >= 0.0 && policy.isConstrained( Qt::Vertical ) )
2017-07-21 18:21:34 +02:00
{
2019-09-18 08:57:08 +02:00
const auto hint = qskSizeConstraint( child, which, constraint );
2019-09-20 07:43:16 +02:00
h = qMax( h, hint.height() );
}
else if ( constraint.height() >= 0.0 && policy.isConstrained( Qt::Horizontal ) )
{
const auto hint = qskSizeConstraint( child, which, constraint );
2019-09-20 07:43:16 +02:00
w = qMax( w, hint.width() );
}
else
{
const auto hint = qskSizeConstraint( child, which, QSizeF() );
2019-09-18 08:57:08 +02:00
2019-09-20 07:43:16 +02:00
w = qMax( w, hint.width() );
h = qMax( h, hint.height() );
2017-07-21 18:21:34 +02:00
}
}
return QSizeF( w, h );
}
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"