QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskSkinTransition.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskSkinTransition.h"
7#include "QskColorFilter.h"
8#include "QskControl.h"
9#include "QskWindow.h"
10#include "QskAnimationHint.h"
11#include "QskHintAnimator.h"
12#include "QskSkin.h"
13#include "QskSkinHintTable.h"
14#include "QskFontRole.h"
15#include "QskAspect.h"
16
17#include <qglobalstatic.h>
18#include <qguiapplication.h>
19#include <qobject.h>
20#include <qvector.h>
21#include <qhash.h>
22
23#include <vector>
24
25#if 1
26
27/*
28 We need to find a way how to retrieve the extra states that are provided
29 by QskSkinlet::sampleStates from the control in a generic way. For the moment we
30 return a hardcoded list of states that we know because we know. TODO ...
31 */
32#include "QskMenu.h"
33#include "QskRadioBox.h"
34#include "QskSegmentedBar.h"
35#include "QskListView.h"
36
37static QskAspect::State qskSelectedSampleState( const QskControl* control )
38{
39 if ( qobject_cast< const QskMenu* >( control ) )
40 return QskMenu::Selected;
41
42 if ( qobject_cast< const QskRadioBox* >( control ) )
43 return QskRadioBox::Selected;
44
45 if ( qobject_cast< const QskSegmentedBar* >( control ) )
46 return QskSegmentedBar::Selected;
47
48 if ( qobject_cast< const QskListView* >( control ) )
49 return QskListView::Selected;
50
51 return QskAspect::NoState;
52}
53
54#endif
55
56static bool qskHasHintTable( const QskSkin* skin, const QskSkinHintTable& hintTable )
57{
58 return skin->hintTable().hints().isSharedWith( hintTable.hints() );
59}
60
61static void qskSendStyleEventRecursive( QQuickItem* item )
62{
63 QEvent event( QEvent::StyleChange );
64 QCoreApplication::sendEvent( item, &event );
65
66 const auto children = item->childItems();
67 for ( auto child : children )
68 qskSendStyleEventRecursive( child );
69}
70
71static void qskAddCandidates( const QskSkinTransition::Type mask,
72 const QHash< QskAspect, QVariant >& hints, QSet< QskAspect >& candidates )
73{
74 for ( auto it = hints.constBegin(); it != hints.constEnd(); ++it )
75 {
76 const auto aspect = it.key().trunk();
77
78 if ( aspect.isAnimator() )
79 continue;
80
81 bool isCandidate = false;
82
83 switch( aspect.type() )
84 {
85 case QskAspect::NoType:
86 {
87 if ( aspect.primitive() == QskAspect::GraphicRole )
88 {
89 isCandidate = mask & QskSkinTransition::Color;
90 }
91 else if ( aspect.primitive() == QskAspect::FontRole )
92 {
93 isCandidate = mask & QskSkinTransition::Metric;
94 }
95 break;
96 }
98 {
99 isCandidate = mask & QskSkinTransition::Color;
100 break;
101 }
103 {
104 isCandidate = mask & QskSkinTransition::Metric;
105 break;
106 }
107 }
108
109 if ( isCandidate )
110 candidates += aspect;
111 }
112}
113
114namespace
115{
116 class UpdateInfo
117 {
118 public:
119 enum UpdateMode
120 {
121 Polish = 1,
122 Update = 2
123 };
124
125 static inline bool compare( const UpdateInfo& i1, const UpdateInfo& i2 )
126 {
127 return i1.control.data() < i2.control.data();
128 }
129
130 QPointer< QskControl > control;
131 int updateModes;
132 };
133
134 class HintAnimator : public QskHintAnimator
135 {
136 public:
137 inline HintAnimator( const QskControl* control, const QskAspect aspect,
138 const QVariant& value1, const QVariant& value2, QskAnimationHint hint )
139 {
140 setAspect( aspect );
141 setStartValue( value1 );
142 setEndValue( value2 );
143
144 setDuration( hint.duration );
145 setEasingCurve( hint.type );
146 setUpdateFlags( hint.updateFlags );
147
148 setWindow( control->window() );
149 }
150 };
151
152 class WindowAnimator
153 {
154 public:
155 WindowAnimator( QQuickWindow* = nullptr );
156
157 const QQuickWindow* window() const;
158
159 void start();
160 bool isRunning() const;
161
162 QVariant animatedHint( QskAspect ) const;
163 QVariant animatedGraphicFilter( int graphicRole ) const;
164 QVariant animatedFontSize( const QskFontRole& ) const;
165
166 void addGraphicFilterAnimators( const QskAnimationHint&,
167 const QHash< int, QskColorFilter >&, const QHash< int, QskColorFilter >& );
168
169 void addFontSizeAnimators( const QskAnimationHint&,
170 const QHash< QskFontRole, QFont >&, const QHash< QskFontRole, QFont >& );
171
172 void addItemAspects( QQuickItem*,
173 const QskAnimationHint&, const QSet< QskAspect >&,
174 const QskSkinHintTable&, const QskSkinHintTable& );
175
176 void update();
177
178 private:
179
180 bool isControlAffected( const QskControl*,
181 const QVector< QskAspect::Subcontrol >&, QskAspect ) const;
182
183 void addHint( const QskControl*,
185 const QskSkinHintTable&, const QskSkinHintTable& );
186
187 void storeAnimator( const QskControl*, const QskAspect,
188 const QVariant&, const QVariant&, QskAnimationHint );
189
190 void storeUpdateInfo( const QskControl*, QskAspect );
191
192 QQuickWindow* m_window;
193
194 QHash< QskAspect, HintAnimator > m_animatorMap;
195 QHash< int, QskVariantAnimator > m_graphicFilterAnimatorMap;
196 QHash< QskFontRole, QskVariantAnimator > m_fontSizeAnimatorMap;
197
198 std::vector< UpdateInfo > m_updateInfos; // vector: for fast iteration
199 };
200
201 class ApplicationAnimator : public QObject
202 {
203 Q_OBJECT
204
205 public:
206 ~ApplicationAnimator() override;
207
208 WindowAnimator* windowAnimator( const QQuickWindow* );
209
210 void add( WindowAnimator* );
211
212 void start();
213 void reset();
214 bool isRunning() const;
215
216 private Q_SLOTS:
217 // using functor slots ?
218 void notify( QQuickWindow* );
219 void cleanup( QQuickWindow* );
220
221 private:
222 /*
223 It should be possible to find an implementation, that interpolates
224 a skin hint only once for all windows. But as our animtors are driven by
225 QQuickWindow::afterAnimating the code will have to be somehow tricky.
226 But as skin transitions are no operations, that happen often, we can accept
227 the overhaed of the current implementation and do the finetuning later.
228 */
229 std::vector< WindowAnimator* > m_windowAnimators;
230 QMetaObject::Connection m_connections[2];
231 };
232}
233
234Q_GLOBAL_STATIC( ApplicationAnimator, qskApplicationAnimator )
235
236WindowAnimator::WindowAnimator( QQuickWindow* window )
237 : m_window( window )
238{
239}
240
241inline const QQuickWindow* WindowAnimator::window() const
242{
243 return m_window;
244}
245
246void WindowAnimator::start()
247{
248 for ( auto& it : m_animatorMap )
249 it.start();
250
251 for ( auto& it : m_graphicFilterAnimatorMap )
252 it.start();
253
254 for ( auto& it : m_fontSizeAnimatorMap )
255 it.start();
256}
257
258bool WindowAnimator::isRunning() const
259{
260 if ( !m_animatorMap.empty() )
261 {
262 const auto& animator = m_animatorMap.constBegin().value();
263 if ( animator.isRunning() )
264 return true;
265 }
266
267 if ( !m_graphicFilterAnimatorMap.empty() )
268 {
269 const auto& animator = m_graphicFilterAnimatorMap.constBegin().value();
270 if ( animator.isRunning() )
271 return true;
272 }
273
274 if ( !m_fontSizeAnimatorMap.empty() )
275 {
276 const auto& animator = m_fontSizeAnimatorMap.constBegin().value();
277 if ( animator.isRunning() )
278 return true;
279 }
280
281 return false;
282}
283
284inline QVariant WindowAnimator::animatedHint( QskAspect aspect ) const
285{
286 auto it = m_animatorMap.constFind( aspect );
287 if ( it != m_animatorMap.constEnd() )
288 {
289 const auto& animator = it.value();
290 if ( animator.isRunning() )
291 return animator.currentValue();
292 }
293
294 return QVariant();
295}
296
297inline QVariant WindowAnimator::animatedGraphicFilter( int graphicRole ) const
298{
299 auto it = m_graphicFilterAnimatorMap.constFind( graphicRole );
300 if ( it != m_graphicFilterAnimatorMap.constEnd() )
301 {
302 const auto& animator = it.value();
303 if ( animator.isRunning() )
304 return animator.currentValue();
305 }
306
307 return QVariant();
308}
309
310inline QVariant WindowAnimator::animatedFontSize( const QskFontRole& fontRole ) const
311{
312 auto it = m_fontSizeAnimatorMap.constFind( fontRole );
313 if ( it != m_fontSizeAnimatorMap.constEnd() )
314 {
315 const auto& animator = it.value();
316 if ( animator.isRunning() )
317 return animator.currentValue();
318 }
319
320 return QVariant();
321}
322
323void WindowAnimator::addGraphicFilterAnimators(
324 const QskAnimationHint& animatorHint,
325 const QHash< int, QskColorFilter >& filters1,
326 const QHash< int, QskColorFilter >& filters2 )
327{
328 const QskColorFilter noFilter;
329
330 for ( auto it2 = filters2.constBegin(); it2 != filters2.constEnd(); ++it2 )
331 {
332 auto it1 = filters1.constFind( it2.key() );
333 if ( it1 == filters1.constEnd() )
334 it1 = filters1.constFind( 0 );
335
336 const auto& f1 = ( it1 != filters1.constEnd() ) ? it1.value() : noFilter;
337 const auto& f2 = it2.value();
338
339 if ( f1 != f2 )
340 {
341 QskVariantAnimator animator;
342 animator.setWindow( m_window );
343 animator.setDuration( animatorHint.duration );
344 animator.setEasingCurve( animatorHint.type );
345 animator.setStartValue( QVariant::fromValue( f1 ) );
346 animator.setEndValue( QVariant::fromValue( f2 ) );
347
348 m_graphicFilterAnimatorMap.insert( it2.key(), animator );
349 }
350 }
351}
352
353// from QskSkin.cpp
354extern QFont qskResolvedFont(
355 const QHash< QskFontRole, QFont >&, const QskFontRole& );
356
357void WindowAnimator::addFontSizeAnimators(
358 const QskAnimationHint& animatorHint,
359 const QHash< QskFontRole, QFont >& fonts1,
360 const QHash< QskFontRole, QFont >& fonts2 )
361{
362 for ( int i = 0; i <= QskFontRole::Display; i++ )
363 {
364 for ( int j = 0; j <= QskFontRole::VeryHigh; j++ )
365 {
366 const QskFontRole fontRole(
367 static_cast< QskFontRole::Category >( i ),
368 static_cast< QskFontRole::Emphasis >( j )
369 );
370
371 const auto size1 = qskResolvedFont( fonts1, fontRole ).pixelSize();
372 const auto size2 = qskResolvedFont( fonts2, fontRole ).pixelSize();
373
374 if ( ( size1 > 0 ) && ( size2 > 0 ) && ( size1 != size2 ) )
375 {
376 QskVariantAnimator animator;
377 animator.setWindow( m_window );
378 animator.setDuration( animatorHint.duration );
379 animator.setEasingCurve( animatorHint.type );
380 animator.setStartValue( QVariant::fromValue( size1 ) );
381 animator.setEndValue( QVariant::fromValue( size2 ) );
382
383 m_fontSizeAnimatorMap.insert( fontRole, animator );
384 }
385 }
386 }
387}
388
389void WindowAnimator::addItemAspects( QQuickItem* item,
390 const QskAnimationHint& animatorHint, const QSet< QskAspect >& candidates,
391 const QskSkinHintTable& table1, const QskSkinHintTable& table2 )
392{
393 if ( auto control = qskControlCast( ( const QQuickItem* )item ) )
394 {
395 if ( control->isVisible() && control->isInitiallyPainted() &&
396 qskHasHintTable( control->effectiveSkin(), table2 ) )
397 {
398 const auto subControls = control->subControls();
399
400 const auto& localTable = control->hintTable();
401
402 for ( auto aspect : candidates )
403 {
404 if ( isControlAffected( control, subControls, aspect ) )
405 {
406 aspect.setVariation( control->effectiveVariation() );
407 aspect.setStates( control->skinStates() );
408 aspect.setSection( control->section() );
409
410 if ( !localTable.resolvedHint( aspect ) )
411 addHint( control, animatorHint, aspect, table1, table2 );
412
413 if ( auto state = qskSelectedSampleState( control ) )
414 {
415 aspect.addStates( state );
416 if ( !localTable.resolvedHint( aspect ) )
417 addHint( control, animatorHint, aspect, table1, table2 );
418 }
419 }
420 }
421
422#if 1
423 /*
424 As it is hard to identify which controls depend on the animated
425 graphic filters we schedule an initial update and let the
426 controls do the rest: see QskSkinnable::effectiveGraphicFilter
427 */
428 item->update();
429#endif
430 }
431 }
432
433 const auto children = item->childItems();
434 for ( auto child : children )
435 addItemAspects( child, animatorHint, candidates, table1, table2 );
436}
437
438void WindowAnimator::update()
439{
440 for ( auto& info : m_updateInfos )
441 {
442 if ( auto control = info.control )
443 {
444 if ( info.updateModes & UpdateInfo::Polish )
445 {
446 control->resetImplicitSize();
447 control->polish();
448 }
449
450 if ( info.updateModes & UpdateInfo::Update )
451 control->update();
452 }
453 }
454}
455
456void WindowAnimator::addHint( const QskControl* control,
457 const QskAnimationHint& animatorHint, QskAspect aspect,
458 const QskSkinHintTable& table1, const QskSkinHintTable& table2 )
459{
460 QskAspect r1, r2;
461
462 const auto v1 = table1.resolvedHint( aspect, &r1 );
463 const auto v2 = table2.resolvedHint( aspect, &r2 );
464
465 if ( v1 && v2 )
466 {
467 if ( r1.section() == r2.section() )
468 aspect.setSection( r2.section() );
469
470 if ( r1.variation() == r2.variation() )
471 aspect.setVariation( r2.variation() );
472
473 if ( r1.states() == r2.states() )
474 aspect.setStates( r2.states() );
475
476 bool accecptIdentity = false;
477 if ( aspect != aspect.trunk() )
478 {
479 /*
480 We might need an animator even if the values do not differ
481 to prevent effectiveSkinHint to find its value from
482 another animator that might have been started with
483 less extra bits.
484 */
485 accecptIdentity = true;
486 }
487
488 if ( QskVariantAnimator::maybeInterpolate( *v1, *v2, accecptIdentity ) )
489 {
490 storeAnimator( control, aspect, *v1, *v2, animatorHint );
491 storeUpdateInfo( control, aspect );
492 }
493 }
494 else if ( v1 )
495 {
496 aspect.setVariation( r1.variation() );
497 aspect.setStates( r1.states() );
498
499 storeAnimator( control, aspect, *v1, QVariant(), animatorHint );
500 storeUpdateInfo( control, aspect );
501 }
502 else if ( v2 )
503 {
504 aspect.setVariation( r1.variation() );
505 aspect.setStates( r1.states() );
506
507 storeAnimator( control, aspect, QVariant(), *v2, animatorHint );
508 storeUpdateInfo( control, aspect );
509 }
510}
511
512inline bool WindowAnimator::isControlAffected( const QskControl* control,
513 const QVector< QskAspect::Subcontrol >& subControls, const QskAspect aspect ) const
514{
515 if ( !aspect.isMetric() )
516 {
517 if ( !( control->flags() & QQuickItem::ItemHasContents ) )
518 {
519 // while metrics might have an effect on layouts, we
520 // ignore all others for controls without content
521 return false;
522 }
523 }
524
525 const auto subControl = aspect.subControl();
526 if ( subControl != control->effectiveSubcontrol( subControl ) )
527 {
528 // The control uses subcontrol redirection, so we can assume it
529 // is not interested in this subcontrol.
530
531 return false;
532 }
533
534 if ( subControl != QskAspect::NoSubcontrol )
535 {
536 if ( !subControls.contains( subControl ) )
537 {
538 // the control is not interested in the aspect
539 return false;
540 }
541 }
542
543 return true;
544}
545
546inline void WindowAnimator::storeAnimator(
547 const QskControl* control, const QskAspect aspect,
548 const QVariant& value1, const QVariant& value2, QskAnimationHint hint )
549{
550 if ( m_animatorMap.find( aspect ) == m_animatorMap.cend() )
551 {
552 m_animatorMap.insert( aspect,
553 HintAnimator( control, aspect, value1, value2, hint ) );
554 }
555}
556
557inline void WindowAnimator::storeUpdateInfo( const QskControl* control, QskAspect aspect )
558{
559 UpdateInfo info;
560 info.control = const_cast< QskControl* >( control );
561
562 info.updateModes = UpdateInfo::Update;
563 if ( aspect.isMetric() )
564 info.updateModes |= UpdateInfo::Polish;
565
566 auto it = std::lower_bound(
567 m_updateInfos.begin(), m_updateInfos.end(), info, UpdateInfo::compare );
568
569 if ( ( it != m_updateInfos.end() ) && ( it->control == info.control ) )
570 it->updateModes |= info.updateModes;
571 else
572 m_updateInfos.insert( it, info );
573}
574
575ApplicationAnimator::~ApplicationAnimator()
576{
577 reset();
578}
579
580inline WindowAnimator* ApplicationAnimator::windowAnimator( const QQuickWindow* window )
581{
582 if ( window )
583 {
584 for ( auto animator : m_windowAnimators )
585 {
586 if ( animator->window() == window )
587 return animator;
588 }
589 }
590
591 return nullptr;
592}
593
594void ApplicationAnimator::add( WindowAnimator* animator )
595{
596 m_windowAnimators.push_back( animator );
597}
598
599void ApplicationAnimator::start()
600{
601 m_connections[0] = QskAnimator::addAdvanceHandler(
602 this, SLOT(notify(QQuickWindow*)), Qt::UniqueConnection );
603
604 m_connections[1] = QskAnimator::addCleanupHandler(
605 this, SLOT(cleanup(QQuickWindow*)), Qt::UniqueConnection );
606
607 for ( auto& animator : m_windowAnimators )
608 animator->start();
609}
610
611void ApplicationAnimator::reset()
612{
613 qDeleteAll( m_windowAnimators );
614 m_windowAnimators.clear();
615
616 disconnect( m_connections[0] );
617 disconnect( m_connections[1] );
618}
619
620inline bool ApplicationAnimator::isRunning() const
621{
622 return !m_windowAnimators.empty();
623}
624
625void ApplicationAnimator::notify( QQuickWindow* window )
626{
627 for ( auto& animator : m_windowAnimators )
628 {
629 if ( animator->window() == window )
630 {
631 animator->update();
632 return;
633 }
634 }
635}
636
637void ApplicationAnimator::cleanup( QQuickWindow* window )
638{
639 for ( auto it = m_windowAnimators.begin();
640 it != m_windowAnimators.end(); ++it )
641 {
642 auto animator = *it;
643 if ( animator->window() == window )
644 {
645 if ( !animator->isRunning() )
646 {
647 // The notification might be for other animators
648
649 m_windowAnimators.erase( it );
650 delete animator;
651 }
652
653 // let the items know, that we are done
654 qskSendStyleEventRecursive( window->contentItem() );
655
656 break;
657 }
658 }
659
660 if ( m_windowAnimators.empty() )
661 reset();
662}
663
664class QskSkinTransition::PrivateData
665{
666 public:
667 struct
668 {
669 QskSkinHintTable hintTable;
670 QHash< int, QskColorFilter > graphicFilters;
671 QHash< QskFontRole, QFont > fontTable;
672 } tables[ 2 ];
673
674 Type mask = QskSkinTransition::AllTypes;
675};
676
677QskSkinTransition::QskSkinTransition()
678 : m_data( new PrivateData() )
679{
680}
681
682QskSkinTransition::~QskSkinTransition()
683{
684}
685
686void QskSkinTransition::setMask( Type type )
687{
688 m_data->mask = type;
689}
690
691QskSkinTransition::Type QskSkinTransition::mask() const
692{
693 return m_data->mask;
694}
695
696void QskSkinTransition::setSourceSkin( const QskSkin* skin )
697{
698 auto& tables = m_data->tables[ 0 ];
699
700 tables.hintTable = skin->hintTable();
701 tables.graphicFilters = skin->graphicFilters();
702 tables.fontTable = skin->fontTable();
703}
704
705void QskSkinTransition::setTargetSkin( const QskSkin* skin )
706{
707 auto& tables = m_data->tables[ 1 ];
708
709 tables.hintTable = skin->hintTable();
710 tables.graphicFilters = skin->graphicFilters();
711 tables.fontTable = skin->fontTable();
712}
713
714void QskSkinTransition::run( const QskAnimationHint& animationHint )
715{
716 qskApplicationAnimator->reset();
717
718 const auto& table1 = m_data->tables[ 0 ].hintTable;
719 const auto& table2 = m_data->tables[ 1 ].hintTable;
720
721 const auto& graphicFilters1 = m_data->tables[ 0 ].graphicFilters;
722 const auto& graphicFilters2 = m_data->tables[ 1 ].graphicFilters;
723
724 const auto& fontTable1 = m_data->tables[ 0 ].fontTable;
725 const auto& fontTable2 = m_data->tables[ 1 ].fontTable;
726
727 QSet< QskAspect > candidates;
728
729 if ( ( animationHint.duration > 0 ) && ( m_data->mask != 0 ) )
730 {
731 qskAddCandidates( m_data->mask, table1.hints(), candidates );
732 qskAddCandidates( m_data->mask, table2.hints(), candidates );
733 }
734
735 if ( !candidates.isEmpty() )
736 {
737 bool doGraphicFilter = m_data->mask & QskSkinTransition::Color;
738 bool doFont = m_data->mask & QskSkinTransition::Metric;
739
740 const auto windows = qGuiApp->topLevelWindows();
741
742 for ( const auto window : windows )
743 {
744 if ( auto w = qobject_cast< QQuickWindow* >( window ) )
745 {
746 if ( !w->isVisible() )
747 continue;
748
749 if ( !qskHasHintTable( qskEffectiveSkin( w ), table2 ) )
750 continue;
751
752 auto animator = new WindowAnimator( w );
753
754 if ( doGraphicFilter )
755 {
756 animator->addGraphicFilterAnimators( animationHint,
757 graphicFilters1, graphicFilters2 );
758
759 doGraphicFilter = false;
760 }
761
762 if ( doFont )
763 {
764 animator->addFontSizeAnimators( animationHint,
765 fontTable1, fontTable2 );
766 }
767
768 /*
769 finally we schedule the animators the hard way by running
770 over the the item trees.
771 */
772
773 animator->addItemAspects( w->contentItem(),
774 animationHint, candidates, table1, table2 );
775
776 qskApplicationAnimator->add( animator );
777 }
778 }
779
780 qskApplicationAnimator->start();
781 }
782}
783
784bool QskSkinTransition::isRunning()
785{
786 if ( qskApplicationAnimator.exists() )
787 return qskApplicationAnimator->isRunning();
788
789 return false;
790}
791
792QVariant QskSkinTransition::animatedHint(
793 const QQuickWindow* window, QskAspect aspect )
794{
795 if ( qskApplicationAnimator.exists() )
796 {
797 if ( const auto animator = qskApplicationAnimator->windowAnimator( window ) )
798 return animator->animatedHint( aspect );
799 }
800
801 return QVariant();
802}
803
804QVariant QskSkinTransition::animatedGraphicFilter(
805 const QQuickWindow* window, int graphicRole )
806{
807 if ( qskApplicationAnimator.exists() )
808 {
809 if ( const auto animator = qskApplicationAnimator->windowAnimator( window ) )
810 return animator->animatedGraphicFilter( graphicRole );
811 }
812
813 return QVariant();
814}
815
816QVariant QskSkinTransition::animatedFontSize(
817 const QQuickWindow* window, const QskFontRole& fontRole )
818{
819 if ( qskApplicationAnimator.exists() )
820 {
821 if ( const auto animator = qskApplicationAnimator->windowAnimator( window ) )
822 return animator->animatedFontSize( fontRole );
823 }
824
825 return QVariant();
826}
827
828#include "QskSkinTransition.moc"
Lookup key for a QskSkinHintTable.
Definition QskAspect.h:15
void setStates(States) noexcept
Definition QskAspect.h:472
constexpr bool isMetric() const noexcept
Definition QskAspect.h:457
void addStates(States) noexcept
Definition QskAspect.h:477
constexpr QskAspect trunk() const noexcept
Definition QskAspect.h:396
constexpr Subcontrol subControl() const noexcept
Definition QskAspect.h:417
constexpr Variation variation() const noexcept
Definition QskAspect.h:525
constexpr States states() const noexcept
Definition QskAspect.h:467
@ GraphicRole
Definition QskAspect.h:56
void setVariation(Variation) noexcept
Definition QskAspect.h:530
Base class of all controls.
Definition QskControl.h:23
QVector< QskAspect::Subcontrol > subControls() const
void resetImplicitSize()
Definition QskItem.cpp:721
bool isInitiallyPainted() const
Definition QskItem.cpp:578
const QskSkinHintTable & hintTable() const
Accessor for local skin hint table.
QskSkin * effectiveSkin() const
virtual QskAspect::Variation effectiveVariation() const
QskAspect::Subcontrol effectiveSubcontrol(QskAspect::Subcontrol) const