diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 52d81277..3feca7d4 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -500,7 +500,6 @@ void Editor::setupFocusIndicator() void Editor::setupSegmentedBar() { - // copied from Squiek: we need something similar to a tab bar here. TODO ... using A = QskAspect; using Q = QskSegmentedBar; @@ -518,6 +517,7 @@ void Editor::setupSegmentedBar() setBoxBorderMetrics( Q::Panel, 1_dp ); setBoxBorderColors( Q::Panel, m_pal.outline ); + setBoxBorderColors( Q::Panel | Q::Disabled, m_pal.onSurface12 ); setStrutSize( Q::Panel | A::Horizontal, panelStrutSize ); @@ -529,13 +529,40 @@ void Editor::setupSegmentedBar() setStrutSize( Q::Segment | A::Horizontal, segmentStrutSize ); setStrutSize( Q::Segment | A::Vertical, segmentStrutSize.transposed() ); - setGradient( Q::Segment, Qt::transparent ); - setGradient( Q::Segment | Q::Hovered, m_pal.onSurface12, - { QskStateCombination::CombinationNoState, Q::Minimum | Q::Maximum | Q::Selected } ); + + setBoxBorderMetrics( Q::Segment | A::Horizontal, { 0, 1_dp, 0, 1_dp } ); + setBoxBorderMetrics( Q::Segment | Q::Minimum | A::Horizontal, { 1_dp, 1_dp, 0, 1_dp } ); + setBoxBorderMetrics( Q::Segment | Q::Maximum | A::Horizontal, { 0, 1_dp, 1_dp, 1_dp } ); + + setBoxBorderMetrics( Q::Segment | A::Vertical, { 1_dp, 0, 1_dp, 0 } ); + setBoxBorderMetrics( Q::Segment | Q::Minimum | A::Vertical, { 1_dp, 1_dp, 1_dp, 0 } ); + setBoxBorderMetrics( Q::Segment | Q::Maximum | A::Vertical, { 1_dp, 0, 1_dp, 1_dp } ); + + setBoxBorderColors( Q::Segment, Qt::transparent ); + + setGradient( Q::Segment | Q::Hovered, m_pal.onSurface8, + { QskStateCombination::CombinationNoState, Q::Minimum | Q::Maximum } ); + + setGradient( Q::Segment | Q::Focused, m_pal.onSurface12, + { QskStateCombination::CombinationNoState, Q::Minimum | Q::Maximum } ); + + setGradient( Q::Segment | Q::Selected, m_pal.secondaryContainer, + { QskStateCombination::CombinationNoState, Q::Minimum | Q::Maximum } ); + setGradient( Q::Segment | Q::Selected | Q::Hovered, + flattenedColor( m_pal.onSurface, m_pal.secondaryContainer, m_pal.hoverOpacity ), + { QskStateCombination::CombinationNoState, Q::Minimum | Q::Maximum } ); + setGradient( Q::Segment | Q::Selected | Q::Focused, + flattenedColor( m_pal.onSurface, m_pal.secondaryContainer, m_pal.focusOpacity ), + { QskStateCombination::CombinationNoState, Q::Minimum | Q::Maximum } ); + + setGradient( Q::Segment | Q::Selected | Q::Disabled, m_pal.onSurface12, + { QskStateCombination::CombinationNoState, Q::Minimum | Q::Maximum } ); + setPadding( Q::Segment | A::Horizontal, 12_dp, 0, 12_dp, 0 ); setPadding( Q::Segment | A::Vertical, 0, 12_dp, 0, 12_dp ); setBoxShape( Q::Segment, 0 ); + setBoxShape( Q::Segment | Q::Minimum | A::Horizontal, { 100, 0, 100, 0, Qt::RelativeSize }, { QskStateCombination::CombinationNoState, Q::Disabled } ); @@ -561,34 +588,6 @@ void Editor::setupSegmentedBar() setColor( Q::Separator | Q::Disabled, m_pal.onSurface12 ); } - { - // Cursor - setBoxShape( Q::Cursor, 0 ); - - setBoxShape( Q::Cursor | Q::Minimum | A::Horizontal, - { 100, 0, 100, 0, Qt::RelativeSize }, - { QskStateCombination::CombinationNoState, Q::Disabled } ); - - setBoxShape( Q::Cursor | Q::Maximum | A::Horizontal, - { 0, 100, 0, 100, Qt::RelativeSize }, - { QskStateCombination::CombinationNoState, Q::Disabled } ); - - setBoxShape( Q::Cursor | Q::Minimum | A::Vertical, - { 100, 100, 0, 0, Qt::RelativeSize }, - { QskStateCombination::CombinationNoState, Q::Disabled } ); - - setBoxShape( Q::Cursor | Q::Maximum | A::Vertical, - { 0, 0, 100, 100, Qt::RelativeSize }, - { QskStateCombination::CombinationNoState, Q::Disabled } ); - - setGradient( Q::Cursor, m_pal.secondaryContainer ); - setGradient( Q::Cursor | Q::Disabled, m_pal.onSurface12 ); - setGradient( Q::Cursor | Q::Hovered, stateLayerColor( m_pal.onSurface, m_pal.hoverOpacity ) ); - - setBoxBorderMetrics( Q::Cursor, 1_dp ); - setBoxBorderColors( Q::Cursor, Qt::transparent ); - } - { // Splash setBoxShape( Q::Splash, 20_dp ); diff --git a/src/common/QskAspect.h b/src/common/QskAspect.h index 8503627a..4c20c13f 100644 --- a/src/common/QskAspect.h +++ b/src/common/QskAspect.h @@ -111,7 +111,7 @@ class QSK_EXPORT QskAspect NoState = 0, FirstSystemState = 1 << 0, - FirstUserState = 1 << 4, + FirstUserState = 1 << 5, LastUserState = 1 << 11, LastSystemState = 1 << 15, diff --git a/src/controls/QskSegmentedBar.cpp b/src/controls/QskSegmentedBar.cpp index 493f1b4e..abea3ba2 100644 --- a/src/controls/QskSegmentedBar.cpp +++ b/src/controls/QskSegmentedBar.cpp @@ -24,10 +24,10 @@ QSK_SUBCONTROL( QskSegmentedBar, Cursor ) QSK_SUBCONTROL( QskSegmentedBar, Text ) QSK_SUBCONTROL( QskSegmentedBar, Icon ) -QSK_SYSTEM_STATE( QskSegmentedBar, Selected, QskAspect::FirstSystemState ) -QSK_SYSTEM_STATE( QskSegmentedBar, Pressed, QskAspect::FirstSystemState << 1 ) -QSK_SYSTEM_STATE( QskSegmentedBar, Minimum, QskAspect::FirstSystemState << 2 ) -QSK_SYSTEM_STATE( QskSegmentedBar, Maximum, QskAspect::FirstSystemState << 3 ) +QSK_SYSTEM_STATE( QskSegmentedBar, Minimum, QskAspect::FirstSystemState << 1 ) +QSK_SYSTEM_STATE( QskSegmentedBar, Maximum, QskAspect::FirstSystemState << 2 ) +QSK_SYSTEM_STATE( QskSegmentedBar, Selected, QskAspect::FirstSystemState << 3 ) +QSK_SYSTEM_STATE( QskSegmentedBar, Pressed, QskAspect::FirstSystemState << 4 ) class QskSegmentedBar::PrivateData { @@ -42,6 +42,7 @@ class QskSegmentedBar::PrivateData int selectedIndex = -1; int currentIndex = -1; + int focusedIndex = -1; Qt::Orientation orientation; bool isPressed = false; @@ -166,7 +167,10 @@ void QskSegmentedBar::mousePressEvent( QMouseEvent* event ) if( !QGuiApplication::styleHints()->setFocusOnTouchRelease() ) { if( index != m_data->currentIndex ) + { setCurrentIndex( index ); + setFocusedIndex( index ); + } } } } @@ -226,11 +230,12 @@ void QskSegmentedBar::keyPressEvent( QKeyEvent* event ) else forwards = ( event->key() == Qt::Key_Right ); - const int index = nextIndex( m_data->selectedIndex, forwards ); - if ( index != m_data->selectedIndex ) + const int index = nextIndex( m_data->focusedIndex, forwards ); + + if ( index != m_data->focusedIndex ) { if ( index >= 0 && index < count() ) - setSelectedIndex( index ); + setFocusedIndex( index ); } return; @@ -238,9 +243,11 @@ void QskSegmentedBar::keyPressEvent( QKeyEvent* event ) case Qt::Key_Select: case Qt::Key_Space: - + { + setCurrentIndex( m_data->focusedIndex ); // stop further processing return; + } default: { @@ -248,10 +255,10 @@ void QskSegmentedBar::keyPressEvent( QKeyEvent* event ) if( steps != 0 ) { - const int index = nextIndex( m_data->currentIndex, steps > 0 ); + const int index = nextIndex( m_data->focusedIndex, steps > 0 ); - if( index != m_data->currentIndex ) - setCurrentIndex( index ); + if( index != m_data->focusedIndex ) + setFocusedIndex( index ); if( index >= 0 ) return; @@ -279,7 +286,7 @@ void QskSegmentedBar::hoverEnterEvent( QHoverEvent* event ) { using A = QskAspect; - setSkinHint( Segment | A::Metric | A::Position, qskHoverPosition( event ) ); + setSkinHint( Segment | Hovered | A::Metric | A::Position, qskHoverPosition( event ) ); update(); } @@ -287,21 +294,21 @@ void QskSegmentedBar::hoverMoveEvent( QHoverEvent* event ) { using A = QskAspect; - setSkinHint( Segment | A::Metric | A::Position, qskHoverPosition( event ) ); + setSkinHint( Segment | Hovered | A::Metric | A::Position, qskHoverPosition( event ) ); update(); } -void QskSegmentedBar::hoverLeaveEvent( QHoverEvent* event ) +void QskSegmentedBar::hoverLeaveEvent( QHoverEvent* ) { using A = QskAspect; - setSkinHint( Segment | A::Metric | A::Position, QPointF() ); + setSkinHint( Segment | Hovered | A::Metric | A::Position, QPointF() ); update(); } void QskSegmentedBar::focusInEvent( QFocusEvent* event ) { - int index = m_data->currentIndex; + int index = m_data->focusedIndex; switch( event->reason() ) { @@ -324,12 +331,20 @@ void QskSegmentedBar::focusInEvent( QFocusEvent* event ) } } - if( index != m_data->currentIndex ) - setCurrentIndex( index ); + if( index != m_data->focusedIndex ) + setFocusedIndex( index ); Inherited::focusInEvent( event ); } +void QskSegmentedBar::focusOutEvent( QFocusEvent* event ) +{ + setFocusedIndex( -1 ); + update(); + + Inherited::focusOutEvent( event ); +} + void QskSegmentedBar::clear() { if( count() == 0 ) @@ -495,4 +510,17 @@ QRectF QskSegmentedBar::focusIndicatorRect() const return Inherited::focusIndicatorRect(); } +void QskSegmentedBar::setFocusedIndex( int index ) +{ + if ( m_data->focusedIndex == index ) + return; + + m_data->focusedIndex = index; + setPositionHint( Segment | Focused, index ); + + update(); + + Q_EMIT focusIndicatorRectChanged(); +} + #include "moc_QskSegmentedBar.cpp" diff --git a/src/controls/QskSegmentedBar.h b/src/controls/QskSegmentedBar.h index 790de3c2..e932d058 100644 --- a/src/controls/QskSegmentedBar.h +++ b/src/controls/QskSegmentedBar.h @@ -99,9 +99,11 @@ class QSK_EXPORT QskSegmentedBar : public QskControl void hoverLeaveEvent( QHoverEvent* ) override; void focusInEvent( QFocusEvent* ) override; + void focusOutEvent( QFocusEvent* ) override; private: int nextIndex( int index, bool forward ) const; + void setFocusedIndex( int ); class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/src/controls/QskSegmentedBarSkinlet.cpp b/src/controls/QskSegmentedBarSkinlet.cpp index 5905263a..80595f4a 100644 --- a/src/controls/QskSegmentedBarSkinlet.cpp +++ b/src/controls/QskSegmentedBarSkinlet.cpp @@ -196,7 +196,7 @@ QRectF QskSegmentedBarSkinlet::separatorRect( if( bar->orientation() == Qt::Horizontal ) { - rect.setLeft( rect.right() ); // ### *0.5 or so? + rect.setLeft( rect.right() ); rect.setSize( { strutSize.width(), sh.height() } ); } else @@ -361,9 +361,19 @@ QskAspect::States QskSegmentedBarSkinlet::sampleStates( const auto* bar = static_cast< const QskSegmentedBar* >( skinnable ); - if ( subControl == Q::Segment ) + if ( subControl == Q::Segment || subControl == Q::Cursor ) { - const auto cursorPos = bar->effectiveSkinHint( Q::Segment | A::Metric | A::Position ).toPointF(); + if ( bar->isSegmentEnabled( index ) ) + { + if ( bar->selectedIndex() == index ) + states |= Q::Selected; + } + else + { + states |= Q::Disabled; + } + + const auto cursorPos = bar->effectiveSkinHint( Q::Segment | Q::Hovered | A::Metric | A::Position ).toPointF(); if( !cursorPos.isNull() && bar->indexAtPosition( cursorPos ) == index ) { @@ -374,6 +384,20 @@ QskAspect::States QskSegmentedBarSkinlet::sampleStates( states &= ~Q::Hovered; } + const auto focusIndex = bar->positionHint( Q::Segment | Q::Focused ); + + if( focusIndex >= 0 && focusIndex < bar->count() ) + { + if( focusIndex == index ) + { + states |= Q::Focused; + } + else + { + states &= ~Q::Focused; + } + } + if( bar->count() > 0 ) { if( index == 0 ) @@ -393,7 +417,7 @@ QskAspect::States QskSegmentedBarSkinlet::sampleStates( } } } - else if( subControl == Q::Icon || subControl == Q::Text || subControl == Q::Cursor ) + else if( subControl == Q::Icon || subControl == Q::Text ) { if ( bar->isSegmentEnabled( index ) ) { @@ -418,7 +442,7 @@ QSGNode* QskSegmentedBarSkinlet::updateSampleNode( const QskSkinnable* skinnable const auto rect = sampleRect( bar, bar->contentsRect(), subControl, index ); - if ( subControl == Q::Segment || subControl == Q::Separator ) + if ( subControl == Q::Segment || subControl == Q::Separator || subControl == Q::Cursor ) { return updateBoxNode( skinnable, node, rect, subControl ); }