QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskRadioBoxSkinlet.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskRadioBoxSkinlet.h"
7
8#include "QskRadioBox.h"
9#include "QskFunctions.h"
10
11#include <qfontmetrics.h>
12#include <qmath.h>
13
14namespace
15{
16 QSizeF buttonSizeHint( const QskSkinnable* skinnable,
17 const QFontMetricsF& fm, const QString& text )
18 {
19 using Q = QskRadioBox;
20
21 auto hint = skinnable->strutSizeHint( Q::CheckIndicatorPanel );
22
23 hint.rwidth() += skinnable->spacingHint( Q::Button )
24 + qskHorizontalAdvance( fm, text );
25 hint.rheight() = qMax( hint.height(), fm.height() );
26
27 hint = hint.grownBy( skinnable->paddingHint( Q::Button ) );
28 hint = hint.expandedTo( skinnable->strutSizeHint( Q::Button ) );
29
30 return hint;
31 }
32
33 QSizeF buttonSizeHint( const QskRadioBox* radioBox, int index )
34 {
35 const QFontMetrics fm( radioBox->effectiveFont( QskRadioBox::Text ) );
36 return buttonSizeHint( radioBox, fm, radioBox->optionAt( index ) );
37 }
38}
39
40QskRadioBoxSkinlet::QskRadioBoxSkinlet( QskSkin* )
41{
42 setNodeRoles( { PanelRole, ButtonRole, CheckPanelRole,
43 CheckIndicatorRole, TextRole } );
44}
45
46QskRadioBoxSkinlet::~QskRadioBoxSkinlet()
47{
48}
49
50QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable,
51 const QRectF& contentsRect, QskAspect::Subcontrol subcontrol ) const
52{
53 Q_UNUSED( skinnable );
54 Q_UNUSED( subcontrol );
55
56 return contentsRect;
57}
58
59QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable,
60 quint8 nodeRole, QSGNode* node ) const
61{
62 using Q = QskRadioBox;
63
64 switch( nodeRole )
65 {
66 case PanelRole:
67 return updateBoxNode( skinnable, node, Q::Panel );
68
69 case ButtonRole:
70 return updateSeriesNode( skinnable, Q::Button, node );
71
72 case CheckPanelRole:
73 return updateSeriesNode( skinnable, Q::CheckIndicatorPanel, node );
74
75 case CheckIndicatorRole:
76 return updateSeriesNode( skinnable, Q::CheckIndicator, node );
77
78 case TextRole:
79 return updateSeriesNode( skinnable, Q::Text, node );
80 }
81
82 return Inherited::updateSubNode( skinnable, nodeRole, node );
83}
84
85int QskRadioBoxSkinlet::sampleCount(
86 const QskSkinnable* skinnable, QskAspect::Subcontrol ) const
87{
88 const auto radioBox = static_cast< const QskRadioBox* >( skinnable );
89 return radioBox->options().count();
90}
91
92QRectF QskRadioBoxSkinlet::buttonRect(
93 const QskRadioBox* radioBox, const QRectF& rect, int index ) const
94{
95 using Q = QskRadioBox;
96
97 /*
98 code only works when all buttons have the same height
99 - what might be wron, when lineWrapping is enabled TODO ...
100 */
101
102 const auto h = buttonSizeHint( radioBox, index ).height();
103 const auto y = index * ( h + radioBox->spacingHint( Q::Panel ) );
104
105 const auto r = radioBox->subControlContentsRect( rect, Q::Panel );
106 return QRectF( r.left(), r.top() + y, r.width(), h );
107}
108
109QRectF QskRadioBoxSkinlet::checkPanelRect( const QskRadioBox* radioBox,
110 const QRectF& rect, int index ) const
111{
112 using Q = QskRadioBox;
113
114 auto r = sampleRect( radioBox, rect, Q::Button, index );
115 r = radioBox->innerBox( Q::Button, r );
116
117 auto alignment = radioBox->alignmentHint( Q::CheckIndicatorPanel, Qt::AlignCenter );
118
119 alignment &= Qt::AlignVertical_Mask;
120 alignment |= radioBox->layoutMirroring() ? Qt::AlignRight : Qt::AlignLeft;
121
122 auto size = radioBox->strutSizeHint( Q::CheckIndicatorPanel );
123 size = size.grownBy( radioBox->marginHint( Q::CheckIndicatorPanel ) );
124
125 return qskAlignedRectF( r, size.width(), size.height(), alignment );
126}
127
128QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radioBox,
129 const QRectF& rect, int index ) const
130{
131 using Q = QskRadioBox;
132
133 auto r = sampleRect( radioBox, rect, Q::Button, index );
134 r = radioBox->innerBox( Q::Button, r );
135
136 const auto checkPanelRect = sampleRect(
137 radioBox, rect, Q::CheckIndicatorPanel, index );
138
139 const auto spacing = radioBox->spacingHint( Q::Button );
140
141 if ( !radioBox->layoutMirroring() )
142 r.setLeft( checkPanelRect.right() + spacing );
143 else
144 r.setRight( checkPanelRect.left() - spacing );
145
146 return r;
147}
148
149QRectF QskRadioBoxSkinlet::sampleRect( const QskSkinnable* skinnable,
150 const QRectF& rect, QskAspect::Subcontrol subControl, int index ) const
151{
152 using Q = QskRadioBox;
153
154 auto radioBox = static_cast< const QskRadioBox* >( skinnable );
155
156 if( subControl == Q::Text )
157 return textRect( radioBox, rect, index );
158
159 if( subControl == Q::Button )
160 return buttonRect( radioBox, rect, index );
161
162 if( subControl == Q::CheckIndicatorPanel )
163 return checkPanelRect( radioBox, rect, index );
164
165 if( subControl == Q::CheckIndicator )
166 {
167 auto r = sampleRect( radioBox, rect, Q::CheckIndicatorPanel, index );
168 r = r.marginsRemoved( radioBox->paddingHint( Q::CheckIndicatorPanel ) );
169
170 return r;
171 }
172
173 return QRectF();
174}
175
176QskAspect::States QskRadioBoxSkinlet::sampleStates(
177 const QskSkinnable* skinnable, QskAspect::Subcontrol, int index ) const
178{
179 using Q = QskRadioBox;
180
181 auto radioBox = static_cast< const QskRadioBox* >( skinnable );
182
183 auto states = radioBox->skinStates();
184
185 if( radioBox->selectedIndex() == index )
186 states |= Q::Selected;
187
188 if( radioBox->pressedIndex() == index )
189 states |= Q::Pressed;
190
191#if 1
192 if( radioBox->positionHint( Q::CheckIndicator | Q::Hovered ) == index )
193 states |= Q::Hovered;
194 else
195 states &= ~Q::Hovered;
196
197 if( radioBox->positionHint( Q::CheckIndicator ) == index )
198 states |= Q::Focused;
199 else
200 states &= ~Q::Focused;
201#endif
202
203 return states;
204}
205
206QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable,
207 QskAspect::Subcontrol subcontrol, int index, QSGNode* node ) const
208{
209 using Q = QskRadioBox;
210
211 auto radioBox = static_cast< const QskRadioBox* >( skinnable );
212
213 auto rect = sampleRect( skinnable, radioBox->contentsRect(), subcontrol, index );
214
215 if( subcontrol == Q::Text )
216 {
217 Qt::Alignment alignment = Qt::AlignVCenter;
218 alignment |= ( radioBox->layoutMirroring() ? Qt::AlignRight : Qt::AlignLeft );
219
220 alignment = radioBox->alignmentHint( Q::Text, Qt::AlignCenter );
221 alignment &= Qt::AlignVertical_Mask;
222 alignment |= radioBox->layoutMirroring() ? Qt::AlignRight : Qt::AlignLeft;
223
224 return updateTextNode( radioBox, node, rect,
225 alignment, radioBox->optionAt( index ), subcontrol );
226 }
227
228 if ( subcontrol == Q::CheckIndicatorPanel || subcontrol == Q::CheckIndicator )
229 return updateBoxNode( radioBox, node, rect, subcontrol );
230
231 return node;
232}
233
234QSizeF QskRadioBoxSkinlet::sizeHint( const QskSkinnable* skinnable,
235 Qt::SizeHint which, const QSizeF& constraint ) const
236{
237 using Q = QskRadioBox;
238
239 if ( which != Qt::PreferredSize )
240 return QSizeF();
241
242 if ( constraint.width() >= 0.0 )
243 {
244 // heightForWidth would make sense when word wrapping is enabled TODO ...
245 }
246
247 const auto radioBox = static_cast< const QskRadioBox* >( skinnable );
248
249 const QFontMetrics fm( radioBox->effectiveFont( QskRadioBox::Text ) );
250
251 qreal w = 0.0;
252 qreal h = 0.0;
253
254 const auto options = radioBox->options();
255 for( const auto& option : options )
256 {
257 const auto buttonSize = buttonSizeHint( radioBox, fm, option );
258
259 w = qMax( w, buttonSize.width() );
260 h += buttonSize.height();
261 }
262
263 if ( auto count = radioBox->options().count() )
264 h += ( count - 1 ) * skinnable->spacingHint( Q::Panel );
265
266 QSizeF hint( w, h );
267 hint = hint.grownBy( skinnable->paddingHint( Q::Panel ) );
268 hint = hint.expandedTo( skinnable->strutSizeHint( Q::Panel ) );
269
270 return hint;
271}
272
273#include "moc_QskRadioBoxSkinlet.cpp"
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
Definition QskAspect.h:104
static const QskAspect::State Hovered
Definition QskControl.h:56
QRectF subControlContentsRect(QskAspect::Subcontrol) const
QRectF contentsRect() const
static const QskAspect::State Focused
Definition QskControl.h:56
bool layoutMirroring() const
Definition QskItem.cpp:511
qreal spacingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a spacing hint.
QMarginsF paddingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a padding hint.
QMarginsF marginHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a margin hint.
QFont effectiveFont(QskAspect) const
QSizeF strutSizeHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a strut size hint.
QRectF innerBox(QskAspect, const QRectF &outerBox) const
Calculate the rectangle, whith paddings, indentations being subtracted.
Qt::Alignment alignmentHint(QskAspect, Qt::Alignment=Qt::Alignment()) const
Retrieves an alignment hint.