QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskSwitchButtonSkinlet.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskSwitchButtonSkinlet.h"
7#include "QskSwitchButton.h"
8
9using Q = QskSwitchButton;
10
11static inline qreal qskEffectivePosition( const QskSwitchButton* switchButton )
12{
13 auto pos = switchButton->positionHint( QskSwitchButton::Handle );
14 pos = qBound( 0.0, pos, 1.0 );
15
16 if( switchButton->isInverted() )
17 pos = 1.0 - pos;
18
19 if ( switchButton->orientation() == Qt::Horizontal )
20 {
21 if( switchButton->layoutMirroring() )
22 pos = 1.0 - pos;
23 }
24
25 return pos;
26}
27
28static QSizeF qskIconSize( const QskSwitchButton* button )
29{
30 if( button->iconMode() == Q::NoIcon
31 || ( button->iconMode() == Q::ShowIconWhenSelected && !button->isChecked() ) )
32 {
33 return {};
34 }
35 else
36 {
37 return button->strutSizeHint( Q::Icon );
38 }
39}
40
41QskSwitchButtonSkinlet::QskSwitchButtonSkinlet( QskSkin* skin )
42 : Inherited( skin )
43{
44 setNodeRoles( { GrooveRole, HandleRole, IconRole } );
45}
46
47QskSwitchButtonSkinlet::~QskSwitchButtonSkinlet()
48{
49}
50
51QRectF QskSwitchButtonSkinlet::subControlRect( const QskSkinnable* skinnable,
52 const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
53{
54 const auto button = static_cast< const Q* >( skinnable );
55
56 if ( subControl == Q::Groove )
57 {
58 return grooveRect( button, contentsRect );
59 }
60
61 if ( subControl == Q::Handle )
62 {
63 return handleRect( button, contentsRect );
64 }
65
66 if ( subControl == Q::Icon )
67 {
68 return iconRect( button, contentsRect );
69 }
70
71 return Inherited::subControlRect( skinnable, contentsRect, subControl );
72}
73
74QSizeF QskSwitchButtonSkinlet::sizeHint( const QskSkinnable* skinnable,
75 Qt::SizeHint which, const QSizeF& ) const
76{
77 if ( which != Qt::PreferredSize )
78 return QSizeF();
79
80 const auto grooveHint = skinnable->strutSizeHint( QskSwitchButton::Groove );
81 const auto handleHint = skinnable->strutSizeHint( QskSwitchButton::Handle );
82
83 auto hint = grooveHint;
84 hint = hint.expandedTo( handleHint );
85
86 return hint;
87}
88
89QSGNode* QskSwitchButtonSkinlet::updateSubNode( const QskSkinnable* skinnable,
90 quint8 nodeRole, QSGNode* node ) const
91{
92 switch ( nodeRole )
93 {
94 case HandleRole:
95 return updateBoxNode( skinnable, node, Q::Handle );
96
97 case IconRole:
98 return updateSymbolNode( skinnable, node, Q::Icon );
99
100 case GrooveRole:
101 return updateBoxNode( skinnable, node, Q::Groove );
102 }
103
104 return Inherited::updateSubNode( skinnable, nodeRole, node );
105}
106
107QRectF QskSwitchButtonSkinlet::grooveRect(
108 const QskSwitchButton* button, const QRectF& contentsRect ) const
109{
110 auto size = button->strutSizeHint( Q::Groove );
111
112 if ( button->orientation() == Qt::Vertical )
113 {
114 if ( size.height() < 0.0 )
115 {
116 const auto handleSize = button->strutSizeHint( Q::Handle );
117 size.setHeight( 2 * handleSize.height() );
118 }
119 }
120 else
121 {
122 if ( size.width() < 0.0 )
123 {
124 const auto handleSize = button->strutSizeHint( Q::Handle );
125 size.setWidth( 2 * handleSize.width() );
126 }
127 }
128
129 size = size.expandedTo( QSize( 0.0, 0.0 ) );
130
131 QRectF r;
132 r.setSize( size );
133 r.moveCenter( contentsRect.center() );
134
135 return r;
136}
137
138QRectF QskSwitchButtonSkinlet::handleRect(
139 const QskSwitchButton* button, const QRectF& contentsRect ) const
140{
141 const auto grooveRect = subControlRect( button, contentsRect, Q::Groove );
142 const auto pos = qskEffectivePosition( button );
143
144 auto size = button->strutSizeHint( Q::Handle );
145
146 qreal cx, cy;
147
148 if( button->orientation() == Qt::Vertical )
149 {
150 const qreal y0 = grooveRect.y() + 0.5 * size.height();
151 const qreal h = grooveRect.height() - size.height();
152
153 cx = grooveRect.x() + 0.5 * grooveRect.width();
154 cy = y0 + pos * h;
155 }
156 else
157 {
158 const qreal x0 = grooveRect.x() + 0.5 * size.width();
159 const qreal w = grooveRect.width() - size.width();
160
161 cx = x0 + pos * w;
162 cy = grooveRect.y() + 0.5 * grooveRect.height();
163 }
164
165 auto iconSize = qskIconSize( button );
166
167 if( !iconSize.isNull() )
168 {
169 auto padding = button->paddingHint( Q::Icon );
170
171 // need to compensate for the margins,
172 // which might differ between states:
173 auto margins = button->marginHint( Q::Handle );
174
175 iconSize = iconSize.grownBy( padding ).grownBy( margins );
176 size = size.expandedTo( iconSize );
177 }
178
179 QRectF r;
180 r.setSize( size );
181 r.moveCenter( QPointF( cx, cy ) );
182
183 return r;
184}
185
186QRectF QskSwitchButtonSkinlet::iconRect( const QskSwitchButton* button, const QRectF& contentsRect ) const
187{
188 QRectF rect;
189 rect.setSize( qskIconSize( button ) );
190 const auto hr = handleRect( button, contentsRect );
191 rect.moveCenter( hr.center() );
192 return rect;
193}
194
195
196#include "moc_QskSwitchButtonSkinlet.cpp"
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
Definition QskAspect.h:104
bool layoutMirroring() const
Definition QskItem.cpp:511
QMarginsF paddingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a padding hint.
QMarginsF marginHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a margin hint.
QSizeF strutSizeHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a strut size hint.