qskinny/src/controls/QskInputGrabber.cpp
2018-08-03 08:15:28 +02:00

207 lines
5.2 KiB
C++

/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskInputGrabber.h"
#include "QskWindow.h"
#include <qpointer.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h>
#include <private/qquickitemchangelistener_p.h>
QSK_QT_PRIVATE_END
class QskInputGrabber::PrivateData final : public QQuickItemChangeListener
{
public:
PrivateData( QskInputGrabber* grabber )
: m_grabber( grabber )
{
}
inline QRectF grabberRect() const
{
if ( itemBelow && itemAbove )
{
const auto pos = itemBelow->mapToItem( itemAbove, QPointF() );
return QRectF( pos.x(), pos.y(), itemBelow->width(), itemBelow->height() );
}
return QRectF();
}
void enableListener( QQuickItem* item,
QQuickItemPrivate::ChangeTypes types, bool on )
{
if ( item )
{
auto d = QQuickItemPrivate::get( item );
if ( on )
d->addItemChangeListener( this, types );
else
d->removeItemChangeListener( this, types );
}
}
void setup( QQuickItem* item )
{
QQuickItem* newItemBelow = item ? item->parentItem() : nullptr;
QQuickItem* newItemAbove = item;
if ( newItemBelow != itemBelow )
{
const auto changeTypes = QQuickItemPrivate::Geometry;
enableListener( itemBelow, changeTypes, false );
enableListener( newItemBelow, changeTypes, true );
itemBelow = newItemBelow;
}
if ( newItemAbove != itemAbove )
{
const auto changeTypes = QQuickItemPrivate::Geometry | QQuickItemPrivate::Parent;
enableListener( itemAbove, changeTypes, false );
enableListener( newItemAbove, changeTypes, true );
itemAbove = newItemAbove;
}
}
private:
#if QT_VERSION >= QT_VERSION_CHECK( 5, 8, 0 )
void itemGeometryChanged( QQuickItem* item,
QQuickGeometryChange change, const QRectF& ) override
{
bool doUpdate = false;
if ( item == itemAbove )
doUpdate = change.positionChange();
else
doUpdate = change.sizeChange();
if ( doUpdate )
m_grabber->updateGeometry();
}
#else
void itemGeometryChanged(
QQuickItem* item, const QRectF& newRect, const QRectF& oldRect ) override
{
bool doUpdate = false;
if ( item == itemAbove )
doUpdate = newRect.size() != oldRect.size();
else
doUpdate = newRect.topLeft() != oldRect.topLeft();
if ( doUpdate )
m_grabber->updateGeometry();
}
#endif
void itemParentChanged( QQuickItem* item, QQuickItem* parentItem ) override
{
if ( item == m_grabber && parentItem )
{
setup( parentItem );
m_grabber->updateGeometry();
}
}
QskInputGrabber* m_grabber;
public:
QPointer< QQuickItem > itemAbove;
QPointer< QQuickItem > itemBelow;
};
QskInputGrabber::QskInputGrabber( QQuickItem* parent )
: Inherited( parent )
, m_data( new PrivateData( this ) )
{
setAcceptedMouseButtons( Qt::AllButtons );
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
setAcceptTouchEvents( true );
#endif
setAcceptHoverEvents( true );
setTransparentForPositioner( true );
setFlag( QQuickItem::ItemHasContents, false );
m_data->setup( parent );
updateGeometry();
}
QskInputGrabber::~QskInputGrabber()
{
m_data->setup( nullptr );
}
bool QskInputGrabber::event( QEvent* event )
{
bool doBlock = false;
switch ( static_cast< int >( event->type() ) )
{
case QEvent::MouseButtonPress:
case QEvent::MouseMove:
case QEvent::MouseButtonRelease:
{
const auto ev = static_cast< QMouseEvent* >( event );
doBlock = isBlocking( ev->localPos() );
break;
}
case QEvent::Wheel:
{
const auto ev = static_cast< QWheelEvent* >( event );
doBlock = isBlocking( ev->posF() );
break;
}
case QEvent::HoverEnter:
case QEvent::HoverLeave:
{
const auto ev = static_cast< QHoverEvent* >( event );
doBlock = isBlocking( ev->posF() );
break;
}
}
if ( doBlock )
{
event->accept();
if ( auto w = qobject_cast< QskWindow* >( window() ) )
w->setEventAcceptance( QskWindow::EventPropagationStopped );
return true;
}
return Inherited::event( event );
}
bool QskInputGrabber::isBlocking( const QPointF& pos ) const
{
if ( const auto item = parentItem() )
return !item->contains( position() + pos );
return true;
}
QRectF QskInputGrabber::grabberRect() const
{
return m_data->grabberRect();
}
void QskInputGrabber::updateGeometry()
{
const QRectF rect = grabberRect();
if ( rect != geometry() )
setGeometry( rect );
}
#include "moc_QskInputGrabber.cpp"