qskinny/src/controls/QskControl.cpp

1043 lines
25 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"
#include "QskLayoutConstraint.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;
const Aspect aspect = Control | Color;
auto& table = hintTable();
2017-10-30 12:06:19 +01:00
if ( table.hint( aspect ).isValid() )
{
table.removeHint( aspect );
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;
2019-09-04 06:59:43 +02:00
const auto subControl = effectiveSubcontrol( QskAspect::Control );
2017-07-21 18:21:34 +02:00
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() )
{
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;
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();
Q_D( const QskControl );
2019-09-04 06:59:43 +02:00
if ( polishOnResize() || d->autoLayoutChildren )
polish();
qskSendEventTo( this, QEvent::ContentsRectChange );
2017-10-30 08:48:49 +01:00
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 );
if ( d->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 )
{
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 );
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 d_func()->explicitSizeHint( whichHint );
return QSizeF( -1, -1 );
}
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( -1, -1 );
if ( constraint.isValid() )
{
// having constraints in both directions does not make sense
return constraint;
}
QSizeF hint( -1, -1 );
if ( whichHint == Qt::PreferredSize )
{
if ( constraint.width() >= 0 )
{
hint.setWidth( constraint.width() );
hint.setHeight( heightForWidth( constraint.width() ) );
}
else if ( constraint.height() >= 0 )
{
hint.setWidth( widthForHeight( constraint.height() ) );
hint.setHeight( constraint.height() );
}
else
{
hint = implicitSize();
}
}
else
{
// TODO ...
}
return hint;
}
QSizeF QskControl::effectiveSizeHint(
Qt::SizeHint whichHint, const QSizeF& constraint ) const
2017-07-21 18:21:34 +02:00
{
if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize )
return QSizeF( 0, 0 );
2019-07-25 18:38:09 +02:00
Q_D( const QskControl );
d->blockLayoutRequestEvents = false;
2019-07-25 18:38:09 +02:00
/*
The explicit size has always precedence over te implicit size.
2019-09-04 06:59:43 +02:00
2019-07-25 18:38:09 +02:00
Implicit sizes are currently only implemented for preferred and
explicitSizeHint returns valid explicit hints for minimum/maximum
even if not being set by application code.
*/
2019-07-25 18:38:09 +02:00
QSizeF hint = d->explicitSizeHint( whichHint );
if ( !hint.isValid() )
2017-07-21 18:21:34 +02:00
{
2019-07-25 18:38:09 +02:00
#if 0
if ( hint.width() >= 0 && constraint.width() >= 0 )
constraint.setWidth( hint.width() );
2017-07-21 18:21:34 +02:00
2019-07-25 18:38:09 +02:00
if ( hint.height() >= 0 && constraint.height() >= 0 )
constraint.setHeight( hint.height() );
#endif
2019-07-17 17:52:15 +02:00
2019-07-25 18:38:09 +02:00
const auto implicit = implicitSizeHint( whichHint, constraint );
2017-07-21 18:21:34 +02:00
2019-07-25 18:38:09 +02:00
if ( hint.width() < 0 )
hint.setWidth( implicit.width() );
if ( hint.height() < 0 )
hint.setHeight( implicit.height() );
2019-07-17 17:52:15 +02:00
}
2019-07-25 18:38:09 +02:00
if ( hint.width() >= 0 || hint.height() >= 0 )
2019-07-17 17:52:15 +02:00
{
2019-07-25 18:38:09 +02:00
/*
We might need to normalize the hints, so that
we always have: minimum <= preferred <= maximum.
*/
if ( whichHint == Qt::MaximumSize )
{
const auto minimumHint = d->explicitSizeHint( Qt::MinimumSize );
if ( hint.width() >= 0 )
hint.setWidth( 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.setHeight( qMax( hint.height(), minimumHint.height() ) );
}
else if ( whichHint == Qt::PreferredSize )
{
const auto minimumHint = d->explicitSizeHint( Qt::MinimumSize );
const auto maximumHint = d->explicitSizeHint( Qt::MaximumSize );
if ( hint.width() >= 0 )
{
const auto minW = minimumHint.width();
const auto maxW = qMax( minW, maximumHint.width() );
hint.setWidth( qBound( minW, hint.width(), maxW ) );
}
if ( hint.height() >= 0 )
{
const auto minH = minimumHint.height();
const auto maxH = qMax( minH, maximumHint.height() );
2019-09-04 06:59:43 +02:00
2019-07-25 18:38:09 +02:00
hint.setHeight( qBound( minH, hint.height(), maxH ) );
}
}
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
{
Q_D( const QskControl );
d->blockLayoutRequestEvents = false;
2019-09-05 12:08:31 +02:00
if ( d->autoLayoutChildren )
{
2019-09-05 12:37:27 +02:00
using namespace QskLayoutConstraint;
return constrainedMetric( HeightForWidth, this, width, constrainedChildrenMetric );
2019-09-05 12:08:31 +02:00
}
2019-09-05 12:08:31 +02:00
return -1.0;
}
qreal QskControl::widthForHeight( qreal height ) const
{
Q_D( const QskControl );
d->blockLayoutRequestEvents = false;
2019-09-05 12:08:31 +02:00
if ( d->autoLayoutChildren )
{
2019-09-05 12:37:27 +02:00
using namespace QskLayoutConstraint;
return constrainedMetric( WidthForHeight, this, height, constrainedChildrenMetric );
2019-09-05 12:08:31 +02:00
}
2018-08-03 08:15:28 +02:00
2019-09-05 12:08:31 +02:00
return -1.0;
}
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;
}
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
{
2019-09-04 06:59:43 +02:00
if ( d_func()->autoLayoutChildren && !maybeUnresized() )
2017-07-21 18:21:34 +02:00
{
2019-09-04 06:59:43 +02:00
const auto rect = layoutRect();
2017-07-21 18:21:34 +02:00
2017-10-30 12:06:19 +01:00
const auto children = childItems();
for ( auto child : children )
2017-07-21 18:21:34 +02:00
{
2019-09-05 12:08:31 +02:00
// checking qskIsVisibleToParent ???
2019-09-04 06:59:43 +02:00
if ( !qskIsTransparentForPositioner( child ) )
{
2019-09-05 12:08:31 +02:00
const auto itemRect = QskLayoutConstraint::boundedRect(
child, rect, QskLayoutConstraint::layoutAlignmentHint( child ) );
qskSetItemGeometry( child, itemRect );
}
2017-07-21 18:21:34 +02:00
}
}
2019-09-04 06:59:43 +02:00
updateResources();
2017-07-21 18:21:34 +02:00
updateLayout();
}
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() const
{
qreal w = -1; // no hint
qreal h = -1;
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 );
}
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"