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()
{
// 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 );

View File

@ -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,

View File

@ -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"

View File

@ -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;

View File

@ -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 );
}