From 1d57d87332d6869999f525d198136ff0622187ec Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 3 Feb 2023 11:53:43 +0100 Subject: [PATCH] Gallery: Add buttons with different emphasis and style for M3 --- examples/gallery/button/ButtonPage.cpp | 63 ++++++++++++ skins/material3/QskMaterial3Skin.cpp | 132 ++++++++++++++++++++++--- skins/material3/QskMaterial3Skin.h | 18 +++- src/controls/QskPushButton.cpp | 10 +- src/controls/QskPushButton.h | 10 +- 5 files changed, 204 insertions(+), 29 deletions(-) diff --git a/examples/gallery/button/ButtonPage.cpp b/examples/gallery/button/ButtonPage.cpp index 540d4f8d..d9bd2898 100644 --- a/examples/gallery/button/ButtonPage.cpp +++ b/examples/gallery/button/ButtonPage.cpp @@ -50,6 +50,69 @@ namespace button->setText( texts[ index ] ); } } + + addSpacer( 0 ); + addSpacer( 0 ); + + auto* outlinedButton1 = new QskPushButton( this ); + outlinedButton1->setEmphasis( QskPushButton::LowEmphasis ); + outlinedButton1->setGraphicSource( "plus" ); + outlinedButton1->setText( "Outlined" ); + + auto* outlinedButton2 = new QskPushButton( this ); + outlinedButton2->setEmphasis( QskPushButton::LowEmphasis ); + outlinedButton2->setText( "Outlined" ); + + auto* outlinedButton3 = new QskPushButton( this ); + outlinedButton3->setEmphasis( QskPushButton::LowEmphasis ); + outlinedButton3->setGraphicSource( "plus" ); + + addSpacer( 0 ); + + auto* textButton1 = new QskPushButton( this ); + textButton1->setEmphasis( QskPushButton::VeryLowEmphasis ); + textButton1->setGraphicSource( "plus" ); + textButton1->setText( "Text" ); + + auto* textButton2 = new QskPushButton( this ); + textButton2->setEmphasis( QskPushButton::VeryLowEmphasis ); + textButton2->setText( "Text" ); + + auto* textButton3 = new QskPushButton( this ); + textButton3->setEmphasis( QskPushButton::VeryLowEmphasis ); + textButton3->setGraphicSource( "plus" ); + + addSpacer( 0 ); + + auto* elevatedButton1 = new QskPushButton( this ); + elevatedButton1->setEmphasis( QskPushButton::HighEmphasis ); + elevatedButton1->setGraphicSource( "plus" ); + elevatedButton1->setText( "Elevated" ); + + auto* elevatedButton2 = new QskPushButton( this ); + elevatedButton2->setEmphasis( QskPushButton::HighEmphasis ); + elevatedButton2->setText( "Elevated" ); + + auto* elevatedButton3 = new QskPushButton( this ); + elevatedButton3->setEmphasis( QskPushButton::HighEmphasis ); + elevatedButton3->setGraphicSource( "plus" ); + + addSpacer( 0 ); + + auto* tonalButton1 = new QskPushButton( this ); + tonalButton1->setEmphasis( QskPushButton::VeryHighEmphasis ); + tonalButton1->setGraphicSource( "plus" ); + tonalButton1->setText( "Tonal" ); + + auto* tonalButton2 = new QskPushButton( this ); + tonalButton2->setEmphasis( QskPushButton::VeryHighEmphasis ); + tonalButton2->setText( "Tonal" ); + + auto* tonalButton3 = new QskPushButton( this ); + tonalButton3->setEmphasis( QskPushButton::VeryHighEmphasis ); + tonalButton3->setGraphicSource( "plus" ); + + addSpacer( 0 ); } }; diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 6265185f..11181f65 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -367,7 +367,7 @@ void Editor::setupMenu() const auto panel = flattenedColor( m_pal.primary, m_pal.background, 0.08 ); setGradient( Q::Panel, panel ); - setShadowMetrics( Q::Panel, m_pal.elevationLight2 ); + setShadowMetrics( Q::Panel, m_pal.elevation2 ); setShadowColor( Q::Panel, m_pal.shadow ); setMetric( Q::Separator | A::Size, 1_dp ); @@ -605,8 +605,8 @@ void Editor::setupPageIndicator() void Editor::setupPushButton() { - using A = QskAspect; using Q = QskPushButton; + using M3 = QskMaterial3Skin; setFlagHint( Q::Panel | QskAspect::Direction, Qsk::LeftToRight ); setStrutSize( Q::Panel, -1, 40_dp ); @@ -621,18 +621,47 @@ void Editor::setupPushButton() setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge ); setPadding( Q::Text, 0 ); + setShadowColor( Q::Panel, m_pal.shadow ); + + setAnimation( Q::Ripple | QskAspect::Color, qskDuration ); + + + // elevated buttons: + + setGradient( Q::Panel | M3::Elevated, m_pal.surface1 ); + setShadowMetrics( Q::Panel | M3::Elevated, m_pal.elevation1 ); + setColor( Q::Text | M3::Elevated, m_pal.primary ); + setGraphicRole( Q::Graphic | M3::Elevated, QskMaterial3Skin::GraphicRolePrimary ); + setGradient( Q::Ripple | M3::Elevated, stateLayerColor( m_pal.primary, m_pal.pressedOpacity ) ); + + setGradient( Q::Panel | M3::Elevated | Q::Disabled, m_pal.onSurface12 ); + setShadowMetrics( Q::Panel | M3::Elevated | Q::Disabled, m_pal.elevation0 ); + setColor( Q::Text | M3::Elevated | Q::Disabled, m_pal.onSurface38 ); + setGraphicRole( Q::Graphic | M3::Elevated | Q::Disabled, QskMaterial3Skin::GraphicRoleOnSurface38 ); + + const auto elevatedHoverColor = flattenedColor( m_pal.primary, m_pal.surface, m_pal.hoverOpacity ); + setGradient( Q::Panel | M3::Elevated | Q::Hovered, elevatedHoverColor ); + setShadowMetrics( Q::Panel | M3::Elevated | Q::Hovered, m_pal.elevation2 ); + + const auto elevatedPressedColor = flattenedColor( m_pal.primary, m_pal.surface, m_pal.pressedOpacity ); + setGradient( Q::Panel | M3::Elevated | Q::Focused, elevatedPressedColor ); + setShadowMetrics( Q::Panel | M3::Elevated | Q::Focused, m_pal.elevation1 ); + + setGradient( Q::Panel | M3::Elevated | Q::Pressed, elevatedPressedColor ); + setShadowMetrics( Q::Panel | M3::Elevated | Q::Pressed, m_pal.elevation1 ); + + // normal buttons (i.e. Filled): setGradient( Q::Panel, m_pal.primary ); setGradient( Q::Panel | Q::Disabled, m_pal.onSurface12 ); - const auto hoverColor = flattenedColor( m_pal.onPrimary, m_pal.primary, 0.08 ); + const auto hoverColor = flattenedColor( m_pal.onPrimary, m_pal.primary, m_pal.hoverOpacity ); setGradient( Q::Panel | Q::Hovered, hoverColor ); - setShadowMetrics( Q::Panel | Q::Hovered, m_pal.elevationLight1 ); - setShadowColor( Q::Panel | Q::Hovered, m_pal.shadow ); + setShadowMetrics( Q::Panel | Q::Hovered, m_pal.elevation1 ); - const auto focusColor = flattenedColor( m_pal.onPrimary, m_pal.primary, 0.12 ); + const auto focusColor = flattenedColor( m_pal.onPrimary, m_pal.primary, m_pal.focusOpacity ); setGradient( Q::Panel | Q::Focused, focusColor ); setGradient( Q::Panel | Q::Pressed, focusColor ); @@ -644,10 +673,75 @@ void Editor::setupPushButton() setTextOptions( Q::Text, Qt::ElideMiddle, QskTextOptions::NoWrap ); - setAnimation( Q::Panel | A::Color, qskDuration ); - setAnimation( Q::Panel | A::Metric, qskDuration ); - setAnimation( Q::Ripple | A::Color, qskDuration ); - setAnimation( Q::Text | A::Color, qskDuration ); + + // filled tonal buttons: + + setGradient( Q::Panel | M3::Tonal, m_pal.secondaryContainer ); + setShadowMetrics( Q::Panel | M3::Tonal, m_pal.elevation0 ); + setColor( Q::Text | M3::Tonal, m_pal.onSecondaryContainer ); + setGraphicRole( Q::Graphic | M3::Tonal, QskMaterial3Skin::GraphicRoleOnSecondaryContainer ); + setGradient( Q::Ripple | M3::Tonal, stateLayerColor( m_pal.onSecondaryContainer, m_pal.pressedOpacity ) ); + + setGradient( Q::Panel | M3::Tonal | Q::Disabled, m_pal.onSurface12 ); + setColor( Q::Text | M3::Tonal | Q::Disabled, m_pal.onSurface38 ); + setGraphicRole( Q::Graphic | M3::Tonal | Q::Disabled, QskMaterial3Skin::GraphicRoleOnSurface38 ); + + const auto tonalHoverColor = flattenedColor( m_pal.onSecondaryContainer, m_pal.secondaryContainer, m_pal.hoverOpacity ); + setGradient( Q::Panel | M3::Tonal | Q::Hovered, tonalHoverColor ); + setShadowMetrics( Q::Panel | M3::Tonal | Q::Hovered, m_pal.elevation1 ); + + const auto tonalPressedColor = flattenedColor( m_pal.onSecondaryContainer, m_pal.secondaryContainer, m_pal.pressedOpacity ); + setGradient( Q::Panel | M3::Tonal | Q::Focused, tonalPressedColor ); + setShadowMetrics( Q::Panel | M3::Tonal | Q::Focused, m_pal.elevation0 ); + + setGradient( Q::Panel | M3::Tonal | Q::Pressed, tonalPressedColor ); + setShadowMetrics( Q::Panel | M3::Tonal | Q::Pressed, m_pal.elevation0 ); + + + // outlined buttons: + + setGradient( Q::Panel | M3::Outlined, m_pal.surface ); + setBoxBorderColors( Q::Panel | M3::Outlined, m_pal.outline ); + setBoxBorderMetrics( Q::Panel | M3::Outlined, 1_dp ); + setShadowMetrics( Q::Panel | M3::Outlined, m_pal.elevation0 ); + setColor( Q::Text | M3::Outlined, m_pal.primary ); + setGraphicRole( Q::Graphic | M3::Outlined, QskMaterial3Skin::GraphicRolePrimary ); + setGradient( Q::Ripple | M3::Outlined, stateLayerColor( m_pal.outline, m_pal.pressedOpacity ) ); + + setBoxBorderColors( Q::Panel | M3::Outlined | Q::Disabled, m_pal.onSurface12 ); + setColor( Q::Text | M3::Outlined | Q::Disabled, m_pal.onSurface38 ); + setGraphicRole( Q::Graphic | M3::Outlined | Q::Disabled, QskMaterial3Skin::GraphicRoleOnSurface38 ); + + setBoxBorderColors( Q::Panel | M3::Outlined | Q::Hovered, m_pal.outline ); + setGradient( Q::Panel | M3::Outlined | Q::Hovered, m_pal.primary8 ); + + setGradient( Q::Panel | M3::Outlined | Q::Focused, m_pal.primary12 ); + + setGradient( Q::Panel | M3::Outlined | Q::Pressed, m_pal.primary12 ); + + + // text buttons: + + // trick: Use a transparent color that changes between skins; + // otherwise we would fall back to the filled button color + // during skin change: + QColor c( m_pal.background ); + c.setAlpha( 255 ); + setGradient( Q::Panel | M3::Text, c ); + + setShadowMetrics( Q::Panel | M3::Text, m_pal.elevation0 ); + setColor( Q::Text | M3::Text, m_pal.primary ); + setGraphicRole( Q::Graphic | M3::Text, QskMaterial3Skin::GraphicRolePrimary ); + setGradient( Q::Ripple | M3::Text, stateLayerColor( m_pal.primary, m_pal.pressedOpacity ) ); + + setColor( Q::Text | M3::Text | Q::Disabled, m_pal.onSurface38 ); + setGraphicRole( Q::Graphic | M3::Text | Q::Disabled, QskMaterial3Skin::GraphicRoleOnSurface38 ); + + setGradient( Q::Panel | M3::Text | Q::Hovered, m_pal.primary8 ); + + setGradient( Q::Panel | M3::Text | Q::Focused, m_pal.primary12 ); + + setGradient( Q::Panel | M3::Text | Q::Pressed, m_pal.primary12 ); } void Editor::setupDialogButtonBox() @@ -747,7 +841,7 @@ void Editor::setupSpinBox() const auto hoverColor = flattenedColor( m_pal.onPrimary, m_pal.primary, 0.08 ); setGradient( state | Q::Hovered, hoverColor ); - setShadowMetrics( state | Q::Hovered, m_pal.elevationLight1 ); + setShadowMetrics( state | Q::Hovered, m_pal.elevation1 ); setShadowColor( state | Q::Hovered, m_pal.shadow ); } @@ -1044,7 +1138,7 @@ void Editor::setupSubWindow() setBoxShape( Q::Panel, 28_dp ); setBoxBorderMetrics( Q::Panel, 0 ); setGradient( Q::Panel, m_pal.secondaryContainer ); - setShadowMetrics( Q::Panel, m_pal.elevationLight3 ); + setShadowMetrics( Q::Panel, m_pal.elevation3 ); setShadowColor( Q::Panel, m_pal.shadow ); // TitleBarPanel @@ -1154,6 +1248,9 @@ QskMaterial3Theme::QskMaterial3Theme( Lightness lightness, primary8 = QskRgb::toTransparentF( primary, 0.08 ); primary12 = QskRgb::toTransparentF( primary, 0.12 ); + onSecondaryContainer8 = QskRgb::toTransparentF( onSecondaryContainer, 0.08 ); + onSecondaryContainer12 = QskRgb::toTransparentF( onSecondaryContainer, 0.12 ); + error8 = QskRgb::toTransparentF( error, 0.08 ); error12 = QskRgb::toTransparentF( error, 0.12 ); @@ -1169,9 +1266,10 @@ QskMaterial3Theme::QskMaterial3Theme( Lightness lightness, surfaceVariant12 = QskRgb::toTransparentF( surfaceVariant, 0.12 ); - elevationLight1 = QskShadowMetrics( -3, 5, { 0, 2 } ); - elevationLight2 = QskShadowMetrics( -2, 8, { 0, 2 } ); - elevationLight3 = QskShadowMetrics( -1, 11, { 0, 2 } ); + elevation0 = QskShadowMetrics( 0, 0 ); + elevation1 = QskShadowMetrics( -2, 9, { 0, 1 } ); + elevation2 = QskShadowMetrics( -2, 8, { 0, 2 } ); + elevation3 = QskShadowMetrics( -1, 11, { 0, 2 } ); shapeExtraSmallTop = QskBoxShapeMetrics( 4_dp, 4_dp, 0, 0 ); } @@ -1270,6 +1368,10 @@ void QskMaterial3Skin::setupGraphicFilters( const QskMaterial3Theme& palette ) onSurfaceVariantFilter.addColorSubstitution( Qt::white, palette.onSurfaceVariant ); setGraphicFilter( GraphicRoleOnSurfaceVariant, onSurfaceVariantFilter ); + QskColorFilter primaryFilter; + primaryFilter.addColorSubstitution( Qt::white, palette.primary ); + setGraphicFilter( GraphicRolePrimary, primaryFilter ); + QskColorFilter surfaceFilter; surfaceFilter.addColorSubstitution( Qt::white, palette.surface ); setGraphicFilter( GraphicRoleSurface, surfaceFilter ); diff --git a/skins/material3/QskMaterial3Skin.h b/skins/material3/QskMaterial3Skin.h index bd03653a..b41684a9 100644 --- a/skins/material3/QskMaterial3Skin.h +++ b/skins/material3/QskMaterial3Skin.h @@ -41,7 +41,7 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Theme QskMaterial3Theme( Lightness, std::array< QskHctColor, NumPaletteTypes > ); QRgb primary; - QRgb primary8; + QRgb primary8; // ### rename to primaryHovered or so? QRgb primary12; QRgb onPrimary; QRgb primaryContainer; @@ -51,6 +51,8 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Theme QRgb onSecondary; QRgb secondaryContainer; QRgb onSecondaryContainer; + QRgb onSecondaryContainer8; + QRgb onSecondaryContainer12; QRgb tertiary; QRgb onTertiary; @@ -85,9 +87,10 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Theme QRgb shadow; - QskShadowMetrics elevationLight1; - QskShadowMetrics elevationLight2; - QskShadowMetrics elevationLight3; + QskShadowMetrics elevation0; + QskShadowMetrics elevation1; + QskShadowMetrics elevation2; + QskShadowMetrics elevation3; const qreal hoverOpacity = 0.08; const qreal focusOpacity = 0.12; @@ -133,6 +136,7 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin GraphicRoleOnSurface, GraphicRoleOnSurface38, GraphicRoleOnSurfaceVariant, + GraphicRolePrimary, GraphicRoleSurface, }; @@ -144,6 +148,12 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin M3LabelLarge, }; + static constexpr QskAspect::Variation Filled = QskAspect::NoVariation; + static constexpr QskAspect::Variation Tonal = QskAspect::Huge; + static constexpr QskAspect::Variation Elevated = QskAspect::Large; + static constexpr QskAspect::Variation Outlined = QskAspect::Small; + static constexpr QskAspect::Variation Text = QskAspect::Tiny; + private: void setupFonts(); void setupGraphicFilters( const QskMaterial3Theme& palette ); diff --git a/src/controls/QskPushButton.cpp b/src/controls/QskPushButton.cpp index 3224dad4..6b99dc68 100644 --- a/src/controls/QskPushButton.cpp +++ b/src/controls/QskPushButton.cpp @@ -26,7 +26,7 @@ class QskPushButton::PrivateData : text( txt ) , isCheckable( false ) , isGraphicSourceDirty( false ) - , emphasis( Emphasis3 ) + , emphasis( NoEmphasis ) { } @@ -245,16 +245,16 @@ QskAspect::Variation QskPushButton::effectiveVariation() const { switch( m_data->emphasis ) { - case Emphasis1: + case VeryLowEmphasis: return QskAspect::Tiny; - case Emphasis2: + case LowEmphasis: return QskAspect::Small; - case Emphasis4: + case HighEmphasis: return QskAspect::Large; - case Emphasis5: + case VeryHighEmphasis: return QskAspect::Huge; default: diff --git a/src/controls/QskPushButton.h b/src/controls/QskPushButton.h index 372fd745..4ff74366 100644 --- a/src/controls/QskPushButton.h +++ b/src/controls/QskPushButton.h @@ -49,11 +49,11 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton enum Emphasis { - Emphasis1 = -2, - Emphasis2 = -1, - Emphasis3 = 0, - Emphasis4 = 1, - Emphasis5 = 2 + VeryLowEmphasis = -2, + LowEmphasis = -1, + NoEmphasis = 0, + HighEmphasis = 1, + VeryHighEmphasis = 2 }; Q_ENUM( Emphasis )