QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskControl.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskControl.h"
7#include "QskControlPrivate.h"
8
9#include "QskAspect.h"
10#include "QskFunctions.h"
11#include "QskEvent.h"
12#include "QskQuick.h"
13#include "QskSetup.h"
14#include "QskSkin.h"
15#include "QskSkinlet.h"
16#include "QskSkinHintTable.h"
17#include "QskMargins.h"
18#include "QskTreeNode.h"
19
20#include <qlocale.h>
21#include <qvector.h>
22
23QSK_SUBCONTROL( QskControl, Background )
24
25QSK_SYSTEM_STATE( QskControl, Disabled, QskAspect::FirstSystemState )
26QSK_SYSTEM_STATE( QskControl, Hovered, QskAspect::LastSystemState >> 1 )
27QSK_SYSTEM_STATE( QskControl, Focused, QskAspect::LastSystemState )
28
29static inline void qskSendEventTo( QObject* object, QEvent::Type type )
30{
31 QEvent event( type );
32 QCoreApplication::sendEvent( object, &event );
33}
34
35static inline bool qskMaybeGesture( QQuickItem* item,
36 const QQuickItem* child, const QEvent* event )
37{
38 if ( qskIsTouchOrMouseEvent( event->type() ) )
39 {
40 QskGestureFilterEvent ev( child, event );
41 QCoreApplication::sendEvent( item, &ev );
42
43 return ev.maybeGesture();
44 }
45
46 return false;
47}
48
49QskControl::QskControl( QQuickItem* parent )
50 : QskItem( *( new QskControlPrivate() ), parent )
51{
52 if ( parent )
53 {
54 // inheriting attributes from parent
55 QskControlPrivate::resolveLocale( this );
56 QskControlPrivate::resolveSection( this );
57 }
58}
59
61{
62#if defined( QT_DEBUG )
63 if ( auto w = window() )
64 {
65 if( this == w->mouseGrabberItem() )
66 {
67 // to catch suicide situations as a result of mouse clicks
68 qWarning() << "QskControl::~QskControl: probably suicide situation detected, "
69 "control is the mouse grabber item" << this;
70 }
71
72 }
73#endif
74}
75
77{
78 Q_D( QskControl );
79 if ( on != d->autoLayoutChildren )
80 {
81 d->autoLayoutChildren = on;
82 if ( on )
83 polish();
84 }
85}
86
88{
89 return d_func()->autoLayoutChildren;
90}
91
92void QskControl::setBackgroundColor( const QColor& color )
93{
95}
96
98{
99 if ( setGradientHint( QskControl::Background, gradient ) )
100 Q_EMIT backgroundChanged();
101}
102
104{
105 if ( resetColor( QskControl::Background ) )
106 Q_EMIT backgroundChanged();
107}
108
110{
111 return gradientHint( QskControl::Background );
112}
113
114void QskControl::setMargins( qreal margin )
115{
116 setMargins( QskMargins( margin ) );
117}
118
119void QskControl::setMargins( qreal left, qreal top, qreal right, qreal bottom )
120{
121 setMargins( QskMargins( left, top, right, bottom ) );
122}
123
124void QskControl::setMargins( const QMarginsF& margins )
125{
126 const auto m = QskMargins().expandedTo( margins );
127
128 if ( setPaddingHint( QskControl::Background, m ) )
129 {
130 qskSendEventTo( this, QEvent::ContentsRectChange );
131 Q_EMIT marginsChanged( m );
132 }
133}
134
136{
137 if ( resetPaddingHint( QskControl::Background ) )
138 {
139 qskSendEventTo( this, QEvent::ContentsRectChange );
140 Q_EMIT marginsChanged( margins() );
141 }
142}
143
144QMarginsF QskControl::margins() const
145{
146 return paddingHint( QskControl::Background );
147}
148
150{
151 return qskValidOrEmptyInnerRect( rect(), margins() );
152}
153
155{
156 return subControlRect( contentsRect(), subControl );
157}
158
160 const QSizeF& size, QskAspect::Subcontrol subControl ) const
161{
162 QRectF rect( 0.0, 0.0, size.width(), size.height() );
163 rect = qskValidOrEmptyInnerRect( rect, margins() );
164
165 return subControlRect( rect, subControl );
166}
167
169{
170 return subControlContentsRect( contentsRect(), subControl );
171}
172
174 const QSizeF& size, QskAspect::Subcontrol subControl ) const
175{
176 QRectF rect( 0.0, 0.0, size.width(), size.height() );
177 rect = qskValidOrEmptyInnerRect( rect, margins() );
178
179 return subControlContentsRect( rect, subControl );
180}
181
182QLocale QskControl::locale() const
183{
184 return d_func()->locale;
185}
186
187void QskControl::setLocale( const QLocale& locale )
188{
189 Q_D( QskControl );
190
191 d->explicitLocale = true;
192
193 if ( d->locale != locale )
194 {
195 extern void qskInheritLocale( QObject*, const QLocale& );
196
197 d->locale = locale;
198 qskSendEventTo( this, QEvent::LocaleChange );
199
200 qskInheritLocale( this, locale );
201 }
202}
203
205{
206 Q_D( QskControl );
207
208 if ( d->explicitLocale )
209 {
210 d->explicitLocale = false;
211 QskControlPrivate::resolveLocale( this );
212 }
213}
214
215void QskControl::setSection( QskAspect::Section section )
216{
217 if ( section > QskAspect::LastSection )
218 {
219 qWarning() << "Trying to set an invalid section, ignored";
220 return;
221 }
222
223 Q_D( QskControl );
224
225 d->explicitSection = true;
226
227 if ( d->section != section )
228 {
229 extern void qskInheritSection( QskControl*, const QskAspect::Section );
230
231 d->section = section;
232
233 update();
235
236 qskInheritSection( this, section );
237 }
238}
239
240void QskControl::resetSection()
241{
242 Q_D( QskControl );
243
244 if ( d->explicitSection )
245 {
246 d->explicitSection = false;
247 QskControlPrivate::resolveSection( this );
248 }
249}
250
251QskAspect::Section QskControl::section() const
252{
253 return static_cast< QskAspect::Section >( d_func()->section );
254}
255
257 QskSizePolicy::Policy horizontalPolicy,
258 QskSizePolicy::Policy verticalPolicy )
259{
260 Q_D( QskControl );
261
262 /*
263 In constructors of derived classes you don't need
264 to propagate changes by layoutConstraintChanged.
265 Sometimes it is even worse as the parent might not be
266 even prepared to handle the LayouRequest event.
267 */
268
269 d->sizePolicy.setHorizontalPolicy( horizontalPolicy );
270 d->sizePolicy.setVerticalPolicy( verticalPolicy );
271
272 if ( horizontalPolicy == QskSizePolicy::Constrained
273 && verticalPolicy == QskSizePolicy::Constrained )
274 {
275 qWarning( "QskControl::initSizePolicy: conflicting constraints" );
276 }
277}
278
280{
281 Q_D( QskControl );
282
283 if ( policy != d->sizePolicy )
284 {
285 d->sizePolicy = policy;
286 d->layoutConstraintChanged();
287
288 if ( policy.policy( Qt::Horizontal ) == QskSizePolicy::Constrained
289 && policy.policy( Qt::Vertical ) == QskSizePolicy::Constrained )
290 {
291 qWarning( "QskControl::setSizePolicy: conflicting constraints" );
292 }
293 }
294}
295
297 QskSizePolicy::Policy horizontalPolicy,
298 QskSizePolicy::Policy verticalPolicy )
299{
300 setSizePolicy( QskSizePolicy( horizontalPolicy, verticalPolicy ) );
301}
302
304 Qt::Orientation orientation, QskSizePolicy::Policy policy )
305{
306 Q_D( QskControl );
307
308 if ( d->sizePolicy.policy( orientation ) != policy )
309 {
310 d->sizePolicy.setPolicy( orientation, policy );
311 d->layoutConstraintChanged();
312 }
313}
314
316{
317 return d_func()->sizePolicy;
318}
319
320QskSizePolicy::Policy QskControl::sizePolicy( Qt::Orientation orientation ) const
321{
322 return d_func()->sizePolicy.policy( orientation );
323}
324
325/*
326 Layout attributes belong more to the layout code, than
327 being parameters of the control. So storing them here is kind of a
328 design flaw ( similar to QWidget/QSizePolicy ).
329 But this way we don't need to add the attributes to all type of
330 layout engines + we can make use of them when doing layouts
331 manually ( f.e autoLayoutChildren ).
332 */
333void QskControl::setLayoutAlignmentHint( Qt::Alignment alignment )
334{
335 Q_D( QskControl );
336
337 if ( layoutAlignmentHint() != alignment )
338 {
339 d->layoutAlignmentHint = alignment;
340 d->layoutConstraintChanged();
341 }
342}
343
344Qt::Alignment QskControl::layoutAlignmentHint() const
345{
346 return static_cast< Qt::Alignment >( d_func()->layoutAlignmentHint );
347}
348
350 Qsk::Visibilities visibilities, QskPlacementPolicy::Policy policy )
351{
352 auto placementPolicy = this->placementPolicy();
353 placementPolicy.setPolicy( visibilities, policy );
354
356}
357
359 QskPlacementPolicy::Policy visiblePolicy, QskPlacementPolicy::Policy hiddenPolicy )
360{
361 setPlacementPolicy( QskPlacementPolicy( visiblePolicy, hiddenPolicy ) );
362}
363
365{
366 Q_D( QskControl );
367
368 if ( policy != placementPolicy() )
369 {
370 d->setPlacementPolicy( true, policy.visiblePolicy() );
371 d->setPlacementPolicy( false, policy.hiddenPolicy() );
372
373 d->layoutConstraintChanged();
374 }
375}
376
377void QskControl::resetPlacementPolicy()
378{
380}
381
383{
384 Q_D( const QskControl );
385
386 return QskPlacementPolicy(
387 d->placementPolicy( true ), d->placementPolicy( false ) );
388}
389
391{
392 return d_func()->placementPolicy( visiblity == Qsk::Visible );
393}
394
395QskPlacementPolicy::Policy QskControl::effectivePlacementPolicy() const
396{
397 return d_func()->placementPolicy( isVisibleToParent() );
398}
399
401{
402 return qskIsVisibleToLayout( this );
403}
404
405void QskControl::setPreferredSize( const QSizeF& size )
406{
407 setExplicitSizeHint( Qt::PreferredSize, size );
408}
409
410void QskControl::setPreferredSize( qreal width, qreal height )
411{
412 setExplicitSizeHint( Qt::PreferredSize, QSizeF( width, height ) );
413}
414
416{
417 const qreal height = explicitSizeHint( Qt::PreferredSize ).height();
418 setExplicitSizeHint( Qt::PreferredSize, QSizeF( width, height ) );
419}
420
422{
423 const qreal width = explicitSizeHint( Qt::PreferredSize ).width();
424 setExplicitSizeHint( Qt::PreferredSize, QSizeF( width, height ) );
425}
426
427void QskControl::setMinimumSize( const QSizeF& size )
428{
429 setExplicitSizeHint( Qt::MinimumSize, size );
430}
431
432void QskControl::setMinimumSize( qreal width, qreal height )
433{
434 setExplicitSizeHint( Qt::MinimumSize, QSizeF( width, height ) );
435}
436
438{
439 const qreal height = explicitSizeHint( Qt::MinimumSize ).height();
440 setExplicitSizeHint( Qt::MinimumSize, QSizeF( width, height ) );
441}
442
444{
445 const qreal width = explicitSizeHint( Qt::MinimumSize ).width();
446 setExplicitSizeHint( Qt::MinimumSize, QSizeF( width, height ) );
447}
448
449void QskControl::setMaximumSize( const QSizeF& size )
450{
451 setExplicitSizeHint( Qt::MaximumSize, size );
452}
453
454void QskControl::setMaximumSize( qreal width, qreal height )
455{
456 setExplicitSizeHint( Qt::MaximumSize, QSizeF( width, height ) );
457}
458
460{
461 const qreal height = explicitSizeHint( Qt::MaximumSize ).height();
462 setExplicitSizeHint( Qt::MaximumSize, QSizeF( width, height ) );
463}
464
466{
467 const qreal width = explicitSizeHint( Qt::MaximumSize ).width();
468 setExplicitSizeHint( Qt::MaximumSize, QSizeF( width, height ) );
469}
470
471void QskControl::setFixedSize( const QSizeF& size )
472{
473 const QSizeF newSize = size.expandedTo( QSizeF( 0, 0 ) );
474
475 const QskSizePolicy policy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
476
477 Q_D( QskControl );
478
479 if ( policy != d->sizePolicy ||
480 d->explicitSizeHint( Qt::PreferredSize ) != newSize )
481 {
482 d->sizePolicy = policy;
483 d->setExplicitSizeHint( Qt::PreferredSize, newSize );
484
485 d->layoutConstraintChanged();
486 }
487}
488
489void QskControl::setFixedSize( qreal width, qreal height )
490{
491 setFixedSize( QSizeF( width, height ) );
492}
493
494void QskControl::setFixedWidth( qreal width )
495{
496 if ( width < 0 )
497 width = 0;
498
499 Q_D( QskControl );
500
501 auto size = d->explicitSizeHint( Qt::PreferredSize );
502
503 if ( ( d->sizePolicy.horizontalPolicy() != QskSizePolicy::Fixed ) ||
504 ( size.width() != width ) )
505 {
506 size.setWidth( width );
507
508 d->sizePolicy.setHorizontalPolicy( QskSizePolicy::Fixed );
509 d->setExplicitSizeHint( Qt::PreferredSize, size );
510
511 d->layoutConstraintChanged();
512 }
513}
514
515void QskControl::setFixedHeight( qreal height )
516{
517 if ( height < 0 )
518 height = 0;
519
520 Q_D( QskControl );
521
522 auto size = d->explicitSizeHint( Qt::PreferredSize );
523
524 if ( ( d->sizePolicy.verticalPolicy() != QskSizePolicy::Fixed ) ||
525 ( size.height() != height ) )
526 {
527 size.setHeight( height );
528
529 d->sizePolicy.setVerticalPolicy( QskSizePolicy::Fixed );
530 d->setExplicitSizeHint( Qt::PreferredSize, size );
531
532 d->layoutConstraintChanged();
533 }
534}
535
536void QskControl::resetExplicitSizeHint( Qt::SizeHint whichHint )
537{
538 if ( whichHint >= Qt::MinimumSize && whichHint <= Qt::MaximumSize )
539 {
540 Q_D( QskControl );
541
542 const auto oldHint = d->explicitSizeHint( whichHint );
543 d->resetExplicitSizeHint( whichHint );
544
545 if ( oldHint != d->explicitSizeHint( whichHint ) )
546 d->layoutConstraintChanged();
547 }
548}
549
550void QskControl::setExplicitSizeHint( Qt::SizeHint whichHint, const QSizeF& size )
551{
552 if ( whichHint >= Qt::MinimumSize && whichHint <= Qt::MaximumSize )
553 {
554 const QSizeF newSize( ( size.width() < 0 ) ? -1.0 : size.width(),
555 ( size.height() < 0 ) ? -1.0 : size.height() );
556
557 Q_D( QskControl );
558
559 if ( newSize != d->explicitSizeHint( whichHint ) )
560 {
561 d->setExplicitSizeHint( whichHint, newSize );
562 d->layoutConstraintChanged();
563 }
564 }
565}
566
567void QskControl::setExplicitSizeHint(
568 Qt::SizeHint whichHint, qreal width, qreal height )
569{
570 setExplicitSizeHint( whichHint, QSizeF( width, height ) );
571}
572
573QSizeF QskControl::explicitSizeHint( Qt::SizeHint whichHint ) const
574{
575 if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize )
576 return QSizeF();
577
578 return d_func()->explicitSizeHint( whichHint );
579}
580
581QSizeF QskControl::implicitSizeHint(
582 Qt::SizeHint whichHint, const QSizeF& constraint ) const
583{
584 if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize )
585 return QSizeF();
586
587 if ( constraint.isValid() )
588 {
589 // having constraints in both directions does not make sense
590 return constraint;
591 }
592
593 QSizeF hint;
594
595 if ( whichHint == Qt::PreferredSize
596 && constraint.width() < 0.0 && constraint.height() < 0.0 )
597 {
598 // this one might be cached
599 hint = implicitSize();
600 }
601 else
602 {
603 hint = d_func()->implicitSizeHint( whichHint, constraint );
604 }
605
606 return hint;
607}
608
609QSizeF QskControl::effectiveSizeHint(
610 Qt::SizeHint which, const QSizeF& constraint ) const
611{
612 if ( which < Qt::MinimumSize || which > Qt::MaximumSize )
613 return QSizeF( 0, 0 );
614
615 if ( constraint.isValid() )
616 return constraint;
617
618 const bool isConstrained =
619 constraint.width() >= 0 || constraint.height() >= 0;
620
621 Q_D( const QskControl );
622
623 d->blockLayoutRequestEvents = false;
624
625 QSizeF hint;
626
627 /*
628 The explicit size has always precedence over the implicit size,
629 and will kill the effect of the constraint
630 */
631
632 hint = d->explicitSizeHint( which );
633
634 if ( !hint.isValid() )
635 {
636 const auto implicitHint = implicitSizeHint( which, constraint );
637
638 if ( hint.width() < 0 )
639 hint.setWidth( implicitHint.width() );
640
641 if ( hint.height() < 0 )
642 hint.setHeight( implicitHint.height() );
643 }
644
645 if ( !isConstrained && ( hint.width() >= 0 || hint.height() >= 0 ) )
646 {
647 /*
648 We normalize the unconstrained hints by the explicit hints, so that
649 we always have: minimum <= preferred <= maximum.
650 */
651
652 if ( which == Qt::MaximumSize )
653 {
654 const auto minimumHint = d->explicitSizeHint( Qt::MinimumSize );
655
656 if ( hint.width() >= 0 )
657 hint.rwidth() = qMax( hint.width(), minimumHint.width() );
658
659 if ( hint.height() >= 0 )
660 hint.rheight() = qMax( hint.height(), minimumHint.height() );
661 }
662 else if ( which == Qt::PreferredSize )
663 {
664 const auto minimumHint = d->explicitSizeHint( Qt::MinimumSize );
665 const auto maximumHint = d->explicitSizeHint( Qt::MaximumSize );
666
667 if ( hint.width() >= 0 )
668 {
669 if ( maximumHint.width() >= 0 )
670 hint.rwidth() = qMin( hint.width(), maximumHint.width() );
671
672 hint.rwidth() = qMax( hint.width(), minimumHint.width() );
673 }
674
675 if ( hint.height() >= 0 )
676 {
677 if ( maximumHint.height() >= 0 )
678 hint.rheight() = qMin( hint.height(), maximumHint.height() );
679
680 hint.rheight() = qMax( hint.height(), minimumHint.height() );
681 }
682 }
683 }
684
685 return hint;
686}
687
688qreal QskControl::heightForWidth( qreal width ) const
689{
690 const auto hint = effectiveSizeHint(
691 Qt::PreferredSize, QSizeF( width, -1.0 ) );
692
693 return hint.height();
694}
695
696qreal QskControl::widthForHeight( qreal height ) const
697{
698 const auto hint = effectiveSizeHint(
699 Qt::PreferredSize, QSizeF( -1.0, height ) );
700
701 return hint.width();
702}
703
705 Qt::SizeHint which, const QSizeF& constraint ) const
706{
707 return qskSizeConstraint( this, which, constraint );
708}
709
710bool QskControl::event( QEvent* event )
711{
712 switch ( static_cast< int >( event->type() ) )
713 {
714 case QEvent::EnabledChange:
715 {
716 setSkinStateFlag( Disabled, !isEnabled() );
717 break;
718 }
719 case QEvent::LocaleChange:
720 {
721 Q_EMIT localeChanged( locale() );
722 break;
723 }
724 case QEvent::ContentsRectChange:
725 {
727 if ( d_func()->autoLayoutChildren )
728 polish();
729
730 break;
731 }
732 case QEvent::LayoutRequest:
733 {
734 if ( d_func()->autoLayoutChildren )
735 {
737 polish();
738 }
739
740 break;
741 }
742 case QEvent::StyleChange:
743 {
744 // The skin has changed
745
746 if ( skinlet() == nullptr )
747 {
748 /*
749 When we don't have a local skinlet, the skinlet
750 from the previous skin might be cached.
751 */
752
753 setSkinlet( nullptr );
754 }
755
756 break;
757 }
758 case QskEvent::Gesture:
759 {
760 gestureEvent( static_cast< QskGestureEvent* >( event ) );
761 return true;
762 }
763 case QEvent::MouseButtonPress:
764 {
765 /*
766 We need to do a gesture detection with abort criterions
767 first. When it fails the input events will be processed
768 in ascending order along the item tree until an item accepts
769 the event.
770
771 This detection can be done in childMouseEventFilter() for all
772 children - but not for the filtering control ( = this ) itself.
773 So we need to do this here.
774 */
775 if ( qskMaybeGesture( this, this, event ) )
776 return true;
777
778 const bool ok = Inherited::event( event );
779
780 if ( !event->isAccepted() )
781 {
782 /*
783 When the initial gesture detection failed and the event
784 has not been handled here we do a second gesture detection
785 without passing a child. It can be used for detections
786 without abort criterions.
787
788 An example is the pan gesture detection, that can be started without
789 any timeouts now.
790 */
791 if ( qskMaybeGesture( this, nullptr, event ) )
792 return true;
793 }
794
795 return ok;
796 }
797 }
798
799 if ( qskMaybeGesture( this, this, event ) )
800 return true;
801
802 return Inherited::event( event );
803}
804
805bool QskControl::childMouseEventFilter( QQuickItem* child, QEvent* event )
806{
807 /*
808 The strategy implemented in many classes of the Qt development is
809 to analyze the events without blocking the handling of the child.
810 Once a gesture is detected the gesture handling trys to steal the
811 mouse grab hoping for the child to abort its operation.
812
813 This approach has obvious problems:
814
815 - operations already started on press can't be aborted anymore
816 - the child needs to agree on losing the grab ( setKeepMouseGrab( false ) )
817 - ...
818
819 We implement a different strategy: processing of the events
820 by the children is blocked until the gesture detection has accepted
821 or rejected. In case of a rejection the events will be replayed.
822 ( see QskGestureRecognizer )
823 */
824
825 return qskMaybeGesture( this, child, event );
826}
827
828void QskControl::gestureEvent( QskGestureEvent* )
829{
830}
831
832void QskControl::hoverEnterEvent( QHoverEvent* event )
833{
834 Inherited::hoverEnterEvent( event );
836}
837
838void QskControl::hoverLeaveEvent( QHoverEvent* event )
839{
840 Inherited::hoverLeaveEvent( event );
841 setSkinStateFlag( Hovered, false );
842}
843
844void QskControl::itemChange( QQuickItem::ItemChange change,
845 const QQuickItem::ItemChangeData& value )
846{
847 switch ( static_cast< int >( change ) )
848 {
849 case QQuickItem::ItemParentHasChanged:
850 {
851 if ( value.item )
852 {
853 if ( !d_func()->explicitLocale )
854 QskControlPrivate::resolveLocale( this );
855
856 if ( !d_func()->explicitSection )
857 QskControlPrivate::resolveSection( this );
858 }
859
860#if 1
861 // not necessarily correct, when parent != parentItem ???
862 qskSendEventTo( this, QEvent::ParentChange );
863#endif
864
865 break;
866 }
867 case QQuickItem::ItemChildAddedChange:
868 case QQuickItem::ItemChildRemovedChange:
869 {
870 if ( autoLayoutChildren() )
871 {
872 if ( qskIsVisibleToLayout( value.item ) )
874
875 if ( qskIsAdjustableByLayout( value.item ) )
876 polish();
877 }
878 break;
879 }
880 case QQuickItem::ItemActiveFocusHasChanged:
881 {
882 setSkinStateFlag( Focused, hasActiveFocus() );
883 break;
884 }
885 }
886
887 Inherited::itemChange( change, value );
888}
889
891 const QRectF& newGeometry, const QRectF& oldGeometry )
892{
893 if ( d_func()->autoLayoutChildren )
894 {
895 if ( newGeometry.size() != oldGeometry.size() )
896 polish();
897 }
898
899 Inherited::geometryChange( newGeometry, oldGeometry );
900}
901
902void QskControl::updateItemPolish()
903{
904 updateResources(); // an extra dirty bit for this ???
905
906 if ( width() >= 0.0 || height() >= 0.0 )
907 {
908 if ( d_func()->autoLayoutChildren && !maybeUnresized() )
909 {
910 const auto rect = layoutRect();
911
912 const auto children = childItems();
913 for ( auto child : children )
914 {
915 if ( qskIsAdjustableByLayout( child ) )
916 {
917 const auto r = qskConstrainedItemRect( child, rect );
918 qskSetItemGeometry( child, r );
919 }
920 }
921 }
922
923 updateLayout();
924 }
925}
926
927QSGNode* QskControl::updateItemPaintNode( QSGNode* node )
928{
929 if ( node == nullptr )
930 node = new QskTreeNode();
931
932 updateNode( node );
933 return node;
934}
935
936QskControl* QskControl::owningItem() const
937{
938 return const_cast< QskControl* >( this );
939}
940
942{
943 Q_D( const QskControl );
944
945 if ( d->width <= 0.0 && d->height <= 0.0 )
946 return QRectF();
947
948 return layoutRectForSize( size() );
949}
950
951QRectF QskControl::layoutRectForSize( const QSizeF& size ) const
952{
953 const QRectF r( 0.0, 0.0, size.width(), size.height() );
954 return qskValidOrEmptyInnerRect( r, margins() );
955}
956
958{
959 return contentsRect();
960}
961
963{
964 return clipRect();
965}
966
967void QskControl::updateLayout()
968{
969}
970
971void QskControl::updateResources()
972{
973}
974
975QSizeF QskControl::contentsSizeHint(
976 Qt::SizeHint which, const QSizeF& constraint ) const
977{
978 return effectiveSkinlet()->sizeHint( this, which, constraint );
979}
980
981QSizeF QskControl::layoutSizeHint(
982 Qt::SizeHint which, const QSizeF& constraint ) const
983{
984 if ( which == Qt::MaximumSize || !d_func()->autoLayoutChildren )
985 return QSizeF();
986
987 qreal w = -1.0;
988 qreal h = -1.0;
989
990 const auto children = childItems();
991
992 for ( const auto child : children )
993 {
994 if ( !qskIsVisibleToLayout( child ) )
995 continue;
996
997 const auto policy = qskSizePolicy( child );
998
999 if ( constraint.width() >= 0.0 && policy.isConstrained( Qt::Vertical ) )
1000 {
1001 const auto hint = qskSizeConstraint( child, which, constraint );
1002 h = qMax( h, hint.height() );
1003 }
1004 else if ( constraint.height() >= 0.0 && policy.isConstrained( Qt::Horizontal ) )
1005 {
1006 const auto hint = qskSizeConstraint( child, which, constraint );
1007 w = qMax( w, hint.width() );
1008 }
1009 else
1010 {
1011 const auto hint = qskSizeConstraint( child, which, QSizeF() );
1012
1013 w = qMax( w, hint.width() );
1014 h = qMax( h, hint.height() );
1015 }
1016 }
1017
1018 return QSizeF( w, h );
1019}
1020
1021QVector< QskAspect::Subcontrol > QskControl::subControls() const
1022{
1023 QVector< QskAspect::Subcontrol > subControls;
1024
1025 for ( auto mo = metaObject(); mo != nullptr; mo = mo->superClass() )
1026 {
1027 const auto moSubControls = QskAspect::subControls( mo );
1028
1029 for ( auto subControl : moSubControls )
1030 {
1031 const auto subControlEffective = effectiveSubcontrol( subControl );
1032
1033 if ( subControlEffective == subControl )
1034 {
1035 subControls += subControlEffective;
1036 }
1037 else
1038 {
1039 // when subControlEffective differs it usually has
1040 // been mapped to a subcontrol of an inherited class
1041 // that is already in the list.
1042
1043 if ( !subControls.contains( subControlEffective ) )
1044 {
1045 subControls += subControlEffective;
1046 }
1047 }
1048 }
1049 }
1050
1051 return subControls;
1052}
1053
1054#include "moc_QskControl.cpp"
Lookup key for a QskSkinHintTable.
Definition QskAspect.h:15
@ LastSystemState
Definition QskAspect.h:118
@ FirstSystemState
Definition QskAspect.h:115
static QVector< Subcontrol > subControls(const QMetaObject *)
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
Definition QskAspect.h:104
Base class of all controls.
Definition QskControl.h:23
void setMaximumWidth(qreal width)
void setLocale(const QLocale &)
QRectF subControlRect(QskAspect::Subcontrol) const
void localeChanged(const QLocale &)
static const QskAspect::State Disabled
Definition QskControl.h:56
static const QskAspect::State Hovered
Definition QskControl.h:56
void setMaximumHeight(qreal height)
void setFixedSize(const QSizeF &)
void hoverLeaveEvent(QHoverEvent *) override
QskGradient background
Definition QskControl.h:41
bool isVisibleToLayout() const
void setMinimumHeight(qreal height)
~QskControl() override
qreal widthForHeight(qreal height) const
virtual QRectF focusIndicatorClipRect() const
void backgroundChanged()
QLocale locale
Definition QskControl.h:27
void setAutoLayoutChildren(bool)
void setLayoutAlignmentHint(Qt::Alignment)
qreal heightForWidth(qreal width) const
void setSizePolicy(QskSizePolicy)
QRectF subControlContentsRect(QskAspect::Subcontrol) const
virtual QRectF focusIndicatorRect() const
void resetBackground()
void marginsChanged(const QMarginsF &)
void itemChange(ItemChange, const ItemChangeData &) override
void resetMargins()
void setPlacementPolicy(QskPlacementPolicy)
void setMinimumSize(const QSizeF &)
QRectF layoutRect() const
void setFixedWidth(qreal width)
QskSizePolicy sizePolicy
Definition QskControl.h:43
void setPreferredSize(const QSizeF &)
void setPreferredWidth(qreal width)
QRectF contentsRect() const
void setMargins(qreal)
void setPreferredHeight(qreal height)
void setBackground(const QskGradient &)
static const QskAspect::State Focused
Definition QskControl.h:56
QskPlacementPolicy placementPolicy
Definition QskControl.h:45
void hoverEnterEvent(QHoverEvent *) override
void geometryChange(const QRectF &, const QRectF &) override
void initSizePolicy(QskSizePolicy::Policy, QskSizePolicy::Policy)
QskMargins margins
Definition QskControl.h:38
virtual QRectF layoutRectForSize(const QSizeF &) const
void setBackgroundColor(const QColor &)
void setMinimumWidth(qreal width)
QSizeF sizeConstraint
Definition QskControl.h:50
void setMaximumSize(const QSizeF &)
void setFixedHeight(qreal height)
QskControl(QQuickItem *parent=nullptr)
QVector< QskAspect::Subcontrol > subControls() const
void resetLocale()
bool autoLayoutChildren
Definition QskControl.h:33
QSizeF implicitSize() const
Definition QskItem.h:219
bool isVisibleToParent() const
Definition QskItem.cpp:325
void geometryChange(const QRectF &, const QRectF &) override
Definition QskItem.cpp:1024
void itemChange(ItemChange, const ItemChangeData &) override
Definition QskItem.cpp:863
bool event(QEvent *) override
Definition QskItem.cpp:736
QRectF rect
Definition QskItem.h:21
void resetImplicitSize()
Definition QskItem.cpp:721
bool maybeUnresized() const
Definition QskItem.cpp:583
Policy hiddenPolicy
Policy for the item, when being hidden ( to its parent )
Policy visiblePolicy
Policy for the item, when being visible ( to its parent )
QMarginsF paddingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a padding hint.
bool resetColor(QskAspect)
Removes a color hint from the local table.
QskGradient gradientHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a color hint as gradient.
bool setPaddingHint(QskAspect, qreal)
Sets a padding hint.
bool setGradientHint(QskAspect, const QskGradient &)
Sets a gradient as color hint.
virtual const QMetaObject * metaObject() const =0
const QskSkinlet * skinlet() const
const QskSkinlet * effectiveSkinlet() const
void setSkinlet(const QskSkinlet *)
Set an individual skinlet to render/display the content.
void setSkinStateFlag(QskAspect::State, bool on=true)
QskAspect::Subcontrol effectiveSubcontrol(QskAspect::Subcontrol) const
QColor color(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a color hint.
bool resetPaddingHint(QskAspect)
Removes a padding hint from the local table.
virtual void updateNode(QSGNode *)
Visibility
Visibility of an object.
@ Visible