2018-05-01 12:26:59 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
2023-04-06 09:23:37 +02:00
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
2018-05-01 12:26:59 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskQuick.h"
|
|
|
|
#include "QskControl.h"
|
2019-09-10 17:01:47 +02:00
|
|
|
#include "QskFunctions.h"
|
2022-08-06 15:41:32 +02:00
|
|
|
#include "QskLayoutElement.h"
|
2023-04-05 09:52:23 +02:00
|
|
|
#include "QskPlatform.h"
|
2018-07-19 14:10:48 +02:00
|
|
|
#include <qquickitem.h>
|
2018-05-01 12:26:59 +02:00
|
|
|
|
|
|
|
QSK_QT_PRIVATE_BEGIN
|
2018-08-03 08:15:28 +02:00
|
|
|
#include <private/qquickitem_p.h>
|
2023-12-17 17:32:07 +01:00
|
|
|
#include <private/qquickwindow_p.h>
|
|
|
|
#include <private/qsgrenderer_p.h>
|
2018-05-01 12:26:59 +02:00
|
|
|
QSK_QT_PRIVATE_END
|
|
|
|
|
|
|
|
#include <qpa/qplatforminputcontext.h>
|
2018-08-03 08:15:28 +02:00
|
|
|
#include <qpa/qplatformintegration.h>
|
2018-05-01 12:26:59 +02:00
|
|
|
|
|
|
|
QRectF qskItemRect( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
auto d = QQuickItemPrivate::get( item );
|
|
|
|
return QRectF( 0, 0, d->width, d->height );
|
|
|
|
}
|
|
|
|
|
|
|
|
QRectF qskItemGeometry( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
auto d = QQuickItemPrivate::get( item );
|
|
|
|
return QRectF( d->x, d->y, d->width, d->height );
|
|
|
|
}
|
|
|
|
|
|
|
|
void qskSetItemGeometry( QQuickItem* item, const QRectF& rect )
|
|
|
|
{
|
2019-04-26 11:56:09 +02:00
|
|
|
if ( auto control = qskControlCast( item ) )
|
2018-05-01 12:26:59 +02:00
|
|
|
{
|
|
|
|
control->setGeometry( rect );
|
|
|
|
}
|
2022-04-07 15:43:45 +02:00
|
|
|
else if ( item )
|
2018-05-01 12:26:59 +02:00
|
|
|
{
|
|
|
|
item->setPosition( rect.topLeft() );
|
|
|
|
item->setSize( rect.size() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool qskIsItemComplete( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
return QQuickItemPrivate::get( item )->componentComplete;
|
|
|
|
}
|
|
|
|
|
2023-10-23 18:32:08 +02:00
|
|
|
bool qskIsItemInDestructor( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
auto d = QQuickItemPrivate::get( item );
|
|
|
|
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 5, 0 )
|
|
|
|
return d->inDestructor;
|
|
|
|
#else
|
|
|
|
/*
|
|
|
|
QskQuickItem sets componentComplete to false in its destructor,
|
|
|
|
but for other items we will will return the wrong information
|
|
|
|
*/
|
|
|
|
return !d->componentComplete;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-05-01 12:26:59 +02:00
|
|
|
bool qskIsAncestorOf( const QQuickItem* item, const QQuickItem* child )
|
|
|
|
{
|
|
|
|
if ( item == nullptr || child == nullptr )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return item->isAncestorOf( child );
|
|
|
|
}
|
|
|
|
|
2018-10-23 19:18:05 +02:00
|
|
|
bool qskIsVisibleToParent( const QQuickItem* item )
|
|
|
|
{
|
2022-04-07 15:43:45 +02:00
|
|
|
if ( item == nullptr )
|
|
|
|
return false;
|
2019-05-17 22:33:02 +02:00
|
|
|
|
2022-04-07 15:43:45 +02:00
|
|
|
return QQuickItemPrivate::get( item )->explicitVisible;
|
2018-10-23 19:18:05 +02:00
|
|
|
}
|
|
|
|
|
2018-06-26 11:10:44 +02:00
|
|
|
bool qskIsVisibleTo( const QQuickItem* item, const QQuickItem* ancestor )
|
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( ancestor == nullptr )
|
|
|
|
return item->isVisible(); // like QWidget::isVisibleTo
|
|
|
|
|
2018-06-26 11:46:51 +02:00
|
|
|
for ( auto it = item->parentItem();
|
|
|
|
it != ancestor; it = it->parentItem() )
|
2018-06-26 11:10:44 +02:00
|
|
|
{
|
2018-06-26 11:46:51 +02:00
|
|
|
if ( it == nullptr )
|
2018-06-26 11:10:44 +02:00
|
|
|
return false; // ancestor is no parent
|
|
|
|
|
2018-06-26 11:46:51 +02:00
|
|
|
if ( !QQuickItemPrivate::get( it )->explicitVisible )
|
2018-06-26 11:10:44 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-05-01 12:26:59 +02:00
|
|
|
bool qskIsTabFence( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return QQuickItemPrivate::get( item )->isTabFence;
|
|
|
|
}
|
|
|
|
|
2019-05-17 22:33:02 +02:00
|
|
|
bool qskIsPolishScheduled( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item )
|
|
|
|
return QQuickItemPrivate::get( item )->polishScheduled;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-05-01 12:26:59 +02:00
|
|
|
bool qskIsShortcutScope( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
We might have something like CTRL+W to close a "window".
|
|
|
|
But in Qt/Quick a window is not necessarily a QQuickWindow
|
|
|
|
like we have f.e QskSubWindow.
|
|
|
|
|
|
|
|
Maybe it's worth to introduce a shortcutScope flag but for
|
|
|
|
the moment we simply use the isFocusScope/isTabFence combination,
|
|
|
|
that should usually be set for those "windows".
|
|
|
|
*/
|
|
|
|
|
|
|
|
return item->isFocusScope() && QQuickItemPrivate::get( item )->isTabFence;
|
|
|
|
}
|
|
|
|
|
2019-09-10 17:01:47 +02:00
|
|
|
bool qskIsVisibleToLayout( const QQuickItem* item )
|
|
|
|
{
|
2022-04-08 16:46:20 +02:00
|
|
|
return qskEffectivePlacementPolicy( item ) != QskPlacementPolicy::Ignore;
|
2022-04-07 17:19:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool qskIsAdjustableByLayout( const QQuickItem* item )
|
|
|
|
{
|
2022-04-08 16:46:20 +02:00
|
|
|
return qskEffectivePlacementPolicy( item ) == QskPlacementPolicy::Adjust;
|
2019-09-10 17:01:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QskSizePolicy qskSizePolicy( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( auto control = qskControlCast( item ) )
|
|
|
|
return control->sizePolicy();
|
|
|
|
|
|
|
|
if ( item )
|
|
|
|
{
|
|
|
|
const QVariant v = item->property( "sizePolicy" );
|
|
|
|
if ( v.canConvert< QskSizePolicy >() )
|
|
|
|
return qvariant_cast< QskSizePolicy >( v );
|
|
|
|
}
|
|
|
|
|
|
|
|
return QskSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Preferred );
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Alignment qskLayoutAlignmentHint( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( auto control = qskControlCast( item ) )
|
|
|
|
return control->layoutAlignmentHint();
|
|
|
|
|
|
|
|
if ( item )
|
|
|
|
{
|
|
|
|
const QVariant v = item->property( "layoutAlignmentHint" );
|
|
|
|
if ( v.canConvert< Qt::Alignment >() )
|
|
|
|
return v.value< Qt::Alignment >();
|
|
|
|
}
|
|
|
|
|
|
|
|
return Qt::Alignment();
|
|
|
|
}
|
|
|
|
|
2022-04-08 16:46:20 +02:00
|
|
|
void qskSetPlacementPolicy( QQuickItem* item, const QskPlacementPolicy policy )
|
2019-09-10 17:01:47 +02:00
|
|
|
{
|
2022-04-08 16:46:20 +02:00
|
|
|
if ( item == nullptr )
|
|
|
|
return;
|
|
|
|
|
2019-09-10 17:01:47 +02:00
|
|
|
if ( auto control = qskControlCast( item ) )
|
2022-04-08 16:46:20 +02:00
|
|
|
{
|
|
|
|
control->setPlacementPolicy( policy );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
item->setProperty( "layoutPolicy", QVariant::fromValue( policy ) );
|
2019-09-10 17:01:47 +02:00
|
|
|
|
2022-04-08 16:46:20 +02:00
|
|
|
auto d = QQuickItemPrivate::get( item );
|
|
|
|
|
|
|
|
const bool ignore = policy.visiblePolicy() == QskPlacementPolicy::Ignore;
|
|
|
|
if ( ignore != d->isTransparentForPositioner() )
|
|
|
|
d->setTransparentForPositioner( ignore );
|
|
|
|
|
|
|
|
// sending a LayoutRequest ?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskPlacementPolicy qskPlacementPolicy( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return QskPlacementPolicy( QskPlacementPolicy::Ignore, QskPlacementPolicy::Ignore );
|
|
|
|
|
|
|
|
if ( auto control = qskControlCast( item ) )
|
2019-09-10 17:01:47 +02:00
|
|
|
{
|
2022-04-08 16:46:20 +02:00
|
|
|
return control->placementPolicy();
|
2019-09-10 17:01:47 +02:00
|
|
|
}
|
2022-04-08 16:46:20 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
QskPlacementPolicy policy;
|
2019-09-10 17:01:47 +02:00
|
|
|
|
2022-04-08 16:46:20 +02:00
|
|
|
const auto v = item->property( "layoutPolicy" );
|
|
|
|
if ( v.canConvert< QskPlacementPolicy >() )
|
|
|
|
policy = v.value< QskPlacementPolicy >();
|
|
|
|
|
|
|
|
auto d = QQuickItemPrivate::get( item );
|
|
|
|
if ( d->isTransparentForPositioner() )
|
|
|
|
policy.setVisiblePolicy( QskPlacementPolicy::Ignore );
|
|
|
|
|
|
|
|
return policy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskPlacementPolicy::Policy qskEffectivePlacementPolicy( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return QskPlacementPolicy::Ignore;
|
|
|
|
|
|
|
|
const auto policy = qskPlacementPolicy( item );
|
|
|
|
|
|
|
|
if ( qskIsVisibleToParent( item ) )
|
|
|
|
return policy.visiblePolicy();
|
|
|
|
else
|
|
|
|
return policy.hiddenPolicy();
|
2019-09-10 17:01:47 +02:00
|
|
|
}
|
|
|
|
|
2018-05-01 12:26:59 +02:00
|
|
|
QQuickItem* qskNearestFocusScope( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item )
|
|
|
|
{
|
2019-09-10 17:01:47 +02:00
|
|
|
for ( auto scope = item->parentItem();
|
2018-05-01 12:26:59 +02:00
|
|
|
scope != nullptr; scope = scope->parentItem() )
|
|
|
|
{
|
|
|
|
if ( scope->isFocusScope() )
|
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
As the default setting of the root item is to be a focus scope
|
|
|
|
we usually never get here - beside the flag has been explicitely
|
|
|
|
disabled in application code.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qskForceActiveFocus( QQuickItem* item, Qt::FocusReason reason )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
For unknown reasons Qt::PopupFocusReason is blocked inside of
|
|
|
|
QQuickItem::setFocus and so we can't use QQuickItem::forceActiveFocus
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ( item == nullptr || item->window() == nullptr )
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
2021-04-26 11:44:25 +02:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 1, 0 )
|
|
|
|
auto wp = QQuickItemPrivate::get( item )->deliveryAgentPrivate();
|
|
|
|
#else
|
|
|
|
auto wp = QQuickWindowPrivate::get( item->window() );
|
|
|
|
#endif
|
2018-05-01 12:26:59 +02:00
|
|
|
while ( const auto scope = qskNearestFocusScope( item ) )
|
|
|
|
{
|
|
|
|
wp->setFocusInScope( scope, item, reason );
|
|
|
|
item = scope;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-12 10:56:06 +02:00
|
|
|
void qskUpdateInputMethod( const QQuickItem* item, Qt::InputMethodQueries queries )
|
2018-05-01 12:26:59 +02:00
|
|
|
{
|
2018-06-12 10:56:06 +02:00
|
|
|
if ( item == nullptr || !( item->flags() & QQuickItem::ItemAcceptsInputMethod ) )
|
|
|
|
return;
|
2018-05-01 12:26:59 +02:00
|
|
|
|
2018-06-12 10:56:06 +02:00
|
|
|
static QPlatformInputContext* context = nullptr;
|
|
|
|
static int methodId = -1;
|
2018-05-01 12:26:59 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
We could also get the inputContext from QInputMethodPrivate
|
|
|
|
but for some reason the gcc sanitizer reports errors
|
|
|
|
when using it. So let's go with QGuiApplicationPrivate.
|
|
|
|
*/
|
|
|
|
|
2023-04-05 09:52:23 +02:00
|
|
|
auto inputContext = qskPlatformIntegration()->inputContext();
|
2018-06-12 10:56:06 +02:00
|
|
|
if ( inputContext == nullptr )
|
2018-05-01 12:26:59 +02:00
|
|
|
{
|
2018-06-12 10:56:06 +02:00
|
|
|
context = nullptr;
|
|
|
|
methodId = -1;
|
2018-05-01 12:26:59 +02:00
|
|
|
|
|
|
|
return;
|
2018-06-12 10:56:06 +02:00
|
|
|
}
|
2018-05-01 12:26:59 +02:00
|
|
|
|
2018-06-12 10:56:06 +02:00
|
|
|
if ( inputContext != context )
|
|
|
|
{
|
|
|
|
context = inputContext;
|
|
|
|
methodId = inputContext->metaObject()->indexOfMethod(
|
|
|
|
"update(const QQuickItem*,Qt::InputMethodQueries)" );
|
|
|
|
}
|
2018-05-01 12:26:59 +02:00
|
|
|
|
2018-06-12 10:56:06 +02:00
|
|
|
if ( methodId >= 0 )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The protocol for input methods does not fit well for a
|
|
|
|
virtual keyboard as it is tied to the focus.
|
|
|
|
So we try to bypass QInputMethod calling the
|
|
|
|
inputContext directly.
|
|
|
|
*/
|
2018-05-01 12:26:59 +02:00
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
const auto method = inputContext->metaObject()->method( methodId );
|
|
|
|
method.invoke( inputContext, Qt::DirectConnection,
|
|
|
|
Q_ARG( const QQuickItem*, item ), Q_ARG( Qt::InputMethodQueries, queries ) );
|
2018-06-12 10:56:06 +02:00
|
|
|
}
|
2018-05-01 12:26:59 +02:00
|
|
|
else
|
2018-06-12 10:56:06 +02:00
|
|
|
{
|
2018-05-01 12:26:59 +02:00
|
|
|
QGuiApplication::inputMethod()->update( queries );
|
2018-06-12 10:56:06 +02:00
|
|
|
}
|
2018-05-01 12:26:59 +02:00
|
|
|
}
|
|
|
|
|
2018-06-12 18:43:14 +02:00
|
|
|
void qskInputMethodSetVisible( const QQuickItem* item, bool on )
|
|
|
|
{
|
|
|
|
static QPlatformInputContext* context = nullptr;
|
|
|
|
static int methodId = -1;
|
|
|
|
|
2023-04-05 09:52:23 +02:00
|
|
|
auto inputContext = qskPlatformIntegration()->inputContext();
|
2018-06-12 18:43:14 +02:00
|
|
|
if ( inputContext == nullptr )
|
|
|
|
{
|
|
|
|
context = nullptr;
|
|
|
|
methodId = -1;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( inputContext != context )
|
|
|
|
{
|
|
|
|
context = inputContext;
|
|
|
|
methodId = inputContext->metaObject()->indexOfMethod(
|
|
|
|
"setInputPanelVisible(const QQuickItem*,bool)" );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( methodId >= 0 )
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
const auto method = inputContext->metaObject()->method( methodId );
|
|
|
|
method.invoke( inputContext, Qt::DirectConnection,
|
|
|
|
Q_ARG( const QQuickItem*, item ), Q_ARG( bool, on ) );
|
2018-06-12 18:43:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( on )
|
|
|
|
QGuiApplication::inputMethod()->show();
|
|
|
|
else
|
|
|
|
QGuiApplication::inputMethod()->hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 12:26:59 +02:00
|
|
|
QList< QQuickItem* > qskPaintOrderChildItems( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item )
|
|
|
|
return QQuickItemPrivate::get( item )->paintOrderChildItems();
|
|
|
|
|
|
|
|
return QList< QQuickItem* >();
|
|
|
|
}
|
|
|
|
|
2023-10-30 17:08:01 +01:00
|
|
|
const QSGTransformNode* qskItemNode( const QQuickItem* item )
|
2018-05-01 12:26:59 +02:00
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return QQuickItemPrivate::get( item )->itemNodeInstance;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QSGNode* qskPaintNode( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return QQuickItemPrivate::get( item )->paintNode;
|
|
|
|
}
|
2019-09-10 17:01:47 +02:00
|
|
|
|
2023-12-17 17:32:07 +01:00
|
|
|
const QSGRootNode* qskScenegraphAnchorNode( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return QQuickItemPrivate::get( item )->rootNode();
|
|
|
|
}
|
|
|
|
|
|
|
|
const QSGRootNode* qskScenegraphAnchorNode( const QQuickWindow* window )
|
|
|
|
{
|
2023-12-17 18:12:57 +01:00
|
|
|
if ( auto w = const_cast< QQuickWindow* >( window ) )
|
2023-12-17 17:32:07 +01:00
|
|
|
{
|
2023-12-17 18:12:57 +01:00
|
|
|
if ( auto renderer = QQuickWindowPrivate::get( w )->renderer )
|
2023-12-17 17:32:07 +01:00
|
|
|
return renderer->rootNode();
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qskSetScenegraphAnchor( QQuickItem* item, bool on )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
For setting up a subtree renderer ( f.e in QskSceneTexture ) we need
|
|
|
|
to insert a QSGRootNode above the paintNode.
|
|
|
|
|
|
|
|
( In Qt this feature is exlusively used in the Qt/Quick Effects module
|
|
|
|
what lead to the not very intuitive name "refFromEffectItem" )
|
|
|
|
|
|
|
|
refFromEffectItem also allows to insert a opacity node of 0 to
|
|
|
|
hide the subtree from the main renderer by setting its parameter to
|
|
|
|
true. We have QskItemNode to achieve the same.
|
|
|
|
*/
|
|
|
|
if ( item )
|
|
|
|
{
|
|
|
|
auto d = QQuickItemPrivate::get( item );
|
|
|
|
if ( on )
|
|
|
|
d->refFromEffectItem( false );
|
|
|
|
else
|
|
|
|
d->derefFromEffectItem( false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-10 17:01:47 +02:00
|
|
|
QSizeF qskEffectiveSizeHint( const QQuickItem* item,
|
|
|
|
Qt::SizeHint whichHint, const QSizeF& constraint )
|
|
|
|
{
|
|
|
|
if ( auto control = qskControlCast( item ) )
|
|
|
|
return control->effectiveSizeHint( whichHint, constraint );
|
|
|
|
|
|
|
|
if ( constraint.width() >= 0.0 || constraint.height() >= 0.0 )
|
|
|
|
{
|
|
|
|
// QQuickItem does not support dynamic constraints
|
|
|
|
return constraint;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( item == nullptr )
|
|
|
|
return QSizeF();
|
|
|
|
|
|
|
|
/*
|
|
|
|
Trying to retrieve something useful for non QskControls:
|
|
|
|
|
|
|
|
First are checking some properties, that usually match the
|
|
|
|
names for the explicit hints. For the implicit hints we only
|
|
|
|
have the implicitSize, what is interpreted as the implicit
|
|
|
|
preferred size.
|
|
|
|
*/
|
|
|
|
QSizeF hint;
|
|
|
|
|
|
|
|
static const char* properties[] =
|
|
|
|
{
|
|
|
|
"minimumSize",
|
|
|
|
"preferredSize",
|
|
|
|
"maximumSize"
|
|
|
|
};
|
|
|
|
|
2020-12-29 09:47:03 +01:00
|
|
|
const auto v = item->property( properties[ whichHint ] );
|
2020-10-23 12:48:34 +02:00
|
|
|
if ( v.canConvert< QSizeF >() )
|
2019-09-10 17:01:47 +02:00
|
|
|
hint = v.toSizeF();
|
|
|
|
|
|
|
|
if ( whichHint == Qt::PreferredSize )
|
|
|
|
{
|
|
|
|
if ( hint.width() < 0 )
|
|
|
|
hint.setWidth( item->implicitWidth() );
|
|
|
|
|
|
|
|
if ( hint.height() < 0 )
|
|
|
|
hint.setHeight( item->implicitHeight() );
|
|
|
|
}
|
|
|
|
|
|
|
|
return hint;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSizeF qskSizeConstraint( const QQuickItem* item,
|
|
|
|
Qt::SizeHint which, const QSizeF& constraint )
|
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return QSizeF( 0, 0 );
|
|
|
|
|
2022-08-06 15:41:32 +02:00
|
|
|
const QskItemLayoutElement layoutElement( item );
|
|
|
|
return layoutElement.sizeConstraint( which, constraint );
|
2019-09-10 17:01:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QSizeF qskConstrainedItemSize( const QQuickItem* item, const QSizeF& size )
|
|
|
|
{
|
2022-08-06 15:41:32 +02:00
|
|
|
if ( item == nullptr )
|
2019-09-15 19:26:46 +02:00
|
|
|
return QSizeF( 0.0, 0.0 );
|
|
|
|
|
2022-08-06 15:41:32 +02:00
|
|
|
const QskItemLayoutElement layoutElement( item );
|
|
|
|
return layoutElement.constrainedSize( size );
|
2019-09-10 17:01:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QRectF qskConstrainedItemRect( const QQuickItem* item,
|
|
|
|
const QRectF& rect, Qt::Alignment alignment )
|
|
|
|
{
|
|
|
|
const auto size = qskConstrainedItemSize( item, rect.size() );
|
2022-07-28 16:51:20 +02:00
|
|
|
return qskAlignedRectF( rect, size, alignment );
|
2019-09-10 17:01:47 +02:00
|
|
|
}
|
|
|
|
|
2019-11-05 11:47:56 +01:00
|
|
|
void qskItemUpdateRecursive( QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return;
|
2019-09-10 17:01:47 +02:00
|
|
|
|
2019-11-05 11:47:56 +01:00
|
|
|
if ( item->flags() & QQuickItem::ItemHasContents )
|
|
|
|
item->update();
|
|
|
|
|
|
|
|
const auto& children = QQuickItemPrivate::get( item )->childItems;
|
|
|
|
for ( auto child : children )
|
|
|
|
qskItemUpdateRecursive( child );
|
|
|
|
}
|
2021-03-08 12:56:13 +01:00
|
|
|
|
2022-03-08 11:53:46 +01:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
2021-03-08 12:56:13 +01:00
|
|
|
|
|
|
|
static const QQuickPointerTouchEvent* qskPointerPressEvent( const QQuickWindowPrivate* wd )
|
|
|
|
{
|
2023-07-20 08:36:07 +02:00
|
|
|
for ( const auto event : std::as_const( wd->pointerEventInstances ) )
|
2021-03-08 12:56:13 +01:00
|
|
|
{
|
|
|
|
if ( auto touchEvent = event->asPointerTouchEvent() )
|
|
|
|
{
|
|
|
|
if ( touchEvent->isPressEvent() )
|
|
|
|
return touchEvent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool qskGrabMouse( QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item == nullptr || item->window() == nullptr )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( const auto mouseGrabber = item->window()->mouseGrabberItem() )
|
|
|
|
{
|
|
|
|
if ( mouseGrabber == item )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if ( mouseGrabber->keepMouseGrab() )
|
|
|
|
{
|
|
|
|
// we respect this
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
item->setKeepMouseGrab( true );
|
|
|
|
|
2022-03-08 11:53:46 +01:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
2021-03-08 12:56:13 +01:00
|
|
|
|
|
|
|
auto wd = QQuickWindowPrivate::get( item->window() );
|
|
|
|
if ( wd->touchMouseDevice == nullptr )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
For synthesized mouse events QQuickWindow sends
|
|
|
|
an initial QEvent::MouseButtonPress before setting
|
|
|
|
touchMouseDevice/touchMouseId. As the mouse grabber is
|
|
|
|
stored depending on these attributes the following
|
|
|
|
mouse event callbacks will look for the grabber at a
|
|
|
|
a different place as it was stored.
|
2021-08-04 09:31:16 +02:00
|
|
|
*/
|
2021-03-08 12:56:13 +01:00
|
|
|
|
|
|
|
if ( const auto event = qskPointerPressEvent( wd ) )
|
|
|
|
{
|
|
|
|
if ( const auto p = event->point( 0 ) )
|
|
|
|
{
|
|
|
|
wd->touchMouseDevice = event->device();
|
|
|
|
wd->touchMouseId = p->pointId();
|
|
|
|
|
|
|
|
item->grabMouse();
|
|
|
|
|
|
|
|
wd->touchMouseDevice = nullptr;
|
|
|
|
wd->touchMouseId = -1;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
item->grabMouse();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qskUngrabMouse( QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item )
|
|
|
|
{
|
|
|
|
item->setKeepMouseGrab( false );
|
|
|
|
|
|
|
|
if ( qskIsMouseGrabber( item ) )
|
|
|
|
item->ungrabMouse();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool qskIsMouseGrabber( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item )
|
|
|
|
{
|
|
|
|
if ( const auto window = item->window() )
|
|
|
|
return window->mouseGrabberItem() == item;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|