FocusIndicator improved

This commit is contained in:
Uwe Rathmann 2023-12-01 18:43:31 +01:00
parent c3c9405b65
commit 1dee82c29e
2 changed files with 151 additions and 75 deletions

View File

@ -7,27 +7,46 @@
#include <QskBoxBorderColors.h> #include <QskBoxBorderColors.h>
#include <QskRgbValue.h> #include <QskRgbValue.h>
#include <QQuickWindow> #include <qquickwindow.h>
#include <qbasictimer.h>
QSK_STATE( FocusIndicator, Concealed, QskAspect::FirstUserState ) QSK_STATE( FocusIndicator, Concealed, QskAspect::FirstUserState )
static inline bool qskIsExposingKeyPress( const QKeyEvent* event )
{
// 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 ( auto w = indicator->window() )
{
if ( w->isExposed() && w->isActive() )
indicator->setExposed( true );
}
}
else
{
indicator->setExposed( false );
}
#endif
}
class FocusIndicator::PrivateData class FocusIndicator::PrivateData
{ {
public: public:
void restartTimer( FocusIndicator* indicator, int ms ) inline bool isAutoConcealing() const { return timeout > 0; }
{
if( timerId > 0 )
{
indicator->killTimer( timerId );
timerId = 0;
}
if ( ms > 0 ) int timeout = 0;
timerId = indicator->startTimer( ms ); QBasicTimer concealTimer;
}
const int timeout = 4500;
int timerId = 0;
bool blockAutoRepeatKeyEvents = false; bool blockAutoRepeatKeyEvents = false;
}; };
@ -36,8 +55,6 @@ FocusIndicator::FocusIndicator( QQuickItem* parent )
: Inherited( parent ) : Inherited( parent )
, m_data( new PrivateData() ) , m_data( new PrivateData() )
{ {
if( window() )
window()->installEventFilter( this );
#if 1 #if 1
auto colors = boxBorderColorsHint( Panel ); auto colors = boxBorderColorsHint( Panel );
@ -47,34 +64,91 @@ FocusIndicator::FocusIndicator( QQuickItem* parent )
setAnimationHint( Panel | QskAspect::Color | Concealed, 500 ); setAnimationHint( Panel | QskAspect::Color | Concealed, 500 );
#endif #endif
m_data->restartTimer( this, m_data->timeout ); setExposedTimeout( 4500 );
} }
FocusIndicator::~FocusIndicator() 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; return;
setSkinStateFlag( Concealed, on ); m_data->timeout = ms;
int timeout = 0; if ( m_data->isAutoConcealing() )
if ( !on ) {
timeout = m_data->timeout + animationHint( Panel | QskAspect::Color ).duration; 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 ) bool FocusIndicator::eventFilter( QObject* object, QEvent* event )
{ {
if( object != window() ) if( ( object != window() ) || !m_data->isAutoConcealing() )
return Inherited::eventFilter( object, event ); 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() ) ) switch( static_cast< int >( event->type() ) )
{ {
case QEvent::KeyPress: case QEvent::KeyPress:
@ -82,37 +156,22 @@ bool FocusIndicator::eventFilter( QObject* object, QEvent* event )
const auto keyEvent = static_cast< QKeyEvent* >( event ); const auto keyEvent = static_cast< QKeyEvent* >( event );
if( keyEvent->isAutoRepeat() && m_data->blockAutoRepeatKeyEvents ) if( keyEvent->isAutoRepeat() && m_data->blockAutoRepeatKeyEvents )
return true;
if ( qskIsButtonPressKey( keyEvent ) )
{ {
if ( isConcealed() ) /*
{ We swallow all auto repeated events to avoid running along
setConcealed( false ); the tab chain by accident.
return true; */
} return true;
return false;
} }
if( qskFocusChainIncrement( keyEvent ) != 0 ) if ( !isExposed() && qskIsExposingKeyPress( keyEvent ) )
{ {
if ( isConcealed() ) setExposed( true );
{ m_data->blockAutoRepeatKeyEvents = true;
setConcealed( false ); return true;
m_data->blockAutoRepeatKeyEvents = true;
return true;
}
else
{
// extending the timer
m_data->restartTimer( this, m_data->timeout );
return false;
}
} }
m_data->blockAutoRepeatKeyEvents = false; m_data->blockAutoRepeatKeyEvents = false;
break; break;
} }
@ -129,15 +188,11 @@ bool FocusIndicator::eventFilter( QObject* object, QEvent* event )
break; break;
} }
case QEvent::Expose:
case QEvent::FocusIn:
case QEvent::FocusOut: case QEvent::FocusOut:
{ {
setConcealed( true ); qskMaybeExpose( this, event->type() != QEvent::FocusOut );
break;
}
case QEvent::FocusIn:
{
setConcealed( false );
break; break;
} }
} }
@ -149,34 +204,36 @@ void FocusIndicator::windowChangeEvent( QskWindowChangeEvent* event )
{ {
Inherited::windowChangeEvent( event ); Inherited::windowChangeEvent( event );
if( event->oldWindow() ) if ( m_data->isAutoConcealing() )
event->oldWindow()->removeEventFilter( this ); {
if ( auto w = event->oldWindow() )
w->removeEventFilter( this );
if( event->window() ) if( auto w = event->window() )
event->window()->installEventFilter( this ); {
w->installEventFilter( this );
qskMaybeExpose( this, true );
}
}
} }
void FocusIndicator::timerEvent( QTimerEvent* event ) void FocusIndicator::timerEvent( QTimerEvent* event )
{ {
if( event->timerId() == m_data->timerId ) if ( m_data->isAutoConcealing() )
{ {
m_data->restartTimer( this, 0 ); if( event->timerId() == m_data->concealTimer.timerId() )
if ( !isConcealed() )
{ {
setSkinStateFlag( Concealed, true ); setExposed( false );
Q_EMIT concealedChanged( true ); return;
} }
return;
} }
Inherited::timerEvent( event ); Inherited::timerEvent( event );
} }
bool FocusIndicator::isConcealed() const bool FocusIndicator::isExposed() const
{ {
return hasSkinState( Concealed ); return !hasSkinState( Concealed );
} }
#include "moc_FocusIndicator.cpp" #include "moc_FocusIndicator.cpp"

