diff --git a/examples/gallery/button/ButtonPage.cpp b/examples/gallery/button/ButtonPage.cpp index abb5727f..e0a177fd 100644 --- a/examples/gallery/button/ButtonPage.cpp +++ b/examples/gallery/button/ButtonPage.cpp @@ -84,7 +84,7 @@ namespace { public: CheckButtonBox( QQuickItem* parent = nullptr ) - : QskLinearBox( Qt::Horizontal, parent ) + : QskLinearBox( Qt::Horizontal, 2, parent ) { setSpacing( 40 ); setExtraSpacingAt( Qt::LeftEdge | Qt::RightEdge | Qt::BottomEdge ); @@ -94,6 +94,9 @@ namespace auto button2 = new QskCheckBox( "Options 2", this ); button2->setLayoutMirroring( true ); + + auto button3 = new QskCheckBox( "Error", this ); + button3->setSkinStateFlag( QskCheckBox::Error ); } }; } diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 0a53e444..b260ce30 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -221,37 +222,75 @@ void Editor::setupControl() void Editor::setupCheckBox() { + // skin hints are ordered according to + // https://m3.material.io/components/checkbox/specs + using Q = QskCheckBox; setSpacing( Q::Panel, 40_dp ); - setStrutSize( Q::Box, 24_dp, 24_dp ); - - setPadding( Q::Box, 4_dp ); + setStrutSize( Q::Box, 18_dp, 18_dp ); setBoxShape( Q::Box, 2_dp ); - setBoxBorderMetrics( Q::Box, 2_dp ); - setBoxBorderColors( Q::Box, m_pal.onBackground ); + + 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 ); - setGradient( Q::Box, m_pal.background ); - setGradient( Q::Box | Q::Checked, m_pal.primary ); - setGradient( Q::Box | Q::Disabled, m_pal.surfaceVariant12 ); - setGradient( Q::Box | Q::Checked | Q::Disabled, m_pal.onSurface12 ); + setPadding( Q::Box, 3_dp ); // "icon size" - setColor( Q::Indicator, m_pal.background ); - setColor( Q::Indicator | Q::Checked, m_pal.onPrimary ); - setColor( Q::Indicator | Q::Checked | Q::Disabled, m_pal.onSurface38 ); + setGraphicRole( Q::Indicator, QskMaterial3Skin::GraphicRoleOnPrimary ); - setColor( Q::Text, m_pal.onBackground ); - setTextOptions( Q::Text, Qt::ElideMiddle, QskTextOptions::NoWrap ); + setBoxBorderColors( Q::Box | Q::Error, m_pal.error ); - setStrutSize( Q::Ripple, { 53.33_dp, 53.33_dp } ); + setGradient( Q::Box | Q::Checked | Q::Error, m_pal.error ); + + setGraphicRole( Q::Indicator | Q::Error, QskMaterial3Skin::GraphicRoleOnError ); + + setStrutSize( Q::Ripple, { 40_dp, 40_dp } ); setBoxShape( Q::Ripple, 100, Qt::RelativeSize ); setGradient( Q::Ripple, Qt::transparent ); + + setColor( Q::Text, m_pal.onBackground ); // not mentioned in the specs + + // States + + // 2. Disabled + + setBoxBorderColors( Q::Box | Q::Disabled, m_pal.onSurface38 ); + setBoxShape( Q::Box | Q::Disabled, 2_dp ); + + setGradient( Q::Box | Q::Disabled | Q::Checked, m_pal.onSurface38 ); + setGradient( Q::Box | Q::Disabled | Q::Checked | Q::Error, m_pal.onSurface38 ); + + setGraphicRole( Q::Indicator | Q::Disabled | Q::Checked, QskMaterial3Skin::GraphicRoleSurface ); + + // 3. Hovered + setGradient( Q::Ripple | Q::Hovered | Q::Checked, m_pal.primary8 ); setGradient( Q::Ripple | Q::Hovered, m_pal.onSurface8 ); - setGradient( Q::Ripple | Q::Hovered | Q::Pressed, m_pal.primary12 ); + setGradient( Q::Ripple | Q::Error | Q::Hovered, m_pal.error8 ); + setGradient( Q::Ripple | Q::Error | Q::Hovered | Q::Checked, m_pal.error8 ); + + // 4. Focused + + setGradient( Q::Ripple | Q::Focused | Q::Checked, m_pal.primary12 ); + setGradient( Q::Ripple | Q::Focused, m_pal.onSurface12 ); + setGradient( Q::Ripple | Q::Error | Q::Focused, m_pal.error12 ); + setGradient( Q::Ripple | Q::Error | Q::Focused | Q::Checked, m_pal.error12 ); + + // 5. Pressed + setGradient( Q::Ripple | Q::Pressed, m_pal.primary12 ); + setGradient( Q::Ripple | Q::Pressed | Q::Checked, m_pal.primary12 ); + setGradient( Q::Ripple | Q::Hovered | Q::Pressed, m_pal.primary12 ); + setGradient( Q::Ripple | Q::Error | Q::Pressed, m_pal.error12 ); + setGradient( Q::Ripple | Q::Error | Q::Pressed | Q::Checked, m_pal.error12 ); } void Editor::setupBox() @@ -917,8 +956,8 @@ QskMaterial3Theme::QskMaterial3Theme( Lightness lightness ) { } -QskMaterial3Theme::QskMaterial3Theme(Lightness lightness, - std::array palettes ) +QskMaterial3Theme::QskMaterial3Theme( Lightness lightness, + std::array< QskHctColor, NumPaletteTypes > palettes ) : m_palettes( palettes ) { if ( lightness == Light ) @@ -991,6 +1030,9 @@ QskMaterial3Theme::QskMaterial3Theme(Lightness lightness, primary8 = QskRgb::toTransparentF( primary, 0.08 ); primary12 = QskRgb::toTransparentF( primary, 0.12 ); + error8 = QskRgb::toTransparentF( error, 0.08 ); + error12 = QskRgb::toTransparentF( error, 0.12 ); + surface1 = flattenedColor( primary, background, 0.05 ); surface2 = flattenedColor( primary, background, 0.08 ); surface3 = flattenedColor( primary, background, 0.11 ); @@ -1027,6 +1069,7 @@ QskMaterial3Skin::QskMaterial3Skin( const QskMaterial3Theme& palette, QObject* p addGraphicProvider( {}, new QskMaterial3GraphicProvder() ); setupFonts(); + setupGraphicFilters( palette ); Editor editor( &hintTable(), palette ); editor.setup(); @@ -1064,4 +1107,19 @@ void QskMaterial3Skin::setupFonts() setFont( M3LabelLarge, createFont( "Roboto Medium", 20_dp, 14_dp, 0.1, QFont::Medium ) ); } +void QskMaterial3Skin::setupGraphicFilters( const QskMaterial3Theme& palette ) +{ + QskColorFilter onPrimaryFilter; + onPrimaryFilter.addColorSubstitution( Qt::white, palette.onPrimary ); + setGraphicFilter( GraphicRoleOnPrimary, onPrimaryFilter ); + + QskColorFilter onErrorFilter; + onErrorFilter.addColorSubstitution( Qt::white, palette.onError ); + setGraphicFilter( GraphicRoleOnError, onErrorFilter ); + + QskColorFilter surfaceFilter; + surfaceFilter.addColorSubstitution( Qt::white, palette.surface ); + setGraphicFilter( GraphicRoleSurface, surfaceFilter ); +} + #include "moc_QskMaterial3Skin.cpp" diff --git a/skins/material3/QskMaterial3Skin.h b/skins/material3/QskMaterial3Skin.h index abe37236..a0299853 100644 --- a/skins/material3/QskMaterial3Skin.h +++ b/skins/material3/QskMaterial3Skin.h @@ -57,6 +57,8 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Theme QRgb onTertiaryContainer; QRgb error; + QRgb error8; + QRgb error12; QRgb onError; QRgb errorContainer; QRgb onErrorContainer; @@ -120,6 +122,13 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin virtual QskGraphic symbol( int symbolType ) const override; + enum GraphicRole + { + GraphicRoleOnError, + GraphicRoleOnPrimary, + GraphicRoleSurface, + }; + enum FontRole { M3BodyMedium = QskSkin::HugeFont + 1, @@ -130,6 +139,7 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin private: void setupFonts(); + void setupGraphicFilters( const QskMaterial3Theme& palette ); }; #endif diff --git a/src/controls/QskCheckBox.cpp b/src/controls/QskCheckBox.cpp index 72b2960a..286a2ea4 100644 --- a/src/controls/QskCheckBox.cpp +++ b/src/controls/QskCheckBox.cpp @@ -11,6 +11,8 @@ QSK_SUBCONTROL( QskCheckBox, Indicator ) QSK_SUBCONTROL( QskCheckBox, Text ) QSK_SUBCONTROL( QskCheckBox, Ripple ) +QSK_SYSTEM_STATE( QskCheckBox, Error, QskAspect::FirstSystemState << 1 ) + class QskCheckBox::PrivateData { public: diff --git a/src/controls/QskCheckBox.h b/src/controls/QskCheckBox.h index cac63fe1..bc010749 100644 --- a/src/controls/QskCheckBox.h +++ b/src/controls/QskCheckBox.h @@ -18,6 +18,7 @@ class QSK_EXPORT QskCheckBox : public QskAbstractButton public: QSK_SUBCONTROLS( Panel, Box, Indicator, Text, Ripple ) + QSK_STATES( Error ) QskCheckBox( QQuickItem* parent = nullptr ); QskCheckBox( const QString&, QQuickItem* parent = nullptr ); diff --git a/src/controls/QskCheckBoxSkinlet.cpp b/src/controls/QskCheckBoxSkinlet.cpp index 0ab03219..d7fa07f4 100644 --- a/src/controls/QskCheckBoxSkinlet.cpp +++ b/src/controls/QskCheckBoxSkinlet.cpp @@ -147,19 +147,6 @@ QSGNode* QskCheckBoxSkinlet::updateIndicatorNode( } auto graphic = checkBox->effectiveSkin()->symbol( symbol ); - -#if 1 - /* - Our default skins do not have the concept of colorRoles - implemented. Until then we do the recoloring manually here - */ - QskColorFilter filter; - filter.addColorSubstitution( Qt::black, - checkBox->color( QskCheckBox::Indicator ).rgba() ); - - graphic = QskGraphic::fromGraphic( graphic, filter ); -#endif - return updateGraphicNode( checkBox, node, graphic, QskCheckBox::Indicator ); }