6#include "QskFocusIndicator.h"
8#include "QskAnimationHint.h"
11#include "QskInternalMacros.h"
14#include <qquickwindow.h>
15#include <qbasictimer.h>
18#include <private/qquickitem_p.h>
23static inline QRectF qskFocusIndicatorRect(
const QQuickItem* item )
25 if (
auto control = qskControlCast( item ) )
26 return control->focusIndicatorRect();
28 const QVariant v = item->property(
"focusIndicatorRect" );
29 if ( v.canConvert< QRectF >() )
32 return qskItemRect( item );
35static inline QRectF qskFocusIndicatorClipRect(
const QQuickItem* item )
37 QRectF rect( 0.0, 0.0, -1.0, -1.0 );
41 if (
auto control = qskControlCast( item ) )
42 rect = control->focusIndicatorClipRect();
44 rect = item->clipRect();
50static inline QskAspect::Section qskItemSection(
const QQuickItem* item )
52 if (
auto control = qskControlCast( item ) )
53 return control->section();
55 return QskAspect::Body;
58static inline bool qskIsEnablingKey(
const QKeyEvent* event )
61 return qskIsButtonPressKey( event ) || qskFocusChainIncrement( event );
64static inline bool qskIsEditing(
const QQuickWindow* window )
66 if ( !QGuiApplication::inputMethod()->isVisible() )
68 if (
auto item = window->activeFocusItem() )
70 const QVariant v = item->property(
"editing" );
71 if ( v.value<
bool >() )
79class QskFocusIndicator::PrivateData
82 void resetConnections()
84 for (
const auto& connection : std::as_const( connections ) )
85 QObject::disconnect( connection );
90 inline bool isAutoDisabling()
const {
return duration > 0; }
91 inline bool isAutoEnabling()
const {
return false; }
93 QPointer< QQuickItem > clippingItem;
94 QVector< QMetaObject::Connection > connections;
99 bool blockAutoRepeatKeyEvents =
false;
102QskFocusIndicator::QskFocusIndicator( QQuickItem* parent )
103 : Inherited( parent )
104 , m_data( new PrivateData() )
107 connectWindow( window(),
true );
112QskFocusIndicator::~QskFocusIndicator()
116void QskFocusIndicator::setDuration(
int ms )
118 ms = std::max( ms, 0 );
119 if ( ms == m_data->duration )
122 m_data->duration = ms;
124 if ( m_data->isAutoDisabling() )
126 if (
auto w = window() )
127 w->installEventFilter(
this );
132 m_data->timer.start( m_data->duration,
this );
137 connect(
this, &QQuickItem::enabledChanged,
138 this, &QskFocusIndicator::resetTimer );
142 if (
auto w = window() )
143 w->removeEventFilter(
this );
147 disconnect(
this, &QQuickItem::enabledChanged,
148 this, &QskFocusIndicator::resetTimer );
151 Q_EMIT durationChanged( ms );
154int QskFocusIndicator::duration()
const
156 return m_data->duration;
159void QskFocusIndicator::maybeEnable(
bool on )
161 if ( !m_data->isAutoEnabling() )
166 if (
auto w = window() )
168 if ( w->isExposed() && w->isActive() )
178void QskFocusIndicator::resetTimer()
180 if ( m_data->isAutoDisabling() )
185 m_data->timer.start( m_data->duration + hint.duration,
this );
189 m_data->timer.stop();
194bool QskFocusIndicator::eventFilter( QObject*
object, QEvent* event )
196 if( (
object != window() ) || !m_data->isAutoDisabling() )
197 return Inherited::eventFilter(
object, event );
199 switch(
static_cast< int >( event->type() ) )
201 case QEvent::KeyPress:
202 case QEvent::KeyRelease:
203 case QEvent::ShortcutOverride:
205 if ( qskIsEditing( window() ) )
208 if ( m_data->timer.isActive() )
211 m_data->timer.start( m_data->duration,
this );
217 switch(
static_cast< int >( event->type() ) )
219 case QEvent::KeyPress:
221 const auto keyEvent =
static_cast< QKeyEvent*
>( event );
223 if( keyEvent->isAutoRepeat() && m_data->blockAutoRepeatKeyEvents )
232 if ( !isEnabled() && qskIsEnablingKey( keyEvent ) )
235 m_data->blockAutoRepeatKeyEvents =
true;
239 m_data->blockAutoRepeatKeyEvents =
false;
243 case QEvent::KeyRelease:
245 if( m_data->blockAutoRepeatKeyEvents )
247 if( !
static_cast< QKeyEvent*
>( event )->isAutoRepeat() )
248 m_data->blockAutoRepeatKeyEvents =
false;
257 case QEvent::FocusIn:
258 case QEvent::FocusOut:
260 maybeEnable( event->type() != QEvent::FocusOut );
265 return Inherited::eventFilter(
object, event );
268void QskFocusIndicator::timerEvent( QTimerEvent* event )
270 if ( m_data->isAutoDisabling() )
272 if( event->timerId() == m_data->timer.timerId() )
279 Inherited::timerEvent( event );
282bool QskFocusIndicator::contains(
const QPointF& )
const
288QRectF QskFocusIndicator::clipRect()
const
290 if ( m_data->clippingItem )
292 auto rect = qskFocusIndicatorClipRect( m_data->clippingItem );
293 rect = mapRectFromItem( m_data->clippingItem,
rect );
298 return Inherited::clipRect();
301void QskFocusIndicator::onFocusItemGeometryChanged()
306void QskFocusIndicator::onWindowSizeChanged(
int )
311void QskFocusIndicator::onFocusItemDestroyed()
313 m_data->resetConnections();
317void QskFocusIndicator::onFocusItemChanged()
319 m_data->resetConnections();
321 if ( !( window() && window()->contentItem() ) )
325 setParentItem( window()->contentItem() );
328 const auto focusItem = window()->activeFocusItem();
329 QQuickItem* clippingItem =
nullptr;
331 if ( focusItem && ( focusItem != window()->contentItem() ) )
333 setSection( qskItemSection( focusItem ) );
335 auto item = focusItem;
336 m_data->connections += connectItem( item );
338 while (
auto itemParent = item->parentItem() )
340 m_data->connections += connectItem( itemParent );
342 if ( clippingItem ==
nullptr && itemParent->clip() )
343 clippingItem = itemParent;
349 m_data->clippingItem = clippingItem;
353void QskFocusIndicator::updateFocusFrame()
355 QRectF r = focusRect();
356 setVisible( !r.isEmpty() );
362 if (
auto w = window() )
364 QRectF clipRect( 0, 0, w->width(), w->height() );
365 clipRect = parentItem()->mapRectFromScene( clipRect );
367 r = r.intersected( clipRect );
372 const auto clipRect = qskFocusIndicatorClipRect( m_data->clippingItem );
373 setClip( !clipRect.isEmpty() );
384 QQuickItemPrivate::get(
this )->dirty( QQuickItemPrivate::Size );
391QRectF QskFocusIndicator::focusRect()
const
393 if ( window() && parentItem() )
395 const auto item = window()->activeFocusItem();
397 if ( item && ( item !=
this ) && item->isVisible() &&
398 ( item != window()->contentItem() ) )
400 const auto rect = qskFocusIndicatorRect( item );
401 return parentItem()->mapRectFromItem( item,
rect );
412 connectWindow( event->oldWindow(),
false );
413 connectWindow( event->window(),
true );
415 onFocusItemChanged();
417 if ( m_data->isAutoDisabling() )
419 if (
auto w = event->oldWindow() )
420 w->removeEventFilter(
this );
422 if(
auto w = event->window() )
424 w->installEventFilter(
this );
430void QskFocusIndicator::connectWindow(
const QQuickWindow* window,
bool on )
432 if ( window ==
nullptr )
437 connect( window, &QQuickWindow::activeFocusItemChanged,
438 this, &QskFocusIndicator::onFocusItemChanged );
440 connect( window, &QQuickWindow::widthChanged,
441 this, &QskFocusIndicator::onWindowSizeChanged );
443 connect( window, &QQuickWindow::heightChanged,
444 this, &QskFocusIndicator::onWindowSizeChanged );
448 disconnect( window, &QQuickWindow::activeFocusItemChanged,
449 this, &QskFocusIndicator::onFocusItemChanged );
451 disconnect( window, &QQuickWindow::widthChanged,
452 this, &QskFocusIndicator::onWindowSizeChanged );
454 disconnect( window, &QQuickWindow::heightChanged,
455 this, &QskFocusIndicator::onWindowSizeChanged );
459QVector< QMetaObject::Connection > QskFocusIndicator::connectItem(
const QQuickItem* sender )
461 QVector< QMetaObject::Connection > c;
464 c += QObject::connect( sender, &QObject::destroyed,
465 this, &QskFocusIndicator::onFocusItemDestroyed );
467 const auto method = &QskFocusIndicator::onFocusItemGeometryChanged;
469 c += QObject::connect( sender, &QQuickItem::xChanged,
this, method );
470 c += QObject::connect( sender, &QQuickItem::yChanged,
this, method );
471 c += QObject::connect( sender, &QQuickItem::widthChanged,
this, method );
472 c += QObject::connect( sender, &QQuickItem::heightChanged,
this, method );
473 c += QObject::connect( sender, &QQuickItem::visibleChanged,
this, method );
475 if (
const auto control = qskControlCast( sender ) )
481 if ( sender->metaObject()->indexOfSignal(
"focusIndicatorRectChanged()" ) >= 0 )
484 this, SLOT(onFocusItemGeometryChanged()) );
491#include "moc_QskFocusIndicator.cpp"
void focusIndicatorRectChanged()
void windowChangeEvent(QskWindowChangeEvent *) override
bool isInitiallyPainted() const
virtual void windowChangeEvent(QskWindowChangeEvent *)
void setGeometry(qreal x, qreal y, qreal width, qreal height)
QMarginsF paddingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a padding hint.
QskAnimationHint animationHint(QskAspect, QskSkinHintStatus *=nullptr) const