View File

@ -10,8 +10,11 @@ class FocusIndicator : public QskFocusIndicator
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY( bool concealed READ isConcealed Q_PROPERTY( bool exposed READ isExposed
WRITE setConcealed NOTIFY concealedChanged ) WRITE setExposed NOTIFY exposedChanged )
Q_PROPERTY( int exposedTimeout READ exposedTimeout
WRITE setExposedTimeout NOTIFY exposedTimeoutChanged )
using Inherited = QskFocusIndicator; using Inherited = QskFocusIndicator;
@ -21,15 +24,21 @@ class FocusIndicator : public QskFocusIndicator
FocusIndicator( QQuickItem* parent = nullptr ); FocusIndicator( QQuickItem* parent = nullptr );
~FocusIndicator() override; ~FocusIndicator() override;
bool isExposed() const;
bool isConcealed() const; bool isConcealed() const;
bool eventFilter( QObject*, QEvent* ) override; bool eventFilter( QObject*, QEvent* ) override;
void setExposedTimeout( int ms );
int exposedTimeout() const;
public Q_SLOTS: public Q_SLOTS:
void setConcealed( bool ); void setExposed( bool = true );
void setConcealed( bool = true );
Q_SIGNALS: Q_SIGNALS:
void concealedChanged( bool ); void exposedChanged( bool );
void exposedTimeoutChanged( int );
protected: protected:
void windowChangeEvent( QskWindowChangeEvent* ) override; void windowChangeEvent( QskWindowChangeEvent* ) override;
@ -39,3 +48,13 @@ class FocusIndicator : public QskFocusIndicator
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;
}; };
inline void FocusIndicator::setConcealed( bool on )
{
setExposed( !on );
}
inline bool FocusIndicator::isConcealed() const
{
return !isExposed();
}