segmented bar: Support focus

This commit is contained in:
Peter Hartmann 2023-03-27 14:05:45 +02:00 committed by uwerat
parent acb225bb82
commit caba0d5735
5 changed files with 109 additions and 56 deletions

View File

@ -500,7 +500,6 @@ void Editor::setupFocusIndicator()
void Editor::setupSegmentedBar() void Editor::setupSegmentedBar()
{ {
// copied from Squiek: we need something similar to a tab bar here. TODO ...
using A = QskAspect; using A = QskAspect;
using Q = QskSegmentedBar; using Q = QskSegmentedBar;
@ -518,6 +517,7 @@ void Editor::setupSegmentedBar()
setBoxBorderMetrics( Q::Panel, 1_dp ); setBoxBorderMetrics( Q::Panel, 1_dp );
setBoxBorderColors( Q::Panel, m_pal.outline ); setBoxBorderColors( Q::Panel, m_pal.outline );
setBoxBorderColors( Q::Panel | Q::Disabled, m_pal.onSurface12 ); setBoxBorderColors( Q::Panel | Q::Disabled, m_pal.onSurface12 );
setStrutSize( Q::Panel | A::Horizontal, panelStrutSize ); setStrutSize( Q::Panel | A::Horizontal, panelStrutSize );
@ -529,13 +529,40 @@ void Editor::setupSegmentedBar()
setStrutSize( Q::Segment | A::Horizontal, segmentStrutSize ); setStrutSize( Q::Segment | A::Horizontal, segmentStrutSize );
setStrutSize( Q::Segment | A::Vertical, segmentStrutSize.transposed() ); setStrutSize( Q::Segment | A::Vertical, segmentStrutSize.transposed() );
setGradient( Q::Segment, Qt::transparent );
setGradient( Q::Segment | Q::Hovered, m_pal.onSurface12, setBoxBorderMetrics( Q::Segment | A::Horizontal, { 0, 1_dp, 0, 1_dp } );
{ QskStateCombination::CombinationNoState, Q::Minimum | Q::Maximum | Q::Selected } ); 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::Horizontal, 12_dp, 0, 12_dp, 0 );
setPadding( Q::Segment | A::Vertical, 0, 12_dp, 0, 12_dp ); setPadding( Q::Segment | A::Vertical, 0, 12_dp, 0, 12_dp );
setBoxShape( Q::Segment, 0 ); setBoxShape( Q::Segment, 0 );
setBoxShape( Q::Segment | Q::Minimum | A::Horizontal, setBoxShape( Q::Segment | Q::Minimum | A::Horizontal,
{ 100, 0, 100, 0, Qt::RelativeSize }, { 100, 0, 100, 0, Qt::RelativeSize },
{ QskStateCombination::CombinationNoState, Q::Disabled } ); { QskStateCombination::CombinationNoState, Q::Disabled } );
@ -561,34 +588,6 @@ void Editor::setupSegmentedBar()
setColor( Q::Separator | Q::Disabled, m_pal.onSurface12 ); 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 // Splash
setBoxShape( Q::Splash, 20_dp ); setBoxShape( Q::Splash, 20_dp );

View File

@ -111,7 +111,7 @@ class QSK_EXPORT QskAspect
NoState = 0, NoState = 0,
FirstSystemState = 1 << 0, FirstSystemState = 1 << 0,
FirstUserState = 1 << 4, FirstUserState = 1 << 5,
LastUserState = 1 << 11, LastUserState = 1 << 11,
LastSystemState = 1 << 15, LastSystemState = 1 << 15,

View File

@ -24,10 +24,10 @@ QSK_SUBCONTROL( QskSegmentedBar, Cursor )
QSK_SUBCONTROL( QskSegmentedBar, Text ) QSK_SUBCONTROL( QskSegmentedBar, Text )
QSK_SUBCONTROL( QskSegmentedBar, Icon ) QSK_SUBCONTROL( QskSegmentedBar, Icon )
QSK_SYSTEM_STATE( QskSegmentedBar, Selected, QskAspect::FirstSystemState ) QSK_SYSTEM_STATE( QskSegmentedBar, Minimum, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskSegmentedBar, Pressed, QskAspect::FirstSystemState << 1 ) QSK_SYSTEM_STATE( QskSegmentedBar, Maximum, QskAspect::FirstSystemState << 2 )
QSK_SYSTEM_STATE( QskSegmentedBar, Minimum, QskAspect::FirstSystemState << 2 ) QSK_SYSTEM_STATE( QskSegmentedBar, Selected, QskAspect::FirstSystemState << 3 )
QSK_SYSTEM_STATE( QskSegmentedBar, Maximum, QskAspect::FirstSystemState << 3 ) QSK_SYSTEM_STATE( QskSegmentedBar, Pressed, QskAspect::FirstSystemState << 4 )
class QskSegmentedBar::PrivateData class QskSegmentedBar::PrivateData
{ {
@ -42,6 +42,7 @@ class QskSegmentedBar::PrivateData
int selectedIndex = -1; int selectedIndex = -1;
int currentIndex = -1; int currentIndex = -1;
int focusedIndex = -1;
Qt::Orientation orientation; Qt::Orientation orientation;
bool isPressed = false; bool isPressed = false;
@ -166,7 +167,10 @@ void QskSegmentedBar::mousePressEvent( QMouseEvent* event )
if( !QGuiApplication::styleHints()->setFocusOnTouchRelease() ) if( !QGuiApplication::styleHints()->setFocusOnTouchRelease() )
{ {
if( index != m_data->currentIndex ) if( index != m_data->currentIndex )
{
setCurrentIndex( index ); setCurrentIndex( index );
setFocusedIndex( index );
}
} }
} }
} }
@ -226,11 +230,12 @@ void QskSegmentedBar::keyPressEvent( QKeyEvent* event )
else else
forwards = ( event->key() == Qt::Key_Right ); forwards = ( event->key() == Qt::Key_Right );
const int index = nextIndex( m_data->selectedIndex, forwards ); const int index = nextIndex( m_data->focusedIndex, forwards );
if ( index != m_data->selectedIndex )
if ( index != m_data->focusedIndex )
{ {
if ( index >= 0 && index < count() ) if ( index >= 0 && index < count() )
setSelectedIndex( index ); setFocusedIndex( index );
} }
return; return;
@ -238,9 +243,11 @@ void QskSegmentedBar::keyPressEvent( QKeyEvent* event )
case Qt::Key_Select: case Qt::Key_Select:
case Qt::Key_Space: case Qt::Key_Space:
{
setCurrentIndex( m_data->focusedIndex );
// stop further processing // stop further processing
return; return;
}
default: default:
{ {
@ -248,10 +255,10 @@ void QskSegmentedBar::keyPressEvent( QKeyEvent* event )
if( steps != 0 ) 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 ) if( index != m_data->focusedIndex )
setCurrentIndex( index ); setFocusedIndex( index );
if( index >= 0 ) if( index >= 0 )
return; return;
@ -279,7 +286,7 @@ void QskSegmentedBar::hoverEnterEvent( QHoverEvent* event )
{ {
using A = QskAspect; using A = QskAspect;
setSkinHint( Segment | A::Metric | A::Position, qskHoverPosition( event ) ); setSkinHint( Segment | Hovered | A::Metric | A::Position, qskHoverPosition( event ) );
update(); update();
} }
@ -287,21 +294,21 @@ void QskSegmentedBar::hoverMoveEvent( QHoverEvent* event )
{ {
using A = QskAspect; using A = QskAspect;
setSkinHint( Segment | A::Metric | A::Position, qskHoverPosition( event ) ); setSkinHint( Segment | Hovered | A::Metric | A::Position, qskHoverPosition( event ) );
update(); update();
} }
void QskSegmentedBar::hoverLeaveEvent( QHoverEvent* event ) void QskSegmentedBar::hoverLeaveEvent( QHoverEvent* )
{ {
using A = QskAspect; using A = QskAspect;
setSkinHint( Segment | A::Metric | A::Position, QPointF() ); setSkinHint( Segment | Hovered | A::Metric | A::Position, QPointF() );
update(); update();
} }
void QskSegmentedBar::focusInEvent( QFocusEvent* event ) void QskSegmentedBar::focusInEvent( QFocusEvent* event )
{ {
int index = m_data->currentIndex; int index = m_data->focusedIndex;
switch( event->reason() ) switch( event->reason() )
{ {
@ -324,12 +331,20 @@ void QskSegmentedBar::focusInEvent( QFocusEvent* event )
} }
} }
if( index != m_data->currentIndex ) if( index != m_data->focusedIndex )
setCurrentIndex( index ); setFocusedIndex( index );
Inherited::focusInEvent( event ); Inherited::focusInEvent( event );
} }
void QskSegmentedBar::focusOutEvent( QFocusEvent* event )
{
setFocusedIndex( -1 );
update();
Inherited::focusOutEvent( event );
}
void QskSegmentedBar::clear() void QskSegmentedBar::clear()
{ {
if( count() == 0 ) if( count() == 0 )
@ -495,4 +510,17 @@ QRectF QskSegmentedBar::focusIndicatorRect() const
return Inherited::focusIndicatorRect(); 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" #include "moc_QskSegmentedBar.cpp"

View File

@ -99,9 +99,11 @@ class QSK_EXPORT QskSegmentedBar : public QskControl
void hoverLeaveEvent( QHoverEvent* ) override; void hoverLeaveEvent( QHoverEvent* ) override;
void focusInEvent( QFocusEvent* ) override; void focusInEvent( QFocusEvent* ) override;
void focusOutEvent( QFocusEvent* ) override;
private: private:
int nextIndex( int index, bool forward ) const; int nextIndex( int index, bool forward ) const;
void setFocusedIndex( int );
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;

View File

@ -196,7 +196,7 @@ QRectF QskSegmentedBarSkinlet::separatorRect(
if( bar->orientation() == Qt::Horizontal ) if( bar->orientation() == Qt::Horizontal )
{ {
rect.setLeft( rect.right() ); // ### *0.5 or so? rect.setLeft( rect.right() );
rect.setSize( { strutSize.width(), sh.height() } ); rect.setSize( { strutSize.width(), sh.height() } );
} }
else else
@ -361,9 +361,19 @@ QskAspect::States QskSegmentedBarSkinlet::sampleStates(
const auto* bar = static_cast< const QskSegmentedBar* >( skinnable ); 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 ) if( !cursorPos.isNull() && bar->indexAtPosition( cursorPos ) == index )
{ {
@ -374,6 +384,20 @@ QskAspect::States QskSegmentedBarSkinlet::sampleStates(
states &= ~Q::Hovered; 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( bar->count() > 0 )
{ {
if( index == 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 ) ) if ( bar->isSegmentEnabled( index ) )
{ {
@ -418,7 +442,7 @@ QSGNode* QskSegmentedBarSkinlet::updateSampleNode( const QskSkinnable* skinnable
const auto rect = sampleRect( bar, bar->contentsRect(), subControl, index ); 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 ); return updateBoxNode( skinnable, node, rect, subControl );
} }