working on fade/slide in/out effects for popups
This commit is contained in:
parent
1ddb7aee6b
commit
f1ac0cc13d
|
@ -15,6 +15,7 @@ QSK_QT_PRIVATE_BEGIN
|
||||||
QSK_QT_PRIVATE_END
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
QSK_SUBCONTROL( QskPopup, Overlay )
|
QSK_SUBCONTROL( QskPopup, Overlay )
|
||||||
|
QSK_STATE( QskPopup, Closed, QskAspect::FirstSystemState << 1 )
|
||||||
|
|
||||||
static void qskSetFocus( QQuickItem* item, bool on )
|
static void qskSetFocus( QQuickItem* item, bool on )
|
||||||
{
|
{
|
||||||
|
@ -101,7 +102,7 @@ class QskPopup::PrivateData
|
||||||
PrivateData()
|
PrivateData()
|
||||||
: flags( 0 )
|
: flags( 0 )
|
||||||
, isModal( false )
|
, isModal( false )
|
||||||
, isOpen( false )
|
, hasFaderEffect( true )
|
||||||
, autoGrabFocus( true )
|
, autoGrabFocus( true )
|
||||||
, handoverFocus( true )
|
, handoverFocus( true )
|
||||||
{
|
{
|
||||||
|
@ -110,10 +111,11 @@ class QskPopup::PrivateData
|
||||||
InputGrabber* inputGrabber = nullptr;
|
InputGrabber* inputGrabber = nullptr;
|
||||||
|
|
||||||
uint priority = 0;
|
uint priority = 0;
|
||||||
|
QskAspect::Aspect faderAspect;
|
||||||
|
|
||||||
int flags : 4;
|
int flags : 4;
|
||||||
bool isModal : 1;
|
bool isModal : 1;
|
||||||
bool isOpen : 1;
|
bool hasFaderEffect : 1;
|
||||||
|
|
||||||
const bool autoGrabFocus : 1;
|
const bool autoGrabFocus : 1;
|
||||||
const bool handoverFocus : 1;
|
const bool handoverFocus : 1;
|
||||||
|
@ -123,6 +125,10 @@ QskPopup::QskPopup( QQuickItem* parent )
|
||||||
: Inherited( parent )
|
: Inherited( parent )
|
||||||
, m_data( new PrivateData() )
|
, m_data( new PrivateData() )
|
||||||
{
|
{
|
||||||
|
// initially the popup is closed and invisible
|
||||||
|
Inherited::setVisible( false );
|
||||||
|
setSkinStateFlag( QskPopup::Closed );
|
||||||
|
|
||||||
// we need to stop event propagation
|
// we need to stop event propagation
|
||||||
setAcceptedMouseButtons( Qt::AllButtons );
|
setAcceptedMouseButtons( Qt::AllButtons );
|
||||||
setWheelEnabled( true );
|
setWheelEnabled( true );
|
||||||
|
@ -134,6 +140,11 @@ QskPopup::QskPopup( QQuickItem* parent )
|
||||||
setTabFence( true );
|
setTabFence( true );
|
||||||
setFocusPolicy( Qt::StrongFocus );
|
setFocusPolicy( Qt::StrongFocus );
|
||||||
|
|
||||||
|
/*
|
||||||
|
sending a notification to the window, that can
|
||||||
|
be used to register popups for some sort of
|
||||||
|
popup/window management
|
||||||
|
*/
|
||||||
qskSendPopupEvent( window(), this, true );
|
qskSendPopupEvent( window(), this, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,33 +155,61 @@ QskPopup::~QskPopup()
|
||||||
|
|
||||||
void QskPopup::open()
|
void QskPopup::open()
|
||||||
{
|
{
|
||||||
setFading( true );
|
setOpen( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskPopup::close()
|
void QskPopup::close()
|
||||||
{
|
{
|
||||||
const bool wasOpen = m_data->isOpen;
|
setOpen( false );
|
||||||
m_data->isOpen = false;
|
|
||||||
|
|
||||||
setFading( false );
|
|
||||||
|
|
||||||
if ( wasOpen )
|
|
||||||
{
|
|
||||||
Q_EMIT closed();
|
|
||||||
|
|
||||||
if ( testPopupFlag( DeleteOnClose ) )
|
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskPopup::setFading( bool on )
|
void QskPopup::setOpen( bool on )
|
||||||
{
|
{
|
||||||
setVisible( on );
|
if ( on == isOpen() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( on )
|
||||||
|
QskControl::setVisible( on );
|
||||||
|
|
||||||
|
setSkinStateFlag( QskPopup::Closed, !on );
|
||||||
|
|
||||||
|
Q_EMIT openChanged( on );
|
||||||
|
|
||||||
|
if ( on )
|
||||||
|
Q_EMIT opened();
|
||||||
|
else
|
||||||
|
Q_EMIT closed();
|
||||||
|
|
||||||
|
if ( isFading() )
|
||||||
|
{
|
||||||
|
Q_EMIT fadingChanged( true );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( !on )
|
||||||
|
{
|
||||||
|
Inherited::setVisible( false );
|
||||||
|
|
||||||
|
if ( testPopupFlag( QskPopup::DeleteOnClose ) )
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QskPopup::isOpen() const
|
bool QskPopup::isOpen() const
|
||||||
{
|
{
|
||||||
return m_data->isOpen;
|
return !( skinState() & QskPopup::Closed );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QskPopup::isFading() const
|
||||||
|
{
|
||||||
|
if ( m_data->faderAspect.value() == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QskSkinHintStatus status;
|
||||||
|
(void) effectiveHint( m_data->faderAspect, &status );
|
||||||
|
|
||||||
|
return status.source == QskSkinHintStatus::Animator;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF QskPopup::overlayRect() const
|
QRectF QskPopup::overlayRect() const
|
||||||
|
@ -210,6 +249,55 @@ void QskPopup::updateInputGrabber()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QskAspect::Aspect QskPopup::faderAspect() const
|
||||||
|
{
|
||||||
|
return m_data->faderAspect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskPopup::setFaderAspect( QskAspect::Aspect aspect )
|
||||||
|
{
|
||||||
|
auto faderAspect = aspect;
|
||||||
|
faderAspect.clearStates(); // animated values are always stateless
|
||||||
|
|
||||||
|
if ( faderAspect == m_data->faderAspect )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( isFading() )
|
||||||
|
{
|
||||||
|
// stop the running animation TODO ...
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data->faderAspect = faderAspect;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QskPopup::isTransitionAccepted( QskAspect::Aspect aspect ) const
|
||||||
|
{
|
||||||
|
if ( isVisible() && m_data->hasFaderEffect )
|
||||||
|
{
|
||||||
|
if ( ( aspect.value() == 0 ) )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
QskAspect::Aspect() is an early check that is used
|
||||||
|
to find out if more detailed checking of aspects
|
||||||
|
is necessary.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( aspect == m_data->faderAspect )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ( aspect.type() == QskAspect::Color )
|
||||||
|
{
|
||||||
|
if ( aspect.subControl() == effectiveSubcontrol( QskPopup::Overlay ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Inherited::isTransitionAccepted( aspect );
|
||||||
|
}
|
||||||
|
|
||||||
void QskPopup::setPriority( uint priority )
|
void QskPopup::setPriority( uint priority )
|
||||||
{
|
{
|
||||||
if ( m_data->priority != priority )
|
if ( m_data->priority != priority )
|
||||||
|
@ -240,6 +328,20 @@ bool QskPopup::isModal() const
|
||||||
return m_data->isModal;
|
return m_data->isModal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QskPopup::setFaderEffect( bool on )
|
||||||
|
{
|
||||||
|
if ( on != m_data->hasFaderEffect )
|
||||||
|
{
|
||||||
|
m_data->hasFaderEffect = on;
|
||||||
|
Q_EMIT faderEffectChanged( on );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QskPopup::hasFaderEffect() const
|
||||||
|
{
|
||||||
|
return m_data->hasFaderEffect;
|
||||||
|
}
|
||||||
|
|
||||||
void QskPopup::setPopupFlags( PopupFlags flags )
|
void QskPopup::setPopupFlags( PopupFlags flags )
|
||||||
{
|
{
|
||||||
m_data->flags = flags;
|
m_data->flags = flags;
|
||||||
|
@ -323,7 +425,7 @@ bool QskPopup::event( QEvent* event )
|
||||||
{
|
{
|
||||||
bool ok = Inherited::event( event );
|
bool ok = Inherited::event( event );
|
||||||
|
|
||||||
switch ( event->type() )
|
switch ( static_cast< int >( event->type() ) )
|
||||||
{
|
{
|
||||||
case QEvent::KeyPress:
|
case QEvent::KeyPress:
|
||||||
case QEvent::KeyRelease:
|
case QEvent::KeyRelease:
|
||||||
|
@ -344,6 +446,26 @@ bool QskPopup::event( QEvent* event )
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case QskEvent::Animator:
|
||||||
|
{
|
||||||
|
const auto animtorEvent = static_cast< QskAnimatorEvent* >( event );
|
||||||
|
|
||||||
|
if ( ( animtorEvent->state() == QskAnimatorEvent::Terminated )
|
||||||
|
&& ( animtorEvent->aspect() == m_data->faderAspect ) )
|
||||||
|
{
|
||||||
|
if ( !isOpen() )
|
||||||
|
{
|
||||||
|
Inherited::setVisible( false );
|
||||||
|
|
||||||
|
if ( testPopupFlag( QskPopup::DeleteOnClose ) )
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_EMIT fadingChanged( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -418,8 +540,6 @@ QQuickItem* QskPopup::focusSuccessor() const
|
||||||
|
|
||||||
void QskPopup::aboutToShow()
|
void QskPopup::aboutToShow()
|
||||||
{
|
{
|
||||||
m_data->isOpen = true;
|
|
||||||
|
|
||||||
if ( m_data->autoGrabFocus )
|
if ( m_data->autoGrabFocus )
|
||||||
{
|
{
|
||||||
// What to do, when we are hidden below another popup ??
|
// What to do, when we are hidden below another popup ??
|
||||||
|
@ -435,17 +555,16 @@ void QskPopup::itemChange( QQuickItem::ItemChange change,
|
||||||
Inherited::itemChange( change, value );
|
Inherited::itemChange( change, value );
|
||||||
|
|
||||||
if ( change == QQuickItem::ItemVisibleHasChanged )
|
if ( change == QQuickItem::ItemVisibleHasChanged )
|
||||||
{
|
|
||||||
if ( !value.boolValue )
|
|
||||||
{
|
{
|
||||||
updateInputGrabber();
|
updateInputGrabber();
|
||||||
|
|
||||||
grabFocus( false );
|
if ( value.boolValue )
|
||||||
if ( m_data->isOpen )
|
|
||||||
{
|
{
|
||||||
if ( testPopupFlag( CloseOnHide ) )
|
polish(); // so that aboutToShow is called. TODO ...
|
||||||
close();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
grabFocus( false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( change == QQuickItem::ItemParentHasChanged )
|
else if ( change == QQuickItem::ItemParentHasChanged )
|
||||||
|
|
|
@ -12,20 +12,25 @@ class QSK_EXPORT QskPopup : public QskControl
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY( bool open READ isOpen WRITE setOpen NOTIFY openChanged )
|
||||||
Q_PROPERTY( bool modal READ isModal WRITE setModal NOTIFY modalChanged )
|
Q_PROPERTY( bool modal READ isModal WRITE setModal NOTIFY modalChanged )
|
||||||
Q_PROPERTY( bool overlay READ hasOverlay WRITE setOverlay NOTIFY overlayChanged )
|
Q_PROPERTY( bool overlay READ hasOverlay WRITE setOverlay NOTIFY overlayChanged )
|
||||||
|
|
||||||
|
Q_PROPERTY( bool faderEffect READ hasFaderEffect
|
||||||
|
WRITE setFaderEffect NOTIFY faderEffectChanged )
|
||||||
|
|
||||||
Q_PROPERTY( uint priority READ priority WRITE setPriority NOTIFY priorityChanged )
|
Q_PROPERTY( uint priority READ priority WRITE setPriority NOTIFY priorityChanged )
|
||||||
|
|
||||||
using Inherited = QskControl;
|
using Inherited = QskControl;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QSK_SUBCONTROLS( Overlay )
|
QSK_SUBCONTROLS( Overlay )
|
||||||
|
QSK_STATES( Closed )
|
||||||
|
|
||||||
enum PopupFlag
|
enum PopupFlag
|
||||||
{
|
{
|
||||||
CloseOnHide = 1 << 0,
|
DeleteOnClose = 1 << 0,
|
||||||
DeleteOnClose = 1 << 1,
|
CloseOnPressOutside = 1 << 1
|
||||||
CloseOnPressOutside = 1 << 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_ENUM( PopupFlag )
|
Q_ENUM( PopupFlag )
|
||||||
|
@ -46,27 +51,39 @@ class QSK_EXPORT QskPopup : public QskControl
|
||||||
void setOverlay( bool on = true );
|
void setOverlay( bool on = true );
|
||||||
bool hasOverlay() const;
|
bool hasOverlay() const;
|
||||||
|
|
||||||
// allows for stacking according to priorities
|
// allows for stacking orders based on priorities
|
||||||
void setPriority( uint );
|
void setPriority( uint );
|
||||||
uint priority() const;
|
uint priority() const;
|
||||||
|
|
||||||
|
void setFaderEffect( bool );
|
||||||
|
bool hasFaderEffect() const;
|
||||||
|
|
||||||
|
QskAspect::Aspect faderAspect() const;
|
||||||
|
void setFaderAspect( QskAspect::Aspect );
|
||||||
|
|
||||||
virtual QRectF overlayRect() const;
|
virtual QRectF overlayRect() const;
|
||||||
|
|
||||||
bool isOpen() const;
|
bool isOpen() const;
|
||||||
|
bool isFading() const;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void open();
|
void open();
|
||||||
void close();
|
void close();
|
||||||
|
void setOpen( bool );
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
void opened();
|
||||||
void closed();
|
void closed();
|
||||||
|
void openChanged( bool );
|
||||||
|
void fadingChanged( bool );
|
||||||
|
|
||||||
void modalChanged( bool );
|
void modalChanged( bool );
|
||||||
void overlayChanged( bool );
|
void overlayChanged( bool );
|
||||||
void priorityChanged( uint );
|
void priorityChanged( uint );
|
||||||
|
void faderEffectChanged( bool );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void aboutToShow() override;
|
void aboutToShow() override;
|
||||||
virtual void setFading( bool on );
|
|
||||||
|
|
||||||
bool event( QEvent* ) override;
|
bool event( QEvent* ) override;
|
||||||
void focusInEvent( QFocusEvent* ) override;
|
void focusInEvent( QFocusEvent* ) override;
|
||||||
|
@ -77,14 +94,21 @@ class QSK_EXPORT QskPopup : public QskControl
|
||||||
const QQuickItem::ItemChangeData& ) override;
|
const QQuickItem::ItemChangeData& ) override;
|
||||||
|
|
||||||
virtual QQuickItem* focusSuccessor() const;
|
virtual QQuickItem* focusSuccessor() const;
|
||||||
|
bool isTransitionAccepted( QskAspect::Aspect ) const override;
|
||||||
|
|
||||||
void grabFocus( bool );
|
void grabFocus( bool );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void show() = delete;
|
||||||
|
void hide() = delete;
|
||||||
|
void setVisible( bool ) = delete;
|
||||||
|
|
||||||
void updateInputGrabber();
|
void updateInputGrabber();
|
||||||
|
|
||||||
class PrivateData;
|
class PrivateData;
|
||||||
std::unique_ptr< PrivateData > m_data;
|
std::unique_ptr< PrivateData > m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS( QskPopup::PopupFlags )
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -692,6 +692,21 @@ QRectF QskSkinnable::outerBox(
|
||||||
return innerBox.marginsAdded( m );
|
return innerBox.marginsAdded( m );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QskSkinnable::isTransitionAccepted( QskAspect::Aspect aspect ) const
|
||||||
|
{
|
||||||
|
Q_UNUSED( aspect )
|
||||||
|
|
||||||
|
/*
|
||||||
|
Usually we only need smooth transitions, when state changes
|
||||||
|
happen while the skinnable is visible. There are few exceptions
|
||||||
|
like QskPopup::Closed, that is used to slide/fade in.
|
||||||
|
*/
|
||||||
|
if ( auto control = owningControl() )
|
||||||
|
return control->isInitiallyPainted();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void QskSkinnable::startTransition( QskAspect::Aspect aspect,
|
void QskSkinnable::startTransition( QskAspect::Aspect aspect,
|
||||||
QskAnimationHint animationHint, QVariant from, QVariant to )
|
QskAnimationHint animationHint, QVariant from, QVariant to )
|
||||||
{
|
{
|
||||||
|
@ -699,7 +714,7 @@ void QskSkinnable::startTransition( QskAspect::Aspect aspect,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QskControl* control = this->owningControl();
|
QskControl* control = this->owningControl();
|
||||||
if ( control->window() == nullptr || !control->isInitiallyPainted() )
|
if ( control->window() == nullptr || !isTransitionAccepted( aspect ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We might be invalid for one of the values, when an aspect
|
// We might be invalid for one of the values, when an aspect
|
||||||
|
@ -759,7 +774,7 @@ void QskSkinnable::setSkinStateFlag( QskAspect::State state, bool on )
|
||||||
<< skinStateAsPrintable( newState );
|
<< skinStateAsPrintable( newState );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( control->window() && control->isInitiallyPainted() )
|
if ( control->window() && isTransitionAccepted( QskAspect::Aspect() ) )
|
||||||
{
|
{
|
||||||
const auto placement = effectivePlacement();
|
const auto placement = effectivePlacement();
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,7 @@ class QSK_EXPORT QskSkinnable
|
||||||
protected:
|
protected:
|
||||||
void setSkinStateFlag( QskAspect::State, bool = true );
|
void setSkinStateFlag( QskAspect::State, bool = true );
|
||||||
virtual void updateNode( QSGNode* );
|
virtual void updateNode( QSGNode* );
|
||||||
|
virtual bool isTransitionAccepted( QskAspect::Aspect ) const;
|
||||||
|
|
||||||
QskSkinHintTable& hintTable();
|
QskSkinHintTable& hintTable();
|
||||||
const QskSkinHintTable& hintTable() const;
|
const QskSkinHintTable& hintTable() const;
|
||||||
|
|
|
@ -59,7 +59,7 @@ QskDialog::DialogCode QskDialogSubWindow::exec()
|
||||||
mouseGrabber->ungrabMouse();
|
mouseGrabber->ungrabMouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
show();
|
open();
|
||||||
|
|
||||||
QEventLoop eventLoop;
|
QEventLoop eventLoop;
|
||||||
|
|
||||||
|
|
|
@ -34,9 +34,14 @@ void QskInputWindow::setSubWindow( QskInputSubWindow* subWindow )
|
||||||
|
|
||||||
if ( m_subWindow )
|
if ( m_subWindow )
|
||||||
{
|
{
|
||||||
|
#if 1
|
||||||
|
// we shoudn't have a subwindow here TODO ...
|
||||||
m_subWindow->setModal( false );
|
m_subWindow->setModal( false );
|
||||||
m_subWindow->setDecorated( false );
|
m_subWindow->setDecorated( false );
|
||||||
m_subWindow->setOverlay( false );
|
m_subWindow->setOverlay( false );
|
||||||
|
m_subWindow->setFaderEffect( false );
|
||||||
|
m_subWindow->open();
|
||||||
|
#endif
|
||||||
|
|
||||||
addItem( m_subWindow );
|
addItem( m_subWindow );
|
||||||
|
|
||||||
|
|
|
@ -397,11 +397,10 @@ void QskInputContext::showPanel( const QQuickItem* item )
|
||||||
|
|
||||||
popup->setParentItem( item->window()->contentItem() );
|
popup->setParentItem( item->window()->contentItem() );
|
||||||
popup->setParent( this );
|
popup->setParent( this );
|
||||||
#if 1
|
|
||||||
popup->setVisible( true );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
channel->popup = popup;
|
channel->popup = popup;
|
||||||
|
|
||||||
|
popup->open();
|
||||||
}
|
}
|
||||||
|
|
||||||
panel->attachInputItem( const_cast< QQuickItem* >( item ) );
|
panel->attachInputItem( const_cast< QQuickItem* >( item ) );
|
||||||
|
|
Loading…
Reference in New Issue