From 3aa320f233053ea14078bc9e050166a0f4088a0a Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sat, 26 Mar 2022 16:22:47 +0100 Subject: [PATCH 01/28] accepting hover events as default --- src/controls/QskTextInput.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/controls/QskTextInput.cpp b/src/controls/QskTextInput.cpp index 800b6de4..5a76f81d 100644 --- a/src/controls/QskTextInput.cpp +++ b/src/controls/QskTextInput.cpp @@ -295,6 +295,8 @@ QskTextInput::QskTextInput( QQuickItem* parent ) m_data->hasPanel = true; setPolishOnResize( true ); + + setAcceptHoverEvents( true ); setFocusPolicy( Qt::StrongFocus ); setFlag( QQuickItem::ItemAcceptsInputMethod ); From 7778baecc5f5cbc850be1dbce50a0801c45dbc98 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 27 Mar 2022 17:54:16 +0200 Subject: [PATCH 02/28] alpha -> opacity --- src/common/QskRgbValue.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/common/QskRgbValue.h b/src/common/QskRgbValue.h index 6fea8d95..9f7a3d9b 100644 --- a/src/common/QskRgbValue.h +++ b/src/common/QskRgbValue.h @@ -461,19 +461,19 @@ namespace QskRgb return ( rgb & ColorMask ) | ( ( static_cast< uint >( alpha ) & 0xffu ) << 24 ); } - inline QColor toTransparentF( const QColor& color, qreal alpha ) + inline QColor toTransparentF( const QColor& color, qreal opacity ) { - return toTransparent( color, qRound( alpha * 255 ) ); + return toTransparent( color, qRound( opacity * 255 ) ); } - inline QColor toTransparentF( Qt::GlobalColor color, qreal alpha ) + inline QColor toTransparentF( Qt::GlobalColor color, qreal opacity ) { - return toTransparent( QColor( color ), qRound( alpha * 255 ) ); + return toTransparent( QColor( color ), qRound( opacity * 255 ) ); } - inline constexpr QRgb toTransparentF( QRgb rgb, qreal alpha ) noexcept + inline constexpr QRgb toTransparentF( QRgb rgb, qreal opacity ) noexcept { - return toTransparent( rgb, qRound( alpha * 255 ) ); + return toTransparent( rgb, qRound( opacity * 255 ) ); } QSK_EXPORT QRgb lighter( QRgb, int factor = 150 ) noexcept; From 48a8a10b629498f10414089fdb720c1947e7cdc8 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 27 Mar 2022 19:05:05 +0200 Subject: [PATCH 03/28] avoid crashes, when failing loading a skin --- support/SkinnyShortcut.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/support/SkinnyShortcut.cpp b/support/SkinnyShortcut.cpp index 670405ca..582827fb 100644 --- a/support/SkinnyShortcut.cpp +++ b/support/SkinnyShortcut.cpp @@ -77,30 +77,31 @@ void SkinnyShortcut::enable( Types types ) void SkinnyShortcut::rotateSkin() { - const QStringList names = qskSkinManager->skinNames(); + const auto names = qskSkinManager->skinNames(); if ( names.size() <= 1 ) return; int index = names.indexOf( qskSetup->skinName() ); index = ( index + 1 ) % names.size(); - QskSkin* oldSkin = qskSetup->skin(); + auto oldSkin = qskSetup->skin(); if ( oldSkin->parent() == qskSetup ) oldSkin->setParent( nullptr ); // otherwise setSkin deletes it - QskSkin* newSkin = qskSetup->setSkin( names[ index ] ); + if ( auto newSkin = qskSetup->setSkin( names[ index ] ) ) + { + QskSkinTransition transition; - QskSkinTransition transition; + //transition.setMask( QskAspect::Color ); // Metrics are flickering -> TODO + transition.setSourceSkin( oldSkin ); + transition.setTargetSkin( newSkin ); + transition.setAnimation( 500 ); - //transition.setMask( QskAspect::Color ); // Metrics are flickering -> TODO - transition.setSourceSkin( oldSkin ); - transition.setTargetSkin( newSkin ); - transition.setAnimation( 500 ); + transition.process(); - transition.process(); - - if ( oldSkin->parent() == nullptr ) - delete oldSkin; + if ( oldSkin->parent() == nullptr ) + delete oldSkin; + } } void SkinnyShortcut::showBackground() From f68095a0d1796bdb71338354381814e87c5aee9d Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 27 Mar 2022 19:05:40 +0200 Subject: [PATCH 04/28] making code more readable --- src/common/QskBoxBorderColors.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/common/QskBoxBorderColors.cpp b/src/common/QskBoxBorderColors.cpp index 054696dd..cbb12e5d 100644 --- a/src/common/QskBoxBorderColors.cpp +++ b/src/common/QskBoxBorderColors.cpp @@ -172,8 +172,14 @@ QskBoxBorderColors QskBoxBorderColors::interpolated( for ( size_t i = 0; i < 4; i++ ) { - colors.m_gradients[ i ] = colors.m_gradients[ i ].interpolated( - to.m_gradients[ i ], ratio ); +#if 1 + /* + When one border has a width of 0 we would prefer to ignore + the color and use always use the other color. TODO ... + */ +#endif + auto& gradient = colors.m_gradients[ i ]; + gradient = gradient.interpolated( to.m_gradients[ i ], ratio ); } return colors; From 60e27536e8f106386388df9c79f06e3b8d59280e Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 27 Mar 2022 19:06:29 +0200 Subject: [PATCH 05/28] using QString::compare --- skins/material/QskMaterialSkinFactory.cpp | 2 +- skins/squiek/QskSquiekSkinFactory.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/skins/material/QskMaterialSkinFactory.cpp b/skins/material/QskMaterialSkinFactory.cpp index 1b68a4aa..40683a6a 100644 --- a/skins/material/QskMaterialSkinFactory.cpp +++ b/skins/material/QskMaterialSkinFactory.cpp @@ -24,7 +24,7 @@ QStringList QskMaterialSkinFactory::skinNames() const QskSkin* QskMaterialSkinFactory::createSkin( const QString& skinName ) { - if ( skinName.toLower() == materialSkinName ) + if ( QString::compare( skinName, materialSkinName, Qt::CaseInsensitive ) == 0 ) return new QskMaterialSkin(); return nullptr; diff --git a/skins/squiek/QskSquiekSkinFactory.cpp b/skins/squiek/QskSquiekSkinFactory.cpp index 16c27524..39074d24 100644 --- a/skins/squiek/QskSquiekSkinFactory.cpp +++ b/skins/squiek/QskSquiekSkinFactory.cpp @@ -24,7 +24,7 @@ QStringList QskSquiekSkinFactory::skinNames() const QskSkin* QskSquiekSkinFactory::createSkin( const QString& skinName ) { - if ( skinName.toLower() == squiekSkinName ) + if ( QString::compare( skinName, squiekSkinName, Qt::CaseInsensitive ) == 0 ) return new QskSquiekSkin(); return nullptr; From 105fdec8d7f31cbddd08d651520d8501d9765586 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 28 Mar 2022 20:15:54 +0200 Subject: [PATCH 06/28] no more page backgrounds - preparation for better themeing --- examples/gallery/Page.cpp | 18 ---------------- examples/gallery/Page.h | 7 ------- examples/gallery/label/LabelPage.cpp | 1 - examples/gallery/main.cpp | 21 ------------------- .../gallery/progressbar/ProgressBarPage.cpp | 2 -- examples/gallery/slider/SliderPage.cpp | 2 -- .../gallery/switchbutton/SwitchButtonPage.cpp | 2 -- 7 files changed, 53 deletions(-) diff --git a/examples/gallery/Page.cpp b/examples/gallery/Page.cpp index 0dbbfcf3..078d96b3 100644 --- a/examples/gallery/Page.cpp +++ b/examples/gallery/Page.cpp @@ -4,29 +4,11 @@ *****************************************************************************/ #include "Page.h" -#include Page::Page( Qt::Orientation orientation, QQuickItem* parent ) : QskLinearBox( orientation, parent ) - , m_gradient( QskRgb::GhostWhite ) { setMargins( 20 ); setPadding( 10 ); setSpacing( 10 ); } - -void Page::setGradient( const QskGradient& gradient ) -{ - if ( gradient != m_gradient ) - { - m_gradient = gradient; - - if ( parentItem() && isVisibleToParent() ) - parentItem()->update(); - } -} - -QskGradient Page::gradient() const -{ - return m_gradient; -} diff --git a/examples/gallery/Page.h b/examples/gallery/Page.h index f0404294..f8f8bf83 100644 --- a/examples/gallery/Page.h +++ b/examples/gallery/Page.h @@ -6,16 +6,9 @@ #pragma once #include -#include class Page : public QskLinearBox { public: Page( Qt::Orientation, QQuickItem* parent = nullptr ); - - void setGradient( const QskGradient& ); - QskGradient gradient() const; - - private: - QskGradient m_gradient; }; diff --git a/examples/gallery/label/LabelPage.cpp b/examples/gallery/label/LabelPage.cpp index 84f2c438..8e4a2813 100644 --- a/examples/gallery/label/LabelPage.cpp +++ b/examples/gallery/label/LabelPage.cpp @@ -67,7 +67,6 @@ namespace LabelPage::LabelPage( QQuickItem* parent ) : Page( Qt::Vertical, parent ) { - setGradient( QskRgb::AliceBlue ); setSpacing( 40 ); (void) new TextBox( this ); diff --git a/examples/gallery/main.cpp b/examples/gallery/main.cpp index 58e52f7a..838d9106 100644 --- a/examples/gallery/main.cpp +++ b/examples/gallery/main.cpp @@ -30,27 +30,6 @@ namespace setMargins( 10 ); setTabPosition( Qsk::Left ); setAutoFitTabs( true ); - - connect( this, &QskTabView::currentIndexChanged, - this, &TabView::updateViewPanel ); - } - - protected: - void aboutToShow() override - { - updateViewPanel(); - } - - private: - void updateViewPanel() - { - /* - We should have a better way to set individual colors - for each tab page background - */ - - if ( auto page = dynamic_cast< const ::Page* >( currentItem() ) ) - setGradientHint( QskTabView::Page, page->gradient() ); } }; } diff --git a/examples/gallery/progressbar/ProgressBarPage.cpp b/examples/gallery/progressbar/ProgressBarPage.cpp index 75fad19e..18985ecf 100644 --- a/examples/gallery/progressbar/ProgressBarPage.cpp +++ b/examples/gallery/progressbar/ProgressBarPage.cpp @@ -45,9 +45,7 @@ namespace ProgressBarPage::ProgressBarPage( QQuickItem* parent ) : Page( Qt::Horizontal, parent ) { - setGradient( QskRgb::AliceBlue ); setSpacing( 40 ); - populate(); } diff --git a/examples/gallery/slider/SliderPage.cpp b/examples/gallery/slider/SliderPage.cpp index 4de7c647..8e164a5c 100644 --- a/examples/gallery/slider/SliderPage.cpp +++ b/examples/gallery/slider/SliderPage.cpp @@ -13,8 +13,6 @@ SliderPage::SliderPage( QQuickItem* parentItem ) : Page( Qt::Vertical, parentItem ) { - setGradient( QskRgb::PeachPuff ); - setMargins( 10 ); setSpacing( 20 ); diff --git a/examples/gallery/switchbutton/SwitchButtonPage.cpp b/examples/gallery/switchbutton/SwitchButtonPage.cpp index 169dac95..1fab35b1 100644 --- a/examples/gallery/switchbutton/SwitchButtonPage.cpp +++ b/examples/gallery/switchbutton/SwitchButtonPage.cpp @@ -15,9 +15,7 @@ SwitchButtonPage::SwitchButtonPage( QQuickItem* parent ) : Page( Qt::Horizontal, parent ) { - setGradient( QskRgb::AliceBlue ); setSpacing( 40 ); - populate(); } From 5dae58fc44d12dd408ecb52db51df5e4a67a923a Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 28 Mar 2022 20:17:56 +0200 Subject: [PATCH 07/28] making code slightly more readable --- src/controls/QskSkinTransition.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/controls/QskSkinTransition.cpp b/src/controls/QskSkinTransition.cpp index 9b769199..04c38e4e 100644 --- a/src/controls/QskSkinTransition.cpp +++ b/src/controls/QskSkinTransition.cpp @@ -315,7 +315,9 @@ namespace for ( const auto& candidate : candidates ) { - if ( !candidate.aspect.isMetric() ) + const auto aspect = candidate.aspect; + + if ( !aspect.isMetric() ) { if ( !( control->flags() & QQuickItem::ItemHasContents ) ) { @@ -325,7 +327,7 @@ namespace } } - const auto subControl = candidate.aspect.subControl(); + const auto subControl = aspect.subControl(); if ( subControl != control->effectiveSubcontrol( subControl ) ) { // The control uses subcontrol redirection, so we can assume it @@ -350,7 +352,7 @@ namespace } } - auto a = candidate.aspect; + auto a = aspect; a.setStates( control->skinStates() ); const auto requestState = control->hintStatus( a ); @@ -361,30 +363,32 @@ namespace continue; } - if ( candidate.aspect != requestState.aspect ) + if ( aspect != requestState.aspect ) { // the aspect was resolved to something else continue; } - addAnimator( control->window(), candidate, animatorHint ); - storeUpdateInfo( control, candidate.aspect ); + addAnimator( control->window(), aspect, + candidate.from, candidate.to, animatorHint ); + + storeUpdateInfo( control, aspect ); } } - void addAnimator( QQuickWindow* window, - const AnimatorCandidate& candidate, QskAnimationHint animationHint ) + void addAnimator( QQuickWindow* window, const QskAspect aspect, + const QVariant& from, const QVariant& to, QskAnimationHint animationHint ) { - auto it = m_hintAnimatorMap.find( candidate.aspect ); + auto it = m_hintAnimatorMap.find( aspect ); if ( it != m_hintAnimatorMap.end() ) return; // already there - it = m_hintAnimatorMap.emplace( candidate.aspect, QskHintAnimator() ).first; + it = m_hintAnimatorMap.emplace( aspect, QskHintAnimator() ).first; auto& animator = it->second; - animator.setAspect( candidate.aspect ); - animator.setStartValue( candidate.from ); - animator.setEndValue( candidate.to ); + animator.setAspect( aspect ); + animator.setStartValue( from ); + animator.setEndValue( to ); animator.setDuration( animationHint.duration ); animator.setEasingCurve( animationHint.type ); From a38a4a101ef3654807fb0a4e4f491b6c09f35bdc Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 28 Mar 2022 20:33:42 +0200 Subject: [PATCH 08/28] more State operators --- src/common/QskAspect.h | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/common/QskAspect.h b/src/common/QskAspect.h index 94e5bd42..fc3a94d7 100644 --- a/src/common/QskAspect.h +++ b/src/common/QskAspect.h @@ -109,8 +109,18 @@ class QSK_EXPORT QskAspect constexpr QskAspect operator|( Type ) const noexcept; constexpr QskAspect operator|( Primitive ) const noexcept; constexpr QskAspect operator|( Placement ) const noexcept; + constexpr QskAspect operator|( State ) const noexcept; + QskAspect& operator|=( State ) noexcept; + + constexpr QskAspect operator&( State ) const noexcept; + QskAspect& operator&=( State ) noexcept; + constexpr QskAspect operator|( States ) const noexcept; + QskAspect& operator|=( States ) noexcept; + + constexpr QskAspect operator&( States ) const noexcept; + QskAspect& operator&=( States ) noexcept; constexpr QskAspect stateless() const noexcept; constexpr QskAspect trunk() const noexcept; @@ -283,12 +293,48 @@ inline constexpr QskAspect QskAspect::operator|( State state ) const noexcept m_bits.primitive, m_bits.placement, m_bits.states | state ); } +inline QskAspect& QskAspect::operator|=( State state ) noexcept +{ + m_bits.states |= state; + return *this; +} + +inline constexpr QskAspect QskAspect::operator&( State state ) const noexcept +{ + return QskAspect( m_bits.subControl, m_bits.type, m_bits.isAnimator, + m_bits.primitive, m_bits.placement, m_bits.states & state ); +} + +inline QskAspect& QskAspect::operator&=( State state ) noexcept +{ + m_bits.states &= state; + return *this; +} + inline constexpr QskAspect QskAspect::operator|( States states ) const noexcept { return QskAspect( m_bits.subControl, m_bits.type, m_bits.isAnimator, m_bits.primitive, m_bits.placement, m_bits.states | states ); } +inline QskAspect& QskAspect::operator|=( States states ) noexcept +{ + m_bits.states |= states; + return *this; +} + +inline constexpr QskAspect QskAspect::operator&( States states ) const noexcept +{ + return QskAspect( m_bits.subControl, m_bits.type, m_bits.isAnimator, + m_bits.primitive, m_bits.placement, m_bits.states & states ); +} + +inline QskAspect& QskAspect::operator&=( States states ) noexcept +{ + m_bits.states &= states; + return *this; +} + inline constexpr QskAspect QskAspect::stateless() const noexcept { return QskAspect( m_bits.subControl, m_bits.type, m_bits.isAnimator, From 1eae47aefac5238e9f85e9261e794721f56d1799 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 28 Mar 2022 21:28:56 +0200 Subject: [PATCH 09/28] tracking states of the aspects in a QskSkinHintTable --- src/controls/QskSkin.cpp | 17 ------------- src/controls/QskSkin.h | 3 --- src/controls/QskSkinHintTable.cpp | 31 +++++++++++------------ src/controls/QskSkinHintTable.h | 9 ++++--- src/controls/QskSkinnable.cpp | 41 ++++++------------------------- 5 files changed, 27 insertions(+), 74 deletions(-) diff --git a/src/controls/QskSkin.cpp b/src/controls/QskSkin.cpp index f99dc41a..85215d98 100644 --- a/src/controls/QskSkin.cpp +++ b/src/controls/QskSkin.cpp @@ -128,7 +128,6 @@ class QskSkin::PrivateData std::unordered_map< const QMetaObject*, SkinletData > skinletMap; QskSkinHintTable hintTable; - QskAspect::States stateMask = QskAspect::AllStates; std::unordered_map< int, QFont > fonts; std::unordered_map< int, QskColorFilter > graphicFilters; @@ -345,22 +344,6 @@ const int* QskSkin::dialogButtonLayout( Qt::Orientation orientation ) const return QPlatformDialogHelper::buttonLayout( orientation, policy ); } -void QskSkin::setStateMask( QskAspect::States mask ) -{ - for ( auto state : { QskControl::Disabled, QskControl::Hovered, QskControl::Focused } ) - { - if ( mask & state ) - m_data->stateMask |= state; - else - m_data->stateMask &= ~state; - } -} - -QskAspect::States QskSkin::stateMask() const -{ - return m_data->stateMask; -} - QskSkinlet* QskSkin::skinlet( const QMetaObject* metaObject ) { while ( metaObject ) diff --git a/src/controls/QskSkin.h b/src/controls/QskSkin.h index adeb2c54..723b0115 100644 --- a/src/controls/QskSkin.h +++ b/src/controls/QskSkin.h @@ -77,9 +77,6 @@ class QSK_EXPORT QskSkin : public QObject virtual const int* dialogButtonLayout( Qt::Orientation ) const; virtual QString dialogButtonText( int button ) const; - void setStateMask( QskAspect::States ); - QskAspect::States stateMask() const; - QskSkinlet* skinlet( const QMetaObject* ); const QskSkinHintTable& hintTable() const; diff --git a/src/controls/QskSkinHintTable.cpp b/src/controls/QskSkinHintTable.cpp index 9bac96f0..d43a4434 100644 --- a/src/controls/QskSkinHintTable.cpp +++ b/src/controls/QskSkinHintTable.cpp @@ -67,7 +67,7 @@ QskSkinHintTable::QskSkinHintTable() QskSkinHintTable::QskSkinHintTable( const QskSkinHintTable& other ) : m_hints( nullptr ) , m_animatorCount( other.m_animatorCount ) - , m_statefulCount( other.m_statefulCount ) + , m_states( other.m_states ) { if ( other.m_hints ) m_hints = new HintMap( *( other.m_hints ) ); @@ -81,7 +81,7 @@ QskSkinHintTable::~QskSkinHintTable() QskSkinHintTable& QskSkinHintTable::operator=( const QskSkinHintTable& other ) { m_animatorCount = other.m_animatorCount; - m_statefulCount = other.m_statefulCount; + m_states = other.m_states; if ( other.m_hints ) { @@ -126,11 +126,7 @@ bool QskSkinHintTable::setHint( QskAspect aspect, const QVariant& skinHint ) QSK_ASSERT_COUNTER( m_animatorCount ); } - if ( aspect.hasStates() ) - { - m_statefulCount++; - QSK_ASSERT_COUNTER( m_statefulCount ); - } + m_states |= aspect.states(); return true; } @@ -158,8 +154,7 @@ bool QskSkinHintTable::removeHint( QskAspect aspect ) if ( aspect.isAnimator() ) m_animatorCount--; - if ( aspect.hasStates() ) - m_statefulCount--; + // how to clear m_states ? TODO ... if ( m_hints->empty() ) { @@ -184,8 +179,7 @@ QVariant QskSkinHintTable::takeHint( QskAspect aspect ) if ( aspect.isAnimator() ) m_animatorCount--; - if ( aspect.hasStates() ) - m_statefulCount--; + // how to clear m_states ? TODO ... if ( m_hints->empty() ) { @@ -206,14 +200,14 @@ void QskSkinHintTable::clear() m_hints = nullptr; m_animatorCount = 0; - m_statefulCount = 0; + m_states = QskAspect::NoState; } const QVariant* QskSkinHintTable::resolvedHint( QskAspect aspect, QskAspect* resolvedAspect ) const { if ( m_hints != nullptr ) - return qskResolvedHint( aspect, *m_hints, resolvedAspect ); + return qskResolvedHint( aspect & m_states, *m_hints, resolvedAspect ); return nullptr; } @@ -223,7 +217,7 @@ QskAspect QskSkinHintTable::resolvedAspect( QskAspect aspect ) const QskAspect a; if ( m_hints != nullptr ) - qskResolvedHint( aspect, *m_hints, &a ); + qskResolvedHint( aspect & m_states, *m_hints, &a ); return a; } @@ -233,6 +227,8 @@ QskAspect QskSkinHintTable::resolvedAnimator( { if ( m_hints && m_animatorCount > 0 ) { + aspect &= m_states; + Q_FOREVER { auto it = m_hints->find( aspect ); @@ -268,15 +264,16 @@ bool QskSkinHintTable::setAnimation( bool QskSkinHintTable::isResolutionMatching( QskAspect aspect1, QskAspect aspect2 ) const { + // remove states we do not have early + aspect1 &= m_states; + aspect2 &= m_states; + if ( aspect1 == aspect2 ) return true; if ( aspect1.trunk() != aspect2.trunk() ) return false; - if ( !hasStates() ) - return false; - const auto a1 = aspect1; const auto a2 = aspect2; diff --git a/src/controls/QskSkinHintTable.h b/src/controls/QskSkinHintTable.h index c1e6a647..ac246376 100644 --- a/src/controls/QskSkinHintTable.h +++ b/src/controls/QskSkinHintTable.h @@ -40,9 +40,10 @@ class QSK_EXPORT QskSkinHintTable const std::unordered_map< QskAspect, QVariant >& hints() const; bool hasAnimators() const; - bool hasStates() const; bool hasHints() const; + QskAspect::States states() const; + void clear(); const QVariant* resolvedHint( QskAspect, @@ -62,7 +63,7 @@ class QSK_EXPORT QskSkinHintTable HintMap* m_hints = nullptr; unsigned short m_animatorCount = 0; - unsigned short m_statefulCount = 0; + QskAspect::States m_states; }; inline bool QskSkinHintTable::hasHints() const @@ -70,9 +71,9 @@ inline bool QskSkinHintTable::hasHints() const return m_hints != nullptr; } -inline bool QskSkinHintTable::hasStates() const +inline QskAspect::States QskSkinHintTable::states() const { - return m_statefulCount > 0; + return m_states; } inline bool QskSkinHintTable::hasAnimators() const diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 1268fcde..fba33948 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -940,23 +940,12 @@ const QVariant& QskSkinnable::storedHint( { const auto skin = effectiveSkin(); - // clearing all state bits not being handled from the skin - aspect.clearStates( ~skin->stateMask() ); - QskAspect resolvedAspect; const auto& localTable = m_data->hintTable; if ( localTable.hasHints() ) { - auto a = aspect; - - if ( !localTable.hasStates() ) - { - // we don't need to clear the state bits stepwise - a.clearStates(); - } - - if ( const QVariant* value = localTable.resolvedHint( a, &resolvedAspect ) ) + if ( const auto value = localTable.resolvedHint( aspect, &resolvedAspect ) ) { if ( status ) { @@ -972,10 +961,7 @@ const QVariant& QskSkinnable::storedHint( const auto& skinTable = skin->hintTable(); if ( skinTable.hasHints() ) { - auto a = aspect; - - const QVariant* value = skinTable.resolvedHint( a, &resolvedAspect ); - if ( value ) + if ( const auto value = skinTable.resolvedHint( aspect, &resolvedAspect ) ) { if ( status ) { @@ -993,8 +979,7 @@ const QVariant& QskSkinnable::storedHint( aspect.setSubControl( QskAspect::Control ); aspect.clearStates(); - value = skinTable.resolvedHint( aspect, &resolvedAspect ); - if ( value ) + if ( const auto value = skinTable.resolvedHint( aspect, &resolvedAspect ) ) { if ( status ) { @@ -1257,7 +1242,8 @@ void QskSkinnable::setSkinStates( QskAspect::States newStates ) if ( skin ) { - const auto mask = skin->stateMask(); + const auto mask = skin->hintTable().states() | m_data->hintTable.states(); + if ( ( newStates & mask ) == ( m_data->skinStates & mask ) ) { // the modified bits are not handled by the skin @@ -1297,24 +1283,13 @@ void QskSkinnable::setSkinStates( QskAspect::States newStates ) const auto primitive = static_cast< QskAspect::Primitive >( i ); aspect.setPrimitive( type, primitive ); - auto a1 = aspect | m_data->skinStates; - auto a2 = aspect | newStates; + const auto a1 = aspect | m_data->skinStates; + const auto a2 = aspect | newStates; bool doTransition = true; - if ( !m_data->hintTable.hasStates() ) - { - /* - The hints are found by stripping the state bits one by - one until a lookup into the hint table is successful. - So for deciding whether two aspects lead to the same hint - we can stop as soon as the aspects have the same state bits. - This way we can reduce the number of lookups significantly - for skinnables with many state bits. - - */ + if ( m_data->hintTable.states() == QskAspect::NoState ) doTransition = !skinTable.isResolutionMatching( a1, a2 ); - } if ( doTransition ) { From 81e2ea2920ae7308209bb96d940e41d4acd1cbb9 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 29 Mar 2022 08:08:06 +0200 Subject: [PATCH 10/28] qHash added --- src/common/QskAspect.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/common/QskAspect.h b/src/common/QskAspect.h index fc3a94d7..4b5f03bc 100644 --- a/src/common/QskAspect.h +++ b/src/common/QskAspect.h @@ -584,6 +584,11 @@ namespace std }; } +inline QskHashValue qHash( const QskAspect aspect, QskHashValue seed = 0 ) noexcept +{ + return qHash( aspect.value(), seed ); +} + #ifndef QT_NO_DEBUG_STREAM class QDebug; From aa3c01dee32e434695167e1300e750c30a25ab70 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 29 Mar 2022 08:08:46 +0200 Subject: [PATCH 11/28] making hintTable() public --- src/controls/QskSkinnable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controls/QskSkinnable.h b/src/controls/QskSkinnable.h index b73ea956..97324e2c 100644 --- a/src/controls/QskSkinnable.h +++ b/src/controls/QskSkinnable.h @@ -230,6 +230,8 @@ class QSK_EXPORT QskSkinnable bool resetGraphicRoleHint( QskAspect ); int graphicRoleHint( QskAspect, QskSkinHintStatus* = nullptr ) const; + const QskSkinHintTable& hintTable() const; + protected: virtual void updateNode( QSGNode* ); virtual bool isTransitionAccepted( QskAspect ) const; @@ -237,7 +239,6 @@ class QSK_EXPORT QskSkinnable virtual QskAspect::Subcontrol substitutedSubcontrol( QskAspect::Subcontrol ) const; QskSkinHintTable& hintTable(); - const QskSkinHintTable& hintTable() const; private: Q_DISABLE_COPY( QskSkinnable ) From 94a7ae45091da21bd25d0a6d06d761ea6bec84f5 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 29 Mar 2022 08:09:19 +0200 Subject: [PATCH 12/28] using qskEffectiveSkin --- src/controls/QskSkinnable.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index fba33948..15603d95 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -1318,12 +1318,7 @@ QskSkin* QskSkinnable::effectiveSkin() const if ( skin == nullptr ) { if ( const auto control = owningControl() ) - { - if ( auto window = qobject_cast< const QskWindow* >( control->window() ) ) - { - skin = window->skin(); - } - } + skin = qskEffectiveSkin( control->window() ); } return skin ? skin : qskSetup->skin(); From 848a22b2a25c4a639dd4427dd448e81f82e5ebb6 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 29 Mar 2022 11:14:23 +0200 Subject: [PATCH 13/28] interpolation between monochrome gradients improved --- src/common/QskGradient.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/common/QskGradient.cpp b/src/common/QskGradient.cpp index 4da8eff8..1b1415b8 100644 --- a/src/common/QskGradient.cpp +++ b/src/common/QskGradient.cpp @@ -499,6 +499,14 @@ QskGradient QskGradient::interpolated( return QskGradient( gradient->orientation(), stops ); } + if ( isMonochrome() && to.isMonochrome() ) + { + const auto c = QskRgb::interpolated( + m_stops[ 0 ].color(), to.m_stops[ 0 ].color(), value ); + + return QskGradient( to.orientation(), c, c ); + } + if ( isMonochrome() ) { // we can ignore our stops From 511c6ddcd3cb6bf484d4e8d61f9391d7a7ca820f Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 29 Mar 2022 11:15:08 +0200 Subject: [PATCH 14/28] try to convert if start/end values have different types --- src/controls/QskVariantAnimator.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/controls/QskVariantAnimator.cpp b/src/controls/QskVariantAnimator.cpp index 6372fbf0..fde0e00f 100644 --- a/src/controls/QskVariantAnimator.cpp +++ b/src/controls/QskVariantAnimator.cpp @@ -104,6 +104,25 @@ void QskVariantAnimator::setup() { m_interpolator = nullptr; + if ( m_startValue.userType() != m_endValue.userType() ) + { + /* + Convert one value so that the types are matching. + + As a side effect startValue()/endValue() won't return what had + been set setStartValue()/setEndValue() ! + */ + + if ( m_startValue.canConvert( m_endValue.userType() ) ) + { + m_startValue.convert( m_endValue.userType() ); + } + else if ( m_endValue.canConvert( m_startValue.userType() ) ) + { + m_endValue.convert( m_startValue.userType() ); + } + } + const auto type = m_startValue.userType(); if ( type == m_endValue.userType() ) { From baee63ea6b5f5891aae0e7ed1a336d0da1302986 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 30 Mar 2022 12:28:45 +0200 Subject: [PATCH 15/28] debug operators improved --- src/common/QskBoxBorderColors.cpp | 50 ++++++++++++++++++++++++++---- src/common/QskBoxBorderColors.h | 4 +-- src/common/QskBoxBorderMetrics.cpp | 21 +++++++++++-- src/common/QskBoxBorderMetrics.h | 7 +++++ src/common/QskGradient.cpp | 49 ++++++++++++++++++++++++++++- src/common/QskGradient.h | 1 + src/common/QskGradientStop.cpp | 7 ++++- src/common/QskMargins.h | 6 ++++ src/common/QskRgbValue.cpp | 26 ++++++++++++++++ src/common/QskRgbValue.h | 12 +++++++ 10 files changed, 170 insertions(+), 13 deletions(-) diff --git a/src/common/QskBoxBorderColors.cpp b/src/common/QskBoxBorderColors.cpp index cbb12e5d..9a201d51 100644 --- a/src/common/QskBoxBorderColors.cpp +++ b/src/common/QskBoxBorderColors.cpp @@ -165,6 +165,14 @@ bool QskBoxBorderColors::isMonochrome() const && m_gradients[ 3 ].isMonochrome(); } +bool QskBoxBorderColors::isValid() const +{ + return m_gradients[ 0 ].isValid() + || m_gradients[ 1 ].isValid() + || m_gradients[ 2 ].isValid() + || m_gradients[ 3 ].isValid(); +} + QskBoxBorderColors QskBoxBorderColors::interpolated( const QskBoxBorderColors& to, qreal ratio ) const { @@ -210,14 +218,44 @@ QDebug operator<<( QDebug debug, const QskBoxBorderColors& colors ) QDebugStateSaver saver( debug ); debug.nospace(); - debug << "BoxBorderColors" << '('; + debug << "BoxBorderColors"; - debug << " L" << colors.gradient( Qsk::Left ); - debug << ", T" << colors.gradient( Qsk::Top ); - debug << ", R" << colors.gradient( Qsk::Right ); - debug << ", B" << colors.gradient( Qsk::Bottom ); + if ( !colors.isValid() ) + { + debug << "()"; + } + else + { + debug << "( "; - debug << " )"; + if ( colors.isMonochrome() ) + { + const auto& gradient = colors.gradient( Qsk::Left ); + QskRgb::debugColor( debug, gradient.startColor() ); + } + else + { + const char prompts[] = { 'L', 'T', 'R', 'B' }; + + for ( int i = 0; i <= Qsk::Bottom; i++ ) + { + if ( i != 0 ) + debug << ", "; + + const auto& gradient = colors.gradient( + static_cast< Qsk::Position >( i ) ); + + debug << prompts[ i ] << ": "; + + if ( gradient.isValid() && gradient.isMonochrome() ) + QskRgb::debugColor( debug, gradient.startColor() ); + else + debug << gradient; + } + } + + debug << " )"; + } return debug; } diff --git a/src/common/QskBoxBorderColors.h b/src/common/QskBoxBorderColors.h index b6ca4b68..df670810 100644 --- a/src/common/QskBoxBorderColors.h +++ b/src/common/QskBoxBorderColors.h @@ -12,8 +12,6 @@ #include #include -class QDebug; - class QSK_EXPORT QskBoxBorderColors { public: @@ -53,6 +51,7 @@ class QSK_EXPORT QskBoxBorderColors bool isMonochrome() const; bool isVisible() const; + bool isValid() const; private: QskGradient m_gradients[ 4 ]; @@ -80,6 +79,7 @@ inline const QskGradient& QskBoxBorderColors::gradient( Qsk::Position position ) #ifndef QT_NO_DEBUG_STREAM +class QDebug; QSK_EXPORT QDebug operator<<( QDebug, const QskBoxBorderColors& ); #endif diff --git a/src/common/QskBoxBorderMetrics.cpp b/src/common/QskBoxBorderMetrics.cpp index 25de9fe6..3e9040bc 100644 --- a/src/common/QskBoxBorderMetrics.cpp +++ b/src/common/QskBoxBorderMetrics.cpp @@ -109,9 +109,24 @@ QDebug operator<<( QDebug debug, const QskBoxBorderMetrics& metrics ) QDebugStateSaver saver( debug ); debug.nospace(); - debug << "BoxBorder" << '('; - debug << metrics.sizeMode() << ',' << metrics.widths(); - debug << ')'; + debug << "BoxBorder" << "( "; + + if ( metrics.sizeMode() != Qt::AbsoluteSize ) + debug << metrics.sizeMode() << ", "; + + const auto& w = metrics.widths(); + + if ( metrics.isEquidistant() ) + { + debug << w.left(); + } + else + { + const char s[] = ", "; + debug << w.left() << s << w.top() << s << w.right() << s << w.bottom(); + } + + debug << " )"; return debug; } diff --git a/src/common/QskBoxBorderMetrics.h b/src/common/QskBoxBorderMetrics.h index 10b7961c..802d2c75 100644 --- a/src/common/QskBoxBorderMetrics.h +++ b/src/common/QskBoxBorderMetrics.h @@ -60,6 +60,8 @@ class QSK_EXPORT QskBoxBorderMetrics static QVariant interpolate( const QskBoxBorderMetrics&, const QskBoxBorderMetrics&, qreal progress ); + constexpr bool isEquidistant() const noexcept; + private: QskMargins m_widths; Qt::SizeMode m_sizeMode; @@ -115,6 +117,11 @@ inline constexpr bool QskBoxBorderMetrics::isNull() const noexcept return m_widths.isNull(); } +inline constexpr bool QskBoxBorderMetrics::isEquidistant() const noexcept +{ + return m_widths.isEquidistant(); +} + inline constexpr const QskMargins& QskBoxBorderMetrics::widths() const noexcept { return m_widths; diff --git a/src/common/QskGradient.cpp b/src/common/QskGradient.cpp index 1b1415b8..49be2f78 100644 --- a/src/common/QskGradient.cpp +++ b/src/common/QskGradient.cpp @@ -229,6 +229,11 @@ QskGradient::QskGradient( Orientation orientation, const QskGradientStops& stops setStops( stops ); } +QskGradient::QskGradient( Qt::Orientation orientation, QGradient::Preset preset ) + : QskGradient( qskOrientation( orientation ), preset ) +{ +} + QskGradient::QskGradient( Orientation orientation, QGradient::Preset preset ) : QskGradient( orientation ) { @@ -632,7 +637,49 @@ void QskGradient::updateStatusBits() const QDebug operator<<( QDebug debug, const QskGradient& gradient ) { - debug << "GR:" << gradient.orientation() << gradient.stops().count(); + QDebugStateSaver saver( debug ); + debug.nospace(); + + debug << "Gradient"; + + if ( !gradient.isValid() ) + { + debug << "()"; + } + else + { + debug << "( "; + + if ( gradient.isMonochrome() ) + { + QskRgb::debugColor( debug, gradient.startColor() ); + } + else + { + const char o[] = { 'H', 'V', 'D' }; + debug << o[ gradient.orientation() ] << ", "; + + if ( gradient.stops().count() == 2 ) + { + QskRgb::debugColor( debug, gradient.startColor() ); + debug << ", "; + QskRgb::debugColor( debug, gradient.endColor() ); + } + else + { + const auto& s = gradient.stops(); + for ( int i = 0; i < s.count(); i++ ) + { + if ( i != 0 ) + debug << ", "; + + debug << s[i]; + } + } + } + debug << " )"; + } + return debug; } diff --git a/src/common/QskGradient.h b/src/common/QskGradient.h index 75005926..be90ad5a 100644 --- a/src/common/QskGradient.h +++ b/src/common/QskGradient.h @@ -52,6 +52,7 @@ class QSK_EXPORT QskGradient QskGradient( Qt::Orientation, const QVector< QskGradientStop >& ); QskGradient( Qt::Orientation, const QColor&, const QColor& ); + QskGradient( Qt::Orientation, QGradient::Preset ); QskGradient( Orientation, const QVector< QskGradientStop >& ); QskGradient( Orientation, const QColor&, const QColor& ); diff --git a/src/common/QskGradientStop.cpp b/src/common/QskGradientStop.cpp index 530a2a1d..ffef7d97 100644 --- a/src/common/QskGradientStop.cpp +++ b/src/common/QskGradientStop.cpp @@ -78,7 +78,12 @@ QColor QskGradientStop::interpolated( QDebug operator<<( QDebug debug, const QskGradientStop& stop ) { - debug << stop.position() << ": " << stop.color(); + QDebugStateSaver saver( debug ); + debug.nospace(); + + debug << stop.position() << ": "; + QskRgb::debugColor( debug, stop.color() ); + return debug; } diff --git a/src/common/QskMargins.h b/src/common/QskMargins.h index e90c9338..3a3bb962 100644 --- a/src/common/QskMargins.h +++ b/src/common/QskMargins.h @@ -61,6 +61,7 @@ class QSK_EXPORT QskMargins : public QMarginsF QskMargins interpolated( const QskMargins&, qreal progress ) const noexcept; constexpr bool isExpanding() const noexcept; + constexpr bool isEquidistant() const noexcept; static QVariant interpolate( const QskMargins&, const QskMargins&, qreal progress ) noexcept; @@ -181,6 +182,11 @@ constexpr inline qreal QskMargins::height() const noexcept return top() + bottom(); } +inline constexpr bool QskMargins::isEquidistant() const noexcept +{ + return ( left() == top() ) && ( left() == right() ) && ( left() == bottom() ); +} + Q_DECLARE_TYPEINFO( QskMargins, Q_MOVABLE_TYPE ); Q_DECLARE_METATYPE( QskMargins ) diff --git a/src/common/QskRgbValue.cpp b/src/common/QskRgbValue.cpp index 49a87f96..7b4c0b8c 100644 --- a/src/common/QskRgbValue.cpp +++ b/src/common/QskRgbValue.cpp @@ -172,3 +172,29 @@ QRgb QskRgb::darker( QRgb rgb, int factor ) noexcept return QColor::fromRgba( rgb ).darker( factor ).rgba(); } +#ifndef QT_NO_DEBUG_STREAM + +#include + +void QskRgb::debugColor( QDebug debug, const QColor& color ) +{ + debugColor( debug, color.rgba() ); +} + +void QskRgb::debugColor( QDebug debug, QRgb rgb ) +{ + QDebugStateSaver saver( debug ); + debug.nospace(); + + debug << '['; + + debug << qRed( rgb ) << "r," << qGreen( rgb ) << "g," + << qBlue( rgb ) << 'b'; + + if ( qAlpha( rgb ) != 255 ) + debug << ',' << qAlpha( rgb ) << 'a'; + + debug << ']'; +} + +#endif diff --git a/src/common/QskRgbValue.h b/src/common/QskRgbValue.h index 9f7a3d9b..8a6059de 100644 --- a/src/common/QskRgbValue.h +++ b/src/common/QskRgbValue.h @@ -480,4 +480,16 @@ namespace QskRgb QSK_EXPORT QRgb darker( QRgb, int factor = 200 ) noexcept; } +#ifndef QT_NO_DEBUG_STREAM + +class QDebug; + +namespace QskRgb +{ + QSK_EXPORT void debugColor( QDebug, const QColor& ); + QSK_EXPORT void debugColor( QDebug, QRgb ); +} + +#endif + #endif From 7d0092ccb39cd4d8dcf65ca8722d64c11d0c8aca Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 30 Mar 2022 18:21:31 +0200 Subject: [PATCH 16/28] QskStateCombination operators added --- src/common/QskStateCombination.cpp | 14 -------------- src/common/QskStateCombination.h | 14 +++++++++++++- src/src.pro | 1 - 3 files changed, 13 insertions(+), 16 deletions(-) delete mode 100644 src/common/QskStateCombination.cpp diff --git a/src/common/QskStateCombination.cpp b/src/common/QskStateCombination.cpp deleted file mode 100644 index 07a7b481..00000000 --- a/src/common/QskStateCombination.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the QSkinny License, Version 1.0 - *****************************************************************************/ - -#include "QskStateCombination.h" - -static void qskRegisterStateCombination() -{ - qRegisterMetaType< QskStateCombination >(); -} - -Q_CONSTRUCTOR_FUNCTION( qskRegisterStateCombination ) - diff --git a/src/common/QskStateCombination.h b/src/common/QskStateCombination.h index 8393c90b..13d64e22 100644 --- a/src/common/QskStateCombination.h +++ b/src/common/QskStateCombination.h @@ -21,6 +21,9 @@ class QSK_EXPORT QskStateCombination constexpr QskStateCombination( QskAspect::States = QskAspect::States() ) noexcept; constexpr QskStateCombination( Type, QskAspect::States = QskAspect::States() ) noexcept; + constexpr bool operator==( QskStateCombination ) const noexcept; + constexpr bool operator!=( QskStateCombination ) const noexcept; + constexpr bool isNull() const noexcept; void setType( Type ) noexcept; @@ -36,7 +39,6 @@ class QSK_EXPORT QskStateCombination }; Q_DECLARE_TYPEINFO( QskStateCombination, Q_MOVABLE_TYPE ); -Q_DECLARE_METATYPE( QskStateCombination ) constexpr inline QskStateCombination::QskStateCombination( QskAspect::State state ) noexcept @@ -90,4 +92,14 @@ constexpr inline QskAspect::States QskStateCombination::states() const noexcept return m_states; } +constexpr bool QskStateCombination::operator==( QskStateCombination other ) const noexcept +{ + return ( m_type == other.m_type ) && ( m_states == other.m_states ); +} + +constexpr bool QskStateCombination::operator!=( QskStateCombination other ) const noexcept +{ + return !( *this == other ); +} + #endif diff --git a/src/src.pro b/src/src.pro index a25be7da..0c00a0ec 100644 --- a/src/src.pro +++ b/src/src.pro @@ -63,7 +63,6 @@ SOURCES += \ common/QskScaleTickmarks.cpp \ common/QskShadowMetrics.cpp \ common/QskSizePolicy.cpp \ - common/QskStateCombination.cpp \ common/QskTextColors.cpp \ common/QskTextOptions.cpp From f991a21a0a1f1dedde3dea0192e5803eb2780257 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 30 Mar 2022 18:30:22 +0200 Subject: [PATCH 17/28] QMetaType definitions added --- src/common/QskArcMetrics.cpp | 4 +++ src/common/QskBoxBorderColors.cpp | 24 ++++++++++++++++++ src/common/QskBoxBorderColors.h | 39 ++++++++++++++++++++++++++++++ src/common/QskBoxBorderMetrics.cpp | 4 +++ src/common/QskBoxShapeMetrics.cpp | 4 +++ src/common/QskGradient.cpp | 4 +++ src/common/QskGradientStop.cpp | 4 +++ src/common/QskIntervalF.cpp | 4 +++ src/common/QskScaleTickmarks.cpp | 4 +++ src/common/QskShadowMetrics.cpp | 4 +++ 10 files changed, 95 insertions(+) diff --git a/src/common/QskArcMetrics.cpp b/src/common/QskArcMetrics.cpp index 991b075d..44d90fde 100644 --- a/src/common/QskArcMetrics.cpp +++ b/src/common/QskArcMetrics.cpp @@ -11,6 +11,10 @@ static void qskRegisterArcMetrics() { qRegisterMetaType< QskArcMetrics >(); + +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QMetaType::registerEqualsComparator< QskArcMetrics >(); +#endif } Q_CONSTRUCTOR_FUNCTION( qskRegisterArcMetrics ) diff --git a/src/common/QskBoxBorderColors.cpp b/src/common/QskBoxBorderColors.cpp index 9a201d51..80493b20 100644 --- a/src/common/QskBoxBorderColors.cpp +++ b/src/common/QskBoxBorderColors.cpp @@ -13,6 +13,10 @@ static void qskRegisterBoxBorderColors() { qRegisterMetaType< QskBoxBorderColors >(); +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QMetaType::registerEqualsComparator< QskBoxBorderColors >(); +#endif + QMetaType::registerConverter< QColor, QskBoxBorderColors >( []( const QColor& color ) { return QskBoxBorderColors( color ); } ); @@ -110,6 +114,26 @@ void QskBoxBorderColors::setGradientAt( Qt::Edges edges, const QskGradient& grad m_gradients[ Qsk::Bottom ] = gradient; } +void QskBoxBorderColors::setLeft( const QskGradient& gradient ) +{ + m_gradients[ Qsk::Left ] = gradient; +} + +void QskBoxBorderColors::setTop( const QskGradient& gradient ) +{ + m_gradients[ Qsk::Top ] = gradient; +} + +void QskBoxBorderColors::setRight( const QskGradient& gradient ) +{ + m_gradients[ Qsk::Right ] = gradient; +} + +void QskBoxBorderColors::setBottom( const QskGradient& gradient ) +{ + m_gradients[ Qsk::Bottom ] = gradient; +} + const QskGradient& QskBoxBorderColors::gradientAt( Qt::Edge edge ) const { switch ( edge ) diff --git a/src/common/QskBoxBorderColors.h b/src/common/QskBoxBorderColors.h index df670810..6011c2d9 100644 --- a/src/common/QskBoxBorderColors.h +++ b/src/common/QskBoxBorderColors.h @@ -14,6 +14,13 @@ class QSK_EXPORT QskBoxBorderColors { + Q_GADGET + + Q_PROPERTY( QskGradient left READ left WRITE setLeft ) + Q_PROPERTY( QskGradient top READ top WRITE setTop ) + Q_PROPERTY( QskGradient right READ right WRITE setRight ) + Q_PROPERTY( QskGradient bottom READ bottom WRITE setBottom ) + public: QskBoxBorderColors(); @@ -42,6 +49,18 @@ class QSK_EXPORT QskBoxBorderColors void setGradientAt( Qt::Edges, const QskGradient& ); const QskGradient& gradientAt( Qt::Edge ) const; + void setLeft( const QskGradient& ); + const QskGradient& left() const; + + void setTop( const QskGradient& ); + const QskGradient& top() const; + + void setRight( const QskGradient& ); + const QskGradient& right() const; + + void setBottom( const QskGradient& ); + const QskGradient& bottom() const; + QskBoxBorderColors interpolated( const QskBoxBorderColors&, qreal value ) const; static QVariant interpolate( const QskBoxBorderColors&, @@ -77,6 +96,26 @@ inline const QskGradient& QskBoxBorderColors::gradient( Qsk::Position position ) return m_gradients[ position ]; } +inline const QskGradient& QskBoxBorderColors::left() const +{ + return m_gradients[ Qsk::Left ]; +} + +inline const QskGradient& QskBoxBorderColors::top() const +{ + return m_gradients[ Qsk::Top ]; +} + +inline const QskGradient& QskBoxBorderColors::right() const +{ + return m_gradients[ Qsk::Right ]; +} + +inline const QskGradient& QskBoxBorderColors::bottom() const +{ + return m_gradients[ Qsk::Bottom ]; +} + #ifndef QT_NO_DEBUG_STREAM class QDebug; diff --git a/src/common/QskBoxBorderMetrics.cpp b/src/common/QskBoxBorderMetrics.cpp index 3e9040bc..18178062 100644 --- a/src/common/QskBoxBorderMetrics.cpp +++ b/src/common/QskBoxBorderMetrics.cpp @@ -12,6 +12,10 @@ static void qskRegisterBoxBorderMetrics() { qRegisterMetaType< QskBoxBorderMetrics >(); +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QMetaType::registerEqualsComparator< QskBoxBorderMetrics >(); +#endif + QMetaType::registerConverter< QskMargins, QskBoxBorderMetrics >( []( const QskMargins& margins ) { return QskBoxBorderMetrics( margins ); } ); diff --git a/src/common/QskBoxShapeMetrics.cpp b/src/common/QskBoxShapeMetrics.cpp index 09e9cc70..17c21be1 100644 --- a/src/common/QskBoxShapeMetrics.cpp +++ b/src/common/QskBoxShapeMetrics.cpp @@ -14,6 +14,10 @@ static void qskRegisterBoxShapeMetrics() { qRegisterMetaType< QskBoxShapeMetrics >(); +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QMetaType::registerEqualsComparator< QskBoxShapeMetrics >(); +#endif + QMetaType::registerConverter< int, QskBoxShapeMetrics >( []( int radius ) { return QskBoxShapeMetrics( radius ); } ); diff --git a/src/common/QskGradient.cpp b/src/common/QskGradient.cpp index 49be2f78..82661437 100644 --- a/src/common/QskGradient.cpp +++ b/src/common/QskGradient.cpp @@ -15,6 +15,10 @@ static void qskRegisterGradient() { qRegisterMetaType< QskGradient >(); +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QMetaType::registerEqualsComparator< QskGradient >(); +#endif + QMetaType::registerConverter< QColor, QskGradient >( []( const QColor& color ) { return QskGradient( color ); } ); } diff --git a/src/common/QskGradientStop.cpp b/src/common/QskGradientStop.cpp index ffef7d97..48dbdac2 100644 --- a/src/common/QskGradientStop.cpp +++ b/src/common/QskGradientStop.cpp @@ -14,6 +14,10 @@ static void qskRegisterGradientStop() { qRegisterMetaType< QskGradientStop >(); + +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QMetaType::registerEqualsComparator< QskGradientStop >(); +#endif } Q_CONSTRUCTOR_FUNCTION( qskRegisterGradientStop ) diff --git a/src/common/QskIntervalF.cpp b/src/common/QskIntervalF.cpp index a27a83c8..f4b19d38 100644 --- a/src/common/QskIntervalF.cpp +++ b/src/common/QskIntervalF.cpp @@ -12,6 +12,10 @@ static void qskRegisterIntervalF() { qRegisterMetaType< QskIntervalF >(); + +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QMetaType::registerEqualsComparator< QskIntervalF >(); +#endif } Q_CONSTRUCTOR_FUNCTION( qskRegisterIntervalF ) diff --git a/src/common/QskScaleTickmarks.cpp b/src/common/QskScaleTickmarks.cpp index 836fc474..65f67089 100644 --- a/src/common/QskScaleTickmarks.cpp +++ b/src/common/QskScaleTickmarks.cpp @@ -9,6 +9,10 @@ static void qskRegisterTickmarks() { qRegisterMetaType< QskScaleTickmarks >(); + +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QMetaType::registerEqualsComparator< QskScaleTickmarks >(); +#endif } Q_CONSTRUCTOR_FUNCTION( qskRegisterTickmarks ) diff --git a/src/common/QskShadowMetrics.cpp b/src/common/QskShadowMetrics.cpp index 37b951b0..384104d3 100644 --- a/src/common/QskShadowMetrics.cpp +++ b/src/common/QskShadowMetrics.cpp @@ -12,6 +12,10 @@ static void qskRegisterShadowMetrics() { qRegisterMetaType< QskShadowMetrics >(); + +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QMetaType::registerEqualsComparator< QskShadowMetrics >(); +#endif } Q_CONSTRUCTOR_FUNCTION( qskRegisterShadowMetrics ) From 27ee0fe42391ba7e05de931a34be1f622776af52 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 31 Mar 2022 12:25:24 +0200 Subject: [PATCH 18/28] using QVariant::metaType --- src/controls/QskSkinnable.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 15603d95..1aca8b64 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -41,12 +41,11 @@ static inline bool qskIsControl( const QskSkinnable* skinnable ) static inline QVariant qskTypedNullValue( const QVariant& value ) { #if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) - const auto vType = static_cast< QMetaType >( value.userType() ); + return QVariant( value.metaType() ); #else - const auto vType = value.userType(); + return QVariant( value.userType(), nullptr ); #endif - return QVariant( vType, nullptr ); } static inline bool qskSetFlag( QskSkinnable* skinnable, From e2d6823927aab0f5cace664648fa849f092a3617 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 31 Mar 2022 18:09:03 +0200 Subject: [PATCH 19/28] skin transition heavily changed --- src/controls/QskSkinHintTable.cpp | 30 - src/controls/QskSkinHintTable.h | 6 +- src/controls/QskSkinTransition.cpp | 972 ++++++++++++++-------------- src/controls/QskSkinnable.cpp | 28 +- src/controls/QskVariantAnimator.cpp | 123 +++- src/controls/QskVariantAnimator.h | 3 + 6 files changed, 590 insertions(+), 572 deletions(-) diff --git a/src/controls/QskSkinHintTable.cpp b/src/controls/QskSkinHintTable.cpp index d43a4434..7b654c65 100644 --- a/src/controls/QskSkinHintTable.cpp +++ b/src/controls/QskSkinHintTable.cpp @@ -64,41 +64,11 @@ QskSkinHintTable::QskSkinHintTable() { } -QskSkinHintTable::QskSkinHintTable( const QskSkinHintTable& other ) - : m_hints( nullptr ) - , m_animatorCount( other.m_animatorCount ) - , m_states( other.m_states ) -{ - if ( other.m_hints ) - m_hints = new HintMap( *( other.m_hints ) ); -} - QskSkinHintTable::~QskSkinHintTable() { delete m_hints; } -QskSkinHintTable& QskSkinHintTable::operator=( const QskSkinHintTable& other ) -{ - m_animatorCount = other.m_animatorCount; - m_states = other.m_states; - - if ( other.m_hints ) - { - if ( m_hints == nullptr ) - m_hints = new HintMap(); - - *m_hints = *other.m_hints; - } - else - { - delete m_hints; - m_hints = nullptr; - } - - return *this; -} - const std::unordered_map< QskAspect, QVariant >& QskSkinHintTable::hints() const { if ( m_hints ) diff --git a/src/controls/QskSkinHintTable.h b/src/controls/QskSkinHintTable.h index ac246376..9ae56be9 100644 --- a/src/controls/QskSkinHintTable.h +++ b/src/controls/QskSkinHintTable.h @@ -17,12 +17,8 @@ class QSK_EXPORT QskSkinHintTable { public: QskSkinHintTable(); - QskSkinHintTable( const QskSkinHintTable& other ); - ~QskSkinHintTable(); - QskSkinHintTable& operator=( const QskSkinHintTable& ); - bool setAnimation( QskAspect, QskAnimationHint ); QskAnimationHint animation( QskAspect ) const; @@ -57,6 +53,8 @@ class QSK_EXPORT QskSkinHintTable bool isResolutionMatching( QskAspect, QskAspect ) const; private: + Q_DISABLE_COPY( QskSkinHintTable ) + static const QVariant invalidHint; typedef std::unordered_map< QskAspect, QVariant > HintMap; diff --git a/src/controls/QskSkinTransition.cpp b/src/controls/QskSkinTransition.cpp index 04c38e4e..b96b6753 100644 --- a/src/controls/QskSkinTransition.cpp +++ b/src/controls/QskSkinTransition.cpp @@ -20,6 +20,51 @@ #include #include +static void qskAddCandidates( const QskSkinTransition::Type mask, + const QskSkin* skin, QSet< QskAspect >& candidates ) +{ + for ( const auto& entry : skin->hintTable().hints() ) + { + const auto aspect = entry.first.trunk(); + + if ( aspect.isAnimator() ) + continue; + + bool isCandidate = false; + + switch( aspect.type() ) + { + case QskAspect::Flag: + { + if ( aspect.flagPrimitive() == QskAspect::GraphicRole ) + { + isCandidate = mask & QskSkinTransition::Color; + } +#if 0 + else if ( aspect.flagPrimitive() == QskAspect::FontRole ) + { + isCandidate = mask & QskSkinTransition::Metric; + } +#endif + break; + } + case QskAspect::Color: + { + isCandidate = mask & QskSkinTransition::Color; + break; + } + case QskAspect::Metric: + { + isCandidate = mask & QskSkinTransition::Metric; + break; + } + } + + if ( isCandidate ) + candidates += aspect; + } +} + namespace { class UpdateInfo @@ -40,479 +85,85 @@ namespace int updateModes; }; - class AnimatorCandidate + class HintAnimator : public QskHintAnimator { public: - AnimatorCandidate() = default; - - inline AnimatorCandidate( QskAspect aspect, - const QVariant& from, const QVariant& to ) - : aspect( aspect ) - , from( from ) - , to( to ) + inline HintAnimator( const QskControl* control, const QskAspect aspect, + const QVariant& value1, const QVariant& value2, QskAnimationHint hint ) { - } + setAspect( aspect ); + setStartValue( value1 ); + setEndValue( value2 ); - QskAspect aspect; - QVariant from; - QVariant to; + setDuration( hint.duration ); + setEasingCurve( hint.type ); + setUpdateFlags( hint.updateFlags ); + + setWindow( control->window() ); + } }; -} -static QVector< AnimatorCandidate > qskAnimatorCandidates( - QskSkinTransition::Type mask, - const QskSkinHintTable& oldTable, - const std::unordered_map< int, QskColorFilter >& oldFilters, - const QskSkinHintTable& newTable, - const std::unordered_map< int, QskColorFilter >& newFilters ) -{ - // building a list of candidates for animations by comparing - // the old/new set of skin hints - - const QskColorFilter noFilter; - QVector< AnimatorCandidate > candidates; - - if ( !oldTable.hasHints() ) - return candidates; - - for ( const auto& entry : newTable.hints() ) - { - const auto aspect = entry.first; - - if ( aspect.isAnimator() ) - continue; - - const auto type = aspect.type(); - - if ( type == QskAspect::Flag ) - { - switch ( aspect.flagPrimitive() ) - { - case QskAspect::GraphicRole: - { - if ( !( mask & QskSkinTransition::Color ) ) - continue; - - int role1 = 0; - - const auto value = oldTable.resolvedHint( aspect ); - if ( value ) - role1 = value->toInt(); - - const int role2 = entry.second.toInt(); - - /* - When the role is the same we already have the animators - for the graphic filter table running - */ - if ( role1 != role2 ) - { - const auto it1 = oldFilters.find( role1 ); - const auto it2 = newFilters.find( role2 ); - - if ( it1 != oldFilters.end() || it2 != newFilters.end() ) - { - const auto& f1 = ( it1 != oldFilters.end() ) ? it1->second : noFilter; - const auto& f2 = ( it2 != newFilters.end() ) ? it2->second : noFilter; - - if ( f1 != f2 ) - { - candidates += AnimatorCandidate( aspect, - QVariant::fromValue( f1 ), QVariant::fromValue( f2 ) ); - } - } - } - break; - } - case QskAspect::FontRole: - { - if ( !( mask & QskSkinTransition::Metric ) ) - continue; - - break; - } - default: - ; - } - } - else - { - if ( ( ( type == QskAspect::Color ) && ( mask & QskSkinTransition::Color ) ) || - ( ( type == QskAspect::Metric ) && ( mask & QskSkinTransition::Metric ) ) ) - { - auto value = oldTable.resolvedHint( aspect ); - if ( value == nullptr && aspect.subControl() != QskAspect::Control ) - { - auto a = aspect; - a.setSubControl( QskAspect::Control ); - a.clearStates(); - value = oldTable.resolvedHint( a ); - } - - /* - We are missing transitions, when a hint in newTable - gets resolved from QskControl. TODO ... - */ - if ( value && *value != entry.second ) - candidates += AnimatorCandidate( aspect, *value, entry.second ); - } - } - } - - return candidates; -} - -namespace -{ - class AnimatorGroup + class WindowAnimator { public: - AnimatorGroup( QQuickWindow* window = nullptr ) - : m_window( window ) - { - } + WindowAnimator( QQuickWindow* = nullptr ); - inline const QQuickWindow* window() const - { - return m_window; - } + const QQuickWindow* window() const; - void start() - { - for ( auto& it : m_hintAnimatorMap ) - it.second.start(); + void start(); + bool isRunning() const; - for ( auto& it : m_graphicFilterAnimatorMap ) - it.second.start(); - } + QVariant animatedHint( QskAspect ) const; + QVariant animatedGraphicFilter( int graphicRole ) const; - bool isRunning() const - { - if ( !m_hintAnimatorMap.empty() ) - { - const auto& animator = m_hintAnimatorMap.begin()->second; - if ( animator.isRunning() ) - return true; - } + void addGraphicFilterAnimators( const QskAnimationHint&, + const QskSkin*, const QskSkin* ); - if ( !m_graphicFilterAnimatorMap.empty() ) - { - const auto& animator = m_graphicFilterAnimatorMap.begin()->second; - if ( animator.isRunning() ) - return true; - } + void addItemAspects( QQuickItem*, + const QskAnimationHint&, const QSet< QskAspect >&, + const QskSkin*, const QskSkin* ); - return false; - } - - inline QVariant animatedHint( QskAspect aspect ) const - { - auto it = m_hintAnimatorMap.find( aspect ); - if ( it != m_hintAnimatorMap.cend() ) - { - const auto& animator = it->second; - if ( animator.isRunning() ) - return animator.currentValue(); - } - - return QVariant(); - } - - inline QVariant animatedGraphicFilter( int graphicRole ) const - { - auto it = m_graphicFilterAnimatorMap.find( graphicRole ); - if ( it != m_graphicFilterAnimatorMap.cend() ) - { - const auto& animator = it->second; - if ( animator.isRunning() ) - return animator.currentValue(); - } - - return QVariant(); - } - - void addGraphicFilterAnimators( - const QskAnimationHint& animatorHint, - const std::unordered_map< int, QskColorFilter >& oldFilters, - const std::unordered_map< int, QskColorFilter >& newFilters ) - { - const QskColorFilter noFilter; - - for ( auto it2 = newFilters.begin(); it2 != newFilters.end(); ++it2 ) - { - auto it1 = oldFilters.find( it2->first ); - if ( it1 == oldFilters.cend() ) - it1 = oldFilters.find( 0 ); - - const auto& f1 = ( it1 != oldFilters.cend() ) ? it1->second : noFilter; - const auto& f2 = it2->second; - - if ( f1 != f2 ) - { - QskVariantAnimator animator; - animator.setWindow( m_window ); - animator.setDuration( animatorHint.duration ); - animator.setEasingCurve( animatorHint.type ); - animator.setStartValue( QVariant::fromValue( f1 ) ); - animator.setEndValue( QVariant::fromValue( f2 ) ); - - m_graphicFilterAnimatorMap.emplace( it2->first, animator ); - } - } - } - - void addAnimators( QQuickItem* item, const QskAnimationHint& animatorHint, - const QVector< AnimatorCandidate >& candidates, QskSkin* skin ) - { - if ( !item->isVisible() ) - return; - - if ( auto control = qskControlCast( item ) ) - { - if ( control->isInitiallyPainted() && ( skin == control->effectiveSkin() ) ) - { - addControlAnimators( control, animatorHint, candidates ); -#if 1 - /* - As it is hard to identify which controls depend on the animated - graphic filters we schedule an initial update and let the - controls do the rest: see QskSkinnable::effectiveGraphicFilter - */ - control->update(); -#endif - } - } - - const auto children = item->childItems(); - for ( auto child : children ) - addAnimators( child, animatorHint, candidates, skin ); - } - - void update() - { - for ( auto& info : m_updateInfos ) - { - if ( auto control = info.control ) - { - if ( info.updateModes & UpdateInfo::Polish ) - { - control->resetImplicitSize(); - control->polish(); - } - - if ( info.updateModes & UpdateInfo::Update ) - control->update(); - } - } - } + void update(); private: - void addControlAnimators( QskControl* control, const QskAnimationHint& animatorHint, - const QVector< AnimatorCandidate >& candidates ) - { - const auto subControls = control->subControls(); + bool isControlAffected( const QskControl*, + const QVector< QskAspect::Subcontrol >&, QskAspect ) const; - for ( const auto& candidate : candidates ) - { - const auto aspect = candidate.aspect; + void addHints( const QskControl*, + const QskAnimationHint&, const QSet< QskAspect >& candidates, + const QskSkin* skin1, const QskSkin* skin2 ); - if ( !aspect.isMetric() ) - { - if ( !( control->flags() & QQuickItem::ItemHasContents ) ) - { - // while metrics might have an effect on layouts, we - // can safely ignore others for controls without content - continue; - } - } + void storeAnimator( const QskControl*, const QskAspect, + const QVariant&, const QVariant&, QskAnimationHint ); - const auto subControl = aspect.subControl(); - if ( subControl != control->effectiveSubcontrol( subControl ) ) - { - // The control uses subcontrol redirection, so we can assume it - // is not interested in this subcontrol. - continue; - } - - if ( subControl != QskAspect::Control ) - { - if ( !subControls.contains( subControl ) ) - { - // the control is not interested in the aspect - continue; - } - } - else - { - if ( !control->autoFillBackground() ) - { - // no need to animate the background unless we show it - continue; - } - } - - auto a = aspect; - a.setStates( control->skinStates() ); - - const auto requestState = control->hintStatus( a ); - - if ( requestState.source != QskSkinHintStatus::Skin ) - { - // The control does not resolve the aspect from the skin. - continue; - } - - if ( aspect != requestState.aspect ) - { - // the aspect was resolved to something else - continue; - } - - addAnimator( control->window(), aspect, - candidate.from, candidate.to, animatorHint ); - - storeUpdateInfo( control, aspect ); - } - } - - void addAnimator( QQuickWindow* window, const QskAspect aspect, - const QVariant& from, const QVariant& to, QskAnimationHint animationHint ) - { - auto it = m_hintAnimatorMap.find( aspect ); - if ( it != m_hintAnimatorMap.end() ) - return; // already there - - it = m_hintAnimatorMap.emplace( aspect, QskHintAnimator() ).first; - auto& animator = it->second; - - animator.setAspect( aspect ); - animator.setStartValue( from ); - animator.setEndValue( to ); - - animator.setDuration( animationHint.duration ); - animator.setEasingCurve( animationHint.type ); - animator.setUpdateFlags( animationHint.updateFlags ); - - animator.setControl( nullptr ); - animator.setWindow( window ); - } - - inline void storeUpdateInfo( QskControl* control, QskAspect aspect ) - { - UpdateInfo info; - info.control = control; - - info.updateModes = UpdateInfo::Update; - if ( aspect.isMetric() ) - info.updateModes |= UpdateInfo::Polish; - - auto it = std::lower_bound( - m_updateInfos.begin(), m_updateInfos.end(), info, UpdateInfo::compare ); - - if ( ( it != m_updateInfos.end() ) && ( it->control == info.control ) ) - it->updateModes |= info.updateModes; - else - m_updateInfos.insert( it, info ); - } + void storeUpdateInfo( const QskControl*, QskAspect ); QQuickWindow* m_window; - std::unordered_map< QskAspect, QskHintAnimator > m_hintAnimatorMap; + std::unordered_map< QskAspect, HintAnimator > m_animatorMap; std::unordered_map< int, QskVariantAnimator > m_graphicFilterAnimatorMap; std::vector< UpdateInfo > m_updateInfos; // vector: for fast iteration }; - class AnimatorGroups : public QObject + class ApplicationAnimator : public QObject { Q_OBJECT public: - ~AnimatorGroups() - { - reset(); - } + ~ApplicationAnimator(); - inline AnimatorGroup* animatorGroup( const QQuickWindow* window ) - { - if ( !m_animatorGroups.empty() && window ) - { - for ( auto group : m_animatorGroups ) - { - if ( group->window() == window ) - return group; - } - } + WindowAnimator* windowAnimator( const QQuickWindow* ); - return nullptr; - } + void add( WindowAnimator* ); - void add( AnimatorGroup* group ) - { - m_animatorGroups.push_back( group ); - } - - void start() - { - m_connections[0] = QskAnimator::addAdvanceHandler( - this, SLOT(notify(QQuickWindow*)), Qt::UniqueConnection ); - - m_connections[1] = QskAnimator::addCleanupHandler( - this, SLOT(cleanup(QQuickWindow*)), Qt::UniqueConnection ); - - for ( auto& group : m_animatorGroups ) - group->start(); - } - - void reset() - { - qDeleteAll( m_animatorGroups ); - m_animatorGroups.clear(); - - disconnect( m_connections[0] ); - disconnect( m_connections[1] ); - } - - inline bool isRunning() const - { - return !m_animatorGroups.empty(); - } + void start(); + void reset(); + bool isRunning() const; private Q_SLOTS: - void notify( QQuickWindow* window ) - { - for ( auto& group : m_animatorGroups ) - { - if ( group->window() == window ) - { - group->update(); - return; - } - } - } - - void cleanup( QQuickWindow* window ) - { - for ( auto it = m_animatorGroups.begin(); - it != m_animatorGroups.end(); ++it ) - { - auto group = *it; - if ( group->window() == window ) - { - if ( !group->isRunning() ) - { - // The notification might be for other animators - - m_animatorGroups.erase( it ); - delete group; - } - - break; - } - } - - if ( m_animatorGroups.empty() ) - reset(); - } + // using functor slots ? + void notify( QQuickWindow* ); + void cleanup( QQuickWindow* ); private: /* @@ -522,12 +173,372 @@ namespace But as skin transitions are no operations, that happen often, we can accept the overhaed of the current implementation and do the finetuning later. */ - std::vector< AnimatorGroup* > m_animatorGroups; + std::vector< WindowAnimator* > m_windowAnimators; QMetaObject::Connection m_connections[2]; }; } -Q_GLOBAL_STATIC( AnimatorGroups, qskSkinAnimator ) +Q_GLOBAL_STATIC( ApplicationAnimator, qskApplicationAnimator ) + +WindowAnimator::WindowAnimator( QQuickWindow* window ) + : m_window( window ) +{ +} + +inline const QQuickWindow* WindowAnimator::window() const +{ + return m_window; +} + +void WindowAnimator::start() +{ + for ( auto& it : m_animatorMap ) + it.second.start(); + + for ( auto& it : m_graphicFilterAnimatorMap ) + it.second.start(); +} + +bool WindowAnimator::isRunning() const +{ + if ( !m_animatorMap.empty() ) + { + const auto& animator = m_animatorMap.begin()->second; + if ( animator.isRunning() ) + return true; + } + + if ( !m_graphicFilterAnimatorMap.empty() ) + { + const auto& animator = m_graphicFilterAnimatorMap.begin()->second; + if ( animator.isRunning() ) + return true; + } + + return false; +} + +inline QVariant WindowAnimator::animatedHint( QskAspect aspect ) const +{ + auto it = m_animatorMap.find( aspect ); + if ( it != m_animatorMap.cend() ) + { + const auto& animator = it->second; + if ( animator.isRunning() ) + return animator.currentValue(); + } + + return QVariant(); +} + +inline QVariant WindowAnimator::animatedGraphicFilter( int graphicRole ) const +{ + auto it = m_graphicFilterAnimatorMap.find( graphicRole ); + if ( it != m_graphicFilterAnimatorMap.cend() ) + { + const auto& animator = it->second; + if ( animator.isRunning() ) + return animator.currentValue(); + } + + return QVariant(); +} + +void WindowAnimator::addGraphicFilterAnimators( const QskAnimationHint& animatorHint, + const QskSkin* skin1, const QskSkin* skin2 ) +{ + const QskColorFilter noFilter; + + const auto& filter1 = skin1->graphicFilters(); + const auto& filter2 = skin2->graphicFilters(); + + for ( auto it2 = filter2.begin(); it2 != filter2.end(); ++it2 ) + { + auto it1 = filter1.find( it2->first ); + if ( it1 == filter1.cend() ) + it1 = filter1.find( 0 ); + + const auto& f1 = ( it1 != filter1.cend() ) ? it1->second : noFilter; + const auto& f2 = it2->second; + + if ( f1 != f2 ) + { + QskVariantAnimator animator; + animator.setWindow( m_window ); + animator.setDuration( animatorHint.duration ); + animator.setEasingCurve( animatorHint.type ); + animator.setStartValue( QVariant::fromValue( f1 ) ); + animator.setEndValue( QVariant::fromValue( f2 ) ); + + m_graphicFilterAnimatorMap.emplace( it2->first, animator ); + } + } +} + +void WindowAnimator::addItemAspects( QQuickItem* item, + const QskAnimationHint& animatorHint, const QSet< QskAspect >& candidates, + const QskSkin* skin1, const QskSkin* skin2 ) +{ + if ( !item->isVisible() ) + return; + + if ( auto control = qskControlCast( item ) ) + { + if ( control->isInitiallyPainted() && ( control->effectiveSkin() == skin2 ) ) + { + addHints( control, animatorHint, candidates, skin1, skin2 ); +#if 1 + /* + As it is hard to identify which controls depend on the animated + graphic filters we schedule an initial update and let the + controls do the rest: see QskSkinnable::effectiveGraphicFilter + */ + control->update(); +#endif + } + } + + const auto children = item->childItems(); + for ( auto child : children ) + addItemAspects( child, animatorHint, candidates, skin1, skin2 ); +} + +void WindowAnimator::update() +{ + for ( auto& info : m_updateInfos ) + { + if ( auto control = info.control ) + { + if ( info.updateModes & UpdateInfo::Polish ) + { + control->resetImplicitSize(); + control->polish(); + } + + if ( info.updateModes & UpdateInfo::Update ) + control->update(); + } + } +} + +void WindowAnimator::addHints( const QskControl* control, + const QskAnimationHint& animatorHint, const QSet< QskAspect >& candidates, + const QskSkin* skin1, const QskSkin* skin2 ) +{ + const auto subControls = control->subControls(); + + const auto& localTable = control->hintTable(); + + const auto& table1 = skin1->hintTable(); + const auto& table2 = skin2->hintTable(); + + for ( auto aspect : candidates ) + { + if ( !isControlAffected( control, subControls, aspect ) ) + continue; + + aspect.setPlacement( control->effectivePlacement() ); + aspect.setStates( control->skinStates() ); + + if ( localTable.resolvedHint( aspect ) ) + { + // value is not from the skin - ignored + continue; + } + + QskAspect r1, r2; + + const auto v1 = table1.resolvedHint( aspect, &r1 ); + const auto v2 = table2.resolvedHint( aspect, &r2 ); + + if ( v1 && v2 ) + { + if ( QskVariantAnimator::maybeInterpolate( *v1, *v2 ) ) + { + if ( r1.placement() == r2.placement() ) + aspect.setPlacement( r2.placement() ); + + if ( r1.states() == r2.states() ) + aspect.setStates( r2.states() ); + + storeAnimator( control, aspect, *v1, *v2, animatorHint ); + storeUpdateInfo( control, aspect ); + } + } + else if ( v1 ) + { + aspect.setPlacement( r1.placement() ); + aspect.setStates( r1.states() ); + + storeAnimator( control, aspect, *v1, QVariant(), animatorHint ); + storeUpdateInfo( control, aspect ); + } + else if ( v2 ) + { + aspect.setPlacement( r1.placement() ); + aspect.setStates( r1.states() ); + + storeAnimator( control, aspect, QVariant(), *v2, animatorHint ); + storeUpdateInfo( control, aspect ); + } + } +} + +inline bool WindowAnimator::isControlAffected( const QskControl* control, + const QVector< QskAspect::Subcontrol >& subControls, const QskAspect aspect ) const +{ + if ( !aspect.isMetric() ) + { + if ( !( control->flags() & QQuickItem::ItemHasContents ) ) + { + // while metrics might have an effect on layouts, we + // ignore all others for controls without content + return false; + } + } + + const auto subControl = aspect.subControl(); + if ( subControl != control->effectiveSubcontrol( subControl ) ) + { + // The control uses subcontrol redirection, so we can assume it + // is not interested in this subcontrol. + + return false; + } + + if ( subControl == QskAspect::Control ) + { + if ( !control->autoFillBackground() ) + { + // no need to animate the background unless we show it + return false; + } + } + else + { + if ( !subControls.contains( subControl ) ) + { + // the control is not interested in the aspect + return false; + } + } + + return true; +} + +inline void WindowAnimator::storeAnimator( const QskControl* control, const QskAspect aspect, + const QVariant& value1, const QVariant& value2, QskAnimationHint hint ) +{ + if ( m_animatorMap.find( aspect ) == m_animatorMap.cend() ) + { + m_animatorMap.emplace( aspect, + HintAnimator( control, aspect, value1, value2, hint ) ); + } +} + +inline void WindowAnimator::storeUpdateInfo( const QskControl* control, QskAspect aspect ) +{ + UpdateInfo info; + info.control = const_cast< QskControl* >( control ); + + info.updateModes = UpdateInfo::Update; + if ( aspect.isMetric() ) + info.updateModes |= UpdateInfo::Polish; + + auto it = std::lower_bound( + m_updateInfos.begin(), m_updateInfos.end(), info, UpdateInfo::compare ); + + if ( ( it != m_updateInfos.end() ) && ( it->control == info.control ) ) + it->updateModes |= info.updateModes; + else + m_updateInfos.insert( it, info ); +} + +ApplicationAnimator::~ApplicationAnimator() +{ + reset(); +} + +inline WindowAnimator* ApplicationAnimator::windowAnimator( const QQuickWindow* window ) +{ + if ( window ) + { + for ( auto animator : m_windowAnimators ) + { + if ( animator->window() == window ) + return animator; + } + } + + return nullptr; +} + +void ApplicationAnimator::add( WindowAnimator* animator ) +{ + m_windowAnimators.push_back( animator ); +} + +void ApplicationAnimator::start() +{ + m_connections[0] = QskAnimator::addAdvanceHandler( + this, SLOT(notify(QQuickWindow*)), Qt::UniqueConnection ); + + m_connections[1] = QskAnimator::addCleanupHandler( + this, SLOT(cleanup(QQuickWindow*)), Qt::UniqueConnection ); + + for ( auto& animator : m_windowAnimators ) + animator->start(); +} + +void ApplicationAnimator::reset() +{ + qDeleteAll( m_windowAnimators ); + m_windowAnimators.clear(); + + disconnect( m_connections[0] ); + disconnect( m_connections[1] ); +} + +inline bool ApplicationAnimator::isRunning() const +{ + return !m_windowAnimators.empty(); +} + +void ApplicationAnimator::notify( QQuickWindow* window ) +{ + for ( auto& animator : m_windowAnimators ) + { + if ( animator->window() == window ) + { + animator->update(); + return; + } + } +} + +void ApplicationAnimator::cleanup( QQuickWindow* window ) +{ + for ( auto it = m_windowAnimators.begin(); + it != m_windowAnimators.end(); ++it ) + { + auto animator = *it; + if ( animator->window() == window ) + { + if ( !animator->isRunning() ) + { + // The notification might be for other animators + + m_windowAnimators.erase( it ); + delete animator; + } + + break; + } + } + + if ( m_windowAnimators.empty() ) + reset(); +} class QskSkinTransition::PrivateData { @@ -593,38 +604,20 @@ void QskSkinTransition::updateSkin( QskSkin*, QskSkin* ) void QskSkinTransition::process() { - auto skinFrom = m_data->skins[ 0 ]; - auto skinTo = m_data->skins[ 1 ]; + qskApplicationAnimator->reset(); - if ( ( skinFrom == nullptr ) || ( skinTo == nullptr ) ) + auto skin1 = m_data->skins[ 0 ]; + auto skin2 = m_data->skins[ 1 ]; + + QSet< QskAspect > candidates; + + if ( skin1 && skin2 ) { - // do nothing - return; - } - - qskSkinAnimator->reset(); - - if ( ( m_data->animationHint.duration <= 0 ) || ( m_data->mask == 0 ) ) - { - // no animations, we can apply the changes - updateSkin( skinFrom, skinTo ); - return; - } - - QVector< AnimatorCandidate > candidates; - const auto oldFilters = skinFrom->graphicFilters(); - - { - // copy out all hints before updating the skin - // - would be good to have Copy on Write here - - const auto oldTable = skinFrom->hintTable(); - - // apply the changes - updateSkin( skinFrom, skinTo ); - - candidates = qskAnimatorCandidates( m_data->mask, oldTable, oldFilters, - skinTo->hintTable(), skinTo->graphicFilters() ); + if ( ( m_data->animationHint.duration > 0 ) && ( m_data->mask != 0 ) ) + { + qskAddCandidates( m_data->mask, skin1, candidates ); + qskAddCandidates( m_data->mask, skin2, candidates ); + } } if ( !candidates.isEmpty() ) @@ -635,21 +628,19 @@ void QskSkinTransition::process() for ( const auto window : windows ) { - if ( auto quickWindow = qobject_cast< QQuickWindow* >( window ) ) + if ( auto w = qobject_cast< QQuickWindow* >( window ) ) { - if ( !quickWindow->isVisible() || - ( qskEffectiveSkin( quickWindow ) != skinTo ) ) + if ( !w->isVisible() || ( qskEffectiveSkin( w ) != skin2 ) ) { continue; } - auto group = new AnimatorGroup( quickWindow ); + auto animator = new WindowAnimator( w ); if ( doGraphicFilter ) { - group->addGraphicFilterAnimators( - m_data->animationHint, oldFilters, - skinTo->graphicFilters() ); + animator->addGraphicFilterAnimators( + m_data->animationHint, skin1, skin2 ); doGraphicFilter = false; } @@ -659,21 +650,24 @@ void QskSkinTransition::process() over the the item trees. */ - group->addAnimators( quickWindow->contentItem(), - m_data->animationHint, candidates, skinTo ); + animator->addItemAspects( w->contentItem(), + m_data->animationHint, candidates, skin1, skin2 ); - qskSkinAnimator->add( group ); + qskApplicationAnimator->add( animator ); } } - qskSkinAnimator->start(); + qskApplicationAnimator->start(); } + + // apply the changes + updateSkin( skin1, skin2 ); } bool QskSkinTransition::isRunning() { - if ( qskSkinAnimator.exists() ) - return qskSkinAnimator->isRunning(); + if ( qskApplicationAnimator.exists() ) + return qskApplicationAnimator->isRunning(); return false; } @@ -681,10 +675,10 @@ bool QskSkinTransition::isRunning() QVariant QskSkinTransition::animatedHint( const QQuickWindow* window, QskAspect aspect ) { - if ( qskSkinAnimator.exists() ) + if ( qskApplicationAnimator.exists() ) { - if ( const auto group = qskSkinAnimator->animatorGroup( window ) ) - return group->animatedHint( aspect ); + if ( const auto animator = qskApplicationAnimator->windowAnimator( window ) ) + return animator->animatedHint( aspect ); } return QVariant(); @@ -693,10 +687,10 @@ QVariant QskSkinTransition::animatedHint( QVariant QskSkinTransition::animatedGraphicFilter( const QQuickWindow* window, int graphicRole ) { - if ( qskSkinAnimator.exists() ) + if ( qskApplicationAnimator.exists() ) { - if ( const auto group = qskSkinAnimator->animatorGroup( window ) ) - return group->animatedGraphicFilter( graphicRole ); + if ( const auto animator = qskApplicationAnimator->windowAnimator( window ) ) + return animator->animatedGraphicFilter( graphicRole ); } return QVariant(); diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 1aca8b64..15d8b0b5 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -38,16 +38,6 @@ static inline bool qskIsControl( const QskSkinnable* skinnable ) return skinnable->metaObject()->inherits( &QskControl::staticMetaObject ); } -static inline QVariant qskTypedNullValue( const QVariant& value ) -{ -#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) - return QVariant( value.metaType() ); -#else - return QVariant( value.userType(), nullptr ); -#endif - -} - static inline bool qskSetFlag( QskSkinnable* skinnable, const QskAspect aspect, int flag ) { @@ -1155,27 +1145,11 @@ void QskSkinnable::startHintTransition( QskAspect aspect, if ( control->window() == nullptr || !isTransitionAccepted( aspect ) ) return; - /* - We might be invalid for one of the values, when an aspect - has not been defined for all states ( f.e. metrics are expected - to fallback to 0.0 ). In this case we create a default one. - */ - auto v1 = from; auto v2 = to; - if ( !v1.isValid() ) - { - v1 = qskTypedNullValue( v2 ); - } - else if ( !v2.isValid() ) - { - v2 = qskTypedNullValue( v1 ); - } - else if ( v1.userType() != v2.userType() ) - { + if ( !QskVariantAnimator::convertValues( v1, v2 ) ) return; - } if ( aspect.flagPrimitive() == QskAspect::GraphicRole ) { diff --git a/src/controls/QskVariantAnimator.cpp b/src/controls/QskVariantAnimator.cpp index fde0e00f..a23fd356 100644 --- a/src/controls/QskVariantAnimator.cpp +++ b/src/controls/QskVariantAnimator.cpp @@ -76,6 +76,31 @@ QSK_DECL_INSANE static inline QVariant qskInterpolate( return f( from.constData(), to.constData(), progress ); } +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + +using QskMetaType = int; +static inline QskMetaType qskMetaType( const QVariant& v ) { return v.userType(); } + +#else + +using QskMetaType = QMetaType; +static inline QskMetaType qskMetaType( const QVariant& v ) { return v.metaType(); } + +#endif + +static inline QVariant qskDefaultVariant( QskMetaType type ) +{ + return QVariant( type, nullptr ); +} + +static inline QVariant qskConvertedVariant( const QVariant& from, QskMetaType type ) +{ + auto v = from; + v.convert( type ); + + return v; +} + QskVariantAnimator::QskVariantAnimator() : m_interpolator( nullptr ) { @@ -100,35 +125,60 @@ void QskVariantAnimator::setCurrentValue( const QVariant& value ) m_currentValue = value; } +bool QskVariantAnimator::convertValues( QVariant& v1, QVariant& v2 ) +{ + if ( !v1.isValid() && !v2.isValid() ) + return false; + + const auto type1 = qskMetaType( v1 ); + const auto type2 = qskMetaType( v2 ); + + if ( !v1.isValid() ) + { + v1 = qskDefaultVariant( type2 ); + return true; + } + + if ( !v2.isValid() ) + { + v2 = qskDefaultVariant( type1 ); + return true; + } + + if ( type1 != type2 ) + { + if ( v1.canConvert( type2 ) ) + { + v1.convert( type2 ); + return true; + } + + if ( v2.canConvert( type1 ) ) + { + v2.convert( type1 ); + return true; + } + + return false; + } + + return true; +} + void QskVariantAnimator::setup() { m_interpolator = nullptr; - if ( m_startValue.userType() != m_endValue.userType() ) + if ( convertValues( m_startValue, m_endValue ) ) { - /* - Convert one value so that the types are matching. - - As a side effect startValue()/endValue() won't return what had - been set setStartValue()/setEndValue() ! - */ - - if ( m_startValue.canConvert( m_endValue.userType() ) ) + if ( m_startValue != m_endValue ) { - m_startValue.convert( m_endValue.userType() ); - } - else if ( m_endValue.canConvert( m_startValue.userType() ) ) - { - m_endValue.convert( m_startValue.userType() ); - } - } + const auto id = m_startValue.userType(); - const auto type = m_startValue.userType(); - if ( type == m_endValue.userType() ) - { - // all what has been registered by qRegisterAnimationInterpolator - m_interpolator = reinterpret_cast< void ( * )() >( - QVariantAnimationPrivate::getInterpolator( type ) ); + // all what has been registered by qRegisterAnimationInterpolator + m_interpolator = reinterpret_cast< void ( * )() >( + QVariantAnimationPrivate::getInterpolator( id ) ); + } } m_currentValue = m_interpolator ? m_startValue : m_endValue; @@ -150,3 +200,32 @@ void QskVariantAnimator::done() { m_interpolator = nullptr; } + +bool QskVariantAnimator::maybeInterpolate( + const QVariant& value1, const QVariant& value2 ) +{ + if ( !value1.isValid() && !value2.isValid() ) + return false; + + const auto type1 = qskMetaType( value1 ); + const auto type2 = qskMetaType( value2 ); + + if ( !value1.isValid() ) + return value2 != qskDefaultVariant( type2 ); + + if ( !value2.isValid() ) + return value1 != qskDefaultVariant( type1 ); + + if ( type1 != type2 ) + { + if ( value1.canConvert( type2 ) ) + return value2 != qskConvertedVariant( value1, type2 ); + + if ( value2.canConvert( type1 ) ) + return value1 != qskConvertedVariant( value2, type1 ); + + return false; + } + + return value1 != value2; +} diff --git a/src/controls/QskVariantAnimator.h b/src/controls/QskVariantAnimator.h index 1507670d..9e036b06 100644 --- a/src/controls/QskVariantAnimator.h +++ b/src/controls/QskVariantAnimator.h @@ -24,6 +24,9 @@ class QSK_EXPORT QskVariantAnimator : public QskAnimator void setEndValue( const QVariant& ); QVariant endValue() const; + static bool maybeInterpolate( const QVariant&, const QVariant& ); + static bool convertValues( QVariant&, QVariant& ); + protected: void setup() override; void advance( qreal value ) override; From a676caf994fffc77a5c7e3feb69c1f6623c70723 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Apr 2022 13:56:16 +0200 Subject: [PATCH 20/28] support lib reorganized --- examples/automotive/main.cpp | 2 - examples/boxes/main.cpp | 2 - examples/buttons/main.cpp | 2 - examples/colorswitch/main.cpp | 2 - examples/gallery/main.cpp | 2 - examples/iotdashboard/main.cpp | 3 - examples/layouts/main.cpp | 2 - examples/listbox/main.cpp | 2 - examples/messagebox/main.cpp | 2 - examples/messageboxQml/main.cpp | 2 - examples/mycontrols/main.cpp | 2 - examples/qvgviewer/main.cpp | 2 - examples/tabview/main.cpp | 2 - playground/anchors/main.cpp | 2 - playground/dialogbuttons/main.cpp | 2 - playground/grids/main.cpp | 11 -- playground/inputpanel/main.cpp | 2 - playground/webview/main.cpp | 2 - support/SkinnyFont.cpp | 43 ------ support/SkinnyGlobal.h | 17 +-- support/SkinnyNamespace.cpp | 140 ++++++++++++++++++++ support/{SkinnyFont.h => SkinnyNamespace.h} | 13 +- support/SkinnyShapeFactory.h | 5 +- support/SkinnyShapeProvider.h | 5 +- support/SkinnyShortcut.cpp | 72 +--------- support/SkinnyShortcut.h | 7 +- support/support.pro | 4 +- 27 files changed, 161 insertions(+), 191 deletions(-) delete mode 100644 support/SkinnyFont.cpp create mode 100644 support/SkinnyNamespace.cpp rename support/{SkinnyFont.h => SkinnyNamespace.h} (63%) diff --git a/examples/automotive/main.cpp b/examples/automotive/main.cpp index ed93e224..d4fd90f2 100644 --- a/examples/automotive/main.cpp +++ b/examples/automotive/main.cpp @@ -7,7 +7,6 @@ #include "SkinFactory.h" #include -#include #include #include @@ -33,7 +32,6 @@ int main( int argc, char** argv ) */ qskSetup->setItemUpdateFlag( QskQuickItem::PreferRasterForTextures, true ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); MainWindow window; diff --git a/examples/boxes/main.cpp b/examples/boxes/main.cpp index bfe8678d..95261fc2 100644 --- a/examples/boxes/main.cpp +++ b/examples/boxes/main.cpp @@ -5,7 +5,6 @@ #include "Box.h" -#include #include #include @@ -555,7 +554,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::Quit | SkinnyShortcut::DebugShortcuts ); auto* tabView = new TabView(); diff --git a/examples/buttons/main.cpp b/examples/buttons/main.cpp index 26ee773f..373e695d 100644 --- a/examples/buttons/main.cpp +++ b/examples/buttons/main.cpp @@ -3,7 +3,6 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#include #include #include @@ -24,7 +23,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); QQmlApplicationEngine engine( QUrl( "qrc:/qml/buttons.qml" ) ); diff --git a/examples/colorswitch/main.cpp b/examples/colorswitch/main.cpp index 59a1361a..00d69450 100644 --- a/examples/colorswitch/main.cpp +++ b/examples/colorswitch/main.cpp @@ -5,7 +5,6 @@ #include "Theme.h" -#include #include #include @@ -28,7 +27,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::Quit | SkinnyShortcut::ChangeFonts | SkinnyShortcut::DebugShortcuts ); diff --git a/examples/gallery/main.cpp b/examples/gallery/main.cpp index 838d9106..1fca95f2 100644 --- a/examples/gallery/main.cpp +++ b/examples/gallery/main.cpp @@ -8,7 +8,6 @@ #include "slider/SliderPage.h" #include "switchbutton/SwitchButtonPage.h" -#include #include #include @@ -44,7 +43,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); auto tabView = new TabView(); diff --git a/examples/iotdashboard/main.cpp b/examples/iotdashboard/main.cpp index 80be72ba..a1457e0d 100644 --- a/examples/iotdashboard/main.cpp +++ b/examples/iotdashboard/main.cpp @@ -7,7 +7,6 @@ #include "GraphicProvider.h" #include "Skin.h" -#include #include #include @@ -61,8 +60,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); - Qsk::addGraphicProvider( QString(), new GraphicProvider() ); // disable default skins diff --git a/examples/layouts/main.cpp b/examples/layouts/main.cpp index f6d59be6..6c829fd5 100644 --- a/examples/layouts/main.cpp +++ b/examples/layouts/main.cpp @@ -10,7 +10,6 @@ #include "StackLayoutPage.h" #include "TestRectangle.h" -#include #include #include @@ -31,7 +30,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); auto tabView = new QskTabView(); diff --git a/examples/listbox/main.cpp b/examples/listbox/main.cpp index 487796aa..2c1e2099 100644 --- a/examples/listbox/main.cpp +++ b/examples/listbox/main.cpp @@ -3,7 +3,6 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#include #include #include @@ -65,7 +64,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); QskWindow window; diff --git a/examples/messagebox/main.cpp b/examples/messagebox/main.cpp index f5702319..f1b96068 100644 --- a/examples/messagebox/main.cpp +++ b/examples/messagebox/main.cpp @@ -3,7 +3,6 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#include #include #include @@ -126,7 +125,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); qskDialog->setPolicy( QskDialog::EmbeddedBox ); diff --git a/examples/messageboxQml/main.cpp b/examples/messageboxQml/main.cpp index 58d084a6..3e7a0694 100644 --- a/examples/messageboxQml/main.cpp +++ b/examples/messageboxQml/main.cpp @@ -3,7 +3,6 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#include #include #include @@ -22,7 +21,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); QQmlApplicationEngine engine( QUrl( "qrc:/qml/messagebox.qml" ) ); diff --git a/examples/mycontrols/main.cpp b/examples/mycontrols/main.cpp index 996bcd02..7102c1a7 100644 --- a/examples/mycontrols/main.cpp +++ b/examples/mycontrols/main.cpp @@ -6,7 +6,6 @@ #include "MySkin.h" #include "MyToggleButton.h" -#include #include #include @@ -136,7 +135,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::DebugBackground | SkinnyShortcut::DebugStatistics | SkinnyShortcut::Quit ); diff --git a/examples/qvgviewer/main.cpp b/examples/qvgviewer/main.cpp index c6a53784..31d62caa 100644 --- a/examples/qvgviewer/main.cpp +++ b/examples/qvgviewer/main.cpp @@ -5,7 +5,6 @@ #include "MainWindow.h" -#include #include #ifdef CONTEXT_MENU @@ -29,7 +28,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); QskFocusIndicator* focusIndicator = new QskFocusIndicator(); diff --git a/examples/tabview/main.cpp b/examples/tabview/main.cpp index 7afab28f..5fbd43dc 100644 --- a/examples/tabview/main.cpp +++ b/examples/tabview/main.cpp @@ -3,7 +3,6 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#include #include #include @@ -90,7 +89,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); auto tabView = new TabView(); diff --git a/playground/anchors/main.cpp b/playground/anchors/main.cpp index 7f758ec6..a75c279d 100644 --- a/playground/anchors/main.cpp +++ b/playground/anchors/main.cpp @@ -5,7 +5,6 @@ #include "AnchorBox.h" -#include #include #include @@ -153,7 +152,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::Quit | SkinnyShortcut::DebugShortcuts ); auto box = new MyBox(); diff --git a/playground/dialogbuttons/main.cpp b/playground/dialogbuttons/main.cpp index 7393099d..b55461f9 100644 --- a/playground/dialogbuttons/main.cpp +++ b/playground/dialogbuttons/main.cpp @@ -5,7 +5,6 @@ #include "Window.h" -#include #include #include @@ -21,7 +20,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); Window window( Qt::Horizontal ); diff --git a/playground/grids/main.cpp b/playground/grids/main.cpp index 40dd8a8a..ea81b96a 100644 --- a/playground/grids/main.cpp +++ b/playground/grids/main.cpp @@ -5,8 +5,6 @@ #include "TestBox.h" -#include - #include #include @@ -389,15 +387,6 @@ int main( int argc, char** argv ) { QApplication app( argc, argv ); -#if 1 - /* - we don't need the fonts, but by calling something from - the support library initializations regarding the skins - are loaded. TODO ... - */ - SkinnyFont::init( &app ); -#endif - int testcase = 0; if ( argc == 2 ) testcase = atoi( argv[1] ); diff --git a/playground/inputpanel/main.cpp b/playground/inputpanel/main.cpp index d26e3361..af6994cd 100644 --- a/playground/inputpanel/main.cpp +++ b/playground/inputpanel/main.cpp @@ -3,7 +3,6 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#include #include #include @@ -285,7 +284,6 @@ int main( int argc, char* argv[] ) QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); #if 1 diff --git a/playground/webview/main.cpp b/playground/webview/main.cpp index 0a6de6ec..454e3639 100644 --- a/playground/webview/main.cpp +++ b/playground/webview/main.cpp @@ -3,7 +3,6 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#include #include #include @@ -43,7 +42,6 @@ int main( int argc, char* argv[] ) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app( argc, argv ); - SkinnyFont::init( &app ); SkinnyShortcut::enable( SkinnyShortcut::Quit | SkinnyShortcut::DebugShortcuts ); QskWindow window; diff --git a/support/SkinnyFont.cpp b/support/SkinnyFont.cpp deleted file mode 100644 index 7278c388..00000000 --- a/support/SkinnyFont.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the 3-clause BSD License - *****************************************************************************/ - -#include "SkinnyFont.h" - -#include -#include -#include -#include - -#define STRINGIFY(x) #x -#define STRING(x) STRINGIFY(x) - -void SkinnyFont::init( QGuiApplication* ) -{ -#ifdef FONTCONFIG_FILE - const char env[] = "FONTCONFIG_FILE"; - if ( !qEnvironmentVariableIsSet( env ) ) - qputenv( env, STRING( FONTCONFIG_FILE ) ); -#endif - - QElapsedTimer timer; - timer.start(); - - QFontDatabase(); - - const auto elapsed = timer.elapsed(); - - if ( elapsed > 20 ) - { - qWarning() << "Loading fonts needed" << elapsed << "ms" - << "- usually because of creating a font cache."; - } - - /* - The default initialization in QskSkin sets up its font table - with using the application font for the default font role. - */ - QGuiApplication::setFont( QFont( "DejaVuSans", 12 ) ); -} - diff --git a/support/SkinnyGlobal.h b/support/SkinnyGlobal.h index 4f5a9a17..9c350ab8 100644 --- a/support/SkinnyGlobal.h +++ b/support/SkinnyGlobal.h @@ -3,23 +3,20 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#ifndef SKINNY_GLOBAL_H -#define SKINNY_GLOBAL_H +#pragma once #include #ifdef QSK_DLL -#if defined( SKINNY_MAKEDLL ) // create a DLL library -#define SKINNY_EXPORT Q_DECL_EXPORT -#else // use a DLL library -#define SKINNY_EXPORT Q_DECL_IMPORT -#endif + #if defined( SKINNY_MAKEDLL ) // create a DLL library + #define SKINNY_EXPORT Q_DECL_EXPORT + #else // use a DLL library + #define SKINNY_EXPORT Q_DECL_IMPORT + #endif #endif // QSK_DLL #ifndef SKINNY_EXPORT -#define SKINNY_EXPORT -#endif - + #define SKINNY_EXPORT #endif diff --git a/support/SkinnyNamespace.cpp b/support/SkinnyNamespace.cpp new file mode 100644 index 00000000..baf2d6a6 --- /dev/null +++ b/support/SkinnyNamespace.cpp @@ -0,0 +1,140 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#include "SkinnyNamespace.h" + +#include +#include +#include +#include +#include + +#include +#include + +#define STRINGIFY(x) #x +#define STRING(x) STRINGIFY(x) + +#if defined( ENSURE_SKINS ) + + #include + #include + + static void initSkins() + { + if ( qskSkinManager->skinNames().isEmpty() ) + { + /* + To avoid having problems with not finding the skin plugins + we manually add them here. + */ + + qskSkinManager->registerFactory( "SquiekFactory", new QskSquiekSkinFactory() ); + qskSkinManager->registerFactory( "MaterialFactory", new QskMaterialSkinFactory() ); + + qWarning() << "Couldn't find skin plugins, adding some manually."; + } + } + + Q_COREAPP_STARTUP_FUNCTION( initSkins ) + +#endif + +#define ENSURE_FONTS + +#if defined( ENSURE_FONTS ) + + #include + #include + + static void initFonts() + { + #ifdef FONTCONFIG_FILE + const char env[] = "FONTCONFIG_FILE"; + if ( !qEnvironmentVariableIsSet( env ) ) + qputenv( env, STRING( FONTCONFIG_FILE ) ); + #endif + + QElapsedTimer timer; + timer.start(); + + QFontDatabase(); + + const auto elapsed = timer.elapsed(); + + if ( elapsed > 20 ) + { + qWarning() << "Loading fonts needed" << elapsed << "ms" + << "- usually because of creating a font cache."; + } + + /* + The default initialization in QskSkin sets up its font table + with using the application font for the default font role. + */ + QGuiApplication::setFont( QFont( "DejaVuSans", 12 ) ); + } +#endif + +Q_COREAPP_STARTUP_FUNCTION( initFonts ) + +void Skinny::changeSkin( QskAnimationHint hint ) +{ + const auto names = qskSkinManager->skinNames(); + if ( names.size() <= 1 ) + return; + + int index = names.indexOf( qskSetup->skinName() ); + index = ( index + 1 ) % names.size(); + + auto oldSkin = qskSetup->skin(); + if ( oldSkin->parent() == qskSetup ) + oldSkin->setParent( nullptr ); // otherwise setSkin deletes it + + if ( auto newSkin = qskSetup->setSkin( names[ index ] ) ) + { + QskSkinTransition transition; + + //transition.setMask( QskAspect::Color ); // Metrics are flickering -> TODO + transition.setSourceSkin( oldSkin ); + transition.setTargetSkin( newSkin ); + transition.setAnimation( hint ); + + transition.process(); + + if ( oldSkin->parent() == nullptr ) + delete oldSkin; + } +} + +void Skinny::changeFonts( int increment ) +{ + auto skin = qskSetup->skin(); + + const auto fonts = skin->fonts(); + + for ( auto it = fonts.begin(); it != fonts.end(); ++it ) + { + auto role = it->first; + auto font = it->second; + + if ( font.pixelSize() > 0 ) + { + const auto newSize = font.pixelSize() + increment; + if ( newSize > 0 ) + font.setPixelSize( newSize ); + } + else + { + const auto newSize = font.pointSizeF() + increment; + if ( newSize > 0 ) + font.setPointSizeF( font.pointSizeF() + increment ); + } + + skin->setFont( role, font ); + } + + Q_EMIT qskSetup->skinChanged( skin ); +} diff --git a/support/SkinnyFont.h b/support/SkinnyNamespace.h similarity index 63% rename from support/SkinnyFont.h rename to support/SkinnyNamespace.h index db2675a9..072e60b2 100644 --- a/support/SkinnyFont.h +++ b/support/SkinnyNamespace.h @@ -3,16 +3,13 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#ifndef SKINNY_FONT_H_ -#define SKINNY_FONT_H_ +#pragma once #include "SkinnyGlobal.h" +#include -class QGuiApplication; - -namespace SkinnyFont +namespace Skinny { - SKINNY_EXPORT void init( QGuiApplication* ); + SKINNY_EXPORT void changeSkin( QskAnimationHint hint = 500 ); + SKINNY_EXPORT void changeFonts( int increment ); } - -#endif diff --git a/support/SkinnyShapeFactory.h b/support/SkinnyShapeFactory.h index 3cbb591d..42794218 100644 --- a/support/SkinnyShapeFactory.h +++ b/support/SkinnyShapeFactory.h @@ -3,8 +3,7 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#ifndef SKINNY_SHAPE_FACTORY_H_ -#define SKINNY_SHAPE_FACTORY_H_ +#pragma once #include "SkinnyGlobal.h" #include @@ -32,5 +31,3 @@ namespace SkinnyShapeFactory SKINNY_EXPORT QPainterPath shapePath( Shape, const QSizeF& ); } - -#endif diff --git a/support/SkinnyShapeProvider.h b/support/SkinnyShapeProvider.h index 3b5f7962..fb0a8155 100644 --- a/support/SkinnyShapeProvider.h +++ b/support/SkinnyShapeProvider.h @@ -3,8 +3,7 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#ifndef SKINNY_SHAPE_PROVIDER_H -#define SKINNY_SHAPE_PROVIDER_H +#pragma once #include "SkinnyGlobal.h" #include @@ -15,5 +14,3 @@ class SKINNY_EXPORT SkinnyShapeProvider : public QskGraphicProvider const QskGraphic* loadGraphic( const QString& id ) const override final; }; -#endif - diff --git a/support/SkinnyShortcut.cpp b/support/SkinnyShortcut.cpp index 582827fb..6226f559 100644 --- a/support/SkinnyShortcut.cpp +++ b/support/SkinnyShortcut.cpp @@ -1,15 +1,11 @@ #include "SkinnyShortcut.h" +#include "SkinnyNamespace.h" #include #include -#include #include -#include -#include #include #include -#include -#include #include #include @@ -17,7 +13,6 @@ #include #include -#include #include SkinnyShortcut::SkinnyShortcut( QObject* parent ): @@ -34,17 +29,17 @@ void SkinnyShortcut::enable( Types types ) if ( types & RotateSkin ) { QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL | Qt::Key_S ), - false, &s_shortcut, &SkinnyShortcut::rotateSkin ); + false, &s_shortcut, [] { Skinny::changeSkin(); } ); cout << "CTRL-S to change the skin." << endl; } if ( types & ChangeFonts ) { QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL | Qt::Key_F ), - false, &s_shortcut, [] { s_shortcut.changeFonts( +1 ); } ); + false, &s_shortcut, [] { Skinny::changeFonts( +1 ); } ); QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL | Qt::Key_G ), - false, &s_shortcut, [] { s_shortcut.changeFonts( -1 ); } ); + false, &s_shortcut, [] { Skinny::changeFonts( -1 ); } ); cout << "CTRL-F to increase the font size." << endl; cout << "CTRL-G to decrease the font size." << endl; @@ -75,35 +70,6 @@ void SkinnyShortcut::enable( Types types ) } } -void SkinnyShortcut::rotateSkin() -{ - const auto names = qskSkinManager->skinNames(); - if ( names.size() <= 1 ) - return; - - int index = names.indexOf( qskSetup->skinName() ); - index = ( index + 1 ) % names.size(); - - auto oldSkin = qskSetup->skin(); - if ( oldSkin->parent() == qskSetup ) - oldSkin->setParent( nullptr ); // otherwise setSkin deletes it - - if ( auto newSkin = qskSetup->setSkin( names[ index ] ) ) - { - QskSkinTransition transition; - - //transition.setMask( QskAspect::Color ); // Metrics are flickering -> TODO - transition.setSourceSkin( oldSkin ); - transition.setTargetSkin( newSkin ); - transition.setAnimation( 500 ); - - transition.process(); - - if ( oldSkin->parent() == nullptr ) - delete oldSkin; - } -} - void SkinnyShortcut::showBackground() { #if 0 @@ -149,36 +115,6 @@ void SkinnyShortcut::showBackground() } } -void SkinnyShortcut::changeFonts( int increment ) -{ - auto skin = qskSetup->skin(); - - const auto fonts = skin->fonts(); - - for ( auto it = fonts.begin(); it != fonts.end(); ++it ) - { - auto role = it->first; - auto font = it->second; - - if ( font.pixelSize() > 0 ) - { - const auto newSize = font.pixelSize() + increment; - if ( newSize > 0 ) - font.setPixelSize( newSize ); - } - else - { - const auto newSize = font.pointSizeF() + increment; - if ( newSize > 0 ) - font.setPointSizeF( font.pointSizeF() + increment ); - } - - skin->setFont( role, font ); - } - - Q_EMIT qskSetup->skinChanged( skin ); -} - static inline void countNodes( const QSGNode* node, int& counter ) { if ( node ) diff --git a/support/SkinnyShortcut.h b/support/SkinnyShortcut.h index 52222f18..8f63781f 100644 --- a/support/SkinnyShortcut.h +++ b/support/SkinnyShortcut.h @@ -3,8 +3,7 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ -#ifndef SKINNY_SHORTCUT_H_ -#define SKINNY_SHORTCUT_H_ +#pragma once #include "SkinnyGlobal.h" #include @@ -34,12 +33,8 @@ class SKINNY_EXPORT SkinnyShortcut : public QObject private: SkinnyShortcut( QObject* parent = nullptr ); - void rotateSkin(); - void changeFonts( int increment ); void showBackground(); void debugStatistics(); }; Q_DECLARE_OPERATORS_FOR_FLAGS( SkinnyShortcut::Types ) - -#endif diff --git a/support/support.pro b/support/support.pro index 699b1f2b..b02cb0d9 100644 --- a/support/support.pro +++ b/support/support.pro @@ -12,13 +12,13 @@ contains(QSK_CONFIG, QskDll): DEFINES += SKINNY_MAKEDLL HEADERS += \ SkinnyGlobal.h \ - SkinnyFont.h \ + SkinnyNamespace.h \ SkinnyShapeFactory.h \ SkinnyShapeProvider.h \ SkinnyShortcut.h SOURCES += \ - SkinnyFont.cpp \ + SkinnyNamespace.cpp \ SkinnyPlugin.cpp \ SkinnyShapeFactory.cpp \ SkinnyShapeProvider.cpp \ From 0cd577c977a3df2c7f5bfb3adeaa1848443cc82b Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Apr 2022 13:57:26 +0200 Subject: [PATCH 21/28] making QskSwtchButton smaller --- skins/squiek/QskSquiekSkin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index f7031ae1..bfdd6706 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -892,7 +892,7 @@ void Editor::setupSwitchButton() using A = QskAspect; using Q = QskSwitchButton; - const qreal radius = qskDpiScaled( 18 ); + const qreal radius = qskDpiScaled( 12 ); const qreal handleSize = 2 * ( radius - 2 ); setBoxShape( Q::Groove, 100, Qt::RelativeSize ); From 01afcd85575947568bf5dd85568fe801cef3b41a Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Apr 2022 14:41:56 +0200 Subject: [PATCH 22/28] using c++11 --- src/common/QskAspect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/QskAspect.cpp b/src/common/QskAspect.cpp index a45febbb..6162df0e 100644 --- a/src/common/QskAspect.cpp +++ b/src/common/QskAspect.cpp @@ -144,7 +144,7 @@ QVector< QskAspect::Subcontrol > QskAspect::subControls( const QMetaObject* meta static QByteArray qskEnumString( const char* name, int value ) { - const QMetaObject& mo = QskAspect::staticMetaObject; + const auto& mo = QskAspect::staticMetaObject; const QMetaEnum metaEnum = mo.enumerator( mo.indexOfEnumerator( name ) ); const char* key = metaEnum.valueToKey( value ); From a40ca46556f853e3d569ce4509723c2a9298bcb6 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Apr 2022 14:42:18 +0200 Subject: [PATCH 23/28] font initialization changed --- src/controls/QskSkin.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/controls/QskSkin.cpp b/src/controls/QskSkin.cpp index 85215d98..e438816c 100644 --- a/src/controls/QskSkin.cpp +++ b/src/controls/QskSkin.cpp @@ -12,6 +12,7 @@ #include "QskGraphicProviderMap.h" #include "QskSkinHintTable.h" #include "QskStandardSymbol.h" +#include "QskPlatform.h" #include "QskMargins.h" @@ -216,13 +217,14 @@ void QskSkin::declareSkinlet( const QMetaObject* metaObject, void QskSkin::setupFonts( const QString& family, int weight, bool italic ) { + const int sizes[] = { 10, 15, 20, 32, 66 }; + static_assert( sizeof( sizes ) / sizeof( sizes[ 0 ] ) == HugeFont ); + QFont font( family, -1, weight, italic ); - const uint base = TinyFont; for ( int i = TinyFont; i <= HugeFont; i++ ) { - // TODO: make the scaling components configurable - font.setPixelSize( int( std::pow( uint( i ) - base + 2, 2.5 ) ) ); + font.setPixelSize( qskDpiScaled( sizes[i-1] ) ); m_data->fonts[ i ] = font; } From ff8b4245a68271efd4bd9a899a1610b170c5745a Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Apr 2022 14:43:22 +0200 Subject: [PATCH 24/28] text box reimplemented --- examples/gallery/label/LabelPage.cpp | 48 ++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/examples/gallery/label/LabelPage.cpp b/examples/gallery/label/LabelPage.cpp index 8e4a2813..7b945ce8 100644 --- a/examples/gallery/label/LabelPage.cpp +++ b/examples/gallery/label/LabelPage.cpp @@ -8,29 +8,51 @@ #include #include #include +#include namespace { + class TextLabel : public QskTextLabel + { + public: + TextLabel( int role, QQuickItem* parent = nullptr ) + : QskTextLabel( parent ) + { + setText( textFromRole( role ) ); + setFontRole( role ); + + setSizePolicy( Qt::Horizontal, QskSizePolicy::Ignored ); + } + + private: + QString textFromRole( int role ) const + { + static QMetaEnum metaEnum; + + if ( !metaEnum.isValid() ) + { + const auto& mo = QskSkin::staticMetaObject; + metaEnum = mo.enumerator( mo.indexOfEnumerator( "SkinFontRole" ) ); + } + + QString s( metaEnum.valueToKey( role ) ); + s.remove( QStringLiteral( "Font" ) ); + + return s; + } + }; + class TextBox : public QskLinearBox { public: TextBox( QQuickItem* parent = nullptr ) - : QskLinearBox( Qt::Vertical, 3, parent ) + : QskLinearBox( Qt::Horizontal, 3, parent ) { setMargins( 10 ); - //setDefaultAlignment( Qt::AlignTop ); - setExtraSpacingAt( Qt::BottomEdge ); + setDefaultAlignment( Qt::AlignCenter ); - const QStringList texts = - { "Default", "Tiny", "Small", "Medium", "Large", "Huge" }; - - for ( int i = 0; i < texts.size(); i++ ) - { - auto label = new QskTextLabel( texts[ i ] + " Font", this ); - - //label->setPanel( true ); - label->setFontRole( i ); - } + for ( int i = 0; i <= QskSkin::HugeFont; i++ ) + ( void ) new TextLabel( i, this ); } }; From bd9718007d8200125f3404b560117e3dfdfdf5ed Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Apr 2022 14:53:20 +0200 Subject: [PATCH 25/28] workaround for Qt 6.2 incompatibility --- playground/images/images.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/playground/images/images.qml b/playground/images/images.qml index 1ee7fb4f..b5132ff5 100644 --- a/playground/images/images.qml +++ b/playground/images/images.qml @@ -17,7 +17,8 @@ Qsk.Window orientation: Qt.Horizontal dimension: 3 - margins: 10 + //margins: 10 // only possible with Qt <= 6.1 + margins { left: 10; top: 10; right: 10; bottom: 10 } spacing: 10 Repeater From 4cb3301045c3201592e93ff2c79bd0d8320dc725 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Apr 2022 14:54:31 +0200 Subject: [PATCH 26/28] push buttons added --- examples/gallery/button/ButtonPage.cpp | 88 +++++++++++++++++++ .../ButtonPage.h} | 4 +- examples/gallery/gallery.pro | 4 +- examples/gallery/main.cpp | 72 +++++++++++++-- .../gallery/switchbutton/SwitchButtonPage.cpp | 54 ------------ 5 files changed, 155 insertions(+), 67 deletions(-) create mode 100644 examples/gallery/button/ButtonPage.cpp rename examples/gallery/{switchbutton/SwitchButtonPage.h => button/ButtonPage.h} (80%) delete mode 100644 examples/gallery/switchbutton/SwitchButtonPage.cpp diff --git a/examples/gallery/button/ButtonPage.cpp b/examples/gallery/button/ButtonPage.cpp new file mode 100644 index 00000000..9a347c37 --- /dev/null +++ b/examples/gallery/button/ButtonPage.cpp @@ -0,0 +1,88 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#include "ButtonPage.h" + +#include +#include +#include +#include + +namespace +{ + class ButtonBox : public QskLinearBox + { + public: + ButtonBox( QQuickItem* parent = nullptr ) + : QskLinearBox( Qt::Horizontal, 4, parent ) + { + setSpacing( 20 ); + setExtraSpacingAt( Qt::BottomEdge ); + setDefaultAlignment( Qt::AlignCenter ); + + populate(); + } + + private: + void populate() + { + const char* texts[] = { "Press Me", "Check Me" }; + const char* graphics[] = { "diamond/khaki", "ellipse/sandybrown" }; + + for ( int i = 0; i < 6; i++ ) + { + const int index = i % 2; + + auto button = new QskPushButton( this ); + button->setCheckable( index != 0 ); + //button->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed ); + + if ( i > 1 ) + { + auto src = QStringLiteral( "image://shapes/" ) + graphics[ index ]; + button->setGraphicSource( src ); + } + + if ( i < 2 || i > 3 ) + { + button->setText( texts[ index ] ); + } + } + } + }; + + class SwitchButtonBox : public QskLinearBox + { + public: + SwitchButtonBox( QQuickItem* parent = nullptr ) + : QskLinearBox( Qt::Horizontal, parent ) + { + setSpacing( 20 ); + setExtraSpacingAt( Qt::LeftEdge | Qt::RightEdge | Qt::BottomEdge ); + + for ( auto orientation : { Qt::Vertical, Qt::Horizontal } ) + { + (void) new QskSwitchButton( orientation, this ); + + auto button = new QskSwitchButton( orientation, this ); + button->setInverted( true ); + } + } + }; +} + +ButtonPage::ButtonPage( QQuickItem* parent ) + : Page( Qt::Vertical, parent ) +{ + setSpacing( 40 ); + populate(); +} + +void ButtonPage::populate() +{ + new ButtonBox( this ); + new QskSeparator( Qt::Horizontal, this ); + new SwitchButtonBox( this ); +} diff --git a/examples/gallery/switchbutton/SwitchButtonPage.h b/examples/gallery/button/ButtonPage.h similarity index 80% rename from examples/gallery/switchbutton/SwitchButtonPage.h rename to examples/gallery/button/ButtonPage.h index 377092da..ad7cad86 100644 --- a/examples/gallery/switchbutton/SwitchButtonPage.h +++ b/examples/gallery/button/ButtonPage.h @@ -7,10 +7,10 @@ #include "Page.h" -class SwitchButtonPage : public Page +class ButtonPage : public Page { public: - SwitchButtonPage( QQuickItem* = nullptr ); + ButtonPage( QQuickItem* = nullptr ); private: void populate(); diff --git a/examples/gallery/gallery.pro b/examples/gallery/gallery.pro index 75cd1071..2c1eedb3 100644 --- a/examples/gallery/gallery.pro +++ b/examples/gallery/gallery.pro @@ -25,10 +25,10 @@ SOURCES += \ progressbar/ProgressBarPage.cpp \ HEADERS += \ - switchbutton/SwitchButtonPage.h + button/ButtonPage.h SOURCES += \ - switchbutton/SwitchButtonPage.cpp \ + button/ButtonPage.cpp \ HEADERS += \ Page.h diff --git a/examples/gallery/main.cpp b/examples/gallery/main.cpp index 1fca95f2..6d4b79c3 100644 --- a/examples/gallery/main.cpp +++ b/examples/gallery/main.cpp @@ -6,7 +6,7 @@ #include "label/LabelPage.h" #include "progressbar/ProgressBarPage.h" #include "slider/SliderPage.h" -#include "switchbutton/SwitchButtonPage.h" +#include "button/ButtonPage.h" #include #include @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -30,6 +32,61 @@ namespace setTabPosition( Qsk::Left ); setAutoFitTabs( true ); } + + void setTabsEnabled( bool on ) + { + for ( int i = 0; i < count(); i++ ) + itemAt( i )->setEnabled( on ); + } + }; + + /* + Once QskApplicationView and friends are implemented we can replace + Header/ApplicationWindow with it. TODO ... + */ + class Header : public QskLinearBox + { + Q_OBJECT + + public: + Header( QQuickItem* parent = nullptr ) + : QskLinearBox( Qt::Horizontal, parent ) + { + initSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::Fixed ); + setMargins( 10 ); + + addStretch( 10 ); + + new QskTextLabel( "Enabled", this ); + + auto button = new QskSwitchButton( this ); + button->setChecked( true ); + + connect( button, &QskSwitchButton::toggled, + this, &Header::enabledToggled ); + } + + Q_SIGNALS: + void enabledToggled( bool ); + }; + + class ApplicationView : public QskLinearBox + { + public: + ApplicationView( QQuickItem* parent = nullptr ) + : QskLinearBox( Qt::Vertical, parent ) + { + auto header = new Header( this ); + + auto tabView = new TabView( this ); + tabView->addTab( "Labels", new LabelPage() ); + tabView->addTab( "Buttons", new ButtonPage() ); + tabView->addTab( "Sliders", new SliderPage() ); + tabView->addTab( "Progress\nBars", new ProgressBarPage() ); + + connect( header, &Header::enabledToggled, + tabView, &TabView::setTabsEnabled ); + } }; } @@ -45,18 +102,13 @@ int main( int argc, char* argv[] ) SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); - auto tabView = new TabView(); - - tabView->addTab( "Labels", new LabelPage() ); - tabView->addTab( "Sliders", new SliderPage() ); - tabView->addTab( "Progress\nBars", new ProgressBarPage() ); - tabView->addTab( "Switches", new SwitchButtonPage() ); + auto mainView = new ApplicationView(); QSize size( 800, 600 ); - size = size.expandedTo( tabView->sizeHint().toSize() ); + size = size.expandedTo( mainView->sizeHint().toSize() ); QskWindow window; - window.addItem( tabView ); + window.addItem( mainView ); window.addItem( new QskFocusIndicator() ); window.resize( size ); @@ -64,3 +116,5 @@ int main( int argc, char* argv[] ) return app.exec(); } + +#include "main.moc" diff --git a/examples/gallery/switchbutton/SwitchButtonPage.cpp b/examples/gallery/switchbutton/SwitchButtonPage.cpp deleted file mode 100644 index 1fab35b1..00000000 --- a/examples/gallery/switchbutton/SwitchButtonPage.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the 3-clause BSD License - *****************************************************************************/ - -#include "SwitchButtonPage.h" - -#include -#include -#include -#include - -#include - -SwitchButtonPage::SwitchButtonPage( QQuickItem* parent ) - : Page( Qt::Horizontal, parent ) -{ - setSpacing( 40 ); - populate(); -} - -void SwitchButtonPage::populate() -{ - auto hbox1 = new QskLinearBox(); - hbox1->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed ); - hbox1->setExtraSpacingAt( Qt::LeftEdge ); - - auto label = new QskTextLabel( "Disable the switches:", hbox1 ); - label->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed ); - - auto button0 = new QskSwitchButton( hbox1 ); - - auto hbox2 = new QskLinearBox( Qt::Horizontal ); - hbox2->setDefaultAlignment( Qt::AlignHCenter | Qt::AlignTop ); - hbox2->setMargins( 30 ); - - (void) new QskSwitchButton( Qt::Vertical, hbox2 ); - (void) new QskSwitchButton( Qt::Horizontal, hbox2 ); - - auto button3 = new QskSwitchButton( Qt::Vertical, hbox2 ); - button3->setInverted( true ); - - auto button4 = new QskSwitchButton( Qt::Horizontal, hbox2 ); - button4->setInverted( true ); - - auto vbox = new QskLinearBox( Qt::Vertical, this ); - vbox->addItem( hbox1 ); - vbox->addItem( new QskSeparator() ); - vbox->addItem( hbox2 ); - vbox->setExtraSpacingAt( Qt::BottomEdge ); - - QObject::connect( button0, &QskSwitchButton::checkedChanged, - hbox2, &QskQuickItem::setDisabled ); -} From 0c7b14401b31382eb14e6d19954928d8ef892e75 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Apr 2022 15:58:47 +0200 Subject: [PATCH 27/28] change skin button added --- examples/gallery/main.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/examples/gallery/main.cpp b/examples/gallery/main.cpp index 6d4b79c3..7123fe62 100644 --- a/examples/gallery/main.cpp +++ b/examples/gallery/main.cpp @@ -10,12 +10,14 @@ #include #include +#include #include #include #include #include #include +#include #include #include @@ -53,17 +55,32 @@ namespace : QskLinearBox( Qt::Horizontal, parent ) { initSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::Fixed ); + setMargins( 10 ); + setBackgroundColor( Qt::lightGray ); + + { + auto button = new QskPushButton( "Skin", this ); +#if 1 + button->setFlat( true ); // until we have the section bit in QskAspect +#endif + + // transition leads to errors, when changing the tab before being completed. TODO ... + connect( button, &QskSwitchButton::clicked, + [] { Skinny::changeSkin( 500 ); } ); + } addStretch( 10 ); - new QskTextLabel( "Enabled", this ); + { + new QskTextLabel( "Enabled", this ); - auto button = new QskSwitchButton( this ); - button->setChecked( true ); + auto button = new QskSwitchButton( this ); + button->setChecked( true ); - connect( button, &QskSwitchButton::toggled, - this, &Header::enabledToggled ); + connect( button, &QskSwitchButton::toggled, + this, &Header::enabledToggled ); + } } Q_SIGNALS: From 4d724bb6fe378989c11b4283b5455df727407958 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Apr 2022 17:00:05 +0200 Subject: [PATCH 28/28] compiler error fixed --- src/controls/QskSkin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controls/QskSkin.cpp b/src/controls/QskSkin.cpp index e438816c..1f8b67db 100644 --- a/src/controls/QskSkin.cpp +++ b/src/controls/QskSkin.cpp @@ -218,7 +218,8 @@ void QskSkin::declareSkinlet( const QMetaObject* metaObject, void QskSkin::setupFonts( const QString& family, int weight, bool italic ) { const int sizes[] = { 10, 15, 20, 32, 66 }; - static_assert( sizeof( sizes ) / sizeof( sizes[ 0 ] ) == HugeFont ); + static_assert( sizeof( sizes ) / sizeof( sizes[ 0 ] ) == HugeFont, + "QskSkin::setupFonts: bad list size." ); QFont font( family, -1, weight, italic );