From 1dee82c29e8a6d2e77f5d133d2afad2abe568893 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Dec 2023 18:43:31 +0100 Subject: [PATCH] FocusIndicator improved --- examples/gallery/FocusIndicator.cpp | 195 ++++++++++++++++++---------- examples/gallery/FocusIndicator.h | 27 +++- 2 files changed, 149 insertions(+), 73 deletions(-) diff --git a/examples/gallery/FocusIndicator.cpp b/examples/gallery/FocusIndicator.cpp index 4b4bed947..1f24b7982 100644 --- a/examples/gallery/FocusIndicator.cpp +++ b/examples/gallery/FocusIndicator.cpp @@ -7,27 +7,46 @@ #include #include -#include +#include +#include + QSK_STATE( FocusIndicator, Concealed, QskAspect::FirstUserState ) -class FocusIndicator::PrivateData +static inline bool qskIsExposingKeyPress( const QKeyEvent* event ) { - public: - void restartTimer( FocusIndicator* indicator, int ms ) + // what keys do we want have here ??? + return qskIsButtonPressKey( event ) || qskFocusChainIncrement( event ); +} + +static void qskMaybeExpose( FocusIndicator* indicator, bool on ) +{ + Q_UNUSED( indicator ); + Q_UNUSED( on ); + +#if 0 + if ( on ) { - if( timerId > 0 ) + if ( auto w = indicator->window() ) { - indicator->killTimer( timerId ); - timerId = 0; + if ( w->isExposed() && w->isActive() ) + indicator->setExposed( true ); } - - if ( ms > 0 ) - timerId = indicator->startTimer( ms ); } + else + { + indicator->setExposed( false ); + } +#endif +} - const int timeout = 4500; - int timerId = 0; +class FocusIndicator::PrivateData +{ + public: + inline bool isAutoConcealing() const { return timeout > 0; } + + int timeout = 0; + QBasicTimer concealTimer; bool blockAutoRepeatKeyEvents = false; }; @@ -36,8 +55,6 @@ FocusIndicator::FocusIndicator( QQuickItem* parent ) : Inherited( parent ) , m_data( new PrivateData() ) { - if( window() ) - window()->installEventFilter( this ); #if 1 auto colors = boxBorderColorsHint( Panel ); @@ -47,34 +64,91 @@ FocusIndicator::FocusIndicator( QQuickItem* parent ) setAnimationHint( Panel | QskAspect::Color | Concealed, 500 ); #endif - m_data->restartTimer( this, m_data->timeout ); + setExposedTimeout( 4500 ); } FocusIndicator::~FocusIndicator() { } -void FocusIndicator::setConcealed( bool on ) +void FocusIndicator::setExposedTimeout( int ms ) { - if ( on == isConcealed() ) + ms = std::max( ms, 0 ); + if ( ms == m_data->timeout ) return; - setSkinStateFlag( Concealed, on ); + m_data->timeout = ms; - int timeout = 0; - if ( !on ) - timeout = m_data->timeout + animationHint( Panel | QskAspect::Color ).duration; + if ( m_data->isAutoConcealing() ) + { + if ( auto w = window() ) + w->installEventFilter( this ); - m_data->restartTimer( this, timeout ); + if ( isExposed() ) + { + if ( isInitiallyPainted() ) + m_data->concealTimer.start( m_data->timeout, this ); + else + setExposed( false ); + } + } + else + { + if ( auto w = window() ) + w->removeEventFilter( this ); - Q_EMIT concealedChanged( on ); + setExposed( true ); + } + + Q_EMIT exposedTimeoutChanged( ms ); +} + +int FocusIndicator::exposedTimeout() const +{ + return m_data->timeout; +} + +void FocusIndicator::setExposed( bool on ) +{ + if ( on == isExposed() ) + return; + + setSkinStateFlag( Concealed, !on ); + + if ( m_data->isAutoConcealing() ) + { + if ( on ) + { + const auto hint = animationHint( Panel | QskAspect::Color ); + m_data->concealTimer.start( m_data->timeout + hint.duration, this ); + } + else + { + m_data->concealTimer.stop(); + } + } + + Q_EMIT exposedChanged( on ); } bool FocusIndicator::eventFilter( QObject* object, QEvent* event ) { - if( object != window() ) + if( ( object != window() ) || !m_data->isAutoConcealing() ) return Inherited::eventFilter( object, event ); + switch( static_cast< int >( event->type() ) ) + { + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::ShortcutOverride: + if ( m_data->concealTimer.isActive() ) + { + // renew the exposed period + m_data->concealTimer.start( m_data->timeout, this ); + } + break; + } + switch( static_cast< int >( event->type() ) ) { case QEvent::KeyPress: @@ -82,37 +156,22 @@ bool FocusIndicator::eventFilter( QObject* object, QEvent* event ) const auto keyEvent = static_cast< QKeyEvent* >( event ); if( keyEvent->isAutoRepeat() && m_data->blockAutoRepeatKeyEvents ) - return true; - - if ( qskIsButtonPressKey( keyEvent ) ) { - if ( isConcealed() ) - { - setConcealed( false ); - return true; - } - - return false; + /* + We swallow all auto repeated events to avoid running along + the tab chain by accident. + */ + return true; } - if( qskFocusChainIncrement( keyEvent ) != 0 ) + if ( !isExposed() && qskIsExposingKeyPress( keyEvent ) ) { - if ( isConcealed() ) - { - setConcealed( false ); - m_data->blockAutoRepeatKeyEvents = true; - return true; - } - else - { - // extending the timer - m_data->restartTimer( this, m_data->timeout ); - return false; - } + setExposed( true ); + m_data->blockAutoRepeatKeyEvents = true; + return true; } m_data->blockAutoRepeatKeyEvents = false; - break; } @@ -129,15 +188,11 @@ bool FocusIndicator::eventFilter( QObject* object, QEvent* event ) break; } - case QEvent::FocusOut: - { - setConcealed( true ); - break; - } - + case QEvent::Expose: case QEvent::FocusIn: + case QEvent::FocusOut: { - setConcealed( false ); + qskMaybeExpose( this, event->type() != QEvent::FocusOut ); break; } } @@ -149,34 +204,36 @@ void FocusIndicator::windowChangeEvent( QskWindowChangeEvent* event ) { Inherited::windowChangeEvent( event ); - if( event->oldWindow() ) - event->oldWindow()->removeEventFilter( this ); + if ( m_data->isAutoConcealing() ) + { + if ( auto w = event->oldWindow() ) + w->removeEventFilter( this ); - if( event->window() ) - event->window()->installEventFilter( this ); + if( auto w = event->window() ) + { + w->installEventFilter( this ); + qskMaybeExpose( this, true ); + } + } } void FocusIndicator::timerEvent( QTimerEvent* event ) { - if( event->timerId() == m_data->timerId ) + if ( m_data->isAutoConcealing() ) { - m_data->restartTimer( this, 0 ); - - if ( !isConcealed() ) + if( event->timerId() == m_data->concealTimer.timerId() ) { - setSkinStateFlag( Concealed, true ); - Q_EMIT concealedChanged( true ); + setExposed( false ); + return; } - - return; } Inherited::timerEvent( event ); } -bool FocusIndicator::isConcealed() const +bool FocusIndicator::isExposed() const { - return hasSkinState( Concealed ); + return !hasSkinState( Concealed ); } #include "moc_FocusIndicator.cpp" diff --git a/examples/gallery/FocusIndicator.h b/examples/gallery/FocusIndicator.h index 400958096..718845bb6 100644 --- a/examples/gallery/FocusIndicator.h +++ b/examples/gallery/FocusIndicator.h @@ -10,8 +10,11 @@ class FocusIndicator : public QskFocusIndicator { Q_OBJECT - Q_PROPERTY( bool concealed READ isConcealed - WRITE setConcealed NOTIFY concealedChanged ) + Q_PROPERTY( bool exposed READ isExposed + WRITE setExposed NOTIFY exposedChanged ) + + Q_PROPERTY( int exposedTimeout READ exposedTimeout + WRITE setExposedTimeout NOTIFY exposedTimeoutChanged ) using Inherited = QskFocusIndicator; @@ -21,15 +24,21 @@ class FocusIndicator : public QskFocusIndicator FocusIndicator( QQuickItem* parent = nullptr ); ~FocusIndicator() override; + bool isExposed() const; bool isConcealed() const; bool eventFilter( QObject*, QEvent* ) override; + void setExposedTimeout( int ms ); + int exposedTimeout() const; + public Q_SLOTS: - void setConcealed( bool ); + void setExposed( bool = true ); + void setConcealed( bool = true ); Q_SIGNALS: - void concealedChanged( bool ); + void exposedChanged( bool ); + void exposedTimeoutChanged( int ); protected: void windowChangeEvent( QskWindowChangeEvent* ) override; @@ -39,3 +48,13 @@ class FocusIndicator : public QskFocusIndicator class PrivateData; std::unique_ptr< PrivateData > m_data; }; + +inline void FocusIndicator::setConcealed( bool on ) +{ + setExposed( !on ); +} + +inline bool FocusIndicator::isConcealed() const +{ + return !isExposed(); +}