Add SwitchButton (#121)

This commit is contained in:
Clemens Manert 2021-08-02 13:22:37 +02:00 committed by GitHub
parent 02ad876e14
commit 13faf53495
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 404 additions and 1 deletions

View File

@ -3,6 +3,7 @@ TEMPLATE = subdirs
# c++ # c++
SUBDIRS += \ SUBDIRS += \
desktop \ desktop \
switchbuttons \
gallery \ gallery \
layouts \ layouts \
listbox \ listbox \

View File

@ -0,0 +1,54 @@
#include <QGuiApplication>
#include <QskLinearBox.h>
#include <QskSwitchButton.h>
#include <QskTextLabel.h>
#include <QskWindow.h>
#include <SkinnyShortcut.h>
int main(int argc, char* argv[])
{
QGuiApplication app( argc, argv );
QskWindow window;
SkinnyShortcut::enable( SkinnyShortcut::Quit |
SkinnyShortcut::DebugShortcuts );
auto vbox = new QskLinearBox(Qt::Vertical);
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, [target1, target2, target3, target4](bool c){
target1->setEnabled(!c);
target2->setEnabled(!c);
target3->setEnabled(!c);
target4->setEnabled(!c);
});
targets->setExtraSpacingAt(Qt::RightEdge);
vbox->setExtraSpacingAt(Qt::BottomEdge);
window.addItem( vbox );
window.show();
return app.exec();
}

View File

@ -0,0 +1,4 @@
CONFIG += qskexample
SOURCES += \
main.cpp\

View File

