Skip to content

Commit

Permalink
FocusIndicator improved
Browse files Browse the repository at this point in the history
  • Loading branch information
uwerat committed Dec 1, 2023
1 parent c3c9405 commit 1dee82c
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 73 deletions.
195 changes: 126 additions & 69 deletions examples/gallery/FocusIndicator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,46 @@
#include <QskBoxBorderColors.h>
#include <QskRgbValue.h>

#include <QQuickWindow>
#include <qquickwindow.h>
#include <qbasictimer.h>


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

Expand All @@ -47,72 +64,114 @@ 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:
{
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;
}

Expand All @@ -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;
}
}
Expand All @@ -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"
27 changes: 23 additions & 4 deletions examples/gallery/FocusIndicator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

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

0 comments on commit 1dee82c

Please sign in to comment.