From c3c9405b659c15a4921725c105af1950efa380b2 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 30 Nov 2023 08:42:51 +0100 Subject: [PATCH] FocusIndicator, that becomes temporarily visible when using the keyboard. Will become part of QskFocusIndicator later --- examples/gallery/CMakeLists.txt | 1 + examples/gallery/FocusIndicator.cpp | 182 ++++++++++++++++++++++++++++ examples/gallery/FocusIndicator.h | 41 +++++++ examples/gallery/main.cpp | 5 +- 4 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 examples/gallery/FocusIndicator.cpp create mode 100644 examples/gallery/FocusIndicator.h diff --git a/examples/gallery/CMakeLists.txt b/examples/gallery/CMakeLists.txt index e229a560c..3de7a2bab 100644 --- a/examples/gallery/CMakeLists.txt +++ b/examples/gallery/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES dialog/DialogPage.h dialog/DialogPage.cpp listbox/ListBoxPage.h listbox/ListBoxPage.cpp Page.h Page.cpp + FocusIndicator.h FocusIndicator.cpp main.cpp ) qt_add_resources(SOURCES icons.qrc) diff --git a/examples/gallery/FocusIndicator.cpp b/examples/gallery/FocusIndicator.cpp new file mode 100644 index 000000000..4b4bed947 --- /dev/null +++ b/examples/gallery/FocusIndicator.cpp @@ -0,0 +1,182 @@ +#include "FocusIndicator.h" + +#include +#include +#include +#include +#include +#include + +#include + +QSK_STATE( FocusIndicator, Concealed, QskAspect::FirstUserState ) + +class FocusIndicator::PrivateData +{ + public: + void restartTimer( FocusIndicator* indicator, int ms ) + { + if( timerId > 0 ) + { + indicator->killTimer( timerId ); + timerId = 0; + } + + if ( ms > 0 ) + timerId = indicator->startTimer( ms ); + } + + const int timeout = 4500; + int timerId = 0; + + bool blockAutoRepeatKeyEvents = false; +}; + +FocusIndicator::FocusIndicator( QQuickItem* parent ) + : Inherited( parent ) + , m_data( new PrivateData() ) +{ + if( window() ) + window()->installEventFilter( this ); +#if 1 + auto colors = boxBorderColorsHint( Panel ); + + setBoxBorderColorsHint( Panel | Concealed, QskRgb::Transparent ); + + setAnimationHint( Panel | QskAspect::Color, 200 ); + setAnimationHint( Panel | QskAspect::Color | Concealed, 500 ); +#endif + + m_data->restartTimer( this, m_data->timeout ); +} + +FocusIndicator::~FocusIndicator() +{ +} + +void FocusIndicator::setConcealed( bool on ) +{ + if ( on == isConcealed() ) + return; + + setSkinStateFlag( Concealed, on ); + + int timeout = 0; + if ( !on ) + timeout = m_data->timeout + animationHint( Panel | QskAspect::Color ).duration; + + m_data->restartTimer( this, timeout ); + + Q_EMIT concealedChanged( on ); +} + +bool FocusIndicator::eventFilter( QObject* object, QEvent* event ) +{ + if( object != window() ) + return Inherited::eventFilter( object, event ); + + 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; + } + + if( qskFocusChainIncrement( keyEvent ) != 0 ) + { + if ( isConcealed() ) + { + setConcealed( false ); + m_data->blockAutoRepeatKeyEvents = true; + return true; + } + else + { + // extending the timer + m_data->restartTimer( this, m_data->timeout ); + return false; + } + } + + m_data->blockAutoRepeatKeyEvents = false; + + break; + } + + case QEvent::KeyRelease: + { + if( m_data->blockAutoRepeatKeyEvents ) + { + if( !static_cast< QKeyEvent* >( event )->isAutoRepeat() ) + m_data->blockAutoRepeatKeyEvents = false; + + return true; + } + + break; + } + + case QEvent::FocusOut: + { + setConcealed( true ); + break; + } + + case QEvent::FocusIn: + { + setConcealed( false ); + break; + } + } + + return Inherited::eventFilter( object, event ); +} + +void FocusIndicator::windowChangeEvent( QskWindowChangeEvent* event ) +{ + Inherited::windowChangeEvent( event ); + + if( event->oldWindow() ) + event->oldWindow()->removeEventFilter( this ); + + if( event->window() ) + event->window()->installEventFilter( this ); +} + +void FocusIndicator::timerEvent( QTimerEvent* event ) +{ + if( event->timerId() == m_data->timerId ) + { + m_data->restartTimer( this, 0 ); + + if ( !isConcealed() ) + { + setSkinStateFlag( Concealed, true ); + Q_EMIT concealedChanged( true ); + } + + return; + } + + Inherited::timerEvent( event ); +} + +bool FocusIndicator::isConcealed() const +{ + return hasSkinState( Concealed ); +} + +#include "moc_FocusIndicator.cpp" diff --git a/examples/gallery/FocusIndicator.h b/examples/gallery/FocusIndicator.h new file mode 100644 index 000000000..400958096 --- /dev/null +++ b/examples/gallery/FocusIndicator.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +/* + A focus indicator, that becomes temporarily visible when using the keyboard + It is intended to move the code to QskFocusIndicator later. + */ +class FocusIndicator : public QskFocusIndicator +{ + Q_OBJECT + + Q_PROPERTY( bool concealed READ isConcealed + WRITE setConcealed NOTIFY concealedChanged ) + + using Inherited = QskFocusIndicator; + + public: + QSK_STATES( Concealed ) + + FocusIndicator( QQuickItem* parent = nullptr ); + ~FocusIndicator() override; + + bool isConcealed() const; + + bool eventFilter( QObject*, QEvent* ) override; + + public Q_SLOTS: + void setConcealed( bool ); + + Q_SIGNALS: + void concealedChanged( bool ); + + protected: + void windowChangeEvent( QskWindowChangeEvent* ) override; + void timerEvent( QTimerEvent* ) override; + + private: + class PrivateData; + std::unique_ptr< PrivateData > m_data; +}; diff --git a/examples/gallery/main.cpp b/examples/gallery/main.cpp index cf2e19c52..18cba4f08 100644 --- a/examples/gallery/main.cpp +++ b/examples/gallery/main.cpp @@ -3,7 +3,7 @@ * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ -#include "QskLinearBox.h" +#include "FocusIndicator.h" #include "label/LabelPage.h" #include "progressbar/ProgressBarPage.h" #include "inputs/InputPage.h" @@ -16,6 +16,7 @@ #include #include +#include "QskLinearBox.h" #include #include #include @@ -296,7 +297,7 @@ int main( int argc, char* argv[] ) QskWindow window; window.addItem( mainView ); - window.addItem( new QskFocusIndicator() ); + window.addItem( new FocusIndicator() ); window.resize( 800, 600 ); window.show();