QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskSkinnable.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskSkinnable.h"
7
8#include "QskAnimationHint.h"
9#include "QskArcMetrics.h"
10#include "QskAspect.h"
11#include "QskColorFilter.h"
12#include "QskControl.h"
13#include "QskHintAnimator.h"
14#include "QskMargins.h"
15#include "QskSkinManager.h"
16#include "QskSkin.h"
17#include "QskSkinHintTable.h"
18#include "QskSkinTransition.h"
19#include "QskSkinlet.h"
20#include "QskWindow.h"
21
22#include "QskBoxShapeMetrics.h"
23#include "QskBoxBorderMetrics.h"
24#include "QskBoxBorderColors.h"
25#include "QskShadowMetrics.h"
26#include "QskStippleMetrics.h"
27#include "QskBoxHints.h"
28#include "QskGradient.h"
29#include "QskTextOptions.h"
30#include "QskGraphic.h"
31#include "QskFontRole.h"
32
33#include <qfont.h>
34#include <qfontmetrics.h>
35#include <map>
36
37#define DEBUG_MAP 0
38#define DEBUG_ANIMATOR 0
39#define DEBUG_STATE 0
40
41static inline bool qskIsControl( const QskSkinnable* skinnable )
42{
43 return skinnable->metaObject()->inherits( &QskControl::staticMetaObject );
44}
45
46static inline bool qskSetFlag( QskSkinnable* skinnable,
47 const QskAspect aspect, int flag )
48{
49 return skinnable->setSkinHint( aspect, QVariant( flag ) );
50}
51
52static inline int qskFlag( const QskSkinnable* skinnable,
53 const QskAspect aspect, QskSkinHintStatus* status = nullptr )
54{
55 return skinnable->effectiveSkinHint( aspect, status ).toInt();
56}
57
58static inline bool qskSetMetric( QskSkinnable* skinnable,
59 const QskAspect aspect, const QVariant& metric )
60{
61 return skinnable->setSkinHint( aspect | QskAspect::Metric, metric );
62}
63
64static inline bool qskMoveMetric( QskSkinnable* skinnable,
65 const QskAspect aspect, const QVariant& metric )
66{
67 return skinnable->moveSkinHint( aspect | QskAspect::Metric, metric );
68}
69
70template< typename T >
71static inline bool qskSetMetric( QskSkinnable* skinnable,
72 QskAspect aspect, const T& metric )
73{
74 return qskSetMetric( skinnable, aspect, QVariant::fromValue( metric ) );
75}
76
77template< typename T >
78static inline bool qskMoveMetric( QskSkinnable* skinnable,
79 QskAspect aspect, const T& metric )
80{
81 return qskMoveMetric( skinnable, aspect, QVariant::fromValue( metric ) );
82}
83
84template< typename T >
85static inline T qskMetric( const QskSkinnable* skinnable,
86 QskAspect aspect, QskSkinHintStatus* status = nullptr )
87{
88 return skinnable->effectiveSkinHint(
89 aspect | QskAspect::Metric, status ).value< T >();
90}
91
92static inline bool qskSetColor( QskSkinnable* skinnable,
93 const QskAspect aspect, const QVariant& color )
94{
95 return skinnable->setSkinHint( aspect | QskAspect::Color, color );
96}
97
98static inline bool qskMoveColor( QskSkinnable* skinnable,
99 const QskAspect aspect, const QVariant& color )
100{
101 return skinnable->moveSkinHint( aspect | QskAspect::Color, color );
102}
103
104template< typename T >
105static inline bool qskSetColor( QskSkinnable* skinnable,
106 const QskAspect aspect, const T& color )
107{
108 return qskSetColor( skinnable, aspect, QVariant::fromValue( color ) );
109}
110
111template< typename T >
112static inline bool qskMoveColor( QskSkinnable* skinnable,
113 const QskAspect aspect, const T& color )
114{
115 return qskMoveColor( skinnable, aspect, QVariant::fromValue( color ) );
118template< typename T >
119static inline T qskColor( const QskSkinnable* skinnable,
120 QskAspect aspect, QskSkinHintStatus* status = nullptr )
121{
122 return skinnable->effectiveSkinHint(
123 aspect | QskAspect::Color, status ).value< T >();
124}
125
126static inline constexpr QskAspect qskAnimatorAspect( const QskAspect aspect )
127{
128 /*
129 We do not need the extra bits that would slow down resolving
130 the effective aspect in animatedHint.
131 */
132
133 return aspect.type() | aspect.subControl() | aspect.primitive();
134}
135
136static inline void qskTriggerUpdates( QskAspect aspect, QQuickItem* item )
137{
138 /*
139 To put the hint into effect we have to call the usual suspects:
140
141 - resetImplicitSize
142 - polish
143 - update
144
145 The following code decides about these calls based on type/primitive
146 of the aspect. It can be expected, that it results in more calls
147 than what would be mandatory and in rare cases we might even miss necessary
148 calls. This has to be fixed by doing the call manually in the specific
149 controls.
150 */
151
152 if ( item == nullptr || aspect.isAnimator() )
153 return;
154
155 item->update(); // always
156
157 auto control = qskControlCast( item );
158 if ( control == nullptr )
159 return;
160
161 bool maybeLayout = false;
162
163 switch( aspect.type() )
164 {
165 using A = QskAspect;
166
167 case A::Metric:
168 {
169 if ( aspect.metricPrimitive() != A::Position )
170 {
171 control->resetImplicitSize();
172 maybeLayout = true;
173 }
174
175 break;
176 }
177
178 case A::Color:
179 {
180 break;
181 }
182
183 case A::NoType:
184 {
185 switch( aspect.primitive() )
186 {
187 case A::GraphicRole:
188 case A::FontRole:
189 {
190 break;
191 }
192 case A::Alignment:
193 {
194 maybeLayout = true;
195 break;
196 }
197 default:
198 {
199 control->resetImplicitSize();
200 maybeLayout = true;
201 }
202 }
203 }
204 }
205
206 if ( maybeLayout && control->hasChildItems() )
207 {
208 if ( control->polishOnResize() || control->autoLayoutChildren() )
209 control->polish();
210 }
211}
212
213static inline QskAspect qskSubstitutedAspect(
214 const QskSkinnable* skinnable, QskAspect aspect )
215{
216#if 0
217 if ( aspect.hasStates() )
218 {
219 qWarning() << "QskSkinnable::(re)setSkinHint: setting hints with states "
220 "is discouraged - use QskSkinTableEditor if you are sure, that you need this.";
221
222 qWarning() << "QskAspect:" << aspect.stateless()
223 << skinnable->skinStatesAsPrintable( aspect.states() );
224
225#if 0
226 aspect.clearStates();
227#endif
228 }
229#endif
230
231 aspect.setSubcontrol( skinnable->effectiveSubcontrol( aspect.subControl() ) );
232 return aspect;
233}
234
235class QskSkinnable::PrivateData
236{
237 public:
238 ~PrivateData()
239 {
240 if ( hasLocalSkinlet )
241 {
242 if ( skinlet && skinlet->isOwnedBySkinnable() )
243 delete skinlet;
244 }
245
246 delete subcontrolProxies;
247 }
248
249 QskSkinHintTable hintTable;
250 QskHintAnimatorTable animators;
251
252 int sampleIndex = -1; // for the ugly QskSkinStateChanger hack
253
254 typedef std::map< QskAspect::Subcontrol, QskAspect::Subcontrol > ProxyMap;
255 ProxyMap* subcontrolProxies = nullptr;
256
257 const QskSkinlet* skinlet = nullptr;
258
259 QskAspect::States skinStates;
260 bool hasLocalSkinlet = false;
261};
262
264 : m_data( new PrivateData() )
265{
266}
267
271
273{
274 if ( skinlet == m_data->skinlet )
275 {
276 if ( skinlet )
277 {
278 // now we don't depend on global skin changes anymore
279 m_data->hasLocalSkinlet = true;
280 }
281 return;
282 }
283
284 if ( m_data->skinlet && m_data->skinlet->isOwnedBySkinnable() )
285 delete m_data->skinlet;
286
287 m_data->skinlet = skinlet;
288 m_data->hasLocalSkinlet = ( skinlet != nullptr );
289
290 if ( auto item = owningItem() )
291 {
292 if ( auto control = qskControlCast( item ) )
293 control->resetImplicitSize();
294
295 item->polish();
296
297 if ( item->flags() & QQuickItem::ItemHasContents )
298 item->update();
299 }
300}
301
303{
304 return m_data->hasLocalSkinlet ? m_data->skinlet : nullptr;
305}
306
308{
309 if ( m_data->skinlet == nullptr )
310 {
311 m_data->skinlet = effectiveSkin()->skinlet( metaObject() );
312 m_data->hasLocalSkinlet = false;
313 }
314
315 return m_data->skinlet;
316}
317
318void QskSkinnable::setSubcontrolProxy(
320{
321 if ( subControl == QskAspect::NoSubcontrol )
322 return; // nonsense, we ignore this
323
324 if ( proxy == QskAspect::NoSubcontrol || subControl == proxy )
325 {
326 resetSubcontrolProxy( subControl );
327 return;
328 }
329
330 if ( m_data->subcontrolProxies == nullptr )
331 m_data->subcontrolProxies = new PrivateData::ProxyMap();
332
333 ( *m_data->subcontrolProxies )[ subControl ] = proxy;
334}
335
336void QskSkinnable::resetSubcontrolProxy( QskAspect::Subcontrol subcontrol )
337{
338 if ( auto& proxies = m_data->subcontrolProxies )
339 {
340 auto it = proxies->find( subcontrol );
341 if ( it != proxies->end() )
342 {
343 proxies->erase( it );
344 if ( proxies->empty() )
345 {
346 delete proxies;
347 proxies = nullptr;
348 }
349 }
350 }
351}
352
353QskAspect::Subcontrol QskSkinnable::subcontrolProxy( QskAspect::Subcontrol subControl ) const
354{
355 if ( const auto proxies = m_data->subcontrolProxies )
356 {
357 auto it = proxies->find( subControl );
358 if ( it != proxies->end() )
359 return it->second;
360 }
361
362 return QskAspect::NoSubcontrol;
363}
364
366{
367 return m_data->hintTable;
368}
369
371{
372 return m_data->hintTable;
373}
374
375bool QskSkinnable::setFlagHint( const QskAspect aspect, int flag )
376{
377 return qskSetFlag( this, aspect, flag );
378}
379
380bool QskSkinnable::setAlignmentHint( const QskAspect aspect, Qt::Alignment alignment )
381{
382 return qskSetFlag( this, aspect | QskAspect::Alignment, alignment );
383}
384
386{
387 return resetSkinHint( aspect | QskAspect::Alignment );
388}
389
390bool QskSkinnable::setColor( const QskAspect aspect, const QColor& color )
391{
392 return qskSetColor( this, aspect, color );
393}
394
395bool QskSkinnable::setColor( const QskAspect aspect, Qt::GlobalColor color )
396{
397 return qskSetColor( this, aspect, QColor( color ) );
398}
399
400bool QskSkinnable::setColor( const QskAspect aspect, QRgb rgb )
401{
402 return qskSetColor( this, aspect, QColor::fromRgba( rgb ) );
403}
404
405bool QskSkinnable::moveColor( const QskAspect aspect, const QColor& color )
406{
407 return qskMoveColor( this, aspect, color );
408}
409
410bool QskSkinnable::moveColor( const QskAspect aspect, Qt::GlobalColor color )
411{
412 return qskMoveColor( this, aspect, QColor( color ) );
413}
414
415bool QskSkinnable::moveColor( const QskAspect aspect, QRgb rgb )
416{
417 return qskMoveColor( this, aspect, QColor::fromRgba( rgb ) );
418}
419
420QColor QskSkinnable::color( const QskAspect aspect, QskSkinHintStatus* status ) const
421{
422 return qskColor< QColor >( this, aspect, status );
423}
424
425bool QskSkinnable::setMetric( const QskAspect aspect, qreal metric )
426{
427 return qskSetMetric( this, aspect, metric );
428}
429
430bool QskSkinnable::moveMetric( QskAspect aspect, qreal metric )
431{
432 return qskMoveMetric( this, aspect, metric );
433}
434
435qreal QskSkinnable::metric( const QskAspect aspect, QskSkinHintStatus* status ) const
436{
437 return qskMetric< qreal >( this, aspect, status );
438}
439
440bool QskSkinnable::setPositionHint( QskAspect aspect, qreal position )
441{
442 return qskSetMetric( this, aspect | QskAspect::Position, position );
443}
444
445bool QskSkinnable::movePositionHint( QskAspect aspect, qreal position )
446{
447 return qskMoveMetric( this, aspect | QskAspect::Position, position );
448}
449
450bool QskSkinnable::movePositionHint( QskAspect aspect, qreal from, qreal to )
451{
452 return moveSkinHint( aspect | QskAspect::Metric | QskAspect::Position,
453 QVariant::fromValue( from ), QVariant::fromValue( to ) );
454}
455
456bool QskSkinnable::resetPositionHint( QskAspect aspect )
457{
458 return resetMetric( aspect | QskAspect::Position );
459}
460
461qreal QskSkinnable::positionHint( QskAspect aspect, QskSkinHintStatus* status ) const
462{
463 return qskMetric< qreal >( this, aspect | QskAspect::Position, status );
464}
465
467 const QskAspect aspect, qreal width, qreal height )
468{
469 return qskSetMetric( this, aspect | QskAspect::StrutSize, QSizeF( width, height ) );
470}
471
472bool QskSkinnable::setStrutSizeHint( const QskAspect aspect, const QSizeF& size )
473{
474 return qskSetMetric( this, aspect | QskAspect::StrutSize, size );
475}
476
478{
479 return resetMetric( aspect | QskAspect::StrutSize );
480}
481
483 const QskAspect aspect, QskSkinHintStatus* status ) const
484{
485 return qskMetric< QSizeF >( this, aspect | QskAspect::StrutSize, status );
486}
487
488bool QskSkinnable::setMarginHint( const QskAspect aspect, qreal margins )
489{
490 return qskSetMetric( this, aspect | QskAspect::Margin, QskMargins( margins ) );
491}
492
493bool QskSkinnable::setMarginHint( const QskAspect aspect, const QMarginsF& margins )
494{
495 return qskSetMetric( this, aspect | QskAspect::Margin, QskMargins( margins ) );
496}
497
499{
500 return resetMetric( aspect | QskAspect::Margin );
501}
502
504 const QskAspect aspect, QskSkinHintStatus* status ) const
505{
506 return qskMetric< QskMargins >( this, aspect | QskAspect::Margin, status );
507}
508
509bool QskSkinnable::setPaddingHint( const QskAspect aspect, qreal padding )
510{
511 return qskSetMetric( this, aspect | QskAspect::Padding, QskMargins( padding ) );
512}
513
514bool QskSkinnable::setPaddingHint( const QskAspect aspect, const QMarginsF& padding )
515{
516 return qskSetMetric( this, aspect | QskAspect::Padding, QskMargins( padding ) );
517}
518
520{
521 return resetMetric( aspect | QskAspect::Padding );
522}
523
525 const QskAspect aspect, QskSkinHintStatus* status ) const
526{
527 return qskMetric< QskMargins >( this, aspect | QskAspect::Padding, status );
528}
529
531 const QskAspect aspect, const QskGradient& gradient )
532{
533 return qskSetColor( this, aspect, gradient );
534}
535
537 const QskAspect aspect, QskSkinHintStatus* status ) const
538{
539 return qskColor< QskGradient >( this, aspect, status );
540}
541
543 const QskAspect aspect, const QskBoxShapeMetrics& shape )
544{
545 return qskSetMetric( this, aspect | QskAspect::Shape, shape );
546}
547
549{
550 return resetMetric( aspect | QskAspect::Shape );
551}
552
554 const QskAspect aspect, QskSkinHintStatus* status ) const
555{
556 return qskMetric< QskBoxShapeMetrics >(
557 this, aspect | QskAspect::Shape, status );
558}
559
561 const QskAspect aspect, const QskBoxBorderMetrics& border )
562{
563 return qskSetMetric( this, aspect | QskAspect::Border, border );
564}
565
567{
568 return resetMetric( aspect | QskAspect::Border );
569}
570
572 const QskAspect aspect, QskSkinHintStatus* status ) const
573{
574 return qskMetric< QskBoxBorderMetrics >(
575 this, aspect | QskAspect::Border, status );
576}
577
579 const QskAspect aspect, const QskBoxBorderColors& colors )
580{
581 return qskSetColor( this, aspect | QskAspect::Border, colors );
582}
583
585{
586 return resetColor( aspect | QskAspect::Border );
587}
588
590 const QskAspect aspect, QskSkinHintStatus* status ) const
591{
592 return qskColor< QskBoxBorderColors >(
593 this, aspect | QskAspect::Border, status );
594}
595
596bool QskSkinnable::setShadowMetricsHint(
597 QskAspect aspect, const QskShadowMetrics& metrics )
598{
599 return qskSetMetric( this, aspect | QskAspect::Shadow, metrics );
600}
601
602bool QskSkinnable::resetShadowMetricsHint( QskAspect aspect )
603{
604 return resetMetric( aspect | QskAspect::Shadow );
605}
606
607QskShadowMetrics QskSkinnable::shadowMetricsHint(
608 QskAspect aspect, QskSkinHintStatus* status ) const
609{
610 return qskMetric< QskShadowMetrics >(
611 this, aspect | QskAspect::Shadow, status );
612}
613
614bool QskSkinnable::setShadowColorHint( QskAspect aspect, const QColor& color )
615{
616 return qskSetColor( this, aspect | QskAspect::Shadow, color );
617}
618
619bool QskSkinnable::resetShadowColorHint( QskAspect aspect )
620{
621 return resetColor( aspect | QskAspect::Shadow );
622}
623
624QColor QskSkinnable::shadowColorHint( QskAspect aspect, QskSkinHintStatus* status ) const
625{
626 return qskColor< QColor >( this, aspect | QskAspect::Shadow, status );
627}
628
629QskBoxHints QskSkinnable::boxHints( QskAspect aspect ) const
630{
631 return QskBoxHints(
632 boxShapeHint( aspect ), boxBorderMetricsHint( aspect ),
633 boxBorderColorsHint( aspect ), gradientHint( aspect ),
634 shadowMetricsHint( aspect ), shadowColorHint( aspect ) );
635}
636
637bool QskSkinnable::setArcMetricsHint(
638 const QskAspect aspect, const QskArcMetrics& arc )
639{
640 return qskSetMetric( this, aspect | QskAspect::Shape, arc );
641}
642
643bool QskSkinnable::resetArcMetricsHint( const QskAspect aspect )
644{
645 return resetMetric( aspect | QskAspect::Shape );
646}
647
648QskArcMetrics QskSkinnable::arcMetricsHint(
649 const QskAspect aspect, QskSkinHintStatus* status ) const
650{
651 return qskMetric< QskArcMetrics >(
652 this, aspect | QskAspect::Shape, status );
653}
654
655bool QskSkinnable::setStippleMetricsHint(
656 QskAspect aspect, const QskStippleMetrics& metrics )
657{
658 return qskSetMetric( this, aspect | QskAspect::Style, metrics );
659}
660
661bool QskSkinnable::resetStippleMetricsHint( QskAspect aspect )
662{
663 return resetMetric( aspect | QskAspect::Style );
664}
665
666QskStippleMetrics QskSkinnable::stippleMetricsHint(
667 QskAspect aspect, QskSkinHintStatus* status ) const
668{
669 return qskMetric< QskStippleMetrics >(
670 this, aspect | QskAspect::Style, status );
671}
672
673bool QskSkinnable::setSpacingHint( const QskAspect aspect, qreal spacing )
674{
675 return qskSetMetric( this, aspect | QskAspect::Spacing, spacing );
676}
677
679{
680 return resetMetric( aspect | QskAspect::Spacing );
681}
682
684 const QskAspect aspect, QskSkinHintStatus* status ) const
685{
686 return qskMetric< qreal >( this, aspect | QskAspect::Spacing, status );
687}
688
689bool QskSkinnable::setTextOptionsHint(
690 const QskAspect aspect, const QskTextOptions& options )
691{
692 return setSkinHint( aspect | QskAspect::Option,
693 QVariant::fromValue( options ) );
694}
695
696bool QskSkinnable::resetTextOptionsHint( const QskAspect aspect )
697{
698 return resetSkinHint( aspect | QskAspect::Option );
699}
700
701QskTextOptions QskSkinnable::textOptionsHint(
702 const QskAspect aspect, QskSkinHintStatus* status ) const
703{
704 return effectiveSkinHint(
705 aspect | QskAspect::Option, status ).value< QskTextOptions >();
706}
707
709 const QskAspect aspect, const QskFontRole& role )
710{
711 return setSkinHint( aspect | QskAspect::FontRole,
712 QVariant::fromValue( role ) );
713}
714
716{
717 return resetSkinHint( aspect | QskAspect::FontRole );
718}
719
721 const QskAspect aspect, QskSkinHintStatus* status ) const
722{
723 return effectiveSkinHint(
724 aspect | QskAspect::FontRole, status ).value< QskFontRole >();
725}
726
728{
729 const auto hint = effectiveSkinHint( aspect | QskAspect::FontRole );
730 if ( hint.canConvert< QFont >() )
731 {
732 /*
733 The provided skins/controls use font roles only - however
734 application code might want to assign fonts without defining
735 font roles.
736 */
737 return hint.value< QFont >();
738 }
739
740 const auto fontRole = hint.value< QskFontRole >();
741
742 auto font = effectiveSkin()->font( fontRole );
743
744 if ( auto item = owningItem() )
745 {
746 const auto v = QskSkinTransition::animatedFontSize(
747 item->window(), fontRole );
748
749 if ( v.canConvert< int >() )
750 {
751 font.setPixelSize( v.value< int >() );
752 item->update(); // design flaw: see effectiveGraphicFilter
753 }
754 }
755
756 return font;
757}
758
759qreal QskSkinnable::effectiveFontHeight( const QskAspect aspect ) const
760{
761 const QFontMetricsF fm( effectiveFont( aspect ) );
762 return fm.height();
763}
764
765bool QskSkinnable::setGraphicRoleHint( const QskAspect aspect, int role )
766{
767 return qskSetFlag( this, aspect | QskAspect::GraphicRole, role );
768}
769
771{
772 return resetSkinHint( aspect | QskAspect::GraphicRole );
773}
774
776 const QskAspect aspect, QskSkinHintStatus* status ) const
777{
778 return qskFlag( this, aspect | QskAspect::GraphicRole, status );
779}
780
781bool QskSkinnable::setSymbolHint(
782 const QskAspect aspect, const QskGraphic& symbol )
783{
784 return setSkinHint( aspect | QskAspect::Symbol,
785 QVariant::fromValue( symbol ) );
786}
787
788bool QskSkinnable::resetSymbolHint( const QskAspect aspect )
789{
790 return resetSkinHint( aspect | QskAspect::Symbol );
791}
792
793QskGraphic QskSkinnable::symbolHint(
794 const QskAspect aspect, QskSkinHintStatus* status ) const
795{
796 return effectiveSkinHint(
797 aspect | QskAspect::Symbol, status ).value< QskGraphic >();
798}
799
800
802 const QskAspect::Subcontrol subControl ) const
803{
804 /*
805 Usually we find the graphic role and return the related filter
806 from the skin. But as we can't interpolate between graphic roles
807 the corresponding animators interpolate the filters.
808 */
809
810 QskAspect aspect( effectiveSubcontrol( subControl ) | QskAspect::GraphicRole );
811 aspect.setSection( section() );
813
814 QskSkinHintStatus status;
815
816 const auto hint = storedHint( aspect | skinStates(), &status );
817 if ( !status.isValid() )
818 return QskColorFilter();
819
820 aspect.setSubcontrol( status.aspect.subControl() );
821 aspect.setSection( QskAspect::Body );
823
824 {
825 const auto v = animatedHint( aspect, nullptr );
826
827 if ( v.canConvert< QskColorFilter >() )
828 return v.value< QskColorFilter >();
829 }
830
831 if ( auto item = owningItem() )
832 {
833 const auto graphicRole = hint.toInt();
834
835 const auto v = QskSkinTransition::animatedGraphicFilter(
836 item->window(), graphicRole );
837
838 if ( v.canConvert< QskColorFilter >() )
839 {
840#if 1
841 /*
842 Design flaw: the animators for the skin transition do not
843 know about the controls, that are affected from the color
844 filter. As a workaround we schedule the update in the
845 getter: TODO ...
846 */
847 item->update();
848#endif
849 return v.value< QskColorFilter >();
850 }
851 }
852
853 return effectiveSkin()->graphicFilter( hint.toInt() );
854}
855
857 QskAspect aspect, QskAnimationHint hint )
858{
859 aspect.setSubcontrol( effectiveSubcontrol( aspect.subControl() ) );
860 return m_data->hintTable.setAnimation( aspect, hint );
861}
862
864 QskAspect aspect, QskSkinHintStatus* status ) const
865{
866 aspect.setAnimator( true );
867 return effectiveSkinHint( aspect, status ).value< QskAnimationHint >();
868}
869
870bool QskSkinnable::hasAnimationHint( QskAspect aspect ) const
871{
872 return animationHint( aspect ).isValid();
873}
874
876 QskAspect::Type type, QskAspect::Subcontrol subControl,
877 QskAspect::States states, QskSkinHintStatus* status ) const
878{
879#if 0
880 // TODO ...
881 subControl = effectiveSubcontrol( aspect.subControl() );
882#endif
883
884 auto aspect = subControl | type | states;
885 aspect.setAnimator( true );
886
887 QskAnimationHint hint;
888
889 {
890 const auto a = m_data->hintTable.resolvedAnimator( aspect, hint );
891 if ( a.isAnimator() )
892 {
893 if ( status )
894 {
896 status->aspect = a;
897 }
898
899 return hint;
900 }
901 }
902
903 if ( auto skin = effectiveSkin() )
904 {
905 const auto a = skin->hintTable().resolvedAnimator( aspect, hint );
906 if ( a.isAnimator() )
907 {
908 if ( status )
909 {
911 status->aspect = a;
912 }
913
914 return hint;
915 }
916 }
917
918 if ( status )
919 {
921 status->aspect = QskAspect();
922 }
923
924 return hint;
925}
926
927bool QskSkinnable::setSkinHint( QskAspect aspect, const QVariant& hint )
928{
929 aspect = qskSubstitutedAspect( this, aspect );
930
931 if ( m_data->hintTable.setHint( aspect, hint ) )
932 {
933 qskTriggerUpdates( aspect, owningItem() );
934 return true;
935 }
936
937 return false;
938}
939
941{
942 aspect = qskSubstitutedAspect( this, aspect );
943
944 if ( m_data->hintTable.removeHint( aspect ) )
945 {
946 qskTriggerUpdates( aspect, owningItem() );
947 return true;
948 }
949
950 return false;
951}
952
954 QskAspect aspect, QskSkinHintStatus* status ) const
955{
956 aspect.setSubcontrol( effectiveSubcontrol( aspect.subControl() ) );
957
958 if ( !( aspect.isAnimator() || aspect.hasStates() ) )
959 {
960 const auto v = animatedHint( aspect, status );
961 if ( v.isValid() )
962 return v;
963 }
964
965 if ( aspect.section() == QskAspect::Body )
966 aspect.setSection( section() );
967
968 if ( aspect.variation() == QskAspect::NoVariation )
970
971 if ( !aspect.hasStates() )
972 aspect.setStates( skinStates() );
973
974 if ( !aspect.isAnimator() && QskSkinTransition::isRunning() )
975 {
976 /*
977 The skin has changed and the hints are interpolated
978 between the old and the new one over time
979 */
980 const auto v = interpolatedHint( aspect, status );
981 if ( v.isValid() )
982 return v;
983 }
984
985 return storedHint( aspect, status );
986}
987
989{
990 QskSkinHintStatus status;
991
992 ( void ) effectiveSkinHint( aspect, &status );
993 return status;
994}
995
996bool QskSkinnable::moveSkinHint( QskAspect aspect,
997 const QVariant& oldValue, const QVariant& newValue )
998{
999 if ( aspect.isAnimator() )
1000 return false;
1001
1002 const bool ok = setSkinHint( aspect, newValue );
1003
1004 if ( ok && oldValue.isValid() && newValue.isValid() )
1005 {
1006 const auto animation = animationHint( aspect );
1007 if ( animation.isValid() )
1008 {
1009 if ( newValue != oldValue )
1010 startTransition( aspect, animation, oldValue, newValue );
1011 }
1012 }
1013
1014 return ok;
1015}
1016
1017bool QskSkinnable::moveSkinHint( QskAspect aspect, const QVariant& value )
1018{
1019 return moveSkinHint( aspect, effectiveSkinHint( aspect ), value );
1020}
1021
1022const QskHintAnimator* QskSkinnable::runningHintAnimator(
1023 QskAspect aspect, int index ) const
1024{
1025 const auto& animators = m_data->animators;
1026
1027 if ( animators.isEmpty() )
1028 return nullptr;
1029
1030 aspect = qskAnimatorAspect( aspect );
1031
1032 auto animator = animators.animator( aspect, index );
1033 if ( animator == nullptr && index >= 0 )
1034 animator = animators.animator( aspect, -1 );
1035
1036 return animator;
1037}
1038
1039QVariant QskSkinnable::animatedHint(
1040 QskAspect aspect, QskSkinHintStatus* status ) const
1041{
1042 QVariant v;
1043
1044 if ( !m_data->animators.isEmpty() )
1045 {
1046 const auto a = qskAnimatorAspect( aspect );
1047
1048 v = m_data->animators.currentValue( a, m_data->sampleIndex );
1049 if ( !v.isValid() && m_data->sampleIndex >= 0 )
1050 v = m_data->animators.currentValue( a, -1 );
1051 }
1052
1053 if ( status && v.isValid() )
1054 {
1056 status->aspect = aspect;
1057 }
1058
1059 return v;
1060}
1061
1062QVariant QskSkinnable::interpolatedHint(
1063 QskAspect aspect, QskSkinHintStatus* status ) const
1064{
1065 if ( !QskSkinTransition::isRunning() || m_data->hintTable.hasHint( aspect ) )
1066 return QVariant();
1067
1068 const auto item = owningItem();
1069 if ( item == nullptr )
1070 return QVariant();
1071
1072 QVariant v;
1073
1074 auto a = aspect;
1075
1076 Q_FOREVER
1077 {
1078 v = QskSkinTransition::animatedHint( item->window(), aspect );
1079
1080 if ( !v.isValid() )
1081 {
1082 if ( const auto topState = aspect.topState() )
1083 {
1084 aspect.clearState( aspect.topState() );
1085 continue;
1086 }
1087
1088 if ( aspect.variation() )
1089 {
1090 // clear the variation bits and restart
1091 aspect = a;
1093
1094 continue;
1095 }
1096 }
1097
1098 if ( a.section() != QskAspect::Body )
1099 {
1100 // try to resolve with the default section
1101
1102 a.setSection( QskAspect::Body );
1103 aspect = a;
1104
1105 continue;
1106 }
1107
1108 break;
1109 }
1110
1111 if ( status && v.isValid() )
1112 {
1114 status->aspect = aspect;
1115 }
1116
1117 return v;
1118}
1119
1120const QVariant& QskSkinnable::storedHint(
1121 QskAspect aspect, QskSkinHintStatus* status ) const
1122{
1123 const auto skin = effectiveSkin();
1124
1125 QskAspect resolvedAspect;
1126
1127 const auto& localTable = m_data->hintTable;
1128 if ( localTable.hasHints() )
1129 {
1130 if ( const auto value = localTable.resolvedHint( aspect, &resolvedAspect ) )
1131 {
1132 if ( status )
1133 {
1135 status->aspect = resolvedAspect;
1136 }
1137 return *value;
1138 }
1139 }
1140
1141 // next we try the hints from the skin
1142
1143 const auto& skinTable = skin->hintTable();
1144 if ( skinTable.hasHints() )
1145 {
1146 if ( const auto value = skinTable.resolvedHint( aspect, &resolvedAspect ) )
1147 {
1148 if ( status )
1149 {
1151 status->aspect = resolvedAspect;
1152 }
1153
1154 return *value;
1155 }
1156
1157 if ( aspect.hasSubcontrol() )
1158 {
1159 // trying to resolve something from the skin default settings
1160
1161 aspect.clearSubcontrol();
1162 aspect.clearStates();
1163
1164 if ( const auto value = skinTable.resolvedHint( aspect, &resolvedAspect ) )
1165 {
1166 if ( status )
1167 {
1169 status->aspect = resolvedAspect;
1170 }
1171
1172 return *value;
1173 }
1174 }
1175 }
1176
1177 if ( status )
1178 {
1180 status->aspect = QskAspect();
1181 }
1182
1183 static QVariant hintInvalid;
1184 return hintInvalid;
1185}
1186
1187bool QskSkinnable::hasSkinState( QskAspect::State state ) const
1188{
1189 return ( m_data->skinStates & state ) == state;
1190}
1191
1192QskAspect::States QskSkinnable::skinStates() const
1193{
1194 return m_data->skinStates;
1195}
1196
1197const char* QskSkinnable::skinStatesAsPrintable() const
1198{
1199 return skinStatesAsPrintable( skinStates() );
1200}
1201
1202const char* QskSkinnable::skinStatesAsPrintable( QskAspect::States states ) const
1203{
1204 QString tmp;
1205
1206 QDebug debug( &tmp );
1207 qskDebugStates( debug, metaObject(), states );
1208
1209 // we should find a better way
1210 static QByteArray bytes[ 10 ];
1211 static int counter = 0;
1212
1213 counter = ( counter + 1 ) % 10;
1214
1215 bytes[ counter ] = tmp.toUtf8();
1216 return bytes[ counter ].constData();
1217}
1218
1219static inline QskMargins qskEffectivePadding( const QskSkinnable* skinnable,
1220 QskAspect aspect, const QSizeF& size, bool inner )
1221{
1222 const auto shape = skinnable->boxShapeHint( aspect ).toAbsolute( size );
1223 const auto borderMetrics = skinnable->boxBorderMetricsHint( aspect );
1224
1225 const qreal left = qMax( shape.radius( Qt::TopLeftCorner ).width(),
1226 shape.radius( Qt::BottomLeftCorner ).width() );
1227
1228 const qreal top = qMax( shape.radius( Qt::TopLeftCorner ).height(),
1229 shape.radius( Qt::TopRightCorner ).height() );
1230
1231 const qreal right = qMax( shape.radius( Qt::TopRightCorner ).width(),
1232 shape.radius( Qt::BottomRightCorner ).width() );
1233
1234 const qreal bottom = qMax( shape.radius( Qt::BottomLeftCorner ).height(),
1235 shape.radius( Qt::BottomRightCorner ).height() );
1236
1237 QskMargins padding( left, top, right, bottom );
1238
1239 // half of the border goes to the inner side
1240 const auto borderMargins = borderMetrics.toAbsolute( size ).widths() * 0.5;
1241
1242 if ( inner )
1243 {
1244 padding -= borderMargins;
1245 }
1246 else
1247 {
1248 // not correct, but to get things started. TODO ...
1249 padding += borderMargins;
1250 }
1251
1252 // sin 45° ceiled : 0.70710678;
1253 padding *= 1.0 - 0.70710678;
1254
1255 return padding.expandedTo( skinnable->paddingHint( aspect ) );
1256}
1257
1259 QskAspect aspect, const QSizeF& outerBoxSize ) const
1260{
1261 return qskEffectivePadding( this, aspect, outerBoxSize, true );
1262}
1263
1265 QskAspect aspect, const QSizeF& outerBoxSize ) const
1266{
1267 const auto pd = qskEffectivePadding( this, aspect, outerBoxSize, true );
1268
1269 return QSizeF( outerBoxSize.width() - pd.width(),
1270 outerBoxSize.height() - pd.height() );
1271}
1272
1274 QskAspect aspect, const QRectF& outerBox ) const
1275{
1276 const auto pd = qskEffectivePadding( this, aspect, outerBox.size(), true );
1277 return outerBox.marginsRemoved( pd );
1278}
1279
1281 QskAspect aspect, const QSizeF& innerBoxSize ) const
1282{
1283 const auto pd = qskEffectivePadding( this, aspect, innerBoxSize, false );
1284 return innerBoxSize.grownBy( pd );
1285}
1286
1288 QskAspect aspect, const QRectF& innerBox ) const
1289{
1290 const auto m = qskEffectivePadding( this, aspect, innerBox.size(), false );
1291 return innerBox.marginsAdded( m );
1292}
1293
1295 const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
1296{
1297 return effectiveSkinlet()->subControlRect( this, contentsRect, subControl );
1298}
1299
1301 const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
1302{
1303 return innerBox( subControl, subControlRect( contentsRect, subControl ) );
1304}
1305
1307{
1308 Q_UNUSED( aspect )
1309
1310 if ( auto control = qskControlCast( owningItem() ) )
1311 {
1312 /*
1313 Usually we only need smooth transitions, when state changes
1314 happen while the skinnable is visible. There are few exceptions
1315 like QskPopup::Closed, that is used to slide/fade in.
1316 */
1317
1318 if ( control->flags() & QQuickItem::ItemHasContents )
1319 return control->isInitiallyPainted();
1320
1321 return true;
1322 }
1323
1324 return false;
1325}
1326
1327void QskSkinnable::startTransition( QskAspect aspect,
1328 QskAnimationHint animationHint, const QVariant& from, const QVariant& to )
1329{
1330 startTransition( aspect, -1, animationHint, from, to );
1331}
1332
1333void QskSkinnable::startTransition( QskAspect aspect, int index,
1334 QskAnimationHint animationHint, const QVariant& from, const QVariant& to )
1335{
1336 aspect.setSubcontrol( effectiveSubcontrol( aspect.subControl() ) );
1337 startHintTransition( aspect, index, animationHint, from, to );
1338}
1339
1340void QskSkinnable::startHintTransition( QskAspect aspect, int index,
1341 QskAnimationHint animationHint, const QVariant& from, const QVariant& to )
1342{
1343 if ( animationHint.duration <= 0 || ( from == to ) )
1344 return;
1345
1346 auto control = qskControlCast( owningItem() );
1347 if ( control->window() == nullptr || !isTransitionAccepted( aspect ) )
1348 return;
1349
1350 if ( !QskVariantAnimator::maybeInterpolate( from, to, false ) )
1351 return;
1352
1353 auto v1 = from;
1354 auto v2 = to;
1355
1356 if ( aspect.type() == QskAspect::NoType &&
1357 aspect.primitive() == QskAspect::GraphicRole )
1358 {
1359 const auto skin = effectiveSkin();
1360
1361 v1.setValue( skin->graphicFilter( v1.toInt() ) );
1362 v2.setValue( skin->graphicFilter( v2.toInt() ) );
1363 }
1364
1365 aspect = qskAnimatorAspect( aspect );
1366
1367#if DEBUG_ANIMATOR
1368 qDebug() << aspect << index << animationHint.duration;
1369#endif
1370
1371 auto animator = m_data->animators.animator( aspect, index );
1372 if ( animator && animator->isRunning() )
1373 v1 = animator->currentValue();
1374
1375 m_data->animators.start( control, aspect, index, animationHint, v1, v2 );
1376}
1377
1379{
1380 const auto newState = on
1381 ? ( m_data->skinStates | stateFlag )
1382 : ( m_data->skinStates & ~stateFlag );
1383
1384 setSkinStates( newState );
1385}
1386
1387void QskSkinnable::replaceSkinStates(
1388 QskAspect::States newStates, int sampleIndex )
1389{
1390 /*
1391 Hack time: we might need different hints for a specific instance
1392 of a subcontrol ( f.e the selected row in a list box ), what is not
1393 supported by QskAspect.
1394
1395 As a workaround we use QskSkinStateChanger, that sets/restores this state/index
1396 while retrieving the skin hints.
1397 */
1398
1399 m_data->skinStates = newStates;
1400 m_data->sampleIndex = sampleIndex; // needed to find specific animators
1401}
1402
1403void QskSkinnable::addSkinStates( QskAspect::States states )
1404{
1405 setSkinStates( m_data->skinStates | states );
1406}
1407
1408void QskSkinnable::clearSkinStates( QskAspect::States states )
1409{
1410 setSkinStates( m_data->skinStates & ~states );
1411}
1412
1413void QskSkinnable::setSkinStates( QskAspect::States newStates )
1414{
1415 if ( m_data->skinStates == newStates )
1416 return;
1417
1418 auto item = owningItem();
1419
1420#if DEBUG_STATE
1421 const auto className = item ? item->className() : "QskSkinnable";
1422
1423 qDebug() << className << ":"
1424 << skinStateAsPrintable( m_data->skinState ) << "->"
1425 << skinStateAsPrintable( newState );
1426#endif
1427
1428 if ( item && item->window() )
1429 {
1430 if ( const auto skin = effectiveSkin() )
1431 {
1432 const auto mask = m_data->hintTable.states() | skin->hintTable().states();
1433 if ( ( newStates & mask ) != ( m_data->skinStates & mask ) )
1434 {
1435 /*
1436 When there are no aspects for the changed state bits we know
1437 that there won't be any animated transitions
1438 */
1439
1440 startHintTransitions( m_data->skinStates, newStates );
1441 }
1442 }
1443
1444 if ( item->flags() & QQuickItem::ItemHasContents )
1445 item->update();
1446 }
1447
1448 m_data->skinStates = newStates;
1449}
1450
1451bool QskSkinnable::startHintTransitions(
1452 QskAspect::States oldStates, QskAspect::States newStates, int index )
1453{
1454 QVector< QskAspect::Subcontrol > subControls;
1455
1456 if ( const auto control = qskControlCast( owningItem() ) )
1457 subControls = control->subControls();
1458
1459 return startHintTransitions( subControls, oldStates, newStates, index );
1460}
1461
1462bool QskSkinnable::startHintTransitions(
1463 const QVector< QskAspect::Subcontrol >& subControls,
1464 QskAspect::States oldStates, QskAspect::States newStates, int index )
1465{
1466 if ( !isTransitionAccepted( QskAspect() ) || subControls.isEmpty() )
1467 {
1468 // the control does not like any animated transition at the moment
1469 return false;
1470 }
1471
1472 bool started = false; // at least one transition has been started
1473
1474 QskAspect aspect;
1475 aspect.setVariation( effectiveVariation() );
1476 aspect.setSection( section() );
1477
1478 const auto skin = effectiveSkin();
1479 const auto control = qskControlCast( owningItem() );
1480 if ( control == nullptr )
1481 return false;
1482
1483 const auto primitiveCount = QskAspect::primitiveCount();
1484
1485 for ( const auto subControl : subControls )
1486 {
1487 aspect.setSubcontrol( subControl );
1488
1489 const auto& skinTable = skin->hintTable();
1490
1491 for ( uint i = 0; i < QskAspect::typeCount; i++ )
1492 {
1493 const auto type = static_cast< QskAspect::Type >( i );
1494
1495 const auto hint = effectiveAnimation( type, subControl, newStates );
1496
1497 if ( hint.duration > 0 )
1498 {
1499 /*
1500 Starting an animator for all primitives,
1501 that differ between the states
1502 */
1503
1504 for ( uint j = 0; j < primitiveCount; j++ )
1505 {
1506 const auto primitive = static_cast< QskAspect::Primitive >( j );
1507 aspect.setPrimitive( type, primitive );
1508
1509 const auto a1 = aspect | oldStates;
1510 const auto a2 = aspect | newStates;
1511
1512 bool doTransition = true;
1513
1514 if ( m_data->hintTable.states() == QskAspect::NoState )
1515 {
1516 /*
1517 In case we have no state aware aspects in the local
1518 table we can avoid starting animators for aspects,
1519 that are finally resolved from the same hint in
1520 the skin table.
1521 */
1522
1523 doTransition = !skinTable.isResolutionMatching( a1, a2 );
1524 }
1525
1526 if ( doTransition )
1527 {
1528 startHintTransition( aspect, index, hint,
1529 storedHint( a1 ), storedHint( a2 ) );
1530
1531 started = true;
1532 }
1533 }
1534 }
1535 }
1536 }
1537
1538 return started;
1539}
1540
1542{
1543 QskSkin* skin = nullptr;
1544
1545 if ( m_data->skinlet )
1546 skin = m_data->skinlet->skin();
1547
1548 if ( skin == nullptr )
1549 {
1550 if ( const auto item = owningItem() )
1551 skin = qskEffectiveSkin( item->window() );
1552 }
1553
1554 return skin ? skin : qskSkinManager->skin();
1555}
1556
1561
1562QskAspect::Section QskSkinnable::section() const
1563{
1564 return QskAspect::Body;
1565}
1566
1567void QskSkinnable::updateNode( QSGNode* parentNode )
1568{
1569 effectiveSkinlet()->updateNode( this, parentNode );
1570}
1571
1573 QskAspect::Subcontrol subControl ) const
1574{
1575 if ( const auto proxies = m_data->subcontrolProxies )
1576 {
1577 auto it = proxies->find( subControl );
1578 if ( it != proxies->end() )
1579 return it->second;
1580 }
1581
1582 return substitutedSubcontrol( subControl );
1583}
1584
1585QskAspect::Subcontrol QskSkinnable::substitutedSubcontrol(
1586 QskAspect::Subcontrol subControl ) const
1587{
1588 // derived classes might want to redirect a sub-control
1589 return subControl;
1590}
1591
1593{
1594 return qskIsControl( this )
1595 ? static_cast< QskControl* >( this ) : nullptr;
1596}
1597
1599{
1600 return qskIsControl( this )
1601 ? static_cast< const QskControl* >( this ) : nullptr;
1602}
1603
1604void QskSkinnable::debug( QDebug debug, QskAspect aspect ) const
1605{
1606 qskDebugAspect( debug, metaObject(), aspect );
1607}
1608
1609void QskSkinnable::debug( QDebug debug, QskAspect::State state ) const
1610{
1611 qskDebugStates( debug, metaObject(), state );
1612}
1613
1614void QskSkinnable::debug( QskAspect aspect ) const
1615{
1616 qskDebugAspect( qDebug(), metaObject(), aspect );
1617}
1618
1620{
1621 qskDebugStates( qDebug(), metaObject(), state );
1622}
1623
1624#ifndef QT_NO_DEBUG_STREAM
1625
1626#include <qdebug.h>
1627
1628QDebug operator<<( QDebug debug, const QskSkinHintStatus& status )
1629{
1630 QDebugStateSaver saver( debug );
1631 debug.nospace();
1632
1633 switch( status.source )
1634 {
1636 debug << "Skinnable";
1637 break;
1639 debug << "Skin";
1640 break;
1642 debug << "Animator";
1643 break;
1644 default:
1645 debug << "None";
1646 break;
1647 }
1648
1649 debug << ": " << status.aspect;
1650
1651 return debug;
1652}
1653
1654#endif
Lookup key for a QskSkinHintTable.
Definition QskAspect.h:15
State topState() const noexcept
void clearStates(States=AllStates) noexcept
Definition QskAspect.h:492
constexpr bool hasStates() const noexcept
Definition QskAspect.h:482
constexpr bool isAnimator() const noexcept
Definition QskAspect.h:407
void setStates(States) noexcept
Definition QskAspect.h:472
Variation
Some sort of variation.
Definition QskAspect.h:82
@ NoVariation
Definition QskAspect.h:83
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
void setAnimator(bool on) noexcept
Definition QskAspect.h:412
constexpr States states() const noexcept
Definition QskAspect.h:467
Primitive
Represents a specific element or attribute.
Definition QskAspect.h:48
@ GraphicRole
Definition QskAspect.h:56
void setPrimitive(Type, Primitive primitive) noexcept
Definition QskAspect.h:502
void setVariation(Variation) noexcept
Definition QskAspect.h:530
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
void clearState(State) noexcept
Definition QskAspect.h:487
constexpr QskAspect stateless() const noexcept
Definition QskAspect.h:390
constexpr Primitive metricPrimitive() const noexcept
Definition QskAspect.h:514
Base class of all controls.
Definition QskControl.h:23
A paint device for scalable graphics.
Definition QskGraphic.h:28
bool isValid() const
Describes the rendering interface of a QskControl. Change the skinlet to change the appearance of the...
Definition QskSkinlet.h:34
QVariant effectiveSkinHint(QskAspect, QskSkinHintStatus *=nullptr) const
Find the value for a specific aspect.
bool resetGraphicRoleHint(QskAspect)
Removes a graphic role hint from the local table.
qreal spacingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a spacing hint.
QRectF subControlRect(const QRectF &, QskAspect::Subcontrol) const
Calculate position and size of a subControl.
QMarginsF paddingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a padding hint.
virtual ~QskSkinnable()
bool resetColor(QskAspect)
Removes a color hint from the local table.
bool resetSkinHint(QskAspect)
Remove a hint from the local hint table.
bool setAlignmentHint(QskAspect, Qt::Alignment)
Sets an alignment hint.
bool setStrutSizeHint(QskAspect, const QSizeF &)
Sets a metric hint.
bool resetFontRoleHint(QskAspect)
Removes a font role hint from the local table.
QMarginsF marginHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a margin hint.
QskControl * controlCast()
void debug(QskAspect) const
QskGradient gradientHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a color hint as gradient.
QSizeF innerBoxSize(QskAspect, const QSizeF &outerBoxSize) const
Calculate the size, with paddings, indentations being subtracted.
bool setBoxBorderColorsHint(QskAspect, const QskBoxBorderColors &)
Sets a border colors hint.
QskAnimationHint effectiveAnimation(QskAspect::Type, QskAspect::Subcontrol, QskAspect::States, QskSkinHintStatus *status=nullptr) const
bool setPaddingHint(QskAspect, qreal)
Sets a padding hint.
bool resetBoxBorderColorsHint(QskAspect)
Removes a border colors hint from the local table.
bool setColor(QskAspect, Qt::GlobalColor)
Sets a color hint.
bool setGradientHint(QskAspect, const QskGradient &)
Sets a gradient as color hint.
bool setSkinHint(QskAspect, const QVariant &)
Insert a hint into the local hint table.
QMarginsF innerPadding(QskAspect, const QSizeF &) const
Calculate the padding from attributes for the given aspect.
virtual bool isTransitionAccepted(QskAspect) const
Additional check if an transition should be started.
bool setBoxBorderMetricsHint(QskAspect, const QskBoxBorderMetrics &)
Sets a border metrics hint.
QFont effectiveFont(QskAspect) const
QSizeF strutSizeHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a strut size hint.
bool resetBoxBorderMetricsHint(QskAspect)
Removes a border metrics hint from the local table.
QSizeF outerBoxSize(QskAspect, const QSizeF &innerBoxSize) const
Calculate the size, when being expanded by paddings, indentations.
virtual const QMetaObject * metaObject() const =0
const QskSkinlet * skinlet() const
bool setAnimationHint(QskAspect, QskAnimationHint)
const QskSkinHintTable & hintTable() const
Accessor for local skin hint table.
QskBoxShapeMetrics boxShapeHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a shape hint.
bool setFontRoleHint(QskAspect, const QskFontRole &)
Sets a font role hint.
QskSkin * effectiveSkin() const
QskSkinHintStatus hintStatus(QskAspect) const
QskAnimationHint animationHint(QskAspect, QskSkinHintStatus *=nullptr) const
const QskSkinlet * effectiveSkinlet() const
QskBoxBorderColors boxBorderColorsHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves border colors hint.
bool setMarginHint(QskAspect, qreal)
Sets a margin hint.
bool setGraphicRoleHint(QskAspect, int role)
Sets a graphic role hint.
bool setSpacingHint(QskAspect, qreal)
Sets a spacing hint.
virtual QskAspect::Variation effectiveVariation() const
QRectF outerBox(QskAspect, const QRectF &innerBox) const
Calculate the rectangle, when being expanded by paddings, indentations.
void setSkinlet(const QskSkinlet *)
Set an individual skinlet to render/display the content.
QskFontRole fontRoleHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a font role hint.
void setSkinStateFlag(QskAspect::State, bool on=true)
bool setFlagHint(QskAspect, int flag)
Sets a flag hint.
int graphicRoleHint(QskAspect, QskSkinHintStatus *=nullptr) const
A Retrieves a graphic role hint.
bool resetAlignmentHint(QskAspect)
Removes an alignment hint from the local table.
QRectF subControlContentsRect(const QRectF &, QskAspect::Subcontrol) const
Calculate the inner rectangle for subControl.
QskAspect::Subcontrol effectiveSubcontrol(QskAspect::Subcontrol) const
bool setBoxShapeHint(QskAspect, const QskBoxShapeMetrics &)
Sets a shape hint.
bool resetStrutSizeHint(QskAspect)
Removes a strut size hint from the local table.
QskColorFilter effectiveGraphicFilter(QskAspect::Subcontrol) const
QColor color(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a color hint.
QRectF innerBox(QskAspect, const QRectF &outerBox) const
Calculate the rectangle, whith paddings, indentations being subtracted.
QskBoxBorderMetrics boxBorderMetricsHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a border hint.
bool resetPaddingHint(QskAspect)
Removes a padding hint from the local table.
virtual void updateNode(QSGNode *)
bool setMetric(QskAspect, qreal)
Sets a metric hint.
bool resetBoxShapeHint(QskAspect)
Removes a shape hint from the local table.
qreal metric(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a metric hint.
bool resetSpacingHint(QskAspect)
Removes a spacing hint from the local table.
bool resetMetric(QskAspect)
Removes a metric hint from the local table.
bool resetMarginHint(QskAspect)
Removes a margin hint from the local table.