QskSegmentedBarSkinlet fixes

This commit is contained in:
Uwe Rathmann 2023-07-05 18:28:57 +02:00
parent d33e1f1a90
commit 4bf1b019c7
5 changed files with 105 additions and 77 deletions

View File

@ -1180,7 +1180,7 @@ void Editor::setupSegmentedBarColors(
graphicRole = W::GraphicRoleFillColorTextPrimary; graphicRole = W::GraphicRoleFillColorTextPrimary;
} }
else if ( states & Q::Hovered ) else if ( states == Q::Hovered )
{ {
segmentColor = pal.fillColor.control.secondary; segmentColor = pal.fillColor.control.secondary;
borderColor1 = pal.elevation.control.border[0]; borderColor1 = pal.elevation.control.border[0];
@ -1206,7 +1206,7 @@ void Editor::setupSegmentedBarColors(
graphicRole = W::GraphicRoleFillColorTextOnAccentPrimary; graphicRole = W::GraphicRoleFillColorTextOnAccentPrimary;
} }
else if ( states == Q::Disabled ) else if ( states & Q::Disabled )
{ {
segmentColor = pal.fillColor.control.disabled; segmentColor = pal.fillColor.control.disabled;
borderColor1 = borderColor2 = pal.strokeColor.control.defaultColor; borderColor1 = borderColor2 = pal.strokeColor.control.defaultColor;

View File

@ -522,6 +522,8 @@ void Editor::setupSegmentedBar()
setStrutSize( Q::Panel | A::Horizontal, panelStrutSize ); setStrutSize( Q::Panel | A::Horizontal, panelStrutSize );
setStrutSize( Q::Panel | A::Vertical, panelStrutSize.transposed() ); setStrutSize( Q::Panel | A::Vertical, panelStrutSize.transposed() );
setFlag( Q::Panel | A::Option, true ); // adjust segments to the panel radius
} }
{ {
@ -530,53 +532,20 @@ 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() );
setBoxBorderMetrics( Q::Segment | A::Horizontal, { 0, 1_dp, 0, 1_dp } ); setGradient( Q::Segment | Q::Hovered, m_pal.onSurface8 );
setBoxBorderMetrics( Q::Segment | Q::Minimum | A::Horizontal, { 1_dp, 1_dp, 0, 1_dp } ); setGradient( Q::Segment | Q::Focused, m_pal.onSurface12 );
setBoxBorderMetrics( Q::Segment | Q::Maximum | A::Horizontal, { 0, 1_dp, 1_dp, 1_dp } ); setGradient( Q::Segment | Q::Selected, m_pal.secondaryContainer );
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, setGradient( Q::Segment | Q::Selected | Q::Hovered,
flattenedColor( m_pal.onSurface, m_pal.secondaryContainer, m_pal.hoverOpacity ), flattenedColor( m_pal.onSurface, m_pal.secondaryContainer, m_pal.hoverOpacity ) );
{ QskStateCombination::CombinationNoState, Q::Minimum | Q::Maximum } );
setGradient( Q::Segment | Q::Selected | Q::Focused, setGradient( Q::Segment | Q::Selected | Q::Focused,
flattenedColor( m_pal.onSurface, m_pal.secondaryContainer, m_pal.focusOpacity ), 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, 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 );
for( const auto subcontrol : { Q::Segment, Q::Splash } )
{
setBoxShape( subcontrol | Q::Minimum | A::Horizontal,
{ 100, 0, 100, 0, Qt::RelativeSize },
{ QskStateCombination::CombinationNoState, Q::Disabled } );
setBoxShape( subcontrol | Q::Maximum | A::Horizontal,
{ 0, 100, 0, 100, Qt::RelativeSize },
{ QskStateCombination::CombinationNoState, Q::Disabled } );
setBoxShape( subcontrol | Q::Minimum | A::Vertical,
{ 100, 100, 0, 0, Qt::RelativeSize },
{ QskStateCombination::CombinationNoState, Q::Disabled } );
setBoxShape( subcontrol | Q::Maximum | A::Vertical,
{ 0, 0, 100, 100, Qt::RelativeSize },
{ QskStateCombination::CombinationNoState, Q::Disabled } );
}
} }
{ {

View File

@ -24,10 +24,8 @@ QSK_SUBCONTROL( QskSegmentedBar, Cursor )
QSK_SUBCONTROL( QskSegmentedBar, Text ) QSK_SUBCONTROL( QskSegmentedBar, Text )
QSK_SUBCONTROL( QskSegmentedBar, Icon ) QSK_SUBCONTROL( QskSegmentedBar, Icon )
QSK_SYSTEM_STATE( QskSegmentedBar, Minimum, QskAspect::FirstSystemState << 1 ) QSK_SYSTEM_STATE( QskSegmentedBar, Selected, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskSegmentedBar, Maximum, QskAspect::FirstSystemState << 2 ) QSK_SYSTEM_STATE( QskSegmentedBar, Pressed, QskAspect::FirstSystemState << 2 )
QSK_SYSTEM_STATE( QskSegmentedBar, Selected, QskAspect::FirstSystemState << 3 )
QSK_SYSTEM_STATE( QskSegmentedBar, Pressed, QskAspect::FirstSystemState << 4 )
class QskSegmentedBar::PrivateData class QskSegmentedBar::PrivateData
{ {

View File

@ -37,7 +37,7 @@ class QSK_EXPORT QskSegmentedBar : public QskControl
public: public:
QSK_SUBCONTROLS( Panel, Splash, Segment, Separator, Cursor, Text, Icon ) QSK_SUBCONTROLS( Panel, Splash, Segment, Separator, Cursor, Text, Icon )
QSK_STATES( Selected, Pressed, Minimum, Maximum ) QSK_STATES( Selected, Pressed )
QskSegmentedBar( QQuickItem* parent = nullptr ); QskSegmentedBar( QQuickItem* parent = nullptr );
QskSegmentedBar( Qt::Orientation, QQuickItem* parent = nullptr ); QskSegmentedBar( Qt::Orientation, QQuickItem* parent = nullptr );

View File

@ -14,19 +14,81 @@
#include "QskSkin.h" #include "QskSkin.h"
#include "QskSkinStateChanger.h" #include "QskSkinStateChanger.h"
#include "QskSubcontrolLayoutEngine.h" #include "QskSubcontrolLayoutEngine.h"
#include "QskBoxHints.h"
#include <qfontmetrics.h> #include <qfontmetrics.h>
#include <qmath.h> #include <qmath.h>
namespace namespace
{ {
QskBoxHints effectiveBoxHints( QskAspect::Subcontrol subControl,
const QskSegmentedBar* bar, int index )
{
using Q = QskSegmentedBar;
auto boxHints = bar->boxHints( subControl );
const bool leading = ( index == 0 );
const bool trailing = ( index == bar->count() - 1 );
if ( !( leading || trailing ) )
return boxHints;
// something more expressive than just a boolean. TODO ...
if ( !bar->flagHint< bool >( Q::Panel | QskAspect::Option, false ) )
return boxHints;
const auto panelShape = bar->boxShapeHint( Q::Panel );
auto& shape = boxHints.shape;
// when there is only 1 segment we have to fit both ends
if ( leading )
{
Qt::Corner corners[2];
corners[0] = Qt::TopLeftCorner;
if ( bar->orientation() == Qt::Vertical )
corners[1] = Qt::TopRightCorner;
else
corners[1] = Qt::BottomLeftCorner;
shape.setSizeMode( panelShape.sizeMode() );
shape.setRadius( corners[0], panelShape.radius( corners[0] ) );
shape.setRadius( corners[1], panelShape.radius( corners[1] ) );
}
if ( trailing )
{
Qt::Corner corners[2];
corners[0] = Qt::BottomRightCorner;
if ( bar->orientation() == Qt::Vertical )
corners[1] = Qt::BottomLeftCorner;
else
corners[1] = Qt::TopRightCorner;
shape.setSizeMode( panelShape.sizeMode() );
shape.setRadius( corners[0], panelShape.radius( corners[0] ) );
shape.setRadius( corners[1], panelShape.radius( corners[1] ) );
}
boxHints.borderMetrics = bar->boxBorderMetricsHint( Q::Panel );
boxHints.borderColors = QColor();
return boxHints;
}
QskGraphic iconAt( const QskSegmentedBar* bar, const int index ) QskGraphic iconAt( const QskSegmentedBar* bar, const int index )
{ {
using Q = QskSegmentedBar; using Q = QskSegmentedBar;
if ( bar->selectedIndex() == index ) if ( bar->selectedIndex() == index )
{ {
/* /*
Material 3 replaces the icon of the selected element by a checkmark, Material 3 replaces the icon of the selected element by a checkmark,
when icon and text are set. So this code is actually not correct when icon and text are set. So this code is actually not correct
as it also replaces the icon when there is no text as it also replaces the icon when there is no text
@ -386,7 +448,8 @@ QskAspect::States QskSegmentedBarSkinlet::sampleStates(
states |= Q::Disabled; states |= Q::Disabled;
} }
const auto cursorPos = bar->effectiveSkinHint( Q::Segment | Q::Hovered | A::Metric | A::Position ).toPointF(); 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 )
{ {
@ -410,25 +473,6 @@ QskAspect::States QskSegmentedBarSkinlet::sampleStates(
states &= ~Q::Focused; states &= ~Q::Focused;
} }
} }
if( bar->count() > 0 )
{
if( index == 0 )
{
states &= ~Q::Maximum;
states |= Q::Minimum;
}
else if( index == bar->count() - 1 )
{
states &= ~Q::Minimum;
states |= Q::Maximum;
}
else
{
states &= ~Q::Minimum;
states &= ~Q::Maximum;
}
}
} }
else if( subControl == Q::Icon || subControl == Q::Text ) else if( subControl == Q::Icon || subControl == Q::Text )
{ {
@ -455,11 +499,17 @@ 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 || subControl == Q::Cursor ) if ( subControl == Q::Separator )
{ {
return updateBoxNode( skinnable, node, rect, subControl ); return updateBoxNode( skinnable, node, rect, subControl );
} }
if ( subControl == Q::Segment )
{
const auto boxHints = effectiveBoxHints( subControl, bar, index );
return updateBoxNode( bar, node, rect, boxHints );
}
const auto alignment = bar->alignmentHint( subControl, Qt::AlignCenter ); const auto alignment = bar->alignmentHint( subControl, Qt::AlignCenter );
if ( subControl == Q::Text ) if ( subControl == Q::Text )
@ -509,23 +559,34 @@ QSGNode* QskSegmentedBarSkinlet::updateSplashNode(
if ( splashRect.isEmpty() ) if ( splashRect.isEmpty() )
return nullptr; return nullptr;
auto clipNode = updateBoxClipNode( bar, node, auto panelClipNode = updateBoxClipNode(
bar->subControlRect( Q::Cursor ), Q::Cursor ); bar, node, bar->subControlRect( Q::Panel ), Q::Panel );
if ( clipNode ) if ( panelClipNode )
{ {
auto boxNode = QskSGNode::findChildNode( clipNode, SplashRole ); const auto segmentRect = sampleRect(
bar, bar->contentsRect(), Q::Segment, bar->selectedIndex() );
auto segmentClipNode = updateBoxClipNode(
bar, panelClipNode->firstChild(), segmentRect, Q::Segment );
if ( segmentClipNode == nullptr )
return nullptr;
if ( segmentClipNode->parent() == nullptr )
panelClipNode->appendChildNode( segmentClipNode );
auto boxNode = segmentClipNode->firstChild();
boxNode = updateBoxNode( bar, boxNode, splashRect, Q::Splash ); boxNode = updateBoxNode( bar, boxNode, splashRect, Q::Splash );
if ( boxNode == nullptr ) if ( boxNode == nullptr )
return nullptr; return nullptr;
QskSGNode::setNodeRole( boxNode, SplashRole ); if ( boxNode->parent() == nullptr )
if ( boxNode->parent() != clipNode ) segmentClipNode->appendChildNode( boxNode );
clipNode->appendChildNode( boxNode );
} }
return clipNode; return panelClipNode;
} }
#include "moc_QskSegmentedBarSkinlet.cpp" #include "moc_QskSegmentedBarSkinlet.cpp"