diff --git a/designsystems/fusion/QskFusionSkin.cpp b/designsystems/fusion/QskFusionSkin.cpp
index 50188ee8..5feceb48 100644
--- a/designsystems/fusion/QskFusionSkin.cpp
+++ b/designsystems/fusion/QskFusionSkin.cpp
@@ -489,7 +489,7 @@ void Editor::setupRadioBox()
setStrutSize( Q::CheckIndicatorPanel, 20_dp, 20_dp );
- for ( auto subControl : { Q::CheckIndicatorPanel, Q::CheckIndicator, Q::Halo } )
+ for ( auto subControl : { Q::CheckIndicatorPanel, Q::CheckIndicator } )
setBoxShape( subControl, 100, Qt::RelativeSize ); // circular
setBoxBorderMetrics( Q::CheckIndicatorPanel, 1_dp );
diff --git a/designsystems/material3/QskMaterial3Icons.qrc b/designsystems/material3/QskMaterial3Icons.qrc
index 4e55e3be..72725b7a 100644
--- a/designsystems/material3/QskMaterial3Icons.qrc
+++ b/designsystems/material3/QskMaterial3Icons.qrc
@@ -7,6 +7,8 @@
icons/qvg/combo-box-arrow-closed.qvg
icons/qvg/combo-box-arrow-open.qvg
icons/qvg/segmented-button-check.qvg
+ icons/qvg/switchbutton-checked.qvg
+ icons/qvg/switchbutton-unchecked.qvg
diff --git a/designsystems/material3/QskMaterial3Skin.cpp b/designsystems/material3/QskMaterial3Skin.cpp
index ec2686ee..74020ffc 100644
--- a/designsystems/material3/QskMaterial3Skin.cpp
+++ b/designsystems/material3/QskMaterial3Skin.cpp
@@ -40,7 +40,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -194,83 +193,95 @@ namespace
void Editor::setupCheckBox()
{
- // skin hints are ordered according to
- // https://m3.material.io/components/checkbox/specs
-
using Q = QskCheckBox;
+ using A = QskAspect;
+
+ // == metrics
setSpacing( Q::Panel, 40_dp );
- setStrutSize( Q::Box, 18_dp, 18_dp );
- setBoxShape( Q::Box, 2_dp );
-
- setBoxBorderColors( Q::Box, m_pal.onSurface );
-#if 1
- // hack: if border metrics == box shape, alpha value will be discarded
- setBoxBorderMetrics( Q::Box, 1.99_dp );
-#endif
-
- setGradient( Q::Box, m_pal.background ); // not mentioned in the specs, but needed for animation
- setGradient( Q::Box | Q::Checked, m_pal.primary );
- setBoxBorderMetrics( Q::Box | Q::Checked, 0 );
-
- setPadding( Q::Box, 3_dp ); // "icon size"
-
- setGraphicRole( Q::Indicator, QskMaterial3Skin::GraphicRoleOnPrimary );
-
- setBoxBorderColors( Q::Box | Q::Error, m_pal.error );
-
- setGradient( Q::Box | Q::Checked | Q::Error, m_pal.error );
-
- setGraphicRole( Q::Indicator | Q::Error, QskMaterial3Skin::GraphicRoleOnError );
-
- const auto checkMark = symbol( "check_small" );
- for ( auto state : { QskAspect::NoState, Q::Disabled } )
{
- const auto aspect = Q::Indicator | Q::Checked | state;
- setSymbol( aspect, checkMark );
- setSymbol( aspect | Q::Error, checkMark );
+ setStrutSize( Q::Box, 18_dp, 18_dp );
+ setBoxBorderMetrics( Q::Box, 2_dp );
+ setBoxShape( Q::Box, 2_dp );
+ setPadding( Q::Box, 3_dp ); // "icon size"
+
+ QskShadowMetrics shadowMetrics( 12_dp, 0.0 );
+ shadowMetrics.setShapeMode( QskShadowMetrics::Ellipse );
+ setShadowMetrics( Q::Box, shadowMetrics );
}
- setStrutSize( Q::Halo, 40_dp, 40_dp );
- setBoxShape( Q::Halo, 100, Qt::RelativeSize );
- setGradient( Q::Halo, Qt::transparent );
+ {
+ setGraphicRole( Q::Indicator, QskMaterial3Skin::GraphicRoleOnPrimary );
+ setGraphicRole( Q::Indicator | Q::Error, QskMaterial3Skin::GraphicRoleOnError );
+ setGraphicRole( Q::Indicator | Q::Disabled | Q::Checked,
+ QskMaterial3Skin::GraphicRoleSurface );
+
+ const auto checkMark = symbol( "check_small" );
+ for ( auto state : { A::NoState, Q::Disabled } )
+ {
+ const auto aspect = Q::Indicator | Q::Checked | state;
+ setSymbol( aspect, checkMark );
+ setSymbol( aspect | Q::Error, checkMark );
+ }
+ }
+
+ // === colors
setColor( Q::Text, m_pal.onBackground ); // not mentioned in the specs
- // States
+ for ( auto state1 : { Q::Hovered, Q::Focused, Q::Pressed } )
+ {
+ const auto opacity = m_pal.stateOpacity( state1 );
- // 2. Disabled
+ for ( auto state2 : { A::NoState, Q::Checked } )
+ {
+ const auto aspect = Q::Box | state1 | state2;
- setBoxBorderColors( Q::Box | Q::Disabled, m_pal.onSurface38 );
- setBoxShape( Q::Box | Q::Disabled, 2_dp );
+ const auto rgb = ( state2 == Q::Checked ) ? m_pal.primary : m_pal.onSurface;
+ setShadowColor( aspect, stateLayerColor( rgb, opacity ) );
- setGradient( Q::Box | Q::Disabled | Q::Checked, m_pal.onSurface38 );
- setGradient( Q::Box | Q::Disabled | Q::Checked | Q::Error, m_pal.onSurface38 );
+ setShadowColor( aspect | Q::Error, stateLayerColor( m_pal.error, opacity ) );
+ }
+ }
- setGraphicRole( Q::Indicator | Q::Disabled | Q::Checked, QskMaterial3Skin::GraphicRoleSurface );
+ for ( auto state1 : { A::NoState, Q::Disabled, Q::Hovered, Q::Focused, Q::Pressed } )
+ {
+ for ( auto state2 : { A::NoState, Q::Checked } )
+ {
+ const auto aspect = Q::Box | state1 | state2;
- // 3. Hovered
+ QRgb rgb, rgbError;
- setGradient( Q::Halo | Q::Hovered | Q::Checked, m_pal.primary8 );
- setGradient( Q::Halo | Q::Hovered, m_pal.onSurface8 );
- setGradient( Q::Halo | Q::Error | Q::Hovered, m_pal.error8 );
- setGradient( Q::Halo | Q::Error | Q::Hovered | Q::Checked, m_pal.error8 );
+ if ( state1 == A::NoState )
+ {
+ rgb = ( state2 == Q::Checked )
+ ? m_pal.primary : m_pal.onSurfaceVariant;
- // 4. Focused
+ rgbError = m_pal.error;
+ }
+ else if ( state1 == Q::Disabled )
+ {
+ rgb = rgbError = m_pal.onSurface38;
+ }
+ else
+ {
+ rgb = ( state2 == Q::Checked )
+ ? m_pal.primary : m_pal.onSurfaceVariant;
- setGradient( Q::Halo | Q::Focused | Q::Checked, m_pal.primary12 );
- setGradient( Q::Halo | Q::Focused, m_pal.onSurface12 );
- setGradient( Q::Halo | Q::Error | Q::Focused, m_pal.error12 );
- setGradient( Q::Halo | Q::Error | Q::Focused | Q::Checked, m_pal.error12 );
+ rgbError = m_pal.error;
+ }
- // 5. Pressed
+ setBoxBorderColors( aspect, rgb );
+ setBoxBorderColors( aspect | Q::Error, rgbError );
- setGradient( Q::Halo | Q::Pressed, m_pal.primary12 );
- setGradient( Q::Halo | Q::Pressed | Q::Checked, m_pal.primary12 );
- setGradient( Q::Halo | Q::Hovered | Q::Pressed, m_pal.primary12 );
- setGradient( Q::Halo | Q::Error | Q::Pressed, m_pal.error12 );
- setGradient( Q::Halo | Q::Error | Q::Pressed | Q::Checked, m_pal.error12 );
+ if ( state2 == Q::Checked )
+ {
+ setGradient( aspect, rgb );
+ setGradient( aspect | Q::Error, rgbError );
+ }
+ }
+ }
}
void Editor::setupComboBox()
@@ -480,9 +491,8 @@ void Editor::setupRadioBox()
setSpacing( Q::Button, 10_dp );
setStrutSize( Q::CheckIndicatorPanel, 20_dp, 20_dp );
- setStrutSize( Q::Halo, 40_dp, 40_dp );
- for ( auto subControl : { Q::CheckIndicatorPanel, Q::CheckIndicator, Q::Halo } )
+ for ( auto subControl : { Q::CheckIndicatorPanel, Q::CheckIndicator } )
setBoxShape( subControl, 100, Qt::RelativeSize ); // circular
setBoxBorderMetrics( Q::CheckIndicatorPanel, 2_dp );
@@ -494,11 +504,22 @@ void Editor::setupRadioBox()
setColor( Q::Text, m_pal.onBackground );
setColor( Q::Text | Q::Disabled, m_pal.onSurface38 );
- setColor( Q::Halo, stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) );
- setColor( Q::Halo | Q::Selected,
- stateLayerColor( m_pal.primary, m_pal.focusOpacity ) );
+ for ( const auto state1 : { Q::Hovered, Q::Focused, Q::Pressed } )
+ {
+ for ( const auto state2 : { A::NoState, Q::Selected } )
+ {
+ const auto aspect = Q::CheckIndicatorPanel | state1 | state2;
- setColor( Q::CheckIndicator, Qt::transparent);
+ setShadowMetrics( aspect, { 10_dp, 0 } );
+
+ auto rgb = ( state2 == Q::Selected ) ? m_pal.primary : m_pal.onSurface;
+ rgb = stateLayerColor( rgb, m_pal.stateOpacity( state1 ) );
+
+ setShadowColor( aspect, rgb );
+ }
+ }
+
+ setColor( Q::CheckIndicator, Qt::transparent );
setColor( Q::CheckIndicator | Q::Selected, m_pal.primary );
setColor( Q::CheckIndicator | Q::Selected | Q::Disabled, m_pal.onSurface38 );
@@ -509,7 +530,7 @@ void Editor::setupRadioBox()
setBoxBorderColors(
Q::CheckIndicatorPanel | Q::Disabled | Q::Selected, m_pal.onSurface38 );
- setAnimation( Q::Halo | A::Metric | A::Position, qskDuration );
+ setAnimation( Q::CheckIndicator | A::Metric | A::Position, qskDuration );
}
void Editor::setupFocusIndicator()
@@ -1001,6 +1022,8 @@ void Editor::setupSwitchButton()
using A = QskAspect;
using Q = QskSwitchButton;
+ const QskStateCombination allStates ( QskStateCombination::CombinationNoState, QskAspect::AllStates );
+
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
const QSizeF strutSize( 52_dp, 32_dp );
setStrutSize( Q::Groove | A::Horizontal, strutSize );
@@ -1013,30 +1036,66 @@ void Editor::setupSwitchButton()
setGradient( Q::Groove | Q::Checked | Q::Disabled, m_pal.onSurface12 );
setBoxBorderMetrics( Q::Groove, 2_dp );
setBoxBorderColors( Q::Groove, m_pal.outline );
+ setBoxBorderColors( Q::Groove | Q::Disabled, m_pal.onSurface12 );
- setBoxBorderMetrics( Q::Groove | Q::Checked, 0 );
+ setBoxBorderMetrics( Q::Groove | Q::Checked, 0, allStates );
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
- setStrutSize( Q::Handle, 16_dp, 16_dp );
- setStrutSize( Q::Handle | Q::Checked, 24_dp, 24_dp,
- { QskStateCombination::CombinationNoState, Q::Disabled } );
+ setStrutSize( Q::Handle, { 30_dp, 30_dp } );
+ setMargin( Q::Handle, 7_dp );
+ setShadowMetrics( Q::Handle, { 17_dp, 0 } );
+ setShadowColor( Q::Handle, QskRgb::Transparent );
setGradient( Q::Handle, m_pal.outline );
- setGradient( Q::Handle | Q::Checked, m_pal.primaryContainer );
+ setGradient( Q::Handle | Q::Checked, m_pal.onPrimary );
+
+ setStrutSize( Q::Icon, { 16_dp, 16_dp } );
+ setPadding( Q::Icon, 6_dp );
+ setSymbol( Q::Icon, symbol( "switchbutton-unchecked" ) );
+ setSymbol( Q::Icon | Q::Checked, symbol( "switchbutton-checked" ), allStates );
+ setGraphicRole( Q::Icon, QskMaterial3Skin::GraphicRoleSurfaceContainerHighest );
+ setGraphicRole( Q::Icon | Q::Checked, QskMaterial3Skin::GraphicRoleOnPrimaryContainer, allStates );
+ setGraphicRole( Q::Icon | Q::Disabled, QskMaterial3Skin::GraphicRoleSurfaceContainerHighest38, allStates );
+ setGraphicRole( Q::Icon | Q::Checked | Q::Disabled, QskMaterial3Skin::GraphicRoleOnSurface38, allStates );
+
+ for ( auto state1 : { A::NoState, Q::Hovered, Q::Focused, Q::Pressed } )
+ {
+ const qreal opacity = m_pal.stateOpacity( state1 );
+
+ for ( const auto state2 : { A::NoState, Q::Checked } )
+ {
+ const auto aspect = Q::Handle | state1 | state2;
+
+ if ( state1 == Q::Pressed )
+ {
+ setShadowMetrics( aspect, { 10_dp, 0 } );
+ setMargin( aspect, 0.0 );
+ }
+ else if ( state2 == Q::Checked )
+ {
+ setShadowMetrics( aspect, { 13_dp, 0 } );
+ setMargin( aspect, 3_dp );
+ }
+
+ if ( state1 )
+ {
+ if ( state2 == Q::Checked )
+ {
+ setGradient( aspect, m_pal.primaryContainer );
+ setShadowColor( aspect, stateLayerColor( m_pal.primary, opacity ) );
+ }
+ else
+ {
+ setGradient( aspect, m_pal.onSurfaceVariant );
+ setShadowColor( aspect, stateLayerColor( m_pal.onSurface, opacity ) );
+ }
+ }
+ }
+ }
setGradient( Q::Handle | Q::Disabled, m_pal.onSurface38 );
setGradient( Q::Handle | Q::Disabled | Q::Checked, m_pal.surface );
- // just to keep the strut size the same at all times:
- setStrutSize( Q::Halo, 40_dp, 40_dp );
- setGradient( Q::Halo, Qt::transparent );
-
- setStrutSize( Q::Halo | Q::Hovered, 40_dp, 40_dp );
- setBoxShape( Q::Halo, 100, Qt::RelativeSize );
- setGradient( Q::Halo | Q::Hovered, stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) );
- setGradient( Q::Halo | Q::Hovered | Q::Checked,
- stateLayerColor( m_pal.primary, m_pal.focusOpacity ) );
-
setBoxBorderColors( Q::Handle, m_pal.outline );
setBoxBorderColors( Q::Handle | Q::Checked, m_pal.primary );
@@ -1044,8 +1103,8 @@ void Editor::setupSwitchButton()
{
auto aspect = Q::Handle | state;
- setPosition( aspect, 0.15 );
- setPosition( aspect | Q::Checked, 0.85 );
+ setPosition( aspect, 0.10 );
+ setPosition( aspect | Q::Checked, 0.9 );
}
setAnimation( Q::Handle | A::Color, qskDuration );
@@ -1477,6 +1536,8 @@ QskMaterial3Theme::QskMaterial3Theme( QskSkin::ColorScheme colorScheme,
surfaceVariant12 = QskRgb::toTransparentF( surfaceVariant, 0.12 );
+ surfaceContainerHighest38 = QskRgb::toTransparentF( surfaceContainerHighest, 0.38 );
+
elevation0 = QskShadowMetrics( 0, 0 );
elevation1 = QskShadowMetrics( -2, 9, { 0, 1 } );
elevation2 = QskShadowMetrics( -2, 8, { 0, 2 } );
@@ -1485,6 +1546,20 @@ QskMaterial3Theme::QskMaterial3Theme( QskSkin::ColorScheme colorScheme,
shapeExtraSmallTop = QskBoxShapeMetrics( 4_dp, 4_dp, 0, 0 );
}
+qreal QskMaterial3Theme::stateOpacity( int state ) const
+{
+ if ( state == QskControl::Hovered )
+ return hoverOpacity;
+
+ if ( state == QskControl::Focused )
+ return focusOpacity;
+
+ if ( state == QskControl::Disabled )
+ return disabledOpacity;
+
+ return state ? pressedOpacity : 0.0;
+}
+
QskMaterial3Skin::QskMaterial3Skin( QObject* parent )
: Inherited( parent )
{
@@ -1568,6 +1643,7 @@ void QskMaterial3Skin::setGraphicColor( GraphicRole role, QRgb rgb )
void QskMaterial3Skin::setupGraphicFilters( const QskMaterial3Theme& theme )
{
setGraphicColor( GraphicRoleOnPrimary, theme.onPrimary );
+ setGraphicColor( GraphicRoleOnPrimaryContainer, theme.onPrimaryContainer );
setGraphicColor( GraphicRoleOnSecondaryContainer, theme.onSecondaryContainer );
setGraphicColor( GraphicRoleOnError, theme.onError );
setGraphicColor( GraphicRoleOnSurface, theme.onSurface );
@@ -1575,6 +1651,8 @@ void QskMaterial3Skin::setupGraphicFilters( const QskMaterial3Theme& theme )
setGraphicColor( GraphicRoleOnSurfaceVariant, theme.onSurfaceVariant );
setGraphicColor( GraphicRolePrimary, theme.primary );
setGraphicColor( GraphicRoleSurface, theme.surface );
+ setGraphicColor( GraphicRoleSurfaceContainerHighest, theme.surfaceContainerHighest );
+ setGraphicColor( GraphicRoleSurfaceContainerHighest38, theme.surfaceContainerHighest38 );
}
void QskMaterial3Skin::initHints()
diff --git a/designsystems/material3/QskMaterial3Skin.h b/designsystems/material3/QskMaterial3Skin.h
index 06d8fd22..309fd3cd 100644
--- a/designsystems/material3/QskMaterial3Skin.h
+++ b/designsystems/material3/QskMaterial3Skin.h
@@ -80,6 +80,7 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Theme
QRgb outlineVariant;
QRgb surfaceContainerHighest;
+ QRgb surfaceContainerHighest38;
QRgb inverseSurface;
QRgb inverseOnSurface;
@@ -97,6 +98,9 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Theme
const qreal focusOpacity = 0.12;
const qreal pressedOpacity = 0.12;
const qreal draggedOpacity = 0.16;
+ const qreal disabledOpacity = 0.38;
+
+ qreal stateOpacity( int state ) const;
QskBoxShapeMetrics shapeExtraSmallTop;
};
@@ -112,12 +116,15 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin
{
GraphicRoleOnError,
GraphicRoleOnPrimary,
+ GraphicRoleOnPrimaryContainer,
GraphicRoleOnSecondaryContainer,
GraphicRoleOnSurface,
GraphicRoleOnSurface38,
GraphicRoleOnSurfaceVariant,
GraphicRolePrimary,
GraphicRoleSurface,
+ GraphicRoleSurfaceContainerHighest,
+ GraphicRoleSurfaceContainerHighest38,
};
QskMaterial3Skin( QObject* parent = nullptr );
diff --git a/designsystems/material3/icons/qvg/switchbutton-checked.qvg b/designsystems/material3/icons/qvg/switchbutton-checked.qvg
new file mode 100644
index 00000000..c927ddb3
Binary files /dev/null and b/designsystems/material3/icons/qvg/switchbutton-checked.qvg differ
diff --git a/designsystems/material3/icons/qvg/switchbutton-unchecked.qvg b/designsystems/material3/icons/qvg/switchbutton-unchecked.qvg
new file mode 100644
index 00000000..b33f61e4
Binary files /dev/null and b/designsystems/material3/icons/qvg/switchbutton-unchecked.qvg differ
diff --git a/designsystems/material3/icons/switchbutton-checked.svg b/designsystems/material3/icons/switchbutton-checked.svg
new file mode 100644
index 00000000..7f4d9275
--- /dev/null
+++ b/designsystems/material3/icons/switchbutton-checked.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/designsystems/material3/icons/switchbutton-unchecked.svg b/designsystems/material3/icons/switchbutton-unchecked.svg
new file mode 100644
index 00000000..a9e2ee7e
--- /dev/null
+++ b/designsystems/material3/icons/switchbutton-unchecked.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/examples/gallery/button/ButtonPage.cpp b/examples/gallery/button/ButtonPage.cpp
index 7ba35788..bc00b4d1 100644
--- a/examples/gallery/button/ButtonPage.cpp
+++ b/examples/gallery/button/ButtonPage.cpp
@@ -133,13 +133,24 @@ namespace
SwitchButtonBox( QQuickItem* parent = nullptr )
: ButtonBox( Qt::Horizontal, parent )
{
+ setDimension( 6 );
+ setSpacing( 20 );
+ setDefaultAlignment( Qt::AlignCenter );
+
for ( auto orientation : { Qt::Vertical, Qt::Horizontal } )
{
- (void) new QskSwitchButton( orientation, this );
+ using Q = QskSwitchButton;
- auto button = new QskSwitchButton( orientation, this );
- button->setInverted( true );
- button->setChecked( true );
+ for( auto iconMode : { Q::NoIcon, Q::ShowIconWhenSelected, Q::ShowIconAlways } )
+ {
+ auto button = new QskSwitchButton( orientation, this );
+ button->setIconMode( iconMode );
+
+ auto invertedButton = new QskSwitchButton( orientation, this );
+ invertedButton->setInverted( true );
+ invertedButton->setChecked( true );
+ invertedButton->setIconMode( iconMode );
+ }
}
}
};
diff --git a/src/common/QskBoxBorderMetrics.cpp b/src/common/QskBoxBorderMetrics.cpp
index 1272f87e..fe010464 100644
--- a/src/common/QskBoxBorderMetrics.cpp
+++ b/src/common/QskBoxBorderMetrics.cpp
@@ -29,7 +29,7 @@ static void qskRegisterBoxBorderMetrics()
Q_CONSTRUCTOR_FUNCTION( qskRegisterBoxBorderMetrics )
-static inline qreal qskAbsoluted( qreal length, qreal percentage )
+static inline qreal qskToAbsolute( qreal length, qreal percentage )
{
// 100% means -> 0.5 of length
percentage = qBound( 0.0, percentage, 100.0 );
@@ -69,10 +69,10 @@ QskBoxBorderMetrics QskBoxBorderMetrics::toAbsolute( const QSizeF& size ) const
}
else
{
- w.setLeft( qskAbsoluted( size.width(), w.left() ) );
- w.setTop( qskAbsoluted( size.height(), w.top() ) );
- w.setRight( qskAbsoluted( size.width(), w.right() ) );
- w.setBottom( qskAbsoluted( size.height(), w.bottom() ) );
+ w.setLeft( qskToAbsolute( size.width(), w.left() ) );
+ w.setTop( qskToAbsolute( size.height(), w.top() ) );
+ w.setRight( qskToAbsolute( size.width(), w.right() ) );
+ w.setBottom( qskToAbsolute( size.height(), w.bottom() ) );
}
absoluted.m_sizeMode = Qt::AbsoluteSize;
diff --git a/src/common/QskShadowMetrics.cpp b/src/common/QskShadowMetrics.cpp
index b5331dc9..9f8e3878 100644
--- a/src/common/QskShadowMetrics.cpp
+++ b/src/common/QskShadowMetrics.cpp
@@ -95,7 +95,8 @@ QskHashValue QskShadowMetrics::hash( QskHashValue seed ) const noexcept
hash = qHash( m_offset.y(), seed );
hash = qHash( m_spreadRadius, hash );
hash = qHash( m_blurRadius, hash );
- hash = qHash( static_cast< int >( m_sizeMode ), hash );
+ hash = qHash( m_sizeMode, hash );
+ hash = qHash( m_shapeMode, hash );
return hash;
}
diff --git a/src/common/QskShadowMetrics.h b/src/common/QskShadowMetrics.h
index bb85a117..711e4cef 100644
--- a/src/common/QskShadowMetrics.h
+++ b/src/common/QskShadowMetrics.h
@@ -23,8 +23,18 @@ class QSK_EXPORT QskShadowMetrics
Q_PROPERTY( qreal blurRadius READ blurRadius WRITE setBlurRadius )
Q_PROPERTY( Qt::SizeMode sizeMode READ sizeMode WRITE setSizeMode )
+ Q_PROPERTY( ShapeMode shapeMode READ shapeMode WRITE setShapeMode )
public:
+ enum ShapeMode
+ {
+ Aligned = 0, // The shape is related to some external definition
+
+ Ellipse,
+ Rectangle
+ };
+ Q_ENUM( ShapeMode )
+
constexpr QskShadowMetrics( const QPointF& offset = QPointF() ) noexcept;
constexpr QskShadowMetrics( qreal spreadRadius, qreal blurRadius ) noexcept;
@@ -56,6 +66,9 @@ class QSK_EXPORT QskShadowMetrics
void setSizeMode( Qt::SizeMode ) noexcept;
constexpr Qt::SizeMode sizeMode() const noexcept;
+ void setShapeMode( ShapeMode ) noexcept;
+ constexpr ShapeMode shapeMode() const noexcept;
+
QskShadowMetrics interpolated(
const QskShadowMetrics&, qreal value ) const noexcept;
@@ -72,7 +85,8 @@ class QSK_EXPORT QskShadowMetrics
QPointF m_offset;
qreal m_spreadRadius = 0.0;
qreal m_blurRadius = 0.0;
- Qt::SizeMode m_sizeMode = Qt::AbsoluteSize;
+ quint8 m_sizeMode = Qt::AbsoluteSize;
+ quint8 m_shapeMode = QskShadowMetrics::Aligned;
};
inline constexpr QskShadowMetrics::QskShadowMetrics( const QPointF& offset ) noexcept
@@ -101,6 +115,7 @@ inline constexpr bool QskShadowMetrics::operator==(
const QskShadowMetrics& other ) const noexcept
{
return ( m_sizeMode == other.m_sizeMode )
+ && ( m_shapeMode == other.m_shapeMode )
&& ( m_offset == other.m_offset )
&& ( m_spreadRadius == other.m_spreadRadius )
&& ( m_blurRadius == other.m_blurRadius )
@@ -145,7 +160,17 @@ inline void QskShadowMetrics::setSizeMode( Qt::SizeMode sizeMode ) noexcept
inline constexpr Qt::SizeMode QskShadowMetrics::sizeMode() const noexcept
{
- return m_sizeMode;
+ return static_cast< Qt::SizeMode >( m_sizeMode );
+}
+
+inline void QskShadowMetrics::setShapeMode( ShapeMode shapeMode ) noexcept
+{
+ m_shapeMode = shapeMode;
+}
+
+inline constexpr QskShadowMetrics::ShapeMode QskShadowMetrics::shapeMode() const noexcept
+{
+ return static_cast< ShapeMode >( m_shapeMode );
}
inline void QskShadowMetrics::setOffsetX( qreal dx ) noexcept
diff --git a/src/controls/QskCheckBox.cpp b/src/controls/QskCheckBox.cpp
index c457c9fc..3d42f02b 100644
--- a/src/controls/QskCheckBox.cpp
+++ b/src/controls/QskCheckBox.cpp
@@ -9,7 +9,6 @@ QSK_SUBCONTROL( QskCheckBox, Panel )
QSK_SUBCONTROL( QskCheckBox, Box )
QSK_SUBCONTROL( QskCheckBox, Indicator )
QSK_SUBCONTROL( QskCheckBox, Text )
-QSK_SUBCONTROL( QskCheckBox, Halo )
QSK_SYSTEM_STATE( QskCheckBox, Error, QskAspect::FirstSystemState << 1 )
diff --git a/src/controls/QskCheckBox.h b/src/controls/QskCheckBox.h
index 2096ae75..6b5877b7 100644
--- a/src/controls/QskCheckBox.h
+++ b/src/controls/QskCheckBox.h
@@ -17,7 +17,7 @@ class QSK_EXPORT QskCheckBox : public QskAbstractButton
using Inherited = QskAbstractButton;
public:
- QSK_SUBCONTROLS( Panel, Box, Indicator, Text, Halo )
+ QSK_SUBCONTROLS( Panel, Box, Indicator, Text )
QSK_STATES( Error )
QskCheckBox( QQuickItem* parent = nullptr );
diff --git a/src/controls/QskCheckBoxSkinlet.cpp b/src/controls/QskCheckBoxSkinlet.cpp
index 47193a8e..e279b97b 100644
--- a/src/controls/QskCheckBoxSkinlet.cpp
+++ b/src/controls/QskCheckBoxSkinlet.cpp
@@ -11,7 +11,7 @@
QskCheckBoxSkinlet::QskCheckBoxSkinlet( QskSkin* skin )
: QskSkinlet( skin )
{
- setNodeRoles( { BoxRole, IndicatorRole, TextRole, HaloRole } );
+ setNodeRoles( { BoxRole, IndicatorRole, TextRole } );
}
QskCheckBoxSkinlet::~QskCheckBoxSkinlet()
@@ -40,9 +40,6 @@ QRectF QskCheckBoxSkinlet::subControlRect( const QskSkinnable* skinnable,
if ( subControl == Q::Text )
return textRect( checkBox, contentsRect );
- if ( subControl == Q::Halo )
- return haloRect( checkBox, contentsRect );
-
return contentsRect;
}
@@ -83,21 +80,6 @@ QRectF QskCheckBoxSkinlet::boxRect(
return r;
}
-QRectF QskCheckBoxSkinlet::haloRect(
- const QskCheckBox* checkBox, const QRectF& rect ) const
-{
- const auto haloSize = checkBox->strutSizeHint( QskCheckBox::Halo );
- const auto boxSize = checkBox->strutSizeHint( QskCheckBox::Box );
-
- const auto w = ( haloSize.width() - boxSize.width() ) / 2;
- const auto h = ( haloSize.height() - boxSize.height() ) / 2;
-
- auto r = boxRect( checkBox, rect );
- r = r.marginsAdded( { w, h, w, h } );
-
- return r;
-}
-
QSGNode* QskCheckBoxSkinlet::updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
{
@@ -118,9 +100,6 @@ QSGNode* QskCheckBoxSkinlet::updateSubNode(
case TextRole:
return updateTextNode( checkBox, node );
-
- case HaloRole:
- return updateBoxNode( checkBox, node, Q::Halo );
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
diff --git a/src/controls/QskCheckBoxSkinlet.h b/src/controls/QskCheckBoxSkinlet.h
index 60f46be5..c13b528c 100644
--- a/src/controls/QskCheckBoxSkinlet.h
+++ b/src/controls/QskCheckBoxSkinlet.h
@@ -23,7 +23,6 @@ class QSK_EXPORT QskCheckBoxSkinlet : public QskSkinlet
BoxRole,
IndicatorRole,
TextRole,
- HaloRole,
RoleCount
};
@@ -44,7 +43,6 @@ class QSK_EXPORT QskCheckBoxSkinlet : public QskSkinlet
private:
QRectF textRect( const QskCheckBox*, const QRectF& ) const;
QRectF boxRect( const QskCheckBox*, const QRectF& ) const;
- QRectF haloRect( const QskCheckBox*, const QRectF& ) const;
QSGNode* updateTextNode( const QskCheckBox*, QSGNode* ) const;
};
diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp
index e7076222..7cde8fc5 100644
--- a/src/controls/QskRadioBox.cpp
+++ b/src/controls/QskRadioBox.cpp
@@ -13,7 +13,6 @@ QSK_SUBCONTROL( QskRadioBox, Button )
QSK_SUBCONTROL( QskRadioBox, CheckIndicatorPanel )
QSK_SUBCONTROL( QskRadioBox, CheckIndicator )
QSK_SUBCONTROL( QskRadioBox, Text )
-QSK_SUBCONTROL( QskRadioBox, Halo )
QSK_STATE( QskRadioBox, Selected, QskAspect::FirstUserState << 1 )
QSK_STATE( QskRadioBox, Pressed, QskAspect::FirstUserState << 2 )
@@ -38,7 +37,7 @@ QskRadioBox::QskRadioBox( QQuickItem* parent )
setFocusPolicy( Qt::StrongFocus );
setAcceptedMouseButtons( Qt::LeftButton );
- setPositionHint( Halo, -1 );
+ setPositionHint( CheckIndicator, -1 );
setAcceptHoverEvents( true );
}
@@ -182,7 +181,7 @@ void QskRadioBox::keyPressEvent( QKeyEvent* event )
{
setFocusedIndex( nextTabIndex );
- const auto aspect = Halo | QskAspect::Metric | QskAspect::Position;
+ const auto aspect = CheckIndicator | QskAspect::Metric | QskAspect::Position;
const auto hint = animationHint( aspect | skinStates() );
if( hint.isValid() )
@@ -277,7 +276,7 @@ void QskRadioBox::setHoveredIndex( int index )
return;
m_data->hoveredIndex = index;
- setPositionHint( Halo | Hovered, index );
+ setPositionHint( CheckIndicator | Hovered, index );
update();
}
@@ -288,7 +287,7 @@ void QskRadioBox::setFocusedIndex( int index )
return;
m_data->focusedIndex = index;
- setPositionHint( Halo, index );
+ setPositionHint( CheckIndicator, index );
update();
diff --git a/src/controls/QskRadioBox.h b/src/controls/QskRadioBox.h
index de65c457..92bb615e 100644
--- a/src/controls/QskRadioBox.h
+++ b/src/controls/QskRadioBox.h
@@ -22,7 +22,7 @@ class QSK_EXPORT QskRadioBox : public QskControl
using Inherited = QskControl;
public:
- QSK_SUBCONTROLS( Panel, Button, CheckIndicatorPanel, CheckIndicator, Text, Halo )
+ QSK_SUBCONTROLS( Panel, Button, CheckIndicatorPanel, CheckIndicator, Text )
QSK_STATES( Selected, Pressed )
QskRadioBox( QQuickItem* parent = nullptr );
diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp
index 98201ea5..5bbc5987 100644
--- a/src/controls/QskRadioBoxSkinlet.cpp
+++ b/src/controls/QskRadioBoxSkinlet.cpp
@@ -40,7 +40,7 @@ namespace
QskRadioBoxSkinlet::QskRadioBoxSkinlet( QskSkin* )
{
setNodeRoles( { PanelRole, ButtonRole, CheckPanelRole,
- CheckIndicatorRole, TextRole, HaloRole } );
+ CheckIndicatorRole, TextRole } );
}
QskRadioBoxSkinlet::~QskRadioBoxSkinlet()
@@ -50,12 +50,8 @@ QskRadioBoxSkinlet::~QskRadioBoxSkinlet()
QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable,
const QRectF& contentsRect, QskAspect::Subcontrol subcontrol ) const
{
- using Q = QskRadioBox;
-
- auto radioBox = static_cast< const QskRadioBox* >( skinnable );
-
- if( subcontrol == Q::Halo )
- return haloRect( radioBox, contentsRect );
+ Q_UNUSED( skinnable );
+ Q_UNUSED( subcontrol );
return contentsRect;
}
@@ -81,9 +77,6 @@ QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable,
case TextRole:
return updateSeriesNode( skinnable, Q::Text, node );
-
- case HaloRole:
- return updateBoxNode( skinnable, node, Q::Halo );
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
@@ -96,29 +89,6 @@ int QskRadioBoxSkinlet::sampleCount(
return radioBox->options().count();
}
-QRectF QskRadioBoxSkinlet::haloRect(
- const QskRadioBox* radioBox, const QRectF& rect ) const
-{
- using Q = QskRadioBox;
-
- const auto index = qFloor( radioBox->positionHint( Q::Halo ) );
- if( index < 0 )
- return QRectF();
-
- QRectF r;
- r.setSize( radioBox->strutSizeHint( Q::Halo ) );
-
- if ( !r.isEmpty() )
- {
- const auto checkBoxRect = sampleRect(
- radioBox, rect, Q::CheckIndicatorPanel, index );
-
- r.moveCenter( checkBoxRect.center() );
- }
-
- return r;
-}
-
QRectF QskRadioBoxSkinlet::buttonRect(
const QskRadioBox* radioBox, const QRectF& rect, int index ) const
{
@@ -219,12 +189,12 @@ QskAspect::States QskRadioBoxSkinlet::sampleStates(
states |= Q::Pressed;
#if 1
- if( radioBox->positionHint( Q::Halo | Q::Hovered ) == index )
+ if( radioBox->positionHint( Q::CheckIndicator | Q::Hovered ) == index )
states |= Q::Hovered;
else
states &= ~Q::Hovered;
- if( radioBox->positionHint( Q::Halo ) == index )
+ if( radioBox->positionHint( Q::CheckIndicator ) == index )
states |= Q::Focused;
else
states &= ~Q::Focused;
diff --git a/src/controls/QskRadioBoxSkinlet.h b/src/controls/QskRadioBoxSkinlet.h
index 73db392b..7a3f17b4 100644
--- a/src/controls/QskRadioBoxSkinlet.h
+++ b/src/controls/QskRadioBoxSkinlet.h
@@ -24,7 +24,6 @@ class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet
CheckPanelRole,
CheckIndicatorRole,
TextRole,
- HaloRole,
RoleCount
};
@@ -57,8 +56,6 @@ class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet
QRectF textRect( const QskRadioBox*, const QRectF&, int ) const;
QRectF checkPanelRect( const QskRadioBox*, const QRectF&, int index ) const;
QRectF buttonRect( const QskRadioBox*, const QRectF&, int index ) const;
-
- QRectF haloRect( const QskRadioBox*, const QRectF& ) const;
};
#endif
diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp
index e9a90d9e..7befc837 100644
--- a/src/controls/QskSkinlet.cpp
+++ b/src/controls/QskSkinlet.cpp
@@ -141,6 +141,12 @@ static inline QSGNode* qskUpdateGraphicNode(
return graphicNode;
}
+static inline bool qskIsShadowVisible( const QskShadowMetrics& shadowMetrics,
+ const QColor& shadowColor )
+{
+ return !shadowMetrics.isNull() && shadowColor.isValid() && ( shadowColor.alpha() > 0 );
+}
+
static inline bool qskIsBoxVisible( const QskBoxBorderMetrics& borderMetrics,
const QskBoxBorderColors& borderColors, const QskGradient& gradient )
{
@@ -199,23 +205,17 @@ static inline QSGNode* qskUpdateBoxNode(
if ( rect.isEmpty() )
return nullptr;
- const auto size = rect.size();
-
- const auto absoluteMetrics = borderMetrics.toAbsolute( size );
-
- if ( qskIsBoxVisible( absoluteMetrics, borderColors, gradient ) )
+ if ( !qskIsBoxVisible( borderMetrics, borderColors, gradient )
+ && !qskIsShadowVisible( shadowMetrics, shadowColor ) )
{
- const auto absoluteShape = shape.toAbsolute( size );
- const auto absoluteShadowMetrics = shadowMetrics.toAbsolute( size );
-
- auto boxNode = QskSGNode::ensureNode< QskBoxNode >( node );
- boxNode->updateNode( rect, absoluteShape, absoluteMetrics,
- borderColors, gradient, absoluteShadowMetrics, shadowColor );
-
- return boxNode;
+ return nullptr;
}
- return nullptr;
+ auto boxNode = QskSGNode::ensureNode< QskBoxNode >( node );
+ boxNode->updateNode( rect, shape, borderMetrics,
+ borderColors, gradient, shadowMetrics, shadowColor );
+
+ return boxNode;
}
static inline QSGNode* qskUpdateArcNode(
diff --git a/src/controls/QskSwitchButton.cpp b/src/controls/QskSwitchButton.cpp
index 1703a5e2..9d6f3b93 100644
--- a/src/controls/QskSwitchButton.cpp
+++ b/src/controls/QskSwitchButton.cpp
@@ -5,9 +5,9 @@
#include "QskSwitchButton.h"
-QSK_SUBCONTROL( QskSwitchButton, Handle )
QSK_SUBCONTROL( QskSwitchButton, Groove )
-QSK_SUBCONTROL( QskSwitchButton, Halo )
+QSK_SUBCONTROL( QskSwitchButton, Handle )
+QSK_SUBCONTROL( QskSwitchButton, Icon )
struct QskSwitchButton::PrivateData
{
@@ -18,6 +18,7 @@ struct QskSwitchButton::PrivateData
bool inverted = false;
Qt::Orientation orientation;
+ IconMode iconMode = NoIcon;
};
QskSwitchButton::QskSwitchButton( QQuickItem* parent )
@@ -77,6 +78,20 @@ void QskSwitchButton::setInverted( bool on )
}
}
+QskSwitchButton::IconMode QskSwitchButton::iconMode() const
+{
+ return m_data->iconMode;
+}
+
+void QskSwitchButton::setIconMode( IconMode iconMode )
+{
+ if( iconMode != m_data->iconMode )
+ {
+ m_data->iconMode = iconMode;
+ Q_EMIT iconModeChanged( m_data->iconMode );
+ }
+}
+
QskAspect::Variation QskSwitchButton::effectiveVariation() const
{
return static_cast< QskAspect::Variation >( m_data->orientation );
diff --git a/src/controls/QskSwitchButton.h b/src/controls/QskSwitchButton.h
index 955e8f25..e12cc65f 100644
--- a/src/controls/QskSwitchButton.h
+++ b/src/controls/QskSwitchButton.h
@@ -21,8 +21,19 @@ class QSK_EXPORT QskSwitchButton : public QskAbstractButton
Q_PROPERTY( bool inverted READ isInverted
WRITE setInverted NOTIFY invertedChanged FINAL )
+ Q_PROPERTY( IconMode iconMode READ iconMode
+ WRITE setIconMode NOTIFY iconModeChanged FINAL )
+
public:
- QSK_SUBCONTROLS( Groove, Handle, Halo )
+ QSK_SUBCONTROLS( Groove, Handle, Icon )
+
+ enum IconMode
+ {
+ NoIcon,
+ ShowIconWhenSelected,
+ ShowIconAlways
+ };
+ Q_ENUM( IconMode )
QskSwitchButton( Qt::Orientation, QQuickItem* parent = nullptr );
QskSwitchButton( QQuickItem* parent = nullptr );
@@ -32,16 +43,20 @@ class QSK_EXPORT QskSwitchButton : public QskAbstractButton
bool isCheckable() const override final;
Qt::Orientation orientation() const;
- void setOrientation(Qt::Orientation);
+ void setOrientation( Qt::Orientation );
bool isInverted() const;
void setInverted( bool );
+ IconMode iconMode() const;
+ void setIconMode( IconMode );
+
QskAspect::Variation effectiveVariation() const override;
Q_SIGNALS:
void orientationChanged( Qt::Orientation );
void invertedChanged( bool );
+ void iconModeChanged( IconMode );
private:
struct PrivateData;
diff --git a/src/controls/QskSwitchButtonSkinlet.cpp b/src/controls/QskSwitchButtonSkinlet.cpp
index 906e589d..471c39d0 100644
--- a/src/controls/QskSwitchButtonSkinlet.cpp
+++ b/src/controls/QskSwitchButtonSkinlet.cpp
@@ -6,6 +6,8 @@
#include "QskSwitchButtonSkinlet.h"
#include "QskSwitchButton.h"
+using Q = QskSwitchButton;
+
static inline qreal qskEffectivePosition( const QskSwitchButton* switchButton )
{
auto pos = switchButton->positionHint( QskSwitchButton::Handle );
@@ -23,10 +25,23 @@ static inline qreal qskEffectivePosition( const QskSwitchButton* switchButton )
return pos;
}
+static QSizeF qskIconSize( const QskSwitchButton* button )
+{
+ if( button->iconMode() == Q::NoIcon
+ || ( button->iconMode() == Q::ShowIconWhenSelected && !button->isChecked() ) )
+ {
+ return {};
+ }
+ else
+ {
+ return button->strutSizeHint( Q::Icon );
+ }
+}
+
QskSwitchButtonSkinlet::QskSwitchButtonSkinlet( QskSkin* skin )
: Inherited( skin )
{
- setNodeRoles( { GrooveRole, HandleRole, HaloRole } );
+ setNodeRoles( { GrooveRole, HandleRole, IconRole } );
}
QskSwitchButtonSkinlet::~QskSwitchButtonSkinlet()
@@ -36,23 +51,22 @@ QskSwitchButtonSkinlet::~QskSwitchButtonSkinlet()
QRectF QskSwitchButtonSkinlet::subControlRect( const QskSkinnable* skinnable,
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
{
- using Q = QskSwitchButton;
-
- if ( subControl == Q::Handle )
- {
- return handleRect( skinnable, contentsRect );
- }
+ const auto button = static_cast< const Q* >( skinnable );
if ( subControl == Q::Groove )
{
- return grooveRect( skinnable, contentsRect );
+ return grooveRect( button, contentsRect );
}
- if ( subControl == Q::Halo )
+ if ( subControl == Q::Handle )
{
- return haloRect( skinnable, contentsRect );
+ return handleRect( button, contentsRect );
}
+ if ( subControl == Q::Icon )
+ {
+ return iconRect( button, contentsRect );
+ }
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
@@ -65,10 +79,8 @@ QSizeF QskSwitchButtonSkinlet::sizeHint( const QskSkinnable* skinnable,
const auto grooveHint = skinnable->strutSizeHint( QskSwitchButton::Groove );
const auto handleHint = skinnable->strutSizeHint( QskSwitchButton::Handle );
- const auto haloHint = skinnable->strutSizeHint( QskSwitchButton::Halo );
auto hint = grooveHint;
- hint = hint.expandedTo( haloHint );
hint = hint.expandedTo( handleHint );
return hint;
@@ -77,16 +89,14 @@ QSizeF QskSwitchButtonSkinlet::sizeHint( const QskSkinnable* skinnable,
QSGNode* QskSwitchButtonSkinlet::updateSubNode( const QskSkinnable* skinnable,
quint8 nodeRole, QSGNode* node ) const
{
- using Q = QskSwitchButton;
-
switch ( nodeRole )
{
- case HaloRole:
- return updateBoxNode( skinnable, node, Q::Halo );
-
case HandleRole:
return updateBoxNode( skinnable, node, Q::Handle );
+ case IconRole:
+ return updateSymbolNode( skinnable, node, Q::Icon );
+
case GrooveRole:
return updateBoxNode( skinnable, node, Q::Groove );
}
@@ -95,19 +105,15 @@ QSGNode* QskSwitchButtonSkinlet::updateSubNode( const QskSkinnable* skinnable,
}
QRectF QskSwitchButtonSkinlet::grooveRect(
- const QskSkinnable* skinnable, const QRectF& contentsRect ) const
+ const QskSwitchButton* button, const QRectF& contentsRect ) const
{
- using Q = QskSwitchButton;
+ auto size = button->strutSizeHint( Q::Groove );
- const auto switchButton = static_cast< const Q* >( skinnable );
-
- auto size = skinnable->strutSizeHint( Q::Groove );
-
- if ( switchButton->orientation() == Qt::Vertical )
+ if ( button->orientation() == Qt::Vertical )
{
if ( size.height() < 0.0 )
{
- const auto handleSize = skinnable->strutSizeHint( Q::Handle );
+ const auto handleSize = button->strutSizeHint( Q::Handle );
size.setHeight( 2 * handleSize.height() );
}
}
@@ -115,7 +121,7 @@ QRectF QskSwitchButtonSkinlet::grooveRect(
{
if ( size.width() < 0.0 )
{
- const auto handleSize = skinnable->strutSizeHint( Q::Handle );
+ const auto handleSize = button->strutSizeHint( Q::Handle );
size.setWidth( 2 * handleSize.width() );
}
}
@@ -130,19 +136,16 @@ QRectF QskSwitchButtonSkinlet::grooveRect(
}
QRectF QskSwitchButtonSkinlet::handleRect(
- const QskSkinnable* skinnable, const QRectF& contentsRect ) const
+ const QskSwitchButton* button, const QRectF& contentsRect ) const
{
- using Q = QskSwitchButton;
+ const auto grooveRect = subControlRect( button, contentsRect, Q::Groove );
+ const auto pos = qskEffectivePosition( button );
- const auto switchButton = static_cast< const Q* >( skinnable );
-
- const auto grooveRect = subControlRect( skinnable, contentsRect, Q::Groove );
- const auto pos = qskEffectivePosition( switchButton );
- const auto size = skinnable->strutSizeHint( Q::Handle );
+ auto size = button->strutSizeHint( Q::Handle );
qreal cx, cy;
- if( switchButton->orientation() == Qt::Vertical )
+ if( button->orientation() == Qt::Vertical )
{
const qreal y0 = grooveRect.y() + 0.5 * size.height();
const qreal h = grooveRect.height() - size.height();
@@ -159,6 +162,20 @@ QRectF QskSwitchButtonSkinlet::handleRect(
cy = grooveRect.y() + 0.5 * grooveRect.height();
}
+ auto iconSize = qskIconSize( button );
+
+ if( !iconSize.isNull() )
+ {
+ auto padding = button->paddingHint( Q::Icon );
+
+ // need to compensate for the margins,
+ // which might differ between states:
+ auto margins = button->marginHint( Q::Handle );
+
+ iconSize = iconSize.grownBy( padding ).grownBy( margins );
+ size = size.expandedTo( iconSize );
+ }
+
QRectF r;
r.setSize( size );
r.moveCenter( QPointF( cx, cy ) );
@@ -166,42 +183,14 @@ QRectF QskSwitchButtonSkinlet::handleRect(
return r;
}
-QRectF QskSwitchButtonSkinlet::haloRect(
- const QskSkinnable* skinnable, const QRectF& contentsRect ) const
+QRectF QskSwitchButtonSkinlet::iconRect( const QskSwitchButton* button, const QRectF& contentsRect ) const
{
- using Q = QskSwitchButton;
-
- const auto switchButton = static_cast< const Q* >( skinnable );
-
- const auto grooveRect = subControlRect( skinnable, contentsRect, Q::Groove );
- const auto pos = qskEffectivePosition( switchButton );
- const auto sizeHandle = skinnable->strutSizeHint( Q::Handle );
- const auto sizeHalo = skinnable->strutSizeHint( Q::Halo );
-
- qreal cx, cy;
-
- if( switchButton->orientation() == Qt::Vertical )
- {
- const qreal y0 = grooveRect.y() + 0.5 * sizeHandle.height();
- const qreal h = grooveRect.height() - sizeHandle.height();
-
- cx = grooveRect.x() + 0.5 * grooveRect.width();
- cy = y0 + pos * h;
- }
- else
- {
- const qreal x0 = grooveRect.x() + 0.5 * sizeHandle.width();
- const qreal w = grooveRect.width() - sizeHandle.width();
-
- cx = x0 + pos * w;
- cy = grooveRect.y() + 0.5 * grooveRect.height();
- }
-
- QRectF r;
- r.setSize( sizeHalo );
- r.moveCenter( QPointF( cx, cy ) );
-
- return r;
+ QRectF rect;
+ rect.setSize( qskIconSize( button ) );
+ const auto hr = handleRect( button, contentsRect );
+ rect.moveCenter( hr.center() );
+ return rect;
}
+
#include "moc_QskSwitchButtonSkinlet.cpp"
diff --git a/src/controls/QskSwitchButtonSkinlet.h b/src/controls/QskSwitchButtonSkinlet.h
index 4b8fa368..1f7e614b 100644
--- a/src/controls/QskSwitchButtonSkinlet.h
+++ b/src/controls/QskSwitchButtonSkinlet.h
@@ -8,6 +8,8 @@
#include "QskSkinlet.h"
+class QskSwitchButton;
+
class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet
{
Q_GADGET
@@ -19,7 +21,7 @@ class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet
{
GrooveRole,
HandleRole,
- HaloRole,
+ IconRole,
RoleCount
};
@@ -38,9 +40,9 @@ class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet
quint8 nodeRole, QSGNode* ) const override;
private:
- QRectF grooveRect( const QskSkinnable*, const QRectF& ) const;
- QRectF handleRect( const QskSkinnable*, const QRectF& ) const;
- QRectF haloRect( const QskSkinnable*, const QRectF& ) const;
+ QRectF grooveRect( const QskSwitchButton*, const QRectF& ) const;
+ QRectF handleRect( const QskSwitchButton*, const QRectF& ) const;
+ QRectF iconRect( const QskSwitchButton*, const QRectF& ) const;
};
#endif
diff --git a/src/nodes/QskBoxNode.cpp b/src/nodes/QskBoxNode.cpp
index 1e7363fd..22cc78c5 100644
--- a/src/nodes/QskBoxNode.cpp
+++ b/src/nodes/QskBoxNode.cpp
@@ -13,6 +13,7 @@
#include "QskShadowMetrics.h"
#include "QskBoxBorderMetrics.h"
#include "QskBoxBorderColors.h"
+#include "QskBoxShapeMetrics.h"
#include "QskRgbValue.h"
namespace
@@ -20,6 +21,7 @@ namespace
enum Role
{
ShadowRole,
+ ShadowFillRole,
BoxRole,
FillRole
};
@@ -27,14 +29,15 @@ namespace
static void qskUpdateChildren( QSGNode* parentNode, quint8 role, QSGNode* node )
{
- static const QVector< quint8 > roles = { ShadowRole, BoxRole, FillRole };
+ static const QVector< quint8 > roles =
+ { ShadowRole, ShadowFillRole, BoxRole, FillRole };
auto oldNode = QskSGNode::findChildNode( parentNode, role );
QskSGNode::replaceChildNode( roles, role, parentNode, oldNode, node );
}
template< typename Node >
-inline Node* qskNode( QSGNode* parentNode, quint8 role )
+static inline Node* qskNode( QSGNode* parentNode, quint8 role )
{
using namespace QskSGNode;
@@ -58,13 +61,14 @@ QskBoxNode::~QskBoxNode()
}
void QskBoxNode::updateNode( const QRectF& rect,
- const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics,
+ const QskBoxShapeMetrics& shapeMetrics, const QskBoxBorderMetrics& borderMetrics,
const QskBoxBorderColors& borderColors, const QskGradient& gradient,
const QskShadowMetrics& shadowMetrics, const QColor& shadowColor )
{
using namespace QskSGNode;
QskBoxShadowNode* shadowNode = nullptr;
+ QskBoxRectangleNode* shadowFillNode = nullptr;
QskBoxRectangleNode* rectNode = nullptr;
QskBoxRectangleNode* fillNode = nullptr;
@@ -72,15 +76,38 @@ void QskBoxNode::updateNode( const QRectF& rect,
{
const auto hasFilling = gradient.isVisible();
const auto hasBorder = !borderMetrics.isNull() && borderColors.isVisible();
-
- const auto hasShadow = hasFilling && !shadowMetrics.isNull()
- && QskRgb::isVisible( shadowColor );
+ const auto hasShadow = !shadowMetrics.isNull() && QskRgb::isVisible( shadowColor );
if ( hasShadow )
{
- shadowNode = qskNode< QskBoxShadowNode >( this, ShadowRole );
- shadowNode->setShadowData( shadowMetrics.shadowRect( rect ),
- shape, shadowMetrics.blurRadius(), shadowColor );
+ const auto shadow = shadowMetrics.toAbsolute( rect.size() );
+ const auto shadowRect = shadow.shadowRect( rect );
+
+ auto shadowShape = shapeMetrics;
+
+ switch( static_cast< int >( shadow.shapeMode() ) )
+ {
+ case QskShadowMetrics::Ellipse:
+ shadowShape.setRadius( 100.0, Qt::RelativeSize );
+ break;
+
+ case QskShadowMetrics::Rectangle:
+ shadowShape.setRadius( 0.0, Qt::AbsoluteSize );
+ break;
+ }
+
+ if ( shadow.blurRadius() <= 0.0 )
+ {
+ // QskBoxRectangleNode allows scene graph batching
+ shadowFillNode = qskNode< QskBoxRectangleNode >( this, ShadowFillRole );
+ shadowFillNode->updateFilling( shadowRect, shadowShape, shadowColor );
+ }
+ else
+ {
+ shadowNode = qskNode< QskBoxShadowNode >( this, ShadowRole );
+ shadowNode->setShadowData( shadowRect,
+ shadowShape, shadow.blurRadius(), shadowColor );
+ }
}
if ( hasBorder || hasFilling )
@@ -95,20 +122,22 @@ void QskBoxNode::updateNode( const QRectF& rect,
if ( !doCombine )
fillNode = qskNode< QskBoxRectangleNode >( this, FillRole );
}
-
+
if ( fillNode )
{
- rectNode->updateBorder( rect, shape, borderMetrics, borderColors );
- fillNode->updateFilling( rect, shape, borderMetrics, gradient );
+ rectNode->updateBorder( rect, shapeMetrics, borderMetrics, borderColors );
+ fillNode->updateFilling( rect, shapeMetrics, borderMetrics, gradient );
}
else
{
- rectNode->updateBox( rect, shape, borderMetrics, borderColors, gradient );
+ rectNode->updateBox( rect, shapeMetrics,
+ borderMetrics, borderColors, gradient );
}
}
}
qskUpdateChildren( this, ShadowRole, shadowNode );
+ qskUpdateChildren( this, ShadowFillRole, shadowFillNode );
qskUpdateChildren( this, BoxRole, rectNode );
qskUpdateChildren( this, FillRole, fillNode );
}
diff --git a/src/nodes/QskBoxRectangleNode.cpp b/src/nodes/QskBoxRectangleNode.cpp
index 461e558b..62fcb8c5 100644
--- a/src/nodes/QskBoxRectangleNode.cpp
+++ b/src/nodes/QskBoxRectangleNode.cpp
@@ -12,7 +12,7 @@
#include "QskGradientDirection.h"
#include "QskFillNodePrivate.h"
-static inline bool qskHasBorder(
+static inline bool qskHasBorder(
const QskBoxBorderMetrics& metrics, const QskBoxBorderColors& colors )
{
return !metrics.isNull() && colors.isVisible();
@@ -142,7 +142,7 @@ void QskBoxRectangleNode::updateFilling( const QRectF& rect,
}
void QskBoxRectangleNode::updateBorder( const QRectF& rect,
- const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics,
+ const QskBoxShapeMetrics& shapeMetrics, const QskBoxBorderMetrics& borderMetrics,
const QskBoxBorderColors& borderColors )
{
Q_D( QskBoxRectangleNode );
@@ -153,6 +153,8 @@ void QskBoxRectangleNode::updateBorder( const QRectF& rect,
return;
}
+ const auto shape = shapeMetrics.toAbsolute( rect.size() );
+
const bool coloredGeometry = hasHint( PreferColoredGeometry )
|| !borderColors.isMonochrome();
@@ -189,7 +191,7 @@ void QskBoxRectangleNode::updateBorder( const QRectF& rect,
}
void QskBoxRectangleNode::updateBox( const QRectF& rect,
- const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics,
+ const QskBoxShapeMetrics& shapeMetrics, const QskBoxBorderMetrics& borderMetrics,
const QskBoxBorderColors& borderColors, const QskGradient& gradient )
{
Q_D( QskBoxRectangleNode );
@@ -205,6 +207,8 @@ void QskBoxRectangleNode::updateBox( const QRectF& rect,
if ( hasFill && hasBorder )
{
+ const auto shape = shapeMetrics.toAbsolute( rect.size() );
+
const bool isDirty = d->updateMetrics( rect, shape, borderMetrics )
|| d->updateColors( borderColors, gradient ) || !isGeometryColored();
@@ -232,11 +236,11 @@ void QskBoxRectangleNode::updateBox( const QRectF& rect,
}
else if ( hasFill )
{
- updateFilling( rect, shape, borderMetrics, gradient );
+ updateFilling( rect, shapeMetrics, borderMetrics, gradient );
}
else if ( hasBorder )
{
- updateBorder( rect, shape, borderMetrics, borderColors );
+ updateBorder( rect, shapeMetrics, borderMetrics, borderColors );
}
else
{
diff --git a/src/nodes/QskBoxShadowNode.cpp b/src/nodes/QskBoxShadowNode.cpp
index cfb0099e..50b42229 100644
--- a/src/nodes/QskBoxShadowNode.cpp
+++ b/src/nodes/QskBoxShadowNode.cpp
@@ -269,7 +269,7 @@ QskBoxShadowNode::~QskBoxShadowNode()
}
void QskBoxShadowNode::setShadowData(
- const QRectF& rect, const QskBoxShapeMetrics& shape,
+ const QRectF& rect, const QskBoxShapeMetrics& shapeMetrics,
qreal blurRadius, const QColor& color )
{
Q_D( QskBoxShadowNode );
@@ -299,6 +299,8 @@ void QskBoxShadowNode::setShadowData(
}
{
+ const auto shape = shapeMetrics.toAbsolute( rect.size() );
+
const float t = std::min( d->rect.width(), d->rect.height() );
const float r1 = shape.radius( Qt::BottomRightCorner ).width();