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_SUBCONTROL( QskPopup, Overlay )
|
||||
QSK_STATE( QskPopup, Closed, QskAspect::FirstSystemState << 1 )
|
||||
|
||||
static void qskSetFocus( QQuickItem* item, bool on )
|
||||
{
|
||||
@ -101,7 +102,7 @@ class QskPopup::PrivateData
|
||||
PrivateData()
|
||||
: flags( 0 )
|
||||
, isModal( false )
|
||||
, isOpen( false )
|
||||
, hasFaderEffect( true )
|
||||
, autoGrabFocus( true )
|
||||
, handoverFocus( true )
|
||||
{
|
||||
@ -110,10 +111,11 @@ class QskPopup::PrivateData
|
||||
InputGrabber* inputGrabber = nullptr;
|
||||
|
||||
uint priority = 0;
|
||||
QskAspect::Aspect faderAspect;
|
||||
|
||||
int flags : 4;
|
||||
bool isModal : 1;
|
||||
bool isOpen : 1;
|
||||
int flags : 4;
|
||||
bool isModal : 1;
|
||||
bool hasFaderEffect : 1;
|
||||
|
||||
const bool autoGrabFocus : 1;
|
||||
const bool handoverFocus : 1;
|
||||
@ -123,6 +125,10 @@ QskPopup::QskPopup( QQuickItem* parent )
|
||||
: Inherited( parent )
|
||||
, m_data( new PrivateData() )
|
||||
{
|
||||
// initially the popup is closed and invisible
|
||||
Inherited::setVisible( false );
|
||||
setSkinStateFlag( QskPopup::Closed );
|
||||
|
||||
// we need to stop event propagation
|
||||
setAcceptedMouseButtons( Qt::AllButtons );
|
||||
setWheelEnabled( true );
|
||||
@ -134,6 +140,11 @@ QskPopup::QskPopup( QQuickItem* parent )
|
||||
setTabFence( true );
|
||||
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 );
|
||||
}
|
||||
|
||||
@ -144,33 +155,61 @@ QskPopup::~QskPopup()
|
||||
|
||||
void QskPopup::open()
|
||||
{
|
||||
setFading( true );
|
||||
setOpen( true );
|
||||
}
|
||||
|
||||
void QskPopup::close()
|
||||
{
|
||||
const bool wasOpen = m_data->isOpen;
|
||||
m_data->isOpen = false;
|
||||
|
||||
setFading( false );
|
||||
|
||||
if ( wasOpen )
|
||||
{
|
||||
Q_EMIT closed();
|
||||
|
||||
if ( testPopupFlag( DeleteOnClose ) )
|
||||
deleteLater();
|
||||
}
|
||||
setOpen( false );
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
@ -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 )
|
||||
{
|
||||
if ( m_data->priority != priority )
|
||||
@ -240,6 +328,20 @@ bool QskPopup::isModal() const
|
||||
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 )
|
||||
{
|
||||
m_data->flags = flags;
|
||||
@ -323,7 +425,7 @@ bool QskPopup::event( QEvent* event )
|
||||
{
|
||||
bool ok = Inherited::event( event );
|
||||
|
||||
switch ( event->type() )
|
||||
switch ( static_cast< int >( event->type() ) )
|
||||
{
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease:
|
||||
@ -344,6 +446,26 @@ bool QskPopup::event( QEvent* event )
|
||||
|
||||
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:
|
||||
{
|
||||
/*
|
||||
@ -418,8 +540,6 @@ QQuickItem* QskPopup::focusSuccessor() const
|
||||
|
||||
void QskPopup::aboutToShow()
|
||||
{
|
||||
m_data->isOpen = true;
|
||||
|
||||
if ( m_data->autoGrabFocus )
|
||||
{
|
||||
// What to do, when we are hidden below another popup ??
|
||||
@ -436,16 +556,15 @@ void QskPopup::itemChange( QQuickItem::ItemChange change,
|
||||
|
||||
if ( change == QQuickItem::ItemVisibleHasChanged )
|
||||
{
|
||||
if ( !value.boolValue )
|
||||
{
|
||||
updateInputGrabber();
|
||||
updateInputGrabber();
|
||||
|
||||
if ( value.boolValue )
|
||||
{
|
||||
polish(); // so that aboutToShow is called. TODO ...
|
||||
}
|
||||
else
|
||||
{
|
||||
grabFocus( false );
|
||||
if ( m_data->isOpen )
|
||||
{
|
||||
if ( testPopupFlag( CloseOnHide ) )
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( change == QQuickItem::ItemParentHasChanged )
|
||||
|
@ -12,20 +12,25 @@ class QSK_EXPORT QskPopup : public QskControl
|
||||
{
|
||||
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 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 )
|
||||
|
||||
using Inherited = QskControl;
|
||||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Overlay )
|
||||
QSK_STATES( Closed )
|
||||
|
||||
enum PopupFlag
|
||||
{
|
||||
CloseOnHide = 1 << 0,
|
||||
DeleteOnClose = 1 << 1,
|
||||
CloseOnPressOutside = 1 << 2
|
||||
DeleteOnClose = 1 << 0,
|
||||
CloseOnPressOutside = 1 << 1
|
||||
};
|
||||
|
||||
Q_ENUM( PopupFlag )
|
||||
@ -46,27 +51,39 @@ class QSK_EXPORT QskPopup : public QskControl
|
||||
void setOverlay( bool on = true );
|
||||
bool hasOverlay() const;
|
||||
|
||||
// allows for stacking according to priorities
|
||||
// allows for stacking orders based on priorities
|
||||
void setPriority( uint );
|
||||
uint priority() const;
|
||||
|
||||
void setFaderEffect( bool );
|
||||
bool hasFaderEffect() const;
|
||||
|
||||
QskAspect::Aspect faderAspect() const;
|
||||
void setFaderAspect( QskAspect::Aspect );
|
||||
|
||||
virtual QRectF overlayRect() const;
|
||||
|
||||
bool isOpen() const;
|
||||
bool isFading() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void open();
|
||||
void close();
|
||||
void setOpen( bool );
|
||||
|
||||
Q_SIGNALS:
|
||||
void opened();
|
||||
void closed();
|
||||
void openChanged( bool );
|
||||
void fadingChanged( bool );
|
||||
|
||||
void modalChanged( bool );
|
||||
void overlayChanged( bool );
|
||||
void priorityChanged( uint );
|
||||
void faderEffectChanged( bool );
|
||||
|
||||
protected:
|
||||
void aboutToShow() override;
|
||||
virtual void setFading( bool on );
|
||||
|
||||
bool event( QEvent* ) override;
|
||||
void focusInEvent( QFocusEvent* ) override;
|
||||
@ -77,14 +94,21 @@ class QSK_EXPORT QskPopup : public QskControl
|
||||
const QQuickItem::ItemChangeData& ) override;
|
||||
|
||||
virtual QQuickItem* focusSuccessor() const;
|
||||
bool isTransitionAccepted( QskAspect::Aspect ) const override;
|
||||
|
||||
void grabFocus( bool );
|
||||
|
||||
private:
|
||||
void show() = delete;
|
||||
void hide() = delete;
|
||||
void setVisible( bool ) = delete;
|
||||
|
||||
void updateInputGrabber();
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QskPopup::PopupFlags )
|
||||
|
||||
#endif
|
||||
|
@ -692,6 +692,21 @@ QRectF QskSkinnable::outerBox(
|
||||
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,
|
||||
QskAnimationHint animationHint, QVariant from, QVariant to )
|
||||
{
|
||||
@ -699,7 +714,7 @@ void QskSkinnable::startTransition( QskAspect::Aspect aspect,
|
||||
return;
|
||||
|
||||
QskControl* control = this->owningControl();
|
||||
if ( control->window() == nullptr || !control->isInitiallyPainted() )
|
||||
if ( control->window() == nullptr || !isTransitionAccepted( aspect ) )
|
||||
return;
|
||||
|
||||
// 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 );
|
||||
#endif
|
||||
|
||||
if ( control->window() && control->isInitiallyPainted() )
|
||||
if ( control->window() && isTransitionAccepted( QskAspect::Aspect() ) )
|
||||
{
|
||||
const auto placement = effectivePlacement();
|
||||
|
||||
|
@ -156,6 +156,7 @@ class QSK_EXPORT QskSkinnable
|
||||
protected:
|
||||
void setSkinStateFlag( QskAspect::State, bool = true );
|
||||
virtual void updateNode( QSGNode* );
|
||||
virtual bool isTransitionAccepted( QskAspect::Aspect ) const;
|
||||
|
||||
QskSkinHintTable& hintTable();
|
||||
const QskSkinHintTable& hintTable() const;
|
||||
|
@ -59,7 +59,7 @@ QskDialog::DialogCode QskDialogSubWindow::exec()
|
||||
mouseGrabber->ungrabMouse();
|
||||
}
|
||||
|
||||
show();
|
||||
open();
|
||||
|
||||
QEventLoop eventLoop;
|
||||
|
||||
|
@ -34,9 +34,14 @@ void QskInputWindow::setSubWindow( QskInputSubWindow* subWindow )
|
||||
|
||||
if ( m_subWindow )
|
||||
{
|
||||
#if 1
|
||||
// we shoudn't have a subwindow here TODO ...
|
||||
m_subWindow->setModal( false );
|
||||
m_subWindow->setDecorated( false );
|
||||
m_subWindow->setOverlay( false );
|
||||
m_subWindow->setFaderEffect( false );
|
||||
m_subWindow->open();
|
||||
#endif
|
||||
|
||||
addItem( m_subWindow );
|
||||
|
||||
|
@ -397,11 +397,10 @@ void QskInputContext::showPanel( const QQuickItem* item )
|
||||
|
||||
popup->setParentItem( item->window()->contentItem() );
|
||||
popup->setParent( this );
|
||||
#if 1
|
||||
popup->setVisible( true );
|
||||
#endif
|
||||
|
||||
channel->popup = popup;
|
||||
|
||||
popup->open();
|
||||
}
|
||||
|
||||
panel->attachInputItem( const_cast< QQuickItem* >( item ) );
|
||||
|
Loading…
x
Reference in New Issue
Block a user