8#include "QskScrollBox.h"
9#include "QskLinearBox.h"
10#include "QskTabButton.h"
11#include "QskTextOptions.h"
12#include "QskAnimationHint.h"
15#include <qquickwindow.h>
19static inline Qt::Orientation qskOrientation( Qt::Edge edge )
21 if ( ( edge == Qt::TopEdge ) || ( edge == Qt::BottomEdge ) )
22 return Qt::Horizontal;
27static inline void qskTransposeSizePolicy(
QskControl* control )
39 ButtonBox( Qt::Orientation orientation, QQuickItem* parent )
42 setObjectName( QStringLiteral(
"QskTabBarLayoutBox" ) );
43 setExtraSpacingAt( Qt::RightEdge | Qt::BottomEdge );
46 void restack(
int currentIndex )
56 for (
int i = 0; i < elementCount(); i++ )
58 if (
auto button = itemAtIndex( i ) )
59 button->setZ( i == currentIndex ? 0.001 : 0.0 );
69 ScrollBox( QQuickItem* parent )
72 setPolishOnResize(
true );
73 setWheelEnabled(
false );
74 enableAutoTranslation(
true );
76 setFocusPolicy( Qt::NoFocus );
78 connect(
this, &ScrollBox::scrollPosChanged,
82 QRectF focusIndicatorClipRect()
const override
88 if (
auto focusItem = window()->activeFocusItem() )
90 const auto itemRect = mapRectFromItem(
91 focusItem, focusItem->boundingRect() );
93 if ( r.intersects( itemRect ) )
103 if (
auto tabBar = qobject_cast< const QskTabBar* >( parentItem() ) )
113 QRectF viewContentsRect()
const override
118 void setOrientation( Qt::Orientation orientation )
120 setFlickableOrientations( orientation );
122 if ( orientation == Qt::Horizontal )
123 setSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::MinimumExpanding );
125 setSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::Ignored );
128 void ensureItemVisible(
const QQuickItem* item )
130 if ( qskIsAncestorOf(
this, item ) )
132 const auto pos = mapFromItem( item, QPointF() );
133 ensureVisible( QRectF( pos.x(), pos.y(), item->width(), item->height() ) );
137 QRectF clipRect()
const override
139 auto r = Inherited::clipRect();
141 if (
auto control = qskControlCast( parentItem() ) )
151 constexpr qreal expanded = 0.90 * std::numeric_limits< int >::max();
153 if ( flickableOrientations() & Qt::Horizontal )
155 r.setTop( r.top() - 0.5 * expanded );
156 r.setHeight( expanded );
160 r.setLeft( r.left() - 0.5 * expanded );
161 r.setWidth( expanded );
169 bool event( QEvent* event )
override
171 if ( event->type() == QEvent::LayoutRequest )
177 return Inherited::event( event );
180 void updateLayout()
override
182 auto box = buttonBox();
184 auto boxSize = viewContentsRect().size();
185 boxSize = qskConstrainedItemSize( box, boxSize );
188 box->setSize( boxSize );
190 enableAutoTranslation(
false );
192 setScrollableSize( boxSize );
193 setScrollPos( scrollPos() );
195 enableAutoTranslation(
true );
197 translateButtonBox();
199 setClip( width() < boxSize.width() || height() < boxSize.height() );
202 QSizeF layoutSizeHint( Qt::SizeHint which,
const QSizeF& constraint )
const override
204 auto hint = buttonBox()->sizeConstraint( which, constraint );
206 if ( which == Qt::MinimumSize )
208 if ( sizePolicy().horizontalPolicy() & QskSizePolicy::ShrinkFlag )
211 if ( sizePolicy().verticalPolicy() & QskSizePolicy::ShrinkFlag )
212 hint.setHeight( -1 );
222 return qobject_cast< QskLinearBox* >( childItems().constFirst() );
225 void enableAutoTranslation(
bool on )
229 connect(
this, &QskScrollBox::scrollPosChanged,
230 this, &ScrollBox::translateButtonBox );
234 disconnect(
this, &QskScrollBox::scrollPosChanged,
235 this, &ScrollBox::translateButtonBox );
239 void translateButtonBox()
241 if (
auto box = buttonBox() )
243 const QPointF pos = viewContentsRect().topLeft() - scrollPos();
244 box->setPosition( pos );
250class QskTabBar::PrivateData
257 connect( button, &QskTabButton::toggled,
258 tabBar, &QskTabBar::adjustCurrentIndex, Qt::UniqueConnection );
262 disconnect( button, &QskTabButton::toggled,
263 tabBar, &QskTabBar::adjustCurrentIndex );
267 ScrollBox* scrollBox =
nullptr;
268 ButtonBox* buttonBox =
nullptr;
269 int currentIndex = -1;
274QskTabBar::QskTabBar( QQuickItem* parent )
275 : Inherited( parent )
276 , m_data( new PrivateData() )
278 setAutoLayoutChildren(
true );
280 const auto orientation = qskOrientation( edge() );
282 if ( orientation == Qt::Horizontal )
283 initSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Fixed );
285 initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Preferred );
287 m_data->scrollBox =
new ScrollBox(
this );
288 m_data->scrollBox->setOrientation( orientation );
290 m_data->buttonBox =
new ButtonBox( orientation, m_data->scrollBox );
291 m_data->buttonBox->setSpacing( spacingHint( QskTabBar::Panel ) );
292 m_data->buttonBox->setSizePolicy( QskSizePolicy::Maximum, QskSizePolicy::Maximum );
294 connect(
this, &QskTabBar::currentIndexChanged,
295 m_data->buttonBox, &ButtonBox::restack, Qt::QueuedConnection );
298QskTabBar::QskTabBar( Qt::Edge edge, QQuickItem* parent )
304QskTabBar::~QskTabBar()
308void QskTabBar::setEdge( Qt::Edge edge )
310 const auto oldEdge = this->edge();
314 if ( edge == oldEdge )
317 const auto orientation = qskOrientation( edge );
319 if ( orientation != m_data->buttonBox->orientation() )
321 qskTransposeSizePolicy(
this );
323 m_data->buttonBox->setOrientation( orientation );
324 qskTransposeSizePolicy( m_data->buttonBox );
326 m_data->scrollBox->setOrientation( orientation );
331 for (
int i = 0; i < count(); i++ )
332 buttonAt( i )->update();
334 Q_EMIT edgeChanged( edge );
337void QskTabBar::resetEdge()
340 Q_EMIT edgeChanged( edge() );
343Qt::Edge QskTabBar::edge()
const
350 return flagHint< Qt::Edge > ( aspect, Qt::TopEdge );
353Qt::Orientation QskTabBar::orientation()
const
355 return qskOrientation( edge() );
358void QskTabBar::setAutoScrollFocusedButton(
bool on )
360 if ( m_data->scrollBox->autoScrollFocusItem() != on )
362 m_data->scrollBox->setAutoScrollFocusedItem( on );
363 Q_EMIT autoScrollFocusedButtonChanged( on );
367bool QskTabBar::autoScrollFocusButton()
const
369 return m_data->scrollBox->autoScrollFocusItem();
372void QskTabBar::setAutoFitTabs(
bool on )
374 const auto orientation = qskOrientation( edge() );
375 int policy = m_data->buttonBox->sizePolicy( orientation );
377 if ( ( policy & QskSizePolicy::GrowFlag ) != on )
380 policy |= QskSizePolicy::GrowFlag;
385 m_data->buttonBox->setSizePolicy(
386 orientation,
static_cast< QskSizePolicy::Policy
>( policy ) );
390 Q_EMIT autoFitTabsChanged( on );
394bool QskTabBar::autoFitTabs()
const
396 const auto policy = m_data->buttonBox->sizePolicy( orientation() );
397 return ( policy & QskSizePolicy::GrowFlag );
402 if ( options != m_data->textOptions )
407 m_data->textOptions = options;
408 Q_EMIT textOptionsChanged( options );
410 for (
int i = 0; i < count(); i++ )
411 buttonAt( i )->setTextOptions( options );
417 return m_data->textOptions;
420int QskTabBar::addTab(
const QString& text )
422 return insertTab( -1, text );
425int QskTabBar::insertTab(
int index,
const QString& text )
432 return insertTab( -1, button );
435int QskTabBar::insertTab(
int index,
QskTabButton* button )
437 auto buttonBox = m_data->buttonBox;
439 if ( index < 0 || index >= buttonBox->elementCount() )
440 index = buttonBox->elementCount();
442 if ( isComponentComplete() )
446 m_data->currentIndex = 0;
447 button->setChecked(
true );
451 buttonBox->insertItem( index, button );
452 buttonBox->restack( m_data->currentIndex );
454 if ( button->textOptions() != m_data->textOptions )
455 button->setTextOptions( m_data->textOptions );
457 m_data->connectButton( button,
this,
true );
459 connect( button, &QskAbstractButton::clicked,
460 this, &QskTabBar::handleButtonClick );
462 Q_EMIT countChanged( count() );
467void QskTabBar::removeTab(
int index )
469 auto item = m_data->buttonBox->itemAtIndex( index );
470 if ( item ==
nullptr )
475 if ( index > m_data->currentIndex )
477 Q_EMIT countChanged( count() );
479 else if ( index < m_data->currentIndex )
481 m_data->currentIndex--;
483 Q_EMIT countChanged( count() );
484 Q_EMIT currentIndexChanged( m_data->currentIndex );
491 for (
int i = m_data->currentIndex; i >= 0; i-- )
493 auto button = buttonAt( i );
494 if ( button && button->isEnabled() )
503 if ( nextButton ==
nullptr )
505 for (
int i = m_data->currentIndex + 1; i < count(); i++ )
507 auto button = buttonAt( i );
508 if ( button && button->isEnabled() )
520 m_data->connectButton( nextButton,
this,
false );
521 nextButton->setChecked(
true );
522 m_data->connectButton( nextButton,
this,
true );
525 m_data->currentIndex = nextIndex;
527 Q_EMIT countChanged( count() );
528 Q_EMIT currentIndexChanged( nextIndex );
532void QskTabBar::clear(
bool autoDelete )
537 const int idx = currentIndex();
538 m_data->buttonBox->clear( autoDelete );
540 Q_EMIT countChanged( count() );
543 Q_EMIT currentIndexChanged( -1 );
546bool QskTabBar::isTabEnabled(
int index )
const
548 const auto button = buttonAt( index );
549 return button ? button->isEnabled() :
false;
552void QskTabBar::setTabEnabled(
int index,
bool enabled )
554 if (
auto button = buttonAt( index ) )
557 button->setEnabled( enabled );
561void QskTabBar::setCurrentIndex(
int index )
563 if ( index != m_data->currentIndex )
565 if ( isComponentComplete() )
567 auto button = buttonAt( index );
568 if ( button && button->isEnabled() && !button->isChecked() )
569 button->setChecked(
true );
573 m_data->currentIndex = index;
574 Q_EMIT currentIndexChanged( m_data->currentIndex );
579int QskTabBar::currentIndex()
const
581 return m_data->currentIndex;
584int QskTabBar::count()
const
586 return m_data->buttonBox->elementCount();
591 return qobject_cast< QskTabButton* >(
592 m_data->buttonBox->itemAtIndex( position ) );
595const QskTabButton* QskTabBar::buttonAt(
int position )
const
597 auto that =
const_cast< QskTabBar*
>( this );
598 return that->buttonAt( position );
603 return buttonAt( currentIndex() );
608 return buttonAt( currentIndex() );
611QString QskTabBar::currentButtonText()
const
613 return buttonTextAt( currentIndex() );
616QString QskTabBar::buttonTextAt(
int index )
const
618 if (
const auto button = buttonAt( index ) )
619 return button->text();
626 return m_data->buttonBox->indexOf( button );
629void QskTabBar::ensureButtonVisible(
const QskTabButton* button )
631 m_data->scrollBox->ensureItemVisible( button );
634void QskTabBar::componentComplete()
638 if ( m_data->currentIndex < 0 && count() >= 0 )
639 m_data->currentIndex = 0;
641 if (
auto button = buttonAt( m_data->currentIndex ) )
643 if ( button->isEnabled() && !button->isChecked() )
644 button->setChecked(
true );
648void QskTabBar::adjustCurrentIndex()
652 for (
int i = 0; i < count(); i++ )
654 if (
auto button = buttonAt( i ) )
656 if ( button->isChecked() )
664 if ( index != m_data->currentIndex )
666 m_data->currentIndex = index;
667 Q_EMIT currentIndexChanged( index );
671void QskTabBar::handleButtonClick()
673 if (
auto button = qobject_cast< const QskTabButton* >( sender() ) )
675 const auto index = indexOf( button );
678 Q_EMIT buttonClicked( index );
685 if ( subControl == QskBox::Panel )
686 return QskTabBar::Panel;
688 return Inherited::substitutedSubcontrol( subControl );
711#include "moc_QskTabBar.cpp"
Variation
Some sort of variation.
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
Base class of all controls.
void focusIndicatorRectChanged()
void setSizePolicy(QskSizePolicy)
void componentComplete() override
Layout stringing items in rows and columns.
QMarginsF paddingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a padding hint.
bool resetSkinHint(QskAspect)
Remove a hint from the local hint table.
bool setFlagHint(QskAspect, int flag)
Sets a flag hint.
QskAspect::Variation effectiveVariation() const override