@ -20,6 +20,8 @@
#include <QskSeparator.h> #include <QskSeparator.h>
#include <QskSlider.h> #include <QskSlider.h>
#include <QskSubWindow.h> #include <QskSubWindow.h>
#include <QskSwitchButton.h>
#include <QskSwitchButtonSkinlet.h>
#include <QskTabBar.h> #include <QskTabBar.h>
#include <QskTabButton.h> #include <QskTabButton.h>
#include <QskTabView.h> #include <QskTabView.h>
@ -123,6 +125,7 @@ namespace
void setupSeparator(); void setupSeparator();
void setupSubWindow(); void setupSubWindow();
void setupSlider(); void setupSlider();
void setupSwitchButton();
void setupTabButton(); void setupTabButton();
void setupTabBar(); void setupTabBar();
void setupTabView(); void setupTabView();
@ -152,6 +155,7 @@ void Editor::setup()
setupSeparator(); setupSeparator();
setupSlider(); setupSlider();
setupSubWindow(); setupSubWindow();
setupSwitchButton();
setupTabButton(); setupTabButton();
setupTabBar(); setupTabBar();
setupTabView(); setupTabView();
@ -483,6 +487,45 @@ void Editor::setupSlider()
setAnimation( Q::Handle | A::Metric | A::Position | Q::Pressed, 0 ); setAnimation( Q::Handle | A::Metric | A::Position | Q::Pressed, 0 );
} }
void Editor::setupSwitchButton()
{
using A = QskAspect;
using Q = QskSwitchButton;
const qreal radius = qskDpiScaled( 18 );
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);
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);
for( auto state : { A::NoState, Q::Disabled } )
{
auto aspect = Q::Knop | state | A::Position;
setMetric( aspect | Q::Checked, 0 );
setMetric( aspect, 1 );
aspect = Q::Groove | state | A::Color;
setColor( aspect | Q::Checked, m_pal.baseColor);
}
setAnimation( Q::Knop | A::Metric, qskDuration );
setAnimation( Q::Groove | A::Color, qskDuration );
}
void Editor::setupTabButton() void Editor::setupTabButton()
{ {
using A = QskAspect; using A = QskAspect;

View File

@ -21,6 +21,8 @@
#include <QskSeparator.h> #include <QskSeparator.h>
#include <QskSlider.h> #include <QskSlider.h>
#include <QskSubWindow.h> #include <QskSubWindow.h>
#include <QskSwitchButton.h>
#include <QskSwitchButtonSkinlet.h>
#include <QskTabBar.h> #include <QskTabBar.h>
#include <QskTabButton.h> #include <QskTabButton.h>
#include <QskTabView.h> #include <QskTabView.h>
@ -143,6 +145,7 @@ namespace
void setupSeparator(); void setupSeparator();
void setupSlider(); void setupSlider();
void setupSubWindow(); void setupSubWindow();
void setupSwitchButton();
void setupTabButton(); void setupTabButton();
void setupTabBar(); void setupTabBar();
void setupTabView(); void setupTabView();
@ -260,6 +263,7 @@ void Editor::setup()
setupSeparator(); setupSeparator();
setupSlider(); setupSlider();
setupSubWindow(); setupSubWindow();
setupSwitchButton();
setupTabButton(); setupTabButton();
setupTabBar(); setupTabBar();
setupTabView(); setupTabView();
@ -849,6 +853,45 @@ void Editor::setupSubWindow()
setAnimation( subControl | A::Color, qskDuration ); setAnimation( subControl | A::Color, qskDuration );
} }
void Editor::setupSwitchButton()
{
using A = QskAspect;
using Q = QskSwitchButton;
const qreal radius = qskDpiScaled( 18 );
const qreal knopLength = 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);
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);
for( auto state : { A::NoState, Q::Disabled } )
{
auto aspect = Q::Knop | state | A::Position;
setMetric( aspect | Q::Checked, 0 );
setMetric( aspect, 1 );
aspect = Q::Groove | state | A::Color;
setColor( aspect | Q::Checked, m_pal.baseActive);
}
setAnimation( Q::Knop | A::Metric, qskDuration );
setAnimation( Q::Groove | A::Color, qskDuration );
}
class QskSquiekSkin::PrivateData class QskSquiekSkin::PrivateData
{ {
public: public:

View File

@ -70,6 +70,9 @@ QSK_QT_PRIVATE_END
#include "QskSubWindowArea.h" #include "QskSubWindowArea.h"
#include "QskSubWindowAreaSkinlet.h" #include "QskSubWindowAreaSkinlet.h"
#include "QskSwitchButton.h"
#include "QskSwitchButtonSkinlet.h"
#include "QskPageIndicator.h" #include "QskPageIndicator.h"
#include "QskPageIndicatorSkinlet.h" #include "QskPageIndicatorSkinlet.h"
@ -149,6 +152,7 @@ QskSkin::QskSkin( QObject* parent )
declareSkinlet< QskStatusIndicator, QskStatusIndicatorSkinlet >(); declareSkinlet< QskStatusIndicator, QskStatusIndicatorSkinlet >();
declareSkinlet< QskSubWindow, QskSubWindowSkinlet >(); declareSkinlet< QskSubWindow, QskSubWindowSkinlet >();
declareSkinlet< QskSubWindowArea, QskSubWindowAreaSkinlet >(); declareSkinlet< QskSubWindowArea, QskSubWindowAreaSkinlet >();
declareSkinlet< QskSwitchButton, QskSwitchButtonSkinlet >();
declareSkinlet< QskTabButton, QskTabButtonSkinlet >(); declareSkinlet< QskTabButton, QskTabButtonSkinlet >();
declareSkinlet< QskTabView, QskTabViewSkinlet >(); declareSkinlet< QskTabView, QskTabViewSkinlet >();
declareSkinlet< QskTextLabel, QskTextLabelSkinlet >(); declareSkinlet< QskTextLabel, QskTextLabelSkinlet >();

View File

@ -0,0 +1,57 @@
#include "QskSwitchButton.h"
QSK_SUBCONTROL( QskSwitchButton, Knop )
QSK_SUBCONTROL( QskSwitchButton, Groove )
struct QskSwitchButton::PrivateData
{
PrivateData()
: orientation( Qt::Horizontal )
, layoutDirection( Qt::LeftToRight)
{
}
Qt::Orientation orientation;
Qt::LayoutDirection layoutDirection;
};
QskSwitchButton::QskSwitchButton( QQuickItem* parent )
: QskAbstractButton(parent)
, m_data( new PrivateData() )
{
setCheckable( true );
}
QskSwitchButton::~QskSwitchButton() {
}
Qt::Orientation QskSwitchButton::orientation() const
{
return m_data->orientation;
}
void QskSwitchButton::setOrientation(Qt::Orientation orientation)
{
if(m_data->orientation != orientation)
{
m_data->orientation = orientation;
update();
Q_EMIT orientationChanged( orientation );
}
}
Qt::LayoutDirection QskSwitchButton::layoutDirection() const
{
return m_data->layoutDirection;
}
void QskSwitchButton::setLayoutDirection(Qt::LayoutDirection layoutDirection)
{
if(m_data->layoutDirection != layoutDirection)
{
m_data->layoutDirection = layoutDirection;
update();
Q_EMIT layoutDirectionChanged( layoutDirection );
}
}
#include "moc_QskSwitchButton.cpp"

View File

@ -0,0 +1,39 @@
#ifndef QSK_SWITCH_BUTTON_H
#define QSK_SWITCH_BUTTON_H
#include "QskAbstractButton.h"
#include "QskNamespace.h"
class QSK_EXPORT QskSwitchButton : public QskAbstractButton
{
Q_OBJECT
using Inherited = 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 )
public:
QSK_SUBCONTROLS( Groove, Knop )
QskSwitchButton( QQuickItem* parent = nullptr );
~QskSwitchButton() override;
Qt::Orientation orientation() const;
void setOrientation(Qt::Orientation);
Qt::LayoutDirection layoutDirection() const;
void setLayoutDirection(Qt::LayoutDirection);
Q_SIGNALS:
void orientationChanged( Qt::Orientation );
void layoutDirectionChanged(Qt::LayoutDirection);
private:
struct PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif

View File

@ -0,0 +1,120 @@
#include "QskSwitchButton.h"
#include "QskSwitchButtonSkinlet.h"
#include "QskSGNode.h"
QskSwitchButtonSkinlet::QskSwitchButtonSkinlet(QskSkin* skin)
: Inherited( skin )
{
setNodeRoles( { GrooveRole, KnopRole } );
}
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)
{
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
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 rect = QRectF(0, 0, diameter, diameter);
if(switchButton->layoutDirection() == Qt::RightToLeft)
{
position = 1 - position;
}
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);
}
rect.moveLeft( ( grooveSize.height() - diameter ) / 2
+ position * ( grooveSize.width() - diameter
- ( grooveSize.height() - diameter ) ) );
}
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(grooveSize.height() < diameter)
{
result.moveLeft( ( diameter - result.height() ) / 2);
}
return result.transposed();
}
else
{
if(grooveSize.height() < diameter)
{
result.moveTop( ( diameter - result.height() ) / 2);
}
return result;
}
}
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
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);
auto result = QSizeF(qMax(diameter, grooveSize.width() ),
qMax(diameter, grooveSize.height() ) );
if(switchButton->orientation() == Qt::Vertical)
{
return result.transposed();
}
return result;
}
QSGNode* QskSwitchButtonSkinlet::updateSubNode( const QskSkinnable* skinnable,
quint8 nodeRole, QSGNode* node) const
{
const auto switchButton = static_cast< const QskSwitchButton* >( skinnable );
switch ( nodeRole )
{
case KnopRole:
return updateBoxNode( switchButton, node, QskSwitchButton::Knop );
case GrooveRole:
return updateBoxNode( switchButton, node, QskSwitchButton::Groove );
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
}

View File

@ -0,0 +1,34 @@
#ifndef QSK_SWITCH_BUTTON_SKINLET_H
#define QSK_SWITCH_BUTTON_SKINLET_H
#include "QskSkinlet.h"
class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet
{
Q_GADGET
using Inherited = QskSkinlet;
public:
enum NodeRole
{
KnopRole,
GrooveRole
};
Q_INVOKABLE QskSwitchButtonSkinlet( QskSkin* parent = nullptr );
~QskSwitchButtonSkinlet() override;
QRectF subControlRect( const QskSkinnable*,
const QRectF& rect, QskAspect::Subcontrol ) const override;
QSizeF sizeHint( const QskSkinnable*,
Qt::SizeHint, const QSizeF& ) const override;
protected:
QSGNode* updateSubNode( const QskSkinnable*,
quint8 nodeRole, QSGNode* ) const override;
};
#endif

View File

@ -183,6 +183,8 @@ HEADERS += \
controls/QskSubWindowAreaSkinlet.h \ controls/QskSubWindowAreaSkinlet.h \
controls/QskSubWindow.h \ controls/QskSubWindow.h \
controls/QskSubWindowSkinlet.h \ controls/QskSubWindowSkinlet.h \
controls/QskSwitchButton.h \
controls/QskSwitchButtonSkinlet.h \
controls/QskTabBar.h \ controls/QskTabBar.h \
controls/QskTabButton.h \ controls/QskTabButton.h \
controls/QskTabButtonSkinlet.h \ controls/QskTabButtonSkinlet.h \
@ -257,6 +259,8 @@ SOURCES += \
controls/QskSubWindowAreaSkinlet.cpp \ controls/QskSubWindowAreaSkinlet.cpp \
controls/QskSubWindow.cpp \ controls/QskSubWindow.cpp \
controls/QskSubWindowSkinlet.cpp \ controls/QskSubWindowSkinlet.cpp \
controls/QskSwitchButton.cpp \
controls/QskSwitchButtonSkinlet.cpp \
controls/QskTabBar.cpp \ controls/QskTabBar.cpp \
controls/QskTabButton.cpp \ controls/QskTabButton.cpp \
controls/QskTabButtonSkinlet.cpp \ controls/QskTabButtonSkinlet.cpp \