diff --git a/examples/gallery/dialog/DialogPage.cpp b/examples/gallery/dialog/DialogPage.cpp new file mode 100644 index 00000000..8bd36eb5 --- /dev/null +++ b/examples/gallery/dialog/DialogPage.cpp @@ -0,0 +1,82 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#include "DialogPage.h" + +#include +#include +#include +#include + +namespace +{ + class Box : public QskGridBox + { + public: + Box( QQuickItem* parent ) + : QskGridBox( parent ) + { + auto* messageButton = new QskPushButton( "message", this ); + + connect( messageButton, &QskPushButton::clicked, this, []() + { + qskDialog->message( "message", "text", QskStandardSymbol::Ok ); + } ); + + auto* informationButton = new QskPushButton( "information", this ); + + connect( informationButton, &QskPushButton::clicked, this, []() + { + qskDialog->information( "information", "text" ); + } ); + + auto* warningButton = new QskPushButton( "warning", this ); + + connect( warningButton, &QskPushButton::clicked, this, []() + { + qskDialog->warning( "warning", "text" ); + } ); + + auto* criticalButton = new QskPushButton( "critical", this ); + + connect( criticalButton, &QskPushButton::clicked, this, []() + { + qskDialog->critical( "critical", "text" ); + } ); + + auto* questionButton = new QskPushButton( "question", this ); + + connect( questionButton, &QskPushButton::clicked, this, []() + { + qskDialog->question( "question", "text" ); + } ); + + auto* selectButton = new QskPushButton( "select", this ); + + connect( selectButton, &QskPushButton::clicked, this, []() + { + qskDialog->select( "select", "text", { "yes", "no", "maybe" } ); + } ); + + addItem( messageButton, 0, 0 ); + addItem( informationButton, 0, 1 ); + addItem( warningButton, 0, 2 ); + addItem( criticalButton, 1, 0 ); + addItem( questionButton, 1, 1 ); + addItem( selectButton, 1, 2 ); + } + }; +} + +DialogPage::DialogPage( QQuickItem* parent ) + : Page( Qt::Horizontal, parent ) +{ + populate(); +} + +void DialogPage::populate() +{ + new Box( this ); +} diff --git a/examples/gallery/dialog/DialogPage.h b/examples/gallery/dialog/DialogPage.h new file mode 100644 index 00000000..f41a2a37 --- /dev/null +++ b/examples/gallery/dialog/DialogPage.h @@ -0,0 +1,17 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#pragma once + +#include "Page.h" + +class DialogPage : public Page +{ + public: + DialogPage( QQuickItem* = nullptr ); + + private: + void populate(); +}; diff --git a/examples/gallery/gallery.pro b/examples/gallery/gallery.pro index 0435c5ea..d282c339 100644 --- a/examples/gallery/gallery.pro +++ b/examples/gallery/gallery.pro @@ -36,6 +36,12 @@ HEADERS += \ SOURCES += \ selector/SelectorPage.cpp \ +HEADERS += \ + dialog/DialogPage.h + +SOURCES += \ + dialog/DialogPage.cpp \ + HEADERS += \ Page.h diff --git a/examples/gallery/main.cpp b/examples/gallery/main.cpp index 0d4bf2a5..b2bec795 100644 --- a/examples/gallery/main.cpp +++ b/examples/gallery/main.cpp @@ -9,6 +9,7 @@ #include "button/ButtonPage.h" #include "textinput/TextInputPage.h" #include "selector/SelectorPage.h" +#include "dialog/DialogPage.h" #include #include @@ -138,6 +139,7 @@ namespace tabView->addTab( "Progress\nBars", new ProgressBarPage() ); tabView->addTab( "Text\nInputs", new TextInputPage() ); tabView->addTab( "Selectors", new SelectorPage() ); + tabView->addTab( "Dialogs", new DialogPage() ); connect( header, &Header::enabledToggled, tabView, &TabView::setTabsEnabled ); diff --git a/examples/iotdashboard/main.cpp b/examples/iotdashboard/main.cpp index 12ffb4d9..78b71d87 100644 --- a/examples/iotdashboard/main.cpp +++ b/examples/iotdashboard/main.cpp @@ -67,6 +67,7 @@ int main( int argc, char* argv[] ) // disable default skins qskSkinManager->setPluginPaths( QStringList() ); // no plugins qskSkinManager->unregisterFactory( "materialfactory" ); + qskSkinManager->unregisterFactory( "material3factory" ); qskSkinManager->unregisterFactory( "squiekfactory" ); qskSkinManager->registerFactory( diff --git a/skins/material3/QskMaterial3Global.h b/skins/material3/QskMaterial3Global.h new file mode 100644 index 00000000..be12d9d4 --- /dev/null +++ b/skins/material3/QskMaterial3Global.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_MATERIAL3_GLOBAL_H +#define QSK_MATERIAL3_GLOBAL_H + +#include "QskGlobal.h" + +#ifdef QSK_DLL + +#if defined( QSK_MATERIAL3_MAKEDLL ) // create a DLL library +#define QSK_MATERIAL3_EXPORT Q_DECL_EXPORT +#else // use a DLL library +#define QSK_MATERIAL3_EXPORT Q_DECL_IMPORT +#endif + +#endif // QSK_DLL + +#ifndef QSK_MATERIAL3_EXPORT +#define QSK_MATERIAL3_EXPORT +#endif + +#endif diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp new file mode 100644 index 00000000..c6ad860f --- /dev/null +++ b/skins/material3/QskMaterial3Skin.cpp @@ -0,0 +1,954 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2022 Edelhirsch Software GmbH + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#include "QskMaterial3Skin.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +static const int qskDuration = 150; + +namespace +{ + class Editor : private QskSkinHintTableEditor + { + public: + Editor( QskSkinHintTable* table, const QskMaterial3Theme& palette ) + : QskSkinHintTableEditor( table ) + , m_pal( palette ) + { + } + + void setup(); + + private: + void setupControl(); + + void setupBox(); + void setupCheckBox(); + void setupDialogButtonBox(); + void setupDialogButton(); + void setupFocusIndicator(); + void setupInputPanel(); + void setupVirtualKeyboard(); + void setupListView(); + void setupMenu(); + void setupPageIndicator(); + void setupPopup(); + void setupProgressBar(); + void setupPushButton(); + void setupScrollView(); + void setupSegmentedBar(); + void setupSeparator(); + void setupSubWindow(); + void setupSlider(); + void setupSwitchButton(); + void setupTabButton(); + void setupTabBar(); + void setupTabView(); + void setupTextInput(); + void setupTextLabel(); + + const QskMaterial3Theme& m_pal; + }; + + QFont createFont( int pixelSize, qreal tracking, QFont::Weight weight ) + { + QFont font( "Roboto" ); + font.setPixelSize( pixelSize ); + + if( !qskFuzzyCompare( tracking, 0.0 ) ) + { + font.setLetterSpacing( QFont::AbsoluteSpacing, tracking ); + } + + font.setWeight( weight ); + + return font; + } + + QColor flattenedColor( const QColor& foregroundColor, + const QColor& backgroundColor, qreal opacity ) + { + QColor r( opacity * foregroundColor.red() + ( 1 - opacity ) * backgroundColor.red(), + opacity * foregroundColor.green() + ( 1 - opacity ) * backgroundColor.green(), + opacity * foregroundColor.blue() + ( 1 - opacity ) * backgroundColor.blue() ); + return r; + } + + QColor stateLayerColor( QRgb rgb, qreal opacity ) + { + QColor c( rgb ); + c.setAlphaF( opacity ); + return c; + } +} + +void Editor::setup() +{ + setupControl(); + + setupBox(); + setupCheckBox(); + setupDialogButtonBox(); + setupDialogButton(); + setupFocusIndicator(); + setupInputPanel(); + setupVirtualKeyboard(); + setupListView(); + setupMenu(); + setupPageIndicator(); + setupPopup(); + setupProgressBar(); + setupPushButton(); + setupScrollView(); + setupSegmentedBar(); + setupSeparator(); + setupSlider(); + setupSubWindow(); + setupSwitchButton(); + setupTabButton(); + setupTabBar(); + setupTabView(); + setupTextLabel(); + setupTextInput(); +} + +void Editor::setupControl() +{ + using A = QskAspect; + + setPadding( A::Control, 11 ); + + setGradient( A::Control, m_pal.background ); + setColor( A::Control | A::StyleColor, m_pal.onBackground ); +} + +void Editor::setupCheckBox() +{ + using Q = QskCheckBox; + + setSpacing( Q::Panel, 10 ); + + setStrutSize( Q::Box, 24, 24 ); + + setPadding( Q::Box, 6 ); + setBoxShape( Q::Box, 2 ); + setBoxBorderMetrics( Q::Box, 2 ); + setBoxBorderColors( Q::Box, m_pal.onBackground ); + 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 ); + + setColor( Q::Indicator, m_pal.background ); + setColor( Q::Indicator | Q::Checked, m_pal.onPrimary ); + setColor( Q::Indicator | Q::Checked | Q::Disabled, m_pal.onSurface38 ); + + setColor( Q::Text, m_pal.onBackground ); +} + +void Editor::setupBox() +{ + using Q = QskBox; + + setGradient( Q::Panel, m_pal.background ); + setBoxShape( Q::Panel, 14 ); + setBoxBorderMetrics( Q::Panel, 0 ); +} + +void Editor::setupPopup() +{ + using A = QskAspect; + using Q = QskPopup; + + setFlagHint( Q::Overlay | A::Style, true ); + setGradient( Q::Overlay, Qt::transparent ); +} + +void Editor::setupMenu() +{ + using A = QskAspect; + using Q = QskMenu; + + setBoxShape( Q::Panel, 4 ); + setBoxBorderMetrics( Q::Panel, 0 ); + setPadding( Q::Panel, 0 ); + + // The color here is primary with an opacity of 8% - we blend that + // with the background, because we don't want the menu to have transparency: + QColor panel = flattenedColor( m_pal.primary, m_pal.background, 0.08 ); + setGradient( Q::Panel, panel ); + + setShadowMetrics( Q::Panel, m_pal.elevationLight2 ); + setShadowColor( Q::Panel, m_pal.shadow ); + + setMetric( Q::Separator | A::Size, qskDpiScaled( 1 ) ); + setBoxShape( Q::Separator, 0 ); + setBoxBorderMetrics( Q::Separator, 0 ); + setGradient( Q::Separator, m_pal.primary12 ); + + setPadding( Q::Segment, 6 ); + setSpacing( Q::Segment, 5 ); + setGradient( Q::Segment, Qt::transparent ); + + setGradient( Q::Cursor, m_pal.primary12 ); + + setPadding( Q::Graphic, 7 ); + setStrutSize( Q::Graphic, { 46, -1 } ); + + setColor( Q::Text, m_pal.onSurface ); + setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium ); + + setPosition( Q::Panel, 0 ); + setPosition( Q::Panel | QskPopup::Closed, 1 ); + + setAnimation( Q::Panel | A::Metric, 150 ); + setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic ); +} + +void Editor::setupTextLabel() +{ + using Q = QskTextLabel; + + setAlignment( Q::Text, Qt::AlignCenter ); + setColor( Q::Text, m_pal.onSurface ); + + setPadding( Q::Panel, 5 ); +} + + +void Editor::setupTextInput() +{ + using Q = QskTextInput; + + setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignTop ); + + setColor( Q::Text, m_pal.onBackground ); + + setPadding( Q::Panel, 5 ); + setBoxShape( Q::Panel, 4, 4, 0, 0 ); + setBoxBorderMetrics( Q::Panel, 0, 0, 0, 1 ); + setBoxBorderColors( Q::Panel, m_pal.onSurface ); + + setBoxBorderMetrics( Q::Panel | Q::Focused, 0, 0, 0, 2 ); + setBoxBorderColors( Q::Panel | Q::Focused, m_pal.primary ); + + setBoxBorderMetrics( Q::Panel | Q::Editing, 0, 0, 0, 2 ); + setBoxBorderColors( Q::Panel | Q::Editing, m_pal.primary ); + + setBoxBorderMetrics( Q::Panel | Q::Hovered, 0, 0, 0, 1 ); + setBoxBorderColors( Q::Panel | Q::Hovered, m_pal.onSurface ); + + setGradient( Q::Panel, m_pal.surfaceVariant ); + + QColor c1( m_pal.onSurface ); + c1.setAlphaF( 0.04 ); + setGradient( Q::Panel | Q::Disabled, c1 ); + setBoxBorderMetrics( Q::Panel | Q::Disabled, 0, 0, 0, 1 ); + + setColor( Q::Text | Q::Disabled, m_pal.onSurface38 ); + setBoxBorderColors( Q::Panel | Q::Disabled, m_pal.onSurface38 ); +} + +void Editor::setupProgressBar() +{ + using A = QskAspect; + using Q = QskProgressBar; + + auto size = qskDpiScaled( 5 ); + + for ( auto subControl : { Q::Groove, Q::Bar } ) + { + setMetric( subControl | A::Size, size ); + setPadding( subControl, 0 ); + + setBoxShape( subControl, 0 ); + setBoxBorderMetrics( subControl, 0 ); + } + + setMetric( Q::Groove | A::Size, size ); + setGradient( Q::Groove, m_pal.primaryContainer ); + + setGradient( Q::Groove | Q::Disabled, m_pal.onSurface12 ); + + setGradient( Q::Bar, m_pal.primary ); + setGradient( Q::Bar | Q::Disabled, m_pal.onSurface38 ); +} + +void Editor::setupFocusIndicator() +{ + using Q = QskFocusIndicator; + setGradient( Q::Panel, QskGradient() ); +} + +void Editor::setupSegmentedBar() +{ + // copied from Squiek: we need something similar to a tab bar here. TODO ... + using A = QskAspect; + using Q = QskSegmentedBar; + + const QSize strutSize( -1, 40 ); + + { + // Panel + + setPadding( Q::Panel, 0 ); + setSpacing( Q::Panel, 0 ); + + setBoxShape( Q::Panel, 100, Qt::RelativeSize ); + + setBoxBorderMetrics( Q::Panel, 1 ); + setBoxBorderColors( Q::Panel, m_pal.outline ); + setBoxBorderColors( Q::Panel | Q::Disabled, m_pal.onSurface12 ); + + setStrutSize( Q::Panel | A::Horizontal, strutSize ); + setStrutSize( Q::Panel | A::Vertical, strutSize.transposed() ); + } + + { + // Segment + + setGradient( Q::Segment, Qt::transparent ); + setPadding( Q::Segment, 0 ); + } + + { + // Separator + + setStrutSize( Q::Separator | A::Horizontal, 1, strutSize.height() ); + setStrutSize( Q::Separator | A::Vertical, strutSize.height(), 1 ); + setPadding( Q::Separator, 0 ); + setGradient( Q::Separator, m_pal.outline ); + setColor( Q::Separator | Q::Disabled, m_pal.onSurface38 ); + } + + { + // Cursor + setMargin( Q::Cursor, 1 ); + 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 ); + + setAnimation( Q::Cursor | A::Metric | A::Position, 100 ); + } + + { + // Text + + setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge ); + + setColor( Q::Text, m_pal.onSurface ); + setColor( Q::Text | Q::Selected, m_pal.onSecondaryContainer ); + + setColor( Q::Text | Q::Disabled, m_pal.onSurface38 ); + } + + { + // Graphic + + setPadding( Q::Graphic, 10 ); + setMargin( Q::Graphic, 10 ); + } +} + +void Editor::setupSeparator() +{ + using A = QskAspect; + using Q = QskSeparator; + + for ( auto placement : { A::Horizontal, A::Vertical } ) + { + const auto aspect = Q::Panel | placement; + + setMetric( aspect | A::Size, 4 ); + setBoxShape( Q::Panel, 0 ); + setBoxBorderMetrics( Q::Panel, 0 ); + setGradient( aspect, m_pal.background ); + } +} + +void Editor::setupPageIndicator() +{ + using Q = QskPageIndicator; + + const auto extent = qskDpiScaled( 9 ); + setStrutSize( Q::Bullet, extent, extent ); + + // circles, without border + setBoxShape( Q::Bullet, 100, Qt::RelativeSize ); + setBoxBorderMetrics( Q::Bullet, 0 ); + + setGradient( Q::Bullet, m_pal.primaryContainer ); + setGradient( Q::Bullet | Q::Selected, m_pal.primary ); + + setGradient( Q::Bullet | Q::Disabled, m_pal.onSurface12 ); + setGradient( Q::Bullet | Q::Selected | Q::Disabled, m_pal.onSurface38 ); + + setSpacing( Q::Panel, qskDpiScaled( 3 ) ); + setPadding( Q::Panel, 0 ); + setGradient( Q::Panel, QskGradient() ); // invisible +} + +void Editor::setupPushButton() +{ + using A = QskAspect; + using Q = QskPushButton; + + setFlagHint( Q::Panel | QskAspect::Direction, Qsk::LeftToRight ); + setStrutSize( Q::Panel, -1, 31 ); + setSpacing( Q::Panel, qskDpiScaled( 4 ) ); + setPadding( Q::Panel, { 24, 0, 20, 0 } ); + + setBoxShape( Q::Panel, 100, Qt::RelativeSize ); + + setAlignment( Q::Graphic | A::Alignment, Qt::AlignLeft ); + setPadding( Q::Graphic, 5 ); + + setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge ); + setAlignment( Q::Text, Qt::AlignCenter ); + + + // normal buttons (i.e. Filled): + + setGradient( Q::Panel, m_pal.primary ); + setGradient( Q::Panel | Q::Disabled, m_pal.onSurface12 ); + + QColor hoverColor = flattenedColor( m_pal.onPrimary, m_pal.primary, 0.08 ); + setGradient( Q::Panel | Q::Hovered, hoverColor ); + setShadowMetrics( Q::Panel | Q::Hovered, m_pal.elevationLight1 ); + setShadowColor( Q::Panel | Q::Hovered, m_pal.shadow ); + + QColor focusColor = flattenedColor( m_pal.onPrimary, m_pal.primary, 0.12 ); + setGradient( Q::Panel | Q::Focused, focusColor ); + + setGradient( Q::Panel | Q::Pressed, focusColor ); + + setColor( Q::Text, m_pal.onPrimary ); + setColor( Q::Text | Q::Disabled, m_pal.onSurface38 ); + + setAnimation( Q::Panel | A::Color, qskDuration ); + setAnimation( Q::Panel | A::Metric, qskDuration ); + setAnimation( Q::Text | A::Color, qskDuration ); +} + +void Editor::setupDialogButton() +{ + using Q = QskDialogButton; + + setStrutSize( Q::Panel, 48, -1 ); + setSpacing( Q::Panel, 8 ); + setPadding( Q::Panel, { 12, 13, 12, 13 } ); + setBoxShape( Q::Panel, 100, Qt::RelativeSize ); + setGradient( Q::Panel, m_pal.secondaryContainer ); + + setGradient( Q::Panel | Q::Hovered, stateLayerColor( m_pal.primary, m_pal.hoverOpacity ) ); + setGradient( Q::Panel | Q::Pressed, stateLayerColor( m_pal.primary, m_pal.pressedOpacity ) ); + + setColor( Q::Text, m_pal.primary ); + setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge ); +} + +void Editor::setupDialogButtonBox() +{ + using Q = QskDialogButtonBox; + + setGradient( Q::Panel, m_pal.secondaryContainer ); + setBoxShape( Q::Panel, 0 ); + setBoxBorderMetrics( Q::Panel, 0 ); +} + +void Editor::setupSlider() +{ + using A = QskAspect; + using Q = QskSlider; + + const qreal extent = 30; + + // Panel + + setMetric( Q::Panel | A::Size, extent ); + setBoxShape( Q::Panel, 0 ); + setBoxBorderMetrics( Q::Panel, 0 ); + setGradient( Q::Panel, QskGradient() ); + + setPadding( Q::Panel | A::Horizontal, QskMargins( 0.5 * extent, 0 ) ); + setPadding( Q::Panel | A::Vertical, QskMargins( 0, 0.5 * extent ) ); + + // Groove, Fill + + for ( auto subControl : { Q::Groove, Q::Fill } ) + { + setPadding( subControl, 0 ); + + setBoxShape( subControl, 0 ); + setBoxBorderMetrics( subControl, 0 ); + } + + setMetric( Q::Groove | A::Size, qskDpiScaled( 4 ) ); + setMetric( Q::Fill | A::Size, qskDpiScaled( 6 ) ); + + setGradient( Q::Groove, m_pal.primaryContainer ); + setGradient( Q::Groove | Q::Disabled, m_pal.onSurface12 ); + + setGradient( Q::Fill, m_pal.primary ); + setGradient( Q::Fill | Q::Disabled, m_pal.onSurface38 ); + + setBoxShape( Q::Handle, 100, Qt::RelativeSize ); + setBoxBorderMetrics( Q::Handle, 0 ); + + setStrutSize( Q::Handle, { 20, 20 } ); + + setGradient( Q::Handle, m_pal.primary ); + setGradient( Q::Handle | Q::Pressed, m_pal.primary ); + + const auto disabledColor = flattenedColor( m_pal.onSurface, m_pal.background, 0.38 ); + setGradient( Q::Handle | Q::Disabled, disabledColor ); + + setStrutSize( Q::Ripple, { 40, 40 } ); + setBoxShape( Q::Ripple, 100, Qt::RelativeSize ); + setGradient( Q::Ripple, Qt::transparent ); + setGradient( Q::Ripple | Q::Hovered, m_pal.primary12 ); + setGradient( Q::Ripple | Q::Pressed, m_pal.primary12 ); + + // move the handle smoothly, when using keys + setAnimation( Q::Handle | A::Metric | A::Position, 2 * qskDuration ); + setAnimation( Q::Handle | A::Metric | A::Position | Q::Pressed, 0 ); +} + +void Editor::setupSwitchButton() +{ + using A = QskAspect; + using Q = QskSwitchButton; + + setBoxShape( Q::Groove, 100, Qt::RelativeSize ); + const QSizeF strutSize( 52, 32 ); + setStrutSize( Q::Groove | A::Horizontal, strutSize ); + setStrutSize( Q::Groove | A::Vertical, strutSize.transposed() ); + setGradient( Q::Groove, m_pal.surfaceVariant ); + + setGradient( Q::Groove | Q::Disabled, m_pal.surfaceVariant12 ); + setGradient( Q::Groove | Q::Checked, m_pal.primary ); + + setGradient( Q::Groove | Q::Checked | Q::Disabled, m_pal.onSurface12 ); + setBoxBorderMetrics( Q::Groove, 2 ); + setBoxBorderColors( Q::Groove, m_pal.outline ); + + setBoxBorderMetrics( Q::Groove | Q::Checked, 0 ); + + setBoxShape( Q::Handle, 100, Qt::RelativeSize ); + setStrutSize( Q::Handle, 16, 16 ); + setStrutSize( Q::Handle | Q::Checked, 24, 24, { QskStateCombination::CombinationNoState, Q::Disabled } ); + + setGradient( Q::Handle, m_pal.outline ); + setGradient( Q::Handle | Q::Checked, m_pal.primaryContainer ); + + 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::Ripple, 40, 40 ); + setGradient( Q::Ripple, Qt::transparent ); + + setStrutSize( Q::Ripple | Q::Hovered, 40, 40 ); + setBoxShape( Q::Ripple, 100, Qt::RelativeSize ); + setGradient( Q::Ripple | Q::Hovered, stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) ); + setGradient( Q::Ripple | 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 ); + + for ( auto state : { A::NoState, Q::Disabled } ) + { + auto aspect = Q::Handle | state; + + setPosition( aspect, 0.15 ); + setPosition( aspect | Q::Checked, 0.85 ); + } + + setAnimation( Q::Handle | A::Color, qskDuration ); + setAnimation( Q::Handle | A::Metric, qskDuration ); + setAnimation( Q::Groove | A::Color, qskDuration ); +} + +void Editor::setupTabButton() +{ + using A = QskAspect; + using Q = QskTabButton; + + setStrutSize( Q::Panel, 48, 48 ); + setGradient( Q::Panel, m_pal.surface ); + + setColor( Q::Text, m_pal.onSurfaceVariant ); + setColor( Q::Text | Q::Disabled, m_pal.onSurface38 ); + + setColor( Q::Text | Q::Checked, m_pal.primary ); + setColor( Q::Text | Q::Hovered, m_pal.primary ); + + for ( const auto placement : { A::Left, A::Right, A::Top, A::Bottom } ) + { + const auto aspect = Q::Panel | placement; + + Qt::Edge edge; + + switch( placement ) + { + case A::Left: + edge = Qt::RightEdge; + break; + + case A::Right: + edge = Qt::LeftEdge; + break; + + case A::Top: + edge = Qt::BottomEdge; + break; + + case A::Bottom: + edge = Qt::TopEdge; + break; + + default: + edge = Qt::Edge( 0 ); // making gcc4 happy + } + + QskBoxBorderMetrics border; + border.setWidthAt( edge, 3 ); + setBoxBorderMetrics( aspect, border ); + + QskBoxBorderColors borderColors( m_pal.surface ); + setBoxBorderColors( aspect, borderColors ); + + borderColors.setGradientAt( edge, m_pal.primary ); + setBoxBorderColors( aspect | Q::Checked, borderColors ); + } + + QColor c( m_pal.surface ); + c.setAlphaF( m_pal.hoverOpacity ); + setGradient( Q::Panel | Q::Hovered, c ); + c.setAlphaF( m_pal.focusOpacity ); + setGradient( Q::Panel | Q::Focused, c ); + c.setAlphaF( m_pal.pressedOpacity ); + setGradient( Q::Panel | Q::Pressed, c ); + + setAnimation( Q::Panel | A::Color, qskDuration ); + + setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge ); + setAlignment( Q::Text, Qt::AlignCenter ); +} + +void Editor::setupTabBar() +{ + using A = QskAspect; + using Q = QskTabBar; + + setBoxShape( Q::Panel, 0 ); + setBoxBorderMetrics( Q::Panel, 0 ); + + setGradient( Q::Panel, m_pal.secondaryContainer ); + setPadding( Q::Panel, 0 ); + + // when flicking + setAnimation( Q::Panel | A::Metric, QskAnimationHint( 200, QEasingCurve::InCubic ) ); +} + +void Editor::setupTabView() +{ + using Q = QskTabView; + + setGradient( Q::Page, m_pal.background ); + setAnimation( Q::Page, qskDuration ); +} + +void Editor::setupInputPanel() +{ + using Q = QskInputPanelBox; + + setBoxShape( Q::Panel, 0 ); + setBoxBorderMetrics( Q::Panel, 0 ); + setGradient( Q::Panel, m_pal.secondaryContainer ); + setBoxBorderColors( Q::Panel, m_pal.background ); +} + +void Editor::setupVirtualKeyboard() +{ + using A = QskAspect; + using Q = QskVirtualKeyboard; + + // key panel + setMargin( Q::ButtonPanel, 2 ); + + setBoxShape( Q::ButtonPanel, 20.0, Qt::RelativeSize ); + setBoxBorderMetrics( Q::ButtonPanel, 2 ); + setBoxBorderColors( Q::ButtonPanel, m_pal.background ); + + for ( auto state : { A::NoState, Q::Focused } ) + setBoxBorderColors( Q::ButtonPanel | QskPushButton::Pressed | state, + m_pal.secondary ); + + setAnimation( Q::ButtonPanel | A::Color, qskDuration ); + setAnimation( Q::ButtonPanel | A::Metric, qskDuration ); + + // panel + setBoxShape( Q::Panel, 0 ); + setBoxBorderMetrics( Q::Panel, 0 ); + setGradient( Q::Panel, m_pal.secondaryContainer ); + setBoxBorderColors( Q::Panel, m_pal.background ); +} + +void Editor::setupScrollView() +{ + using A = QskAspect; + using Q = QskScrollView; + + setGradient( Q::Viewport, m_pal.secondaryContainer ); + + for ( auto subControl : { Q::HorizontalScrollBar, Q::VerticalScrollBar } ) + { + setMetric( subControl | A::Size, 10 ); + setPadding( subControl, 0 ); + } + + const auto handleExtent = qskDpiScaled( 40.0 ); + setStrutSize( Q::HorizontalScrollHandle, handleExtent, 0.0 ); + setStrutSize( Q::VerticalScrollHandle, 0.0, handleExtent ); + + for ( auto subControl : { Q::HorizontalScrollHandle, Q::VerticalScrollHandle } ) + { + setBoxShape( subControl, 3 ); + setBoxBorderMetrics( subControl, 0 ); + setGradient( subControl, m_pal.primary ); + setAnimation( subControl | A::Color, qskDuration ); + } + + // when changing the position by QskScrollView::scrollTo + setAnimation( Q::Viewport | A::Metric, QskAnimationHint( 200, QEasingCurve::InCubic ) ); +} + +void Editor::setupListView() +{ + using Q = QskListView; + + setPadding( Q::Cell, { 16, 12, 16, 12 } ); + setBoxBorderMetrics( Q::Cell, { 0, 0, 0, 1 } ); + setBoxBorderColors( Q::Cell, m_pal.outline ); + setColor( Q::Cell, m_pal.surface ); + setColor( Q::Cell | Q::Selected, m_pal.primary12 ); + + setColor( Q::Text, m_pal.onSurfaceVariant ); +} + +void Editor::setupSubWindow() +{ + using A = QskAspect; + using Q = QskSubWindow; + + // Panel + + setPadding( Q::Panel, { 24, 0, 24, 24 } ); + setStrutSize( Q::Panel, { 280, -1 } ); + setBoxShape( Q::Panel, 28 ); + setBoxBorderMetrics( Q::Panel, 0 ); + setGradient( Q::Panel, m_pal.secondaryContainer ); + setShadowMetrics( Q::Panel, m_pal.elevationLight3 ); + setShadowColor( Q::Panel, m_pal.shadow ); + + // TitleBarPanel + setBoxShape( Q::TitleBarPanel, 28 ); + setPadding( Q::TitleBarPanel, { 24, 24, 24, 16 } ); + setFlagHint( Q::TitleBarPanel | QskAspect::Style, + Q::TitleBar | Q::Title | Q::Symbol ); + + setGradient( Q::TitleBarPanel, m_pal.secondaryContainer ); + + // TitleBarText + setFontRole( Q::TitleBarText, QskMaterial3Skin::M3HeadlineSmall ); + setColor( Q::TitleBarText, m_pal.onSurface ); + setAlignment( Q::TitleBarText, Qt::AlignCenter ); + + for ( auto subControl : { Q::Panel, Q::TitleBarPanel, Q::TitleBarText } ) + setAnimation( subControl | A::Color, qskDuration ); + +} + +QskMaterial3Theme::QskMaterial3Theme( Lightness lightness ) + : QskMaterial3Theme( lightness, + { // default Material colors: + 0xff6750A4, + 0xff625B71, + 0xff7D5260, + 0xffB3261E, + 0xff605D62, + 0xff605D66, + } ) +{ +} + +QskMaterial3Theme::QskMaterial3Theme(Lightness lightness, + std::array palettes ) + : m_palettes( palettes ) +{ + if ( lightness == Light ) + { + primary = m_palettes[ Primary ].toned( 40 ).rgb(); + onPrimary = m_palettes[ Primary ].toned( 100 ).rgb(); + primaryContainer = m_palettes[ Primary ].toned( 90 ).rgb(); + onPrimaryContainer = m_palettes[ Primary ].toned( 10 ).rgb(); + + secondary = m_palettes[ Secondary ].toned( 40 ).rgb(); + onSecondary = m_palettes[ Secondary ].toned( 100 ).rgb(); + secondaryContainer = m_palettes[ Secondary ].toned( 90 ).rgb(); + onSecondaryContainer = m_palettes[ Secondary ].toned( 10 ).rgb(); + + tertiary = m_palettes[ Tertiary ].toned( 40 ).rgb(); + onTertiary = m_palettes[ Tertiary ].toned( 100 ).rgb(); + tertiaryContainer = m_palettes[ Tertiary ].toned( 90 ).rgb(); + onTertiaryContainer = m_palettes[ Tertiary ].toned( 10 ).rgb(); + + error = m_palettes[ Error ].toned( 40 ).rgb(); + onError = m_palettes[ Error ].toned( 100 ).rgb(); + errorContainer = m_palettes[ Error ].toned( 90 ).rgb(); + onErrorContainer = m_palettes[ Error ].toned( 10 ).rgb(); + + background = m_palettes[ Neutral ].toned( 99 ).rgb(); + onBackground = m_palettes[ Neutral ].toned( 10 ).rgb(); + surface = m_palettes[ Neutral ].toned( 99 ).rgb(); + onSurface = m_palettes[ Neutral ].toned( 10 ).rgb(); + + surfaceVariant = m_palettes[ NeutralVariant ].toned( 90 ).rgb(); + onSurfaceVariant = m_palettes[ NeutralVariant ].toned( 30 ).rgb(); + outline = m_palettes[ NeutralVariant ].toned( 50 ).rgb(); + + shadow = m_palettes[ Neutral ].toned( 0 ).rgb(); + } + else if ( lightness == Dark ) + { + primary = m_palettes[ Primary ].toned( 80 ).rgb(); + onPrimary = m_palettes[ Primary ].toned( 20 ).rgb(); + primaryContainer = m_palettes[ Primary ].toned( 30 ).rgb(); + onPrimaryContainer = m_palettes[ Primary ].toned( 90 ).rgb(); + + secondary = m_palettes[ Secondary ].toned( 80 ).rgb(); + onSecondary = m_palettes[ Secondary ].toned( 20 ).rgb(); + secondaryContainer = m_palettes[ Secondary ].toned( 30 ).rgb(); + onSecondaryContainer = m_palettes[ Secondary ].toned( 90 ).rgb(); + + tertiary = m_palettes[ Tertiary ].toned( 80 ).rgb(); + onTertiary = m_palettes[ Tertiary ].toned( 20 ).rgb(); + tertiaryContainer = m_palettes[ Tertiary ].toned( 30 ).rgb(); + onTertiaryContainer = m_palettes[ Tertiary ].toned( 90 ).rgb(); + + error = m_palettes[ Error ].toned( 80 ).rgb(); + onError = m_palettes[ Error ].toned( 20 ).rgb(); + errorContainer = m_palettes[ Error ].toned( 30 ).rgb(); + onErrorContainer = m_palettes[ Error ].toned( 90 ).rgb(); + + background = m_palettes[ Neutral ].toned( 10 ).rgb(); + onBackground = m_palettes[ Neutral ].toned( 90 ).rgb(); + surface = m_palettes[ Neutral ].toned( 10 ).rgb(); + onSurface = m_palettes[ Neutral ].toned( 80 ).rgb(); + + surfaceVariant = m_palettes[ NeutralVariant ].toned( 30 ).rgb(); + onSurfaceVariant = m_palettes[ NeutralVariant ].toned( 80 ).rgb(); + outline = m_palettes[ NeutralVariant ].toned( 60 ).rgb(); + + shadow = m_palettes[ Neutral ].toned( 0 ).rgb(); + } + + primary12 = primary; + primary12.setAlphaF( 0.12 ); + + onSurface12 = onSurface; + onSurface12.setAlphaF( 0.12 ); + + onSurface38 = onSurface; + onSurface38.setAlphaF( 0.38 ); + + surfaceVariant12 = surfaceVariant; + surfaceVariant12.setAlphaF( 0.12 ); + + elevationLight1 = QskShadowMetrics( -3, 5, { 0, 2 } ); + elevationLight2 = QskShadowMetrics( -2, 8, { 0, 2 } ); + elevationLight3 = QskShadowMetrics( -1, 11, { 0, 2 } ); +} + +QskMaterial3Skin::QskMaterial3Skin( const QskMaterial3Theme& palette, QObject* parent ) + : Inherited( parent ) +{ + setupFonts(); + + Editor editor( &hintTable(), palette ); + editor.setup(); +} + +QskMaterial3Skin::~QskMaterial3Skin() +{ +} + +void QskMaterial3Skin::setupFonts() +{ + Inherited::setupFonts( QStringLiteral( "Roboto" ) ); + + setFont( M3BodyMedium, createFont( 14, 0.25, QFont::Normal ) ); + setFont( M3BodyLarge, createFont( 16, 0.5, QFont::Normal ) ); + setFont( M3HeadlineSmall, createFont( 28, 0.0, QFont::Normal ) ); + setFont( M3LabelLarge, createFont( 14, 0.1, QFont::Medium ) ); +} + +#include "moc_QskMaterial3Skin.cpp" diff --git a/skins/material3/QskMaterial3Skin.h b/skins/material3/QskMaterial3Skin.h new file mode 100644 index 00000000..646cef4b --- /dev/null +++ b/skins/material3/QskMaterial3Skin.h @@ -0,0 +1,111 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2022 Edelhirsch Software GmbH + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#ifndef QSK_MATERIAL3_SKIN_H +#define QSK_MATERIAL3_SKIN_H + +#include "QskMaterial3Global.h" + +#include +#include +#include + +#include + +class QSK_MATERIAL3_EXPORT QskMaterial3Theme +{ + public: + enum Lightness + { + Light, + Dark + }; + + enum PaletteType + { + Primary, + Secondary, + Tertiary, + Error, + Neutral, + NeutralVariant, + + NumPaletteTypes + }; + + QskMaterial3Theme( Lightness ); + QskMaterial3Theme( Lightness, std::array< QskHctColor, NumPaletteTypes > ); + + QRgb primary; + QColor primary12; + QRgb onPrimary; + QRgb primaryContainer; + QRgb onPrimaryContainer; + + QRgb secondary; + QRgb onSecondary; + QRgb secondaryContainer; + QRgb onSecondaryContainer; + + QRgb tertiary; + QRgb onTertiary; + QRgb tertiaryContainer; + QRgb onTertiaryContainer; + + QRgb error; + QRgb onError; + QRgb errorContainer; + QRgb onErrorContainer; + + QRgb background; + QRgb onBackground; + QRgb surface; + QRgb onSurface; + QColor onSurface12; + QColor onSurface38; + + QRgb surfaceVariant; + QColor surfaceVariant12; + QRgb onSurfaceVariant; + QRgb outline; + + QRgb shadow; + + QskShadowMetrics elevationLight1; + QskShadowMetrics elevationLight2; + QskShadowMetrics elevationLight3; + + const qreal hoverOpacity = 0.08; + const qreal focusOpacity = 0.12; + const qreal pressedOpacity = 0.12; + const qreal draggedOpacity = 0.16; + + private: + std::array< QskHctColor, NumPaletteTypes > m_palettes; +}; + +class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin +{ + Q_OBJECT + + using Inherited = QskSkin; + + public: + QskMaterial3Skin( const QskMaterial3Theme&, QObject* parent = nullptr ); + ~QskMaterial3Skin() override; + + enum FontRole + { + M3BodyMedium = QskSkin::HugeFont + 1, + M3BodyLarge, + M3HeadlineSmall, + M3LabelLarge, + }; + + private: + void setupFonts(); +}; + +#endif diff --git a/skins/material3/QskMaterial3SkinFactory.cpp b/skins/material3/QskMaterial3SkinFactory.cpp new file mode 100644 index 00000000..4f43f841 --- /dev/null +++ b/skins/material3/QskMaterial3SkinFactory.cpp @@ -0,0 +1,42 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#include "QskMaterial3SkinFactory.h" +#include "QskMaterial3Skin.h" + +static const QString materialLightSkinName = QStringLiteral( "material3Light" ); +static const QString materialDarkSkinName = QStringLiteral( "material3Dark" ); + +QskMaterial3SkinFactory::QskMaterial3SkinFactory( QObject* parent ) + : QskSkinFactory( parent ) +{ +} + +QskMaterial3SkinFactory::~QskMaterial3SkinFactory() +{ +} + +QStringList QskMaterial3SkinFactory::skinNames() const +{ + return { materialLightSkinName, materialDarkSkinName }; +} + +QskSkin* QskMaterial3SkinFactory::createSkin( const QString& skinName ) +{ + if ( QString::compare( skinName, materialLightSkinName, Qt::CaseInsensitive ) == 0 ) + { + QskMaterial3Theme theme( QskMaterial3Theme::Light ); + return new QskMaterial3Skin( theme ); + } + else if ( QString::compare( skinName, materialDarkSkinName, Qt::CaseInsensitive ) == 0 ) + { + QskMaterial3Theme theme( QskMaterial3Theme::Dark ); + return new QskMaterial3Skin( theme ); + } + + return nullptr; +} + +#include "moc_QskMaterial3SkinFactory.cpp" diff --git a/skins/material3/QskMaterial3SkinFactory.h b/skins/material3/QskMaterial3SkinFactory.h new file mode 100644 index 00000000..9727a329 --- /dev/null +++ b/skins/material3/QskMaterial3SkinFactory.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#ifndef QSK_MATERIAL_SKIN_FACTORY_H +#define QSK_MATERIAL_SKIN_FACTORY_H + +#include "QskMaterial3Global.h" +#include + +class QSK_MATERIAL3_EXPORT QskMaterial3SkinFactory : public QskSkinFactory +{ + Q_OBJECT + + Q_PLUGIN_METADATA( IID QskSkinFactoryIID FILE "metadata.json" ) + Q_INTERFACES( QskSkinFactory ) + + public: + QskMaterial3SkinFactory( QObject* parent = nullptr ); + ~QskMaterial3SkinFactory() override; + + QStringList skinNames() const override; + QskSkin* createSkin( const QString& skinName ) override; +}; + +#endif diff --git a/skins/material3/material3.pro b/skins/material3/material3.pro new file mode 100644 index 00000000..97317b2d --- /dev/null +++ b/skins/material3/material3.pro @@ -0,0 +1,23 @@ +CONFIG += plugin +CONFIG += qskinny + +TEMPLATE = lib +QSK_PLUGIN_SUBDIR = skins + +TARGET = $$qskPluginTarget(material3skin) +DEFINES += QSK_MATERIAL3_MAKEDLL + +HEADERS += \ + QskMaterial3Global.h \ + QskMaterial3Skin.h \ + QskMaterial3SkinFactory.h + +SOURCES += \ + QskMaterial3Skin.cpp \ + QskMaterial3SkinFactory.cpp + +OTHER_FILES += metadata.json + +target.path = $${QSK_INSTALL_PLUGINS}/$${QSK_PLUGIN_SUBDIR} +INSTALLS = target + diff --git a/skins/material3/metadata.json b/skins/material3/metadata.json new file mode 100644 index 00000000..c668d63e --- /dev/null +++ b/skins/material3/metadata.json @@ -0,0 +1,4 @@ +{ + "FactoryId": "Material3Factory", + "Skins": [ "material3Light", "material3Dark" ] +} diff --git a/skins/skins.pro b/skins/skins.pro index 42e5f9bb..ec1ce1a8 100644 --- a/skins/skins.pro +++ b/skins/skins.pro @@ -2,4 +2,5 @@ TEMPLATE = subdirs SUBDIRS += \ squiek \ - material + material \ + material3 diff --git a/src/controls/QskSlider.cpp b/src/controls/QskSlider.cpp index 4fe96db9..08226db5 100644 --- a/src/controls/QskSlider.cpp +++ b/src/controls/QskSlider.cpp @@ -14,6 +14,7 @@ QSK_SUBCONTROL( QskSlider, Groove ) QSK_SUBCONTROL( QskSlider, Fill ) QSK_SUBCONTROL( QskSlider, Scale ) QSK_SUBCONTROL( QskSlider, Handle ) +QSK_SUBCONTROL( QskSlider, Ripple ) QSK_SYSTEM_STATE( QskSlider, Pressed, QskAspect::FirstSystemState << 2 ) QSK_SYSTEM_STATE( QskSlider, Minimum, QskAspect::LastUserState << 1 ) diff --git a/src/controls/QskSlider.h b/src/controls/QskSlider.h index 9d118cd5..45c39a9b 100644 --- a/src/controls/QskSlider.h +++ b/src/controls/QskSlider.h @@ -23,7 +23,7 @@ class QSK_EXPORT QskSlider : public QskBoundedValueInput using Inherited = QskBoundedValueInput; public: - QSK_SUBCONTROLS( Panel, Groove, Fill, Scale, Handle ) + QSK_SUBCONTROLS( Panel, Groove, Fill, Scale, Handle, Ripple ) QSK_STATES( Pressed, Minimum, Maximum ) explicit QskSlider( QQuickItem* parent = nullptr ); diff --git a/src/controls/QskSliderSkinlet.cpp b/src/controls/QskSliderSkinlet.cpp index 5f89c861..6d25379c 100644 --- a/src/controls/QskSliderSkinlet.cpp +++ b/src/controls/QskSliderSkinlet.cpp @@ -31,7 +31,7 @@ static inline QRectF qskInnerPanelRect( QskSliderSkinlet::QskSliderSkinlet( QskSkin* skin ) : Inherited( skin ) { - setNodeRoles( { PanelRole, GrooveRole, FillRole, HandleRole } ); + setNodeRoles( { PanelRole, GrooveRole, FillRole, HandleRole, RippleRole } ); } QskSliderSkinlet::~QskSliderSkinlet() @@ -68,6 +68,11 @@ QRectF QskSliderSkinlet::subControlRect( const QskSkinnable* skinnable, return scaleRect( slider, contentsRect ); } + if ( subControl == QskSlider::Ripple ) + { + return rippleRect( slider, contentsRect ); + } + return Inherited::subControlRect( skinnable, contentsRect, subControl ); } @@ -97,6 +102,11 @@ QSGNode* QskSliderSkinlet::updateSubNode( { return updateBoxNode( slider, node, QskSlider::Handle ); } + + case RippleRole: + { + return updateBoxNode( slider, node, QskSlider::Ripple ); + } } return Inherited::updateSubNode( skinnable, nodeRole, node ); @@ -223,6 +233,18 @@ QRectF QskSliderSkinlet::handleRect( return handleRect; } +QRectF QskSliderSkinlet::rippleRect( + const QskSlider* slider, const QRectF& rect ) const +{ + auto r = handleRect( slider, rect ); + auto rippleSize = slider->strutSizeHint( QskSlider::Ripple ); + auto handleSize = slider->strutSizeHint( QskSlider::Handle ); + auto w = ( rippleSize.width() - handleSize.width() ) / 2, + h = ( rippleSize.height() - handleSize.height() ) / 2; + r = r.marginsAdded( { w, h, w, h } ); + return r; +} + QSizeF QskSliderSkinlet::sizeHint( const QskSkinnable* skinnable, Qt::SizeHint which, const QSizeF& ) const { diff --git a/src/controls/QskSliderSkinlet.h b/src/controls/QskSliderSkinlet.h index 1b49bb29..25c3ead2 100644 --- a/src/controls/QskSliderSkinlet.h +++ b/src/controls/QskSliderSkinlet.h @@ -23,6 +23,7 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet GrooveRole, FillRole, HandleRole, + RippleRole, RoleCount }; @@ -46,6 +47,7 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet QRectF fillRect( const QskSlider*, const QRectF& ) const; QRectF handleRect( const QskSlider*, const QRectF& ) const; QRectF scaleRect( const QskSlider*, const QRectF& ) const; + QRectF rippleRect( const QskSlider*, const QRectF& ) const; QRectF innerRect( const QskSlider*, const QRectF&, QskAspect::Subcontrol ) const; }; diff --git a/support/SkinnyNamespace.cpp b/support/SkinnyNamespace.cpp index 6878794e..f6e12307 100644 --- a/support/SkinnyNamespace.cpp +++ b/support/SkinnyNamespace.cpp @@ -20,7 +20,7 @@ #if defined( ENSURE_SKINS ) #include - #include + #include static void initSkins() { @@ -32,7 +32,7 @@ */ qskSkinManager->registerFactory( "SquiekFactory", new QskSquiekSkinFactory() ); - qskSkinManager->registerFactory( "MaterialFactory", new QskMaterialSkinFactory() ); + qskSkinManager->registerFactory( "Material3Factory", new QskMaterial3SkinFactory() ); qWarning() << "Couldn't find skin plugins, adding some manually."; } diff --git a/support/SkinnyPlugin.cpp b/support/SkinnyPlugin.cpp index e6718926..0b37eab7 100644 --- a/support/SkinnyPlugin.cpp +++ b/support/SkinnyPlugin.cpp @@ -37,7 +37,7 @@ static bool pluginPath = initPluginPath(); #include #include -#include +#include #include #include @@ -53,7 +53,7 @@ static void initSkins() */ qskSkinManager->registerFactory( "SquiekFactory", new QskSquiekSkinFactory() ); - qskSkinManager->registerFactory( "MaterialFactory", new QskMaterialSkinFactory() ); + qskSkinManager->registerFactory( "Material3Factory", new QskMaterial3SkinFactory() ); cout << "Couldn't find skin plugins, adding some manually." << endl; } diff --git a/support/support.pro b/support/support.pro index b02cb0d9..d7e9155a 100644 --- a/support/support.pro +++ b/support/support.pro @@ -41,6 +41,7 @@ ensure_skins { qskAddLibrary($${QSK_PLUGIN_DIR}/skins, squiekskin) qskAddLibrary($${QSK_PLUGIN_DIR}/skins, materialskin) + qskAddLibrary($${QSK_PLUGIN_DIR}/skins, material3skin) } fontconfig {