layout code in QskSwitchButtonSkinlet improved - still some way to go

until the switch is perfectly themable and looks like in the material
specs
This commit is contained in:
Uwe Rathmann 2021-08-03 15:02:33 +02:00
parent 0e334e5fd9
commit 1b4be3bc23
4 changed files with 146 additions and 97 deletions

View File

@ -492,36 +492,43 @@ void Editor::setupSwitchButton()
using A = QskAspect;
using Q = QskSwitchButton;
const qreal radius = qskDpiScaled( 18 );
const qreal knopLength = radius - 4;
const qreal radius = qskDpiScaled( 10 );
const qreal handleSize = 2 * radius;
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
const QSizeF grooveSize( 3.4 * radius, 1.2 * radius );
setStrutSize( Q::Groove | A::Horizontal, grooveSize );
setStrutSize( Q::Groove | A::Vertical, grooveSize.transposed() );
setGradient( Q::Groove, m_pal.darker125 );
setGradient( Q::Groove | Q::Checkable | Q::Disabled, m_pal.lighter150 );
setGradient( Q::Groove | Q::Checkable | Q::Checked, m_pal.darker200 );
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::Handle, knopLength );
setMetric( Q::Handle | A::Size,knopLength );
setGradient( Q::Handle, QskGradient( Qt::Vertical, m_pal.lighter150, m_pal.lighter125 ) );
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
setStrutSize( Q::Handle, handleSize, handleSize );
setBoxBorderMetrics( Q::Handle, 2 );
setColor( Q::Handle | Q::Disabled, m_pal.lighter125 );
setGradient( Q::Handle, QskGradient( Qt::Vertical, m_pal.lighter150, m_pal.lighter125 ) );
setGradient( Q::Handle | Q::Checkable | Q::Checked, m_pal.accentColor );
setGradient( 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::Handle | state | A::Position;
auto aspect = Q::Handle | Q::Checkable | state | A::Position;
setMetric( aspect | Q::Checked, 0 );
setMetric( aspect, 1 );
aspect = Q::Groove | state | A::Color;
setColor( aspect | Q::Checked, m_pal.baseColor);
setMetric( aspect, 0 );
setMetric( aspect | Q::Checked, 1 );
}
setAnimation( Q::Handle | A::Color, qskDuration );
setAnimation( Q::Handle | A::Metric, qskDuration );
setAnimation( Q::Groove | A::Color, qskDuration );
}

View File

@ -859,33 +859,38 @@ void Editor::setupSwitchButton()
using Q = QskSwitchButton;
const qreal radius = qskDpiScaled( 18 );
const qreal handleLength = radius - 4;
const qreal handleSize = 2 * ( radius - 2 );
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
const QSizeF grooveSize( 3.4 * radius, 2 * radius );
setStrutSize( Q::Groove | A::Horizontal, grooveSize );
setStrutSize( Q::Groove | A::Vertical, grooveSize.transposed() );
setGradient( Q::Groove, m_pal.theme );
setGradient( Q::Groove | Q::Checkable | Q::Checked, m_pal.highlighted );
setGradient( Q::Groove | Q::Checkable | Q::Disabled, m_pal.lighter150 );
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::Handle, handleLength );
setMetric( Q::Handle | A::Size, handleLength );
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
setStrutSize( Q::Handle, handleSize, handleSize );
setGradient( Q::Handle, QskGradient( Qt::Vertical, m_pal.lighter150, m_pal.lighter110 ) );
setGradient( Q::Handle | Q::Disabled, 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::Handle | state | A::Position;
auto aspect = Q::Handle | Q::Checkable | state | A::Position;
setMetric( aspect | Q::Checked, 0 );
setMetric( aspect, 1 );
aspect = Q::Groove | state | A::Color;
setColor( aspect | Q::Checked, m_pal.baseActive);
setMetric( aspect, 0 );
setMetric( aspect | Q::Checked, 1 );
}
setAnimation( Q::Handle | A::Metric, qskDuration );

View File

