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 <QskRgbValue.h>
#include <QQuickWindow>
#include <qquickwindow.h>
#include <qbasictimer.h>
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
{
public:
void restartTimer( FocusIndicator* indicator, int ms )
{
if( timerId > 0 )
{
indicator->killTimer( timerId );
timerId = 0;
}
inline bool isAutoConcealing() const { return timeout > 0; }
if ( ms > 0 )
timerId = indicator->startTimer( ms );
}
const int timeout = 4500;
int timerId = 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::Expose:
case QEvent::FocusIn:
case QEvent::FocusOut:
{
setConcealed( true );
break;
}
case QEvent::FocusIn:
{
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"

View File

@ -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();
}