switch button adjustments

This commit is contained in:
Uwe Rathmann 2021-08-02 19:17:04 +02:00
parent 4a7d7d0e2d
commit 0e334e5fd9
7 changed files with 178 additions and 139 deletions

View File

@ -8,6 +8,7 @@
#include <QskSwitchButton.h>
#include <QskLinearBox.h>
#include <QskTextLabel.h>
#include <QskSeparator.h>
#include <QskRgbValue.h>
@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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"

View File

@ -1,9 +1,8 @@
#ifndef QSK_SWITCH_BUTTON_H
#define QSK_SWITCH_BUTTON_H
#include "QskAbstractButton.h"
#include "QskNamespace.h"
#include <qnamespace.h>
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

View File

@ -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"

View File

@ -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