diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index deeddb90..80b03b95 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -4,6 +4,7 @@ *****************************************************************************/ #include "QskMaterial3Skin.h" +#include "QskTextOptions.h" #include @@ -471,10 +472,9 @@ void Editor::setupRadioBox() using Q = QskRadioBox; using A = QskAspect; - setStrutSize( Q::Text, {100, 20 }); setStrutSize( Q::Button, {20, 20 }); setStrutSize( Q::Symbol, {10, 10 }); - setStrutSize( Q::Ripple | Q::Focused, { 40, 40 }); + setStrutSize( Q::Ripple, { 40, 40 }); setSpacing(Q::Panel, 10); @@ -486,18 +486,17 @@ void Editor::setupRadioBox() setBoxBorderColors( Q::Button | Q::Selected, m_pal.primary ); setBoxShape(Q::Ripple, 40); - - setColor( Q::Symbol, m_pal.primary ); - setColor( Q::Ripple | Q::Focused, - stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) ); - setColor( Q::Ripple | Q::Selected | Q::Focused, - // stateLayerColor( m_pal.primary, m_pal.focusOpacity ) ); - Qt::red); + + setColor( Q::Symbol, m_pal.primary ); + setColor( Q::Ripple, stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) ); + setColor( Q::Ripple | Q::Selected, stateLayerColor( m_pal.primary, m_pal.focusOpacity ) ); + setMargin( Q::Text, QskMargins(10, 0,0,0)); setAlignment( Q::Text, Qt::AlignBottom ); - setAnimation(Q::Ripple | A::Metric, 1000); + + setAnimation( Q::Ripple | A::Metric | A::Position, qskDuration ); } void Editor::setupFocusIndicator() diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index 95edfc01..bad4c1fd 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -1,5 +1,7 @@ #include "QskRadioBox.h" #include "QskEvent.h" +#include "QskAnimationHint.h" + #include QSK_SUBCONTROL( QskRadioBox, Panel ) @@ -17,7 +19,6 @@ public: QStringList items; int selectedIndex = -1; int pressedIndex = -1; - int focusedIndex = -1; }; QskRadioBox::QskRadioBox( QQuickItem* parent ) : @@ -35,6 +36,8 @@ QskRadioBox::QskRadioBox( QQuickItem* parent ) : setFocusPolicy( Qt::NoFocus ); } }); + + setPositionHint( Ripple, -1 ); } QskRadioBox::QskRadioBox( const QStringList& list, QQuickItem* parent ) : @@ -62,10 +65,6 @@ const QStringList& QskRadioBox::items() const { return m_data->items; } -int QskRadioBox::focusedIndex() const { - return m_data->focusedIndex; -} - int QskRadioBox::pressedIndex() const { return m_data->pressedIndex; } @@ -102,48 +101,53 @@ void QskRadioBox::keyPressEvent( QKeyEvent* event ) case Qt::Key_Up: case Qt::Key_Left: m_data->selectedIndex = qMax(m_data->selectedIndex - 1, 0); - m_data->focusedIndex = m_data->selectedIndex; - setSkinStateFlag( QskRadioBox::Selected ); + setPositionHint( Ripple, m_data->selectedIndex ); event->setAccepted( true ); update(); return; case Qt::Key_Down: case Qt::Key_Right: m_data->selectedIndex = qMin(m_data->selectedIndex + 1, items().size() - 1); - m_data->focusedIndex = m_data->selectedIndex; - setSkinStateFlag( QskRadioBox::Selected ); + setPositionHint( Ripple, m_data->selectedIndex ); event->setAccepted( true ); update(); return; case Qt::Key_Select: case Qt::Key_Return: case Qt::Key_Space: - m_data->selectedIndex = m_data->focusedIndex; - setSkinStateFlag( QskRadioBox::Selected ); - setSkinStateFlag( QskRadioBox::Pressed ); + m_data->selectedIndex = positionHint( Ripple ); event->setAccepted( true ); update(); return; } - auto nextTabIndex = m_data->focusedIndex; - nextTabIndex += qskFocusChainIncrement( event ); + auto currentTabIndex = positionHint( Ripple ); + auto nextTabIndex = currentTabIndex + qskFocusChainIncrement( event ); if( nextTabIndex >= items().size() || nextTabIndex < 0 ) { - Inherited::keyPressEvent( event ); - } else { - m_data->focusedIndex = nextTabIndex; - setSkinStateFlag( QskRadioBox::Focused ); - event->setAccepted( true ); + Inherited::keyPressEvent( event ); + setPositionHint(Ripple, -1); update(); + } else { + event->setAccepted( true ); + setPositionHint( Ripple, (float) nextTabIndex ); + + const auto aspect = Ripple | QskAspect::Metric | QskAspect::Position; + auto hint = animationHint(aspect | skinStates()); + if( hint.isValid()) { + startTransition( aspect, + hint, + (float) currentTabIndex, (float) nextTabIndex ); + } + + update(); + } } void QskRadioBox::keyReleaseEvent( QKeyEvent* e ) { - setSkinStateFlag( QskRadioBox::Pressed, false ); e->setAccepted( true ); - update(); } void QskRadioBox::mousePressEvent( QMouseEvent* e ) @@ -153,18 +157,14 @@ void QskRadioBox::mousePressEvent( QMouseEvent* e ) m_data->pressedIndex = indexAtPosition; m_data->selectedIndex = -1; - m_data->focusedIndex = indexAtPosition; - - setSkinStateFlag( QskRadioBox::Pressed ); + setPositionHint( Ripple, indexAtPosition ); e->setAccepted( true ); - update(); + update(); } void QskRadioBox::mouseReleaseEvent( QMouseEvent* e ) { - setSkinStateFlag( QskRadioBox::Pressed, false ); - auto index = indexAt( e->localPos() ); if( index == m_data->pressedIndex ) { setSelectedIndex( index ); @@ -176,19 +176,19 @@ void QskRadioBox::mouseReleaseEvent( QMouseEvent* e ) void QskRadioBox::focusInEvent( QFocusEvent* e ) { if( e->reason() == Qt::TabFocusReason ) { - m_data->focusedIndex = 0; + setPositionHint( Ripple, 0 ); } else if( e->reason() == Qt::BacktabFocusReason ) { - m_data->focusedIndex = items().size() - 1; + setPositionHint( Ripple, items().size() - 1 ); } - setSkinStateFlag( Focused ); + update(); Inherited::focusInEvent( e ); } void QskRadioBox::focusOutEvent( QFocusEvent* e ) { - m_data->focusedIndex = -1; - setSkinStateFlag( Focused, false ); + setPositionHint(Ripple, -1); update(); + Inherited::focusOutEvent( e ); } diff --git a/src/controls/QskRadioBox.h b/src/controls/QskRadioBox.h index 59693698..db9fd6ab 100644 --- a/src/controls/QskRadioBox.h +++ b/src/controls/QskRadioBox.h @@ -31,7 +31,6 @@ class QSK_EXPORT QskRadioBox : public QskControl const QStringList& items() const; int selectedIndex() const; - int focusedIndex() const; int pressedIndex() const; public Q_SLOTS: diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index bfafbc07..789367e9 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -3,6 +3,7 @@ #include "QskAspect.h" #include "QskRadioBox.h" +#include "QskSkinStateChanger.h" #include "QskStandardSymbol.h" #include "QskColorFilter.h" #include "QskGraphic.h" @@ -23,13 +24,31 @@ QskRadioBoxSkinlet::~QskRadioBoxSkinlet() { } +QskAspect::States statesForIndex(const QskRadioBox* radio, int index) { + auto states = radio->skinStates(); + + if( radio->selectedIndex() == index ) { + states |= Q::Selected; + } + + if( radio->pressedIndex() == index ) { + states |= Q::Pressed; + } + + if( radio->positionHint( Q::Ripple ) == index ) { + states |= Q::Focused; + } + + return states; +} + QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subcontrol) const { auto radio = static_cast( skinnable ); if( subcontrol == Q::Ripple ) { - return buttonRect(radio, Q::Ripple, contentsRect, radio->focusedIndex()); + return buttonRect(radio, Q::Ripple, contentsRect, radio->positionHint(Q::Ripple)); } return contentsRect; @@ -83,7 +102,12 @@ QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable, return updateSeriesNode( radio, Q::Text, node ); case RippleRole: + { + QskSkinStateChanger cleaner( radio ); + cleaner.setStates( statesForIndex( radio, radio->positionHint( Q::Ripple ) ) ); + return updateBoxNode( radio, node, Q::Ripple ); + } }; return Inherited::updateSubNode( skinnable, nodeRole, node ); @@ -108,10 +132,11 @@ int QskRadioBoxSkinlet::sampleCount( const QskSkinnable* skinnable, QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, const QskAspect::Subcontrol target, - const QRectF& rect, int index ) const { + const QRectF& rect, double index ) const { if( index < 0 ) { return QRectF(); } + auto result = rect; result.setSize( radio->strutSizeHint( target ) ); @@ -169,19 +194,7 @@ QskAspect::States QskRadioBoxSkinlet::sampleStates( const QskSkinnable* skinnabl auto radio = static_cast( skinnable ); auto states = Inherited::sampleStates( skinnable, subControl, index ); - if( radio->selectedIndex() == index ) { - states |= Q::Selected; - } - - if( radio->pressedIndex() == index ) { - states |= Q::Pressed; - } - - if( radio->focusedIndex() == index ) { - states |= Q::Focused; - } - - return states; + return states | statesForIndex( radio, index ); } QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, @@ -199,10 +212,10 @@ QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, radio->items()[index], subcontrol); } else if (subcontrol == Q::Button) { - return QskSkinlet::updateBoxNode(radio, - node, - rect, - subcontrol); + return QskSkinlet::updateBoxNode( radio, + node, + rect, + subcontrol ); } else if( subcontrol == Q::Symbol ) { auto symbol = QskStandardSymbol::NoSymbol; auto color = radio->color( subcontrol ).rgb(); diff --git a/src/controls/QskRadioBoxSkinlet.h b/src/controls/QskRadioBoxSkinlet.h index dcafffe2..a258125d 100644 --- a/src/controls/QskRadioBoxSkinlet.h +++ b/src/controls/QskRadioBoxSkinlet.h @@ -38,7 +38,7 @@ class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet const QRectF&, QskAspect::Subcontrol, int index ) const override; QRectF textRect( const QskRadioBox*, const QRectF&, int ) const; - QRectF buttonRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, int ) const; + QRectF buttonRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, double ) const; QskAspect::States sampleStates( const QskSkinnable*, QskAspect::Subcontrol, int index ) const override;