qskinny/src/controls/QskSubWindowArea.cpp

281 lines
6.8 KiB
C++

/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskSubWindowArea.h"
#include "QskEvent.h"
#include "QskPlatform.h"
#include "QskSubWindow.h"
#include <qtimer.h>
QSK_SUBCONTROL( QskSubWindowArea, Panel )
static void qskUpdateEventFilter( QskSubWindowArea* area )
{
for ( auto child : area->children() )
{
if ( auto window = qobject_cast< QskSubWindow* >( child ) )
{
window->removeEventFilter( area );
window->installEventFilter( area );
}
}
}
static Qt::Edges qskSelectedEdges( const QRectF& rect, const QPointF& pos )
{
const qreal tolerance = qskDpiScaled( 10.0 );
Qt::Edges edges;
if ( pos.x() <= rect.left() + tolerance )
{
edges |= Qt::LeftEdge;
}
else if ( pos.x() >= rect.right() - tolerance )
{
edges |= Qt::RightEdge;
}
if ( pos.y() <= rect.top() + tolerance )
{
edges |= Qt::TopEdge;
}
else if ( pos.y() >= rect.bottom() - tolerance )
{
edges |= Qt::BottomEdge;
}
return edges;
}
static void qskDragWindow( const QPointF& off, Qt::Edges edges, QskSubWindow* window )
{
if ( edges == 0 )
{
window->setPosition( window->position() + off );
}
else
{
QRectF rect( window->position(), window->size() );
if ( edges & Qt::LeftEdge )
rect.setLeft( rect.left() + off.x() );
if ( edges & Qt::RightEdge )
rect.setRight( rect.right() + off.x() );
if ( edges & Qt::TopEdge )
rect.setTop( rect.top() + off.y() );
if ( edges & Qt::BottomEdge )
rect.setBottom( rect.bottom() + off.y() );
window->setGeometry( rect );
}
}
class QskSubWindowArea::PrivateData
{
public:
PrivateData()
: isDraggableByHeaderOnly( false )
, isDragging( false )
{
}
// data about the window being dragged
bool isDraggableByHeaderOnly : 1;
bool isDragging : 1;
Qt::Edges draggedEdges;
QPointF mousePos;
};
QskSubWindowArea::QskSubWindowArea( QQuickItem* parent )
: Inherited( parent )
, m_data( new PrivateData() )
{
setMargins( 0 );
// setAcceptedMouseButtons( Qt::AllButtons );
}
QskSubWindowArea::~QskSubWindowArea()
{
}
void QskSubWindowArea::geometryChangeEvent( QskGeometryChangeEvent* event )
{
if ( event->isResized() )
{
// what to do with the windows ???
}
Inherited::geometryChangeEvent( event );
}
void QskSubWindowArea::itemChange(
QQuickItem::ItemChange change, const QQuickItem::ItemChangeData& value )
{
Inherited::itemChange( change, value );
switch ( change )
{
case QQuickItem::ItemChildAddedChange:
{
// the child is not fully constructed
// and we have to delay checking for sub windows
QTimer::singleShot( 0, this,
[ this ] { qskUpdateEventFilter( this ); } );
break;
}
case QQuickItem::ItemChildRemovedChange:
{
if ( qobject_cast< QskSubWindow* >( value.item ) )
value.item->removeEventFilter( this );
break;
}
default:
{
break;
}
}
}
bool QskSubWindowArea::eventFilter( QObject* object, QEvent* event )
{
if ( QskSubWindow* window = qobject_cast< QskSubWindow* >( object ) )
{
switch ( event->type() )
{
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseMove:
{
bool ok = mouseEventFilter( window, static_cast< QMouseEvent* >( event ) );
if ( ok )
return true;
break;
}
case QEvent::Enter:
{
setActive( window, true );
break;
}
case QEvent::Leave:
{
setActive( window, false );
break;
}
default:
{
break;
}
}
}
return Inherited::eventFilter( object, event );
}
bool QskSubWindowArea::mouseEventFilter( QskSubWindow* window, const QMouseEvent* event )
{
if ( window == nullptr || window->parentItem() != this )
return false;
const QRectF cr = window->contentsRect();
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
const auto mousePos = qskMousePosition( event );
if ( !( cr.contains( mousePos ) &&
event->button() == Qt::LeftButton ) )
{
return false;
}
if ( event->button() == Qt::LeftButton )
window->setFocus( true );
#if 0
// how to handle not to be process visual
// changes for double click events ???
if ( window->titleBarRect().contains( event->localPos() ) )
{
// block button press until we know it is no double click
///QGuiApplication::styleHints()->mouseDoubleClickInterval()
}
#endif
bool doDrag = !m_data->isDraggableByHeaderOnly;
if ( !doDrag )
{
// dragging by title bar only
doDrag = window->titleBarRect().contains( mousePos );
}
if ( doDrag )
{
m_data->isDragging = true;
m_data->draggedEdges = qskSelectedEdges( cr, mousePos );
m_data->mousePos = qskMouseScenePosition( event );
setDragging( window, true );
return true;
}
break;
}
case QEvent::MouseMove:
{
if ( m_data->isDragging )
{
const auto scenePos = qskMouseScenePosition( event );
qskDragWindow( scenePos - m_data->mousePos,
m_data->draggedEdges, window );
m_data->mousePos = scenePos;
return true;
}
break;
}
case QEvent::MouseButtonRelease:
{
if ( m_data->isDragging )
{
setDragging( window, false );
m_data->mousePos = QPointF();
m_data->isDragging = false;
return true;
}
break;
}
default:
{
break;
}
}
return false;
}
void QskSubWindowArea::setDragging( QskSubWindow* window, bool on )
{
window->setOpacity( on ? 0.6 : 1.0 );
}
void QskSubWindowArea::setActive( QskSubWindow* window, bool on )
{
qDebug() << window << on;
}
#include "moc_QskSubWindowArea.cpp"