diff --git a/examples/gallery/switchbutton/SwitchButtonPage.cpp b/examples/gallery/switchbutton/SwitchButtonPage.cpp index 1ed05e36..fad88b83 100644 --- a/examples/gallery/switchbutton/SwitchButtonPage.cpp +++ b/examples/gallery/switchbutton/SwitchButtonPage.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -22,31 +23,34 @@ SwitchButtonPage::SwitchButtonPage( QQuickItem* parent ) void SwitchButtonPage::populate() { + auto hbox1 = new QskLinearBox(); + hbox1->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed ); + hbox1->setExtraSpacingAt( Qt::LeftEdge ); + + auto label = new QskTextLabel( "Disable the boxes: ", 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 ); - - auto hbox = new QskLinearBox( vbox ); - new QskTextLabel( "Disable the boxes: ", hbox ); - auto disabler = new QskSwitchButton( hbox ); - - auto targets = new QskLinearBox( Qt::Horizontal, vbox ); - - auto target1 = new QskSwitchButton( targets ); - target1->setOrientation( Qt::Vertical ); - - auto target2 = new QskSwitchButton( targets ); - target2->setOrientation( Qt::Horizontal ); - - auto target3 = new QskSwitchButton( targets ); - target3->setChecked( true ); - target3->setOrientation( Qt::Vertical ); - - auto target4 = new QskSwitchButton( targets ); - target4->setChecked( true ); - target4->setOrientation( Qt::Horizontal ); - - QObject::connect( disabler, &QskSwitchButton::checkedChanged, - targets, &QskQuickItem::setDisabled ); - - targets->setExtraSpacingAt( Qt::RightEdge ); + vbox->addItem( hbox1 ); + vbox->addItem( new QskSeparator() ); + vbox->addItem( hbox2 ); vbox->setExtraSpacingAt( Qt::BottomEdge ); + + QObject::connect( button0, &QskSwitchButton::checkedChanged, + hbox2, &QskQuickItem::setDisabled ); } diff --git a/skins/material/QskMaterialSkin.cpp b/skins/material/QskMaterialSkin.cpp index e7d69570..3f4262ab 100644 --- a/skins/material/QskMaterialSkin.cpp +++ b/skins/material/QskMaterialSkin.cpp @@ -496,24 +496,24 @@ void Editor::setupSwitchButton() const qreal knopLength = radius - 4; setBoxShape( Q::Groove, radius); - setStrutSize(Q::Groove, 3.4 * radius, 2 * radius); - setColor( Q::Groove, m_pal.accentColor); - setBoxBorderColors(Q::Groove, m_pal.darker200); - setColor(Q::Groove | Q::Disabled, m_pal.lighter125); - setBoxBorderMetrics(Q::Groove, 2); - setBoxBorderColors(Q::Groove | Q::Disabled, m_pal.darker125); + setStrutSize( Q::Groove, 3.4 * radius, 2 * radius ); + setColor( Q::Groove, m_pal.accentColor ); + setBoxBorderColors( Q::Groove, m_pal.darker200 ); + setColor( Q::Groove | Q::Disabled, m_pal.lighter125 ); + setBoxBorderMetrics( Q::Groove, 2 ); + setBoxBorderColors( Q::Groove | Q::Disabled, m_pal.darker125 ); - setBoxShape( Q::Knop, knopLength); - setMetric(Q::Knop | A::Size,knopLength); - setGradient( Q::Knop, QskGradient(Qt::Vertical, m_pal.lighter150, m_pal.lighter125) ); - setBoxBorderMetrics(Q::Knop, 2); - setColor(Q::Knop | Q::Disabled, m_pal.lighter125); - setBoxBorderColors(Q::Knop, m_pal.darker200); - setBoxBorderColors(Q::Knop | Q::Disabled, m_pal.darker125); + setBoxShape( Q::Handle, knopLength ); + setMetric( Q::Handle | A::Size,knopLength ); + setGradient( Q::Handle, QskGradient( Qt::Vertical, m_pal.lighter150, m_pal.lighter125 ) ); + setBoxBorderMetrics( Q::Handle, 2 ); + setColor( Q::Handle | Q::Disabled, m_pal.lighter125 ); + setBoxBorderColors( Q::Handle, m_pal.darker200 ); + setBoxBorderColors( Q::Handle | Q::Disabled, m_pal.darker125 ); for( auto state : { A::NoState, Q::Disabled } ) { - auto aspect = Q::Knop | state | A::Position; + auto aspect = Q::Handle | state | A::Position; setMetric( aspect | Q::Checked, 0 ); setMetric( aspect, 1 ); @@ -522,7 +522,7 @@ void Editor::setupSwitchButton() setColor( aspect | Q::Checked, m_pal.baseColor); } - setAnimation( Q::Knop | A::Metric, qskDuration ); + setAnimation( Q::Handle | A::Metric, qskDuration ); setAnimation( Q::Groove | A::Color, qskDuration ); } diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index a5d79ae4..24249640 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -859,27 +859,27 @@ void Editor::setupSwitchButton() using Q = QskSwitchButton; const qreal radius = qskDpiScaled( 18 ); - const qreal knopLength = radius - 4; + const qreal handleLength = radius - 4; setBoxShape( Q::Groove, radius); - setStrutSize(Q::Groove, 3.4 * radius, 2 * radius); - setColor( Q::Groove, m_pal.highlighted); - setBoxBorderColors(Q::Groove | Q::Disabled, m_pal.theme); - setColor(Q::Groove | Q::Disabled, m_pal.lighter110); - setBoxBorderMetrics(Q::Groove, 2); - setBoxBorderColors(Q::Groove, m_pal.darker200); + setStrutSize( Q::Groove, 3.4 * radius, 2 * radius ); + setColor( Q::Groove, m_pal.highlighted ); + setBoxBorderColors( Q::Groove | Q::Disabled, m_pal.theme ); + setColor( Q::Groove | Q::Disabled, m_pal.lighter110 ); + setBoxBorderMetrics( Q::Groove, 2 ); + setBoxBorderColors( Q::Groove, m_pal.darker200 ); - setBoxShape( Q::Knop, knopLength); - setMetric(Q::Knop | A::Size,knopLength); - setGradient( Q::Knop, QskGradient(Qt::Vertical, m_pal.lighter150, m_pal.lighter110) ); - setBoxBorderMetrics(Q::Knop, 2); - setColor(Q::Knop | Q::Disabled, m_pal.lighter110); - setBoxBorderColors(Q::Knop, m_pal.darker200); - setBoxBorderColors(Q::Knop | Q::Disabled, m_pal.theme); + setBoxShape( Q::Handle, handleLength ); + setMetric( Q::Handle | A::Size, handleLength ); + setGradient( Q::Handle, QskGradient( Qt::Vertical, m_pal.lighter150, m_pal.lighter110 ) ); + setBoxBorderMetrics( Q::Handle, 2 ); + setColor(Q::Handle | Q::Disabled, m_pal.lighter110 ); + setBoxBorderColors( Q::Handle, m_pal.darker200 ); + setBoxBorderColors( Q::Handle | Q::Disabled, m_pal.theme ); for( auto state : { A::NoState, Q::Disabled } ) { - auto aspect = Q::Knop | state | A::Position; + auto aspect = Q::Handle | state | A::Position; setMetric( aspect | Q::Checked, 0 ); setMetric( aspect, 1 ); @@ -888,7 +888,7 @@ void Editor::setupSwitchButton() setColor( aspect | Q::Checked, m_pal.baseActive); } - setAnimation( Q::Knop | A::Metric, qskDuration ); + setAnimation( Q::Handle | A::Metric, qskDuration ); setAnimation( Q::Groove | A::Color, qskDuration ); } diff --git a/src/controls/QskSwitchButton.cpp b/src/controls/QskSwitchButton.cpp index e8e144a6..84ad520d 100644 --- a/src/controls/QskSwitchButton.cpp +++ b/src/controls/QskSwitchButton.cpp @@ -1,57 +1,79 @@ #include "QskSwitchButton.h" -QSK_SUBCONTROL( QskSwitchButton, Knop ) +QSK_SUBCONTROL( QskSwitchButton, Handle ) QSK_SUBCONTROL( QskSwitchButton, Groove ) struct QskSwitchButton::PrivateData { - PrivateData() - : orientation( Qt::Horizontal ) - , layoutDirection( Qt::LeftToRight) + PrivateData( Qt::Orientation orientation ) + : orientation( orientation ) { } + bool inverted = false; Qt::Orientation orientation; - Qt::LayoutDirection layoutDirection; }; QskSwitchButton::QskSwitchButton( QQuickItem* parent ) - : QskAbstractButton(parent) - , m_data( new PrivateData() ) + : QskSwitchButton( Qt::Horizontal, parent ) { +} + +QskSwitchButton::QskSwitchButton( Qt::Orientation orientation, QQuickItem* parent ) + : QskAbstractButton( parent ) + , m_data( new PrivateData( orientation ) ) +{ setCheckable( true ); + initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed ); } -QskSwitchButton::~QskSwitchButton() { +QskSwitchButton::~QskSwitchButton() +{ } - Qt::Orientation QskSwitchButton::orientation() const { return m_data->orientation; } -void QskSwitchButton::setOrientation(Qt::Orientation orientation) + +void QskSwitchButton::setOrientation( Qt::Orientation orientation ) { - if(m_data->orientation != orientation) + if( m_data->orientation != orientation ) { m_data->orientation = orientation; + + resetImplicitSize(); update(); + Q_EMIT orientationChanged( orientation ); } } -Qt::LayoutDirection QskSwitchButton::layoutDirection() const +bool QskSwitchButton::isInverted() const { - return m_data->layoutDirection; + return m_data->inverted; } -void QskSwitchButton::setLayoutDirection(Qt::LayoutDirection layoutDirection) + +void QskSwitchButton::setInverted( bool on ) { - if(m_data->layoutDirection != layoutDirection) + if( m_data->inverted != on ) { - m_data->layoutDirection = layoutDirection; + m_data->inverted = on; + + resetImplicitSize(); // in case the size hints depend on it update(); - Q_EMIT layoutDirectionChanged( layoutDirection ); + + Q_EMIT invertedChanged( on ); } } +QskAspect::Placement QskSwitchButton::effectivePlacement() const +{ + /* + So you can define different hints depending on the orientation, + but what about the layoutDirection ??? + */ + return static_cast< QskAspect::Placement >( m_data->orientation ); +} + #include "moc_QskSwitchButton.cpp" diff --git a/src/controls/QskSwitchButton.h b/src/controls/QskSwitchButton.h index b836baea..e8703e9a 100644 --- a/src/controls/QskSwitchButton.h +++ b/src/controls/QskSwitchButton.h @@ -1,9 +1,8 @@ #ifndef QSK_SWITCH_BUTTON_H #define QSK_SWITCH_BUTTON_H - #include "QskAbstractButton.h" -#include "QskNamespace.h" +#include class QSK_EXPORT QskSwitchButton : public QskAbstractButton { @@ -13,27 +12,33 @@ class QSK_EXPORT QskSwitchButton : public QskAbstractButton Q_PROPERTY( Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL ) - Q_PROPERTY( Qt::LayoutDirection layoutDirection READ layoutDirection - WRITE setLayoutDirection NOTIFY layoutDirectionChanged FINAL ) + + Q_PROPERTY( bool inverted READ isInverted + WRITE setInverted NOTIFY invertedChanged FINAL ) public: - QSK_SUBCONTROLS( Groove, Knop ) + QSK_SUBCONTROLS( Groove, Handle ) + QskSwitchButton( Qt::Orientation, QQuickItem* parent = nullptr ); QskSwitchButton( QQuickItem* parent = nullptr ); + ~QskSwitchButton() override; Qt::Orientation orientation() const; void setOrientation(Qt::Orientation); - Qt::LayoutDirection layoutDirection() const; - void setLayoutDirection(Qt::LayoutDirection); + bool isInverted() const; + void setInverted( bool ); + + QskAspect::Placement effectivePlacement() const override; Q_SIGNALS: void orientationChanged( Qt::Orientation ); - void layoutDirectionChanged(Qt::LayoutDirection); + void invertedChanged( bool ); private: struct PrivateData; std::unique_ptr< PrivateData > m_data; }; + #endif diff --git a/src/controls/QskSwitchButtonSkinlet.cpp b/src/controls/QskSwitchButtonSkinlet.cpp index 6de73be4..f2813fcc 100644 --- a/src/controls/QskSwitchButtonSkinlet.cpp +++ b/src/controls/QskSwitchButtonSkinlet.cpp @@ -1,55 +1,57 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ #include "QskSwitchButton.h" #include "QskSwitchButtonSkinlet.h" #include "QskSGNode.h" -QskSwitchButtonSkinlet::QskSwitchButtonSkinlet(QskSkin* skin) + +QskSwitchButtonSkinlet::QskSwitchButtonSkinlet( QskSkin* skin ) : Inherited( skin ) { - setNodeRoles( { GrooveRole, KnopRole } ); + setNodeRoles( { GrooveRole, HandleRole } ); } -QskSwitchButtonSkinlet::~QskSwitchButtonSkinlet() {} +QskSwitchButtonSkinlet::~QskSwitchButtonSkinlet() +{ +} QRectF QskSwitchButtonSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl) const { using Q = QskSwitchButton; + const auto switchButton = static_cast< const Q* >( skinnable ); - if (!switchButton) + if ( subControl == Q::Handle ) { - return Inherited::subControlRect( skinnable, contentsRect, subControl ); - } + const auto diameter = 2 * skinnable->metric( Q::Handle | QskAspect::Size ); + const auto grooveSize = skinnable->strutSizeHint( Q::Groove ); - if ( subControl == Q::Knop) - { - const auto diameter = 2 * skinnable->metric(QskSwitchButton::Knop | QskAspect::Size); - const auto grooveSize = skinnable->strutSizeHint(QskSwitchButton::Groove); - auto position = skinnable->metric( Q::Knop | QskAspect::Position ); + auto position = skinnable->metric( Q::Handle | QskAspect::Position ); + if( switchButton->isInverted() ) + position = 1.0 - position; - auto rect = QRectF(0, 0, diameter, diameter); + auto rect = QRectF( 0, 0, diameter, diameter ); - if(switchButton->layoutDirection() == Qt::RightToLeft) + if( switchButton->orientation() == Qt::Vertical ) { - position = 1 - position; - } + if( diameter < grooveSize.height() ) + rect.moveLeft( ( grooveSize.height() - diameter ) / 2 ); - if(switchButton->orientation() == Qt::Vertical) - { - if(diameter < grooveSize.height() ) - { - rect.moveLeft( ( grooveSize.height() - diameter ) / 2); - } rect.moveTop( ( grooveSize.height() - diameter ) / 2 + position * ( grooveSize.width() - diameter - ( grooveSize.height() - diameter ) ) ); } else { - if(diameter < grooveSize.height() ) - { - rect.moveTop( ( grooveSize.height() - diameter ) / 2); - } + if( switchButton->layoutMirroring() ) + position = 1.0 - position; + + if( diameter < grooveSize.height() ) + rect.moveTop( ( grooveSize.height() - diameter ) / 2 ); + rect.moveLeft( ( grooveSize.height() - diameter ) / 2 + position * ( grooveSize.width() - diameter - ( grooveSize.height() - diameter ) ) ); @@ -57,27 +59,27 @@ QRectF QskSwitchButtonSkinlet::subControlRect( const QskSkinnable* skinnable, return rect; } - else if ( subControl == Q::Groove ) - { - auto diameter = 2 * skinnable->metric(QskSwitchButton::Knop | QskAspect::Size); - const auto grooveSize = skinnable->strutSizeHint(QskSwitchButton::Groove); - auto result = contentsRect; - result.setSize( QSizeF(grooveSize.width(), grooveSize.height() ) ); - if(switchButton->orientation() == Qt::Vertical ) + if ( subControl == Q::Groove ) + { + auto diameter = 2 * skinnable->metric( Q::Handle | QskAspect::Size ); + const auto grooveSize = skinnable->strutSizeHint( Q::Groove ); + + auto result = contentsRect; + result.setSize( grooveSize ); + + if( switchButton->orientation() == Qt::Vertical ) { - if(grooveSize.height() < diameter) - { - result.moveLeft( ( diameter - result.height() ) / 2); - } + if( grooveSize.height() < diameter ) + result.moveLeft( ( diameter - result.height() ) / 2 ); + return result.transposed(); } else { - if(grooveSize.height() < diameter) - { - result.moveTop( ( diameter - result.height() ) / 2); - } + if( grooveSize.height() < diameter ) + result.moveTop( ( diameter - result.height() ) / 2 ); + return result; } } @@ -88,33 +90,35 @@ QRectF QskSwitchButtonSkinlet::subControlRect( const QskSkinnable* skinnable, QSizeF QskSwitchButtonSkinlet::sizeHint( const QskSkinnable* skinnable, Qt::SizeHint, const QSizeF&) const { - const auto switchButton = static_cast< const QskSwitchButton* >( skinnable ); - const auto diameter = 2 * skinnable->metric(QskSwitchButton::Knop | QskAspect::Size); - const auto grooveSize = skinnable->strutSizeHint(QskSwitchButton::Groove); + using Q = QskSwitchButton; - auto result = QSizeF(qMax(diameter, grooveSize.width() ), - qMax(diameter, grooveSize.height() ) ); - if(switchButton->orientation() == Qt::Vertical) - { - return result.transposed(); - } + const auto switchButton = static_cast< const Q* >( skinnable ); + const auto diameter = 2 * skinnable->metric( Q::Handle | QskAspect::Size ); - return result; + auto hint = skinnable->strutSizeHint( Q::Groove ); + hint = hint.expandedTo( QSizeF( diameter, diameter ) ); + + if( switchButton->orientation() == Qt::Vertical ) + hint.transpose(); + + return hint; } QSGNode* QskSwitchButtonSkinlet::updateSubNode( const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node) const { - const auto switchButton = static_cast< const QskSwitchButton* >( skinnable ); + using Q = QskSwitchButton; switch ( nodeRole ) { - case KnopRole: - return updateBoxNode( switchButton, node, QskSwitchButton::Knop ); + case HandleRole: + return updateBoxNode( skinnable, node, Q::Handle ); case GrooveRole: - return updateBoxNode( switchButton, node, QskSwitchButton::Groove ); + return updateBoxNode( skinnable, node, Q::Groove ); } return Inherited::updateSubNode( skinnable, nodeRole, node ); } + +#include "moc_QskSwitchButtonSkinlet.cpp" diff --git a/src/controls/QskSwitchButtonSkinlet.h b/src/controls/QskSwitchButtonSkinlet.h index 7810aa99..9c08aa09 100644 --- a/src/controls/QskSwitchButtonSkinlet.h +++ b/src/controls/QskSwitchButtonSkinlet.h @@ -1,7 +1,11 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + #ifndef QSK_SWITCH_BUTTON_SKINLET_H #define QSK_SWITCH_BUTTON_SKINLET_H - #include "QskSkinlet.h" class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet @@ -13,14 +17,13 @@ class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet public: enum NodeRole { - KnopRole, - GrooveRole + GrooveRole, + HandleRole }; Q_INVOKABLE QskSwitchButtonSkinlet( QskSkin* parent = nullptr ); ~QskSwitchButtonSkinlet() override; - QRectF subControlRect( const QskSkinnable*, const QRectF& rect, QskAspect::Subcontrol ) const override; @@ -31,4 +34,5 @@ class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet QSGNode* updateSubNode( const QskSkinnable*, quint8 nodeRole, QSGNode* ) const override; }; + #endif