@ -7,6 +7,23 @@
#include "QskSwitchButtonSkinlet.h"
#include "QskSGNode.h"
static inline qreal qskEffectivePosition( const QskSwitchButton* switchButton )
{
auto pos = switchButton->metric( QskSwitchButton::Handle | QskAspect::Position );
pos = qBound( 0.0, pos, 1.0 );
if( switchButton->isInverted() )
pos = 1.0 - pos;
if ( switchButton->orientation() == Qt::Horizontal )
{
if( switchButton->layoutMirroring() )
pos = 1.0 - pos;
}
return pos;
}
QskSwitchButtonSkinlet::QskSwitchButtonSkinlet( QskSkin* skin )
: Inherited( skin )
{
@ -18,94 +35,38 @@ QskSwitchButtonSkinlet::~QskSwitchButtonSkinlet()
}
QRectF QskSwitchButtonSkinlet::subControlRect( const QskSkinnable* skinnable,
const QRectF& contentsRect, QskAspect::Subcontrol subControl) const
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
{
using Q = QskSwitchButton;
const auto switchButton = static_cast< const Q* >( skinnable );
if ( subControl == Q::Handle )
{
const auto diameter = 2 * skinnable->metric( Q::Handle | QskAspect::Size );
const auto grooveSize = skinnable->strutSizeHint( Q::Groove );
auto position = skinnable->metric( Q::Handle | QskAspect::Position );
if( switchButton->isInverted() )
position = 1.0 - position;
auto rect = QRectF( 0, 0, diameter, diameter );
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( 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 ) ) );
}
return rect;
return handleRect( skinnable, contentsRect );
}
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 );
return result.transposed();
}
else
{
if( grooveSize.height() < diameter )
result.moveTop( ( diameter - result.height() ) / 2 );
return result;
}
return grooveRect( skinnable, contentsRect );
}
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
QSizeF QskSwitchButtonSkinlet::sizeHint( const QskSkinnable* skinnable,
Qt::SizeHint, const QSizeF&) const
Qt::SizeHint which, const QSizeF& ) const
{
using Q = QskSwitchButton;
if ( which != Qt::PreferredSize )
return QSizeF();
const auto switchButton = static_cast< const Q* >( skinnable );
const auto diameter = 2 * skinnable->metric( Q::Handle | QskAspect::Size );
auto hint = skinnable->strutSizeHint( Q::Groove );
hint = hint.expandedTo( QSizeF( diameter, diameter ) );
if( switchButton->orientation() == Qt::Vertical )
hint.transpose();
auto hint = skinnable->strutSizeHint( QskSwitchButton::Groove );
hint = hint.expandedTo( skinnable->strutSizeHint( QskSwitchButton::Handle ) );
return hint;
}
QSGNode* QskSwitchButtonSkinlet::updateSubNode( const QskSkinnable* skinnable,
quint8 nodeRole, QSGNode* node) const
quint8 nodeRole, QSGNode* node ) const
{
using Q = QskSwitchButton;
@ -121,4 +82,76 @@ QSGNode* QskSwitchButtonSkinlet::updateSubNode( const QskSkinnable* skinnable,
return Inherited::updateSubNode( skinnable, nodeRole, node );
}
QRectF QskSwitchButtonSkinlet::grooveRect(
const QskSkinnable* skinnable, const QRectF& contentsRect ) const
{
using Q = QskSwitchButton;
const auto switchButton = static_cast< const Q* >( skinnable );
auto size = skinnable->strutSizeHint( Q::Groove );
if ( switchButton->orientation() == Qt::Vertical )
{
if ( size.height() < 0.0 )
{
const auto handleSize = skinnable->strutSizeHint( Q::Handle );
size.setHeight( 2 * handleSize.height() );
}
}
else
{
if ( size.width() < 0.0 )
{
const auto handleSize = skinnable->strutSizeHint( Q::Handle );
size.setWidth( 2 * handleSize.width() );
}
}
size = size.expandedTo( QSize( 0.0, 0.0 ) );
QRectF r;
r.setSize( size );
r.moveCenter( contentsRect.center() );
return r;
}
QRectF QskSwitchButtonSkinlet::handleRect(
const QskSkinnable* skinnable, const QRectF& contentsRect ) const
{
using Q = QskSwitchButton;
const auto switchButton = static_cast< const Q* >( skinnable );
const auto grooveRect = subControlRect( skinnable, contentsRect, Q::Groove );
const auto pos = qskEffectivePosition( switchButton );
const auto size = skinnable->strutSizeHint( Q::Handle );
qreal cx, cy;
if( switchButton->orientation() == Qt::Vertical )
{
const qreal y0 = grooveRect.y() + 0.5 * size.height();
const qreal h = grooveRect.height() - size.height();
cx = grooveRect.x() + 0.5 * grooveRect.width();
cy = y0 + pos * h;
}
else
{
const qreal x0 = grooveRect.x() + 0.5 * size.width();
const qreal w = grooveRect.width() - size.width();
cx = x0 + pos * w;
cy = grooveRect.y() + 0.5 * grooveRect.height();
}
QRectF r;
r.setSize( size );
r.moveCenter( QPointF( cx, cy ) );
return r;
}
#include "moc_QskSwitchButtonSkinlet.cpp"

View File

@ -21,11 +21,11 @@ class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet
HandleRole
};
Q_INVOKABLE QskSwitchButtonSkinlet( QskSkin* parent = nullptr );
Q_INVOKABLE QskSwitchButtonSkinlet( QskSkin* = nullptr );
~QskSwitchButtonSkinlet() override;
QRectF subControlRect( const QskSkinnable*,
const QRectF& rect, QskAspect::Subcontrol ) const override;
const QRectF&, QskAspect::Subcontrol ) const override;
QSizeF sizeHint( const QskSkinnable*,
Qt::SizeHint, const QSizeF& ) const override;
@ -33,6 +33,10 @@ class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet
protected:
QSGNode* updateSubNode( const QskSkinnable*,
quint8 nodeRole, QSGNode* ) const override;
private:
QRectF grooveRect( const QskSkinnable*, const QRectF& ) const;
QRectF handleRect( const QskSkinnable*, const QRectF& ) const;
};
#endif