QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskAspect.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskAspect.h"
7
8#include <qalgorithms.h>
9#include <qdebug.h>
10#include <qmetaobject.h>
11#include <qvector.h>
12
13#include <bitset>
14#include <string>
15#include <unordered_map>
16
17static_assert( sizeof( QskAspect ) == sizeof( quint64 ),
18 "QskAspect::Aspect has to match quint64" );
19
20static void qskRegisterAspect()
21{
22 qRegisterMetaType< QskAspect >();
23
24#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
25 QMetaType::registerEqualsComparator< QskAspect >();
26#endif
27}
28
29Q_CONSTRUCTOR_FUNCTION( qskRegisterAspect )
30
31namespace
32{
33 using namespace std;
34
35 struct StateInfo
36 {
37 QskAspect::State state;
38 QByteArray name;
39 };
40
41 struct AspectRegistry
42 {
43 QVector< QByteArray > subControlNames;
44 unordered_map< const QMetaObject*, QVector< QskAspect::Subcontrol > > subControlTable;
45 unordered_map< const QMetaObject*, QVector< StateInfo > > stateTable;
46 };
47}
48
49static quint8 qskPrimitiveCount = QMetaEnum::fromType< QskAspect::Primitive >().keyCount();
50
51quint8 QskAspect::primitiveCount()
52{
53 return qskPrimitiveCount;
54}
55
56void QskAspect::reservePrimitives( quint8 count )
57{
58 // applications might need to increase the count to add additional primitives
59
60 constexpr quint8 maxCount = 1 << 5; // we have 5 bits for the primitives
61
62 Q_ASSERT( count <= maxCount );
63
64 if ( count > maxCount )
65 {
66 qWarning() << "QskAspect: having more than"
67 << maxCount << "primitives is not supported.";
68
69 count = maxCount;
70 }
71
72 if ( count > qskPrimitiveCount )
73 qskPrimitiveCount = count;
74}
75
76Q_GLOBAL_STATIC( AspectRegistry, qskAspectRegistry )
77
78QskAspect::State QskAspect::registerState(
79 const QMetaObject* metaObject, State state, const char* name )
80{
81 StateInfo info;
82 info.state = state;
83 info.name = name;
84
85 auto& stateTable = qskAspectRegistry->stateTable;
86 stateTable[ metaObject ] += info;
87
88 return state;
89}
90
92 const QMetaObject* metaObject, const char* name )
93{
94 auto& names = qskAspectRegistry->subControlNames;
95 auto& hashTable = qskAspectRegistry->subControlTable;
96
97 Q_ASSERT_X( names.size() <= LastSubcontrol, "QskAspect",
98 "There are no free subcontrol aspects; please modify your"
99 " application to declare fewer aspects, or increase the mask size of"
100 " QskAspect::Subcontrol in QskAspect.h." );
101
102 names += name;
103
104 // 0 is QskAspect::Control, so we have to start with 1
105 const auto subControl = static_cast< Subcontrol >( names.size() );
106 hashTable[ metaObject ] += subControl;
107
108 return subControl;
109}
110
111QByteArray QskAspect::subControlName( Subcontrol subControl )
112{
113 const auto& names = qskAspectRegistry->subControlNames;
114
115 const int index = subControl;
116 if ( index > 0 && index <= names.size() )
117 return names[ index - 1 ];
118
119 return QByteArray();
120}
121
122QVector< QByteArray > QskAspect::subControlNames( const QMetaObject* metaObject )
123{
124 const auto& names = qskAspectRegistry->subControlNames;
125
126 if ( metaObject == nullptr )
127 return names;
128
129 const auto subControls = QskAspect::subControls( metaObject );
130
131 QVector< QByteArray > subControlNames;
132 subControlNames.reserve( subControls.size() );
133
134 for ( auto subControl : subControls )
135 subControlNames += names[ subControl ];
136
137 return subControlNames;
138}
139
140QVector< QskAspect::Subcontrol > QskAspect::subControls( const QMetaObject* metaObject )
141{
142 if ( metaObject )
143 {
144 const auto& hashTable = qskAspectRegistry->subControlTable;
145
146 auto it = hashTable.find( metaObject );
147 if ( it != hashTable.end() )
148 return it->second;
149 }
150
151 return QVector< Subcontrol >();
152}
153
154#ifndef QT_NO_DEBUG_STREAM
155
156static QByteArray qskEnumString( const char* name, int value )
157{
158 const auto& mo = QskAspect::staticMetaObject;
159
160 const QMetaEnum metaEnum = mo.enumerator( mo.indexOfEnumerator( name ) );
161 const char* key = metaEnum.valueToKey( value );
162
163 return key ? QByteArray( key ) : QString::number( value ).toLatin1();
164}
165
166static QByteArray qskStateKey( const QMetaObject* metaObject, quint16 state )
167{
168 const auto& stateTable = qskAspectRegistry->stateTable;
169
170 for ( auto mo = metaObject; mo != nullptr; mo = mo->superClass() )
171 {
172 const auto it = stateTable.find( mo );
173 if ( it != stateTable.end() )
174 {
175 for ( const auto& info : it->second )
176 {
177 if ( info.state == state )
178 return info.name;
179 }
180 }
181 }
182
183 return QByteArray();
184}
185
186static QByteArray qskStatesToString(
187 const QMetaObject* metaObject, QskAspect::States states )
188{
189 if ( states == 0 )
190 {
191 return "NoState";
192 }
193
194 if ( metaObject == nullptr )
195 {
196 const std::bitset< 16 > stateBits( states );
197 return stateBits.to_string().c_str();
198 }
199
200 // not the fastest implementation, but as it is for debugging only
201
202 QByteArray stateString;
203
204 bool first = true;
205
206 for ( int i = 0; i < 16; i++ )
207 {
208 const uint mask = 1 << i;
209
210 if ( states & mask )
211 {
212 if ( first )
213 first = false;
214 else
215 stateString += ", ";
216
217 const auto key = qskStateKey( metaObject, mask );
218 if ( key.isEmpty() )
219 {
220 const std::bitset< 16 > stateBits( states );
221 stateString += stateBits.to_string().c_str();
222 }
223 else
224 {
225 stateString += key;
226 }
227 }
228 }
229
230 return stateString;
231}
232
233static inline QDebug qskDebugEnum(
234 QDebug debug, const char* name, int value )
235{
236 qt_QMetaEnum_debugOperator( debug, value,
237 &QskAspect::staticMetaObject, name );
238 return debug;
239}
240
241QDebug operator<<( QDebug debug, QskAspect::Type type )
242{
243 return qskDebugEnum( debug, "Type", type );
244}
245
246QDebug operator<<( QDebug debug, QskAspect::Primitive primitive )
247{
248 return qskDebugEnum( debug, "Primitive", primitive );
249}
250
251QDebug operator<<( QDebug debug, QskAspect::Subcontrol subControl )
252{
253 QDebugStateSaver saver( debug );
254
255 debug.nospace();
256 debug << "QskAspect::Subcontrol" << '(';
257 debug << QskAspect::subControlName( subControl );
258 debug << ')';
259
260 return debug;
261}
262
263QDebug operator<<( QDebug debug, QskAspect::Variation variation )
264{
265 qskDebugEnum( debug, "Variation", variation );
266 return debug;
267}
268
269QDebug operator<<( QDebug debug, QskAspect::States states )
270{
271 qskDebugStates( debug, nullptr, states );
272 return debug;
273}
274
275QDebug operator<<( QDebug debug, QskAspect aspect )
276{
277 qskDebugAspect( debug, nullptr, aspect );
278 return debug;
279}
280
281void qskDebugStates( QDebug debug,
282 const QMetaObject* metaObject, QskAspect::States states )
283{
284 QDebugStateSaver saver( debug );
285
286 debug.resetFormat();
287 debug.noquote();
288 debug.nospace();
289
290 debug << "QskAspect::States( " << qskStatesToString( metaObject, states ) << " )";
291}
292
293void qskDebugAspect( QDebug debug, const QMetaObject* metaObject, QskAspect aspect )
294{
295 QDebugStateSaver saver( debug );
296
297 debug.resetFormat();
298 debug.noquote();
299 debug.nospace();
300
301 debug << "QskAspect( ";
302
303 const auto subControlName = QskAspect::subControlName( aspect.subControl() );
304 if ( subControlName.isEmpty() )
305 debug << QByteArrayLiteral( "NoSubcontrol" );
306 else
307 debug << subControlName;
308
309 if ( aspect.section() != QskAspect::Body )
310 debug << ", " << qskEnumString( "Section", aspect.section() );
311
312 debug << ", " << qskEnumString( "Type", aspect.type() );
313 if ( aspect.isAnimator() )
314 debug << "(A)";
315
316 if ( aspect.primitive() != 0 )
317 debug << ", " << qskEnumString( "Primitive", aspect.primitive() );
318
319 if ( aspect.variation() != QskAspect::NoVariation )
320 debug << ", " << qskEnumString( "Variation", aspect.variation() );
321
322 if ( aspect.hasStates() )
323 debug << ", " << qskStatesToString( metaObject, aspect.states() );
324
325 debug << " )";
326}
327
328#endif
329
330const char* QskAspect::toPrintable() const
331{
332 QString tmp;
333
334 QDebug debug( &tmp );
335 debug << *this;
336
337 // we should find a better implementation
338 static QByteArray bytes[ 10 ];
339 static int counter = 0;
340
341 counter = ( counter + 1 ) % 10;
342
343 bytes[ counter ] = tmp.toUtf8();
344 return bytes[ counter ].constData();
345}
346
348{
349 if ( m_bits.states == NoState )
350 return NoState;
351
352 const auto n = qCountLeadingZeroBits( static_cast< quint16 >( m_bits.states ) );
353 return static_cast< QskAspect::State >( 1 << ( 15 - n ) );
354}
355
356#include "moc_QskAspect.cpp"
Lookup key for a QskSkinHintTable.
Definition QskAspect.h:15
State topState() const noexcept
constexpr bool hasStates() const noexcept
Definition QskAspect.h:482
constexpr bool isAnimator() const noexcept
Definition QskAspect.h:407
const char * toPrintable() const
Variation
Some sort of variation.
Definition QskAspect.h:82
@ NoVariation
Definition QskAspect.h:83
static QVector< QByteArray > subControlNames(const QMetaObject *=nullptr)
constexpr Primitive primitive() const noexcept
Definition QskAspect.h:497
constexpr Subcontrol subControl() const noexcept
Definition QskAspect.h:417
constexpr Variation variation() const noexcept
Definition QskAspect.h:525
constexpr Type type() const noexcept
Definition QskAspect.h:447
constexpr States states() const noexcept
Definition QskAspect.h:467
Primitive
Represents a specific element or attribute.
Definition QskAspect.h:48
static QVector< Subcontrol > subControls(const QMetaObject *)
static QByteArray subControlName(Subcontrol)
Type
Represents the type of the Aspect.
Definition QskAspect.h:21
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
Definition QskAspect.h:104
@ LastSubcontrol
Definition QskAspect.h:106
static Subcontrol nextSubcontrol(const QMetaObject *, const char *)
Definition QskAspect.cpp:91