flickable tabbars
This commit is contained in:
parent
3c7308e23f
commit
53e924a999
|
@ -39,7 +39,7 @@ class TabView : public QskTabView
|
||||||
TabView( QQuickItem* parent = nullptr )
|
TabView( QQuickItem* parent = nullptr )
|
||||||
: QskTabView( parent )
|
: QskTabView( parent )
|
||||||
{
|
{
|
||||||
for ( int i = 0; i < 6; i++ )
|
for ( int i = 0; i < 10; i++ )
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
if ( i == 4 )
|
if ( i == 4 )
|
||||||
|
|
|
@ -569,6 +569,9 @@ void QskMaterialSkin::initTabBarHints()
|
||||||
setBoxShape( Q::Panel, 0 );
|
setBoxShape( Q::Panel, 0 );
|
||||||
setBoxBorderMetrics( Q::Panel, 0 );
|
setBoxBorderMetrics( Q::Panel, 0 );
|
||||||
setGradient( Q::Panel, QskGradient() );
|
setGradient( Q::Panel, QskGradient() );
|
||||||
|
|
||||||
|
// when flicking
|
||||||
|
setAnimation( Q::Panel | Metric, QskAnimationHint( 200, QEasingCurve::InCubic ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskMaterialSkin::initTabViewHints()
|
void QskMaterialSkin::initTabViewHints()
|
||||||
|
|
|
@ -641,6 +641,9 @@ void QskSquiekSkin::initTabBarHints()
|
||||||
setMargins( Q::Panel | Padding, 0 );
|
setMargins( Q::Panel | Padding, 0 );
|
||||||
setMargins( Q::Panel | Margin, 0 );
|
setMargins( Q::Panel | Margin, 0 );
|
||||||
setPanel( Q::Panel, NoPanel );
|
setPanel( Q::Panel, NoPanel );
|
||||||
|
|
||||||
|
// when flicking
|
||||||
|
setAnimation( Q::Panel | Metric, QskAnimationHint( 200, QEasingCurve::OutCubic ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskSquiekSkin::initTabViewHints()
|
void QskSquiekSkin::initTabViewHints()
|
||||||
|
|
|
@ -959,6 +959,15 @@ QRectF QskControl::focusIndicatorRect() const
|
||||||
return contentsRect();
|
return contentsRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QskControl::hasFocusIndicatorClip() const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Often we want to clip the focus indicator,
|
||||||
|
when the control is clipped.
|
||||||
|
*/
|
||||||
|
return clip();
|
||||||
|
}
|
||||||
|
|
||||||
void QskControl::updateLayout()
|
void QskControl::updateLayout()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,9 @@ class QSK_EXPORT QskControl : public QskQuickItem, public QskSkinnable
|
||||||
|
|
||||||
virtual QRectF layoutRectForSize( const QSizeF& ) const;
|
virtual QRectF layoutRectForSize( const QSizeF& ) const;
|
||||||
virtual QRectF gestureRect() const;
|
virtual QRectF gestureRect() const;
|
||||||
|
|
||||||
virtual QRectF focusIndicatorRect() const;
|
virtual QRectF focusIndicatorRect() const;
|
||||||
|
virtual bool hasFocusIndicatorClip() const;
|
||||||
|
|
||||||
QRectF subControlRect( QskAspect::Subcontrol ) const;
|
QRectF subControlRect( QskAspect::Subcontrol ) const;
|
||||||
QRectF subControlRect( const QSizeF&, QskAspect::Subcontrol ) const;
|
QRectF subControlRect( const QSizeF&, QskAspect::Subcontrol ) const;
|
||||||
|
|
|
@ -103,17 +103,26 @@ void QskFocusIndicator::onFocusItemChanged()
|
||||||
{
|
{
|
||||||
auto itemParent = item->parentItem();
|
auto itemParent = item->parentItem();
|
||||||
|
|
||||||
if ( itemParent == window()->contentItem() || itemParent->clip() )
|
bool doReparent = ( itemParent == window()->contentItem() );
|
||||||
|
|
||||||
|
if ( !doReparent )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
When the focus item is clipped - maybe because of being at the
|
When the focus item is clipped - maybe because of being at the
|
||||||
border of a scrollarea - the focus indicator needs to be
|
border of a scrollarea - the focus indicator might need to be
|
||||||
clipped as well. The easiest way to have this is to put us
|
clipped as well. The easiest way to have this is to put us
|
||||||
below the item having the clip.
|
below the item having the clip.
|
||||||
*/
|
*/
|
||||||
setParentItem( itemParent );
|
|
||||||
|
if ( auto control = qskControlCast( itemParent ) )
|
||||||
|
doReparent = control->hasFocusIndicatorClip();
|
||||||
|
else
|
||||||
|
doReparent = itemParent->clip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( doReparent )
|
||||||
|
setParentItem( itemParent );
|
||||||
|
|
||||||
if ( itemParent == parentItem() )
|
if ( itemParent == parentItem() )
|
||||||
{
|
{
|
||||||
// We want to be on top, but do we cover all corner cases ???
|
// We want to be on top, but do we cover all corner cases ???
|
||||||
|
|
|
@ -124,9 +124,13 @@ class QskScrollAreaClipItem final : public QskControl, public QQuickItemChangeLi
|
||||||
return scrollArea()->subControlRect( QskScrollView::Viewport );
|
return scrollArea()->subControlRect( QskScrollView::Viewport );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasFocusIndicatorClip() const override
|
||||||
|
{
|
||||||
|
return scrollArea()->hasFocusIndicatorClip();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool event( QEvent* event ) override;
|
bool event( QEvent* event ) override;
|
||||||
void windowChangeEvent( QskWindowChangeEvent* ) override;
|
|
||||||
|
|
||||||
void itemChange( ItemChange, const ItemChangeData& ) override;
|
void itemChange( ItemChange, const ItemChangeData& ) override;
|
||||||
void geometryChanged( const QRectF&, const QRectF& ) override;
|
void geometryChanged( const QRectF&, const QRectF& ) override;
|
||||||
|
@ -151,9 +155,6 @@ class QskScrollAreaClipItem final : public QskControl, public QQuickItemChangeLi
|
||||||
void updateNode( QSGNode* ) override;
|
void updateNode( QSGNode* ) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void connectWindow( const QQuickWindow*, bool on );
|
|
||||||
void onFocusItemChanged();
|
|
||||||
|
|
||||||
inline QskScrollArea* scrollArea()
|
inline QskScrollArea* scrollArea()
|
||||||
{
|
{
|
||||||
return static_cast< QskScrollArea* >( parentItem() );
|
return static_cast< QskScrollArea* >( parentItem() );
|
||||||
|
@ -172,8 +173,6 @@ QskScrollAreaClipItem::QskScrollAreaClipItem( QskScrollArea* scrollArea )
|
||||||
{
|
{
|
||||||
setObjectName( QStringLiteral( "QskScrollAreaClipItem" ) );
|
setObjectName( QStringLiteral( "QskScrollAreaClipItem" ) );
|
||||||
setClip( true );
|
setClip( true );
|
||||||
|
|
||||||
connectWindow( window(), true );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QskScrollAreaClipItem::~QskScrollAreaClipItem()
|
QskScrollAreaClipItem::~QskScrollAreaClipItem()
|
||||||
|
@ -181,23 +180,6 @@ QskScrollAreaClipItem::~QskScrollAreaClipItem()
|
||||||
enableGeometryListener( false );
|
enableGeometryListener( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskScrollAreaClipItem::connectWindow( const QQuickWindow* window, bool on )
|
|
||||||
{
|
|
||||||
if ( window == nullptr )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ( on )
|
|
||||||
{
|
|
||||||
connect( window, &QQuickWindow::activeFocusItemChanged,
|
|
||||||
this, &QskScrollAreaClipItem::onFocusItemChanged );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
disconnect( window, &QQuickWindow::activeFocusItemChanged,
|
|
||||||
this, &QskScrollAreaClipItem::onFocusItemChanged );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskScrollAreaClipItem::updateNode( QSGNode* )
|
void QskScrollAreaClipItem::updateNode( QSGNode* )
|
||||||
{
|
{
|
||||||
auto* d = QQuickItemPrivate::get( this );
|
auto* d = QQuickItemPrivate::get( this );
|
||||||
|
@ -310,20 +292,6 @@ void QskScrollAreaClipItem::enableGeometryListener( bool on )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskScrollAreaClipItem::onFocusItemChanged()
|
|
||||||
{
|
|
||||||
if ( window() == nullptr || !scrollArea()->autoScrollFocusItem() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto focusItem = window()->activeFocusItem();
|
|
||||||
if ( focusItem )
|
|
||||||
{
|
|
||||||
auto reason = QQuickWindowPrivate::get( window() )->lastFocusReason;
|
|
||||||
if ( reason == Qt::TabFocusReason || reason == Qt::BacktabFocusReason )
|
|
||||||
scrollArea()->ensureItemVisible( focusItem );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QskScrollAreaClipItem::event( QEvent* event )
|
bool QskScrollAreaClipItem::event( QEvent* event )
|
||||||
{
|
{
|
||||||
if ( event->type() == QEvent::LayoutRequest )
|
if ( event->type() == QEvent::LayoutRequest )
|
||||||
|
@ -335,20 +303,11 @@ bool QskScrollAreaClipItem::event( QEvent* event )
|
||||||
return Inherited::event( event );
|
return Inherited::event( event );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskScrollAreaClipItem::windowChangeEvent( QskWindowChangeEvent* event )
|
|
||||||
{
|
|
||||||
Inherited::windowChangeEvent( event );
|
|
||||||
|
|
||||||
connectWindow( event->oldWindow(), false );
|
|
||||||
connectWindow( event->window(), true );
|
|
||||||
}
|
|
||||||
|
|
||||||
class QskScrollArea::PrivateData
|
class QskScrollArea::PrivateData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PrivateData()
|
PrivateData()
|
||||||
: isItemResizable( true )
|
: isItemResizable( true )
|
||||||
, autoScrollFocusItem( true )
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +328,6 @@ class QskScrollArea::PrivateData
|
||||||
QskScrollAreaClipItem* clipItem = nullptr;
|
QskScrollAreaClipItem* clipItem = nullptr;
|
||||||
|
|
||||||
bool isItemResizable : 1;
|
bool isItemResizable : 1;
|
||||||
bool autoScrollFocusItem : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -401,16 +359,6 @@ QskScrollArea::~QskScrollArea()
|
||||||
delete m_data->clipItem;
|
delete m_data->clipItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskScrollArea::ensureItemVisible( const QQuickItem* item )
|
|
||||||
{
|
|
||||||
const QQuickItem* scrolledItem = this->scrolledItem();
|
|
||||||
if ( scrolledItem && qskIsAncestorOf( scrolledItem, item ) )
|
|
||||||
{
|
|
||||||
const auto pos = scrolledItem->mapFromItem( item, QPointF() );
|
|
||||||
ensureVisible( QRectF( pos.x(), pos.y(), item->width(), item->height() ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskScrollArea::updateLayout()
|
void QskScrollArea::updateLayout()
|
||||||
{
|
{
|
||||||
Inherited::updateLayout();
|
Inherited::updateLayout();
|
||||||
|
@ -457,18 +405,9 @@ void QskScrollArea::adjustItem()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskScrollArea::setAutoScrollFocusedItem( bool on )
|
bool QskScrollArea::hasFocusIndicatorClip() const
|
||||||
{
|
{
|
||||||
if ( m_data->autoScrollFocusItem != on )
|
return true;
|
||||||
{
|
|
||||||
m_data->autoScrollFocusItem = on;
|
|
||||||
Q_EMIT autoScrollFocusedItemChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QskScrollArea::autoScrollFocusItem() const
|
|
||||||
{
|
|
||||||
return m_data->autoScrollFocusItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskScrollArea::setItemResizable( bool on )
|
void QskScrollArea::setItemResizable( bool on )
|
||||||
|
@ -476,7 +415,7 @@ void QskScrollArea::setItemResizable( bool on )
|
||||||
if ( on != m_data->isItemResizable )
|
if ( on != m_data->isItemResizable )
|
||||||
{
|
{
|
||||||
m_data->isItemResizable = on;
|
m_data->isItemResizable = on;
|
||||||
Q_EMIT itemResizableChanged();
|
Q_EMIT itemResizableChanged( on );
|
||||||
|
|
||||||
if ( m_data->isItemResizable )
|
if ( m_data->isItemResizable )
|
||||||
polish();
|
polish();
|
||||||
|
@ -520,8 +459,7 @@ QQuickItem* QskScrollArea::scrolledItem() const
|
||||||
|
|
||||||
void QskScrollArea::translateItem()
|
void QskScrollArea::translateItem()
|
||||||
{
|
{
|
||||||
auto item = m_data->clipItem->scrolledItem();
|
if ( auto item = m_data->clipItem->scrolledItem() )
|
||||||
if ( item )
|
|
||||||
{
|
{
|
||||||
const QPointF pos = viewContentsRect().topLeft() - scrollPos();
|
const QPointF pos = viewContentsRect().topLeft() - scrollPos();
|
||||||
item->setPosition( pos );
|
item->setPosition( pos );
|
||||||
|
|
|
@ -18,9 +18,6 @@ class QSK_EXPORT QskScrollArea : public QskScrollView
|
||||||
Q_PROPERTY( bool itemResizable READ isItemResizable
|
Q_PROPERTY( bool itemResizable READ isItemResizable
|
||||||
WRITE setItemResizable NOTIFY itemResizableChanged FINAL )
|
WRITE setItemResizable NOTIFY itemResizableChanged FINAL )
|
||||||
|
|
||||||
Q_PROPERTY( bool autoScrollFocusedItem READ autoScrollFocusItem
|
|
||||||
WRITE setAutoScrollFocusedItem NOTIFY autoScrollFocusedItemChanged FINAL )
|
|
||||||
|
|
||||||
using Inherited = QskScrollView;
|
using Inherited = QskScrollView;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -33,15 +30,11 @@ class QSK_EXPORT QskScrollArea : public QskScrollView
|
||||||
void setItemResizable( bool on );
|
void setItemResizable( bool on );
|
||||||
bool isItemResizable() const;
|
bool isItemResizable() const;
|
||||||
|
|
||||||
void setAutoScrollFocusedItem( bool on );
|
bool hasFocusIndicatorClip() const override;
|
||||||
bool autoScrollFocusItem() const;
|
|
||||||
|
|
||||||
void ensureItemVisible( const QQuickItem* );
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void itemResizableChanged();
|
|
||||||
void scrolledItemChanged();
|
void scrolledItemChanged();
|
||||||
void autoScrollFocusedItemChanged();
|
void itemResizableChanged( bool );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void updateLayout() override;
|
void updateLayout() override;
|
||||||
|
|
|
@ -9,6 +9,11 @@
|
||||||
#include "QskFlickAnimator.h"
|
#include "QskFlickAnimator.h"
|
||||||
#include "QskGesture.h"
|
#include "QskGesture.h"
|
||||||
#include "QskPanGestureRecognizer.h"
|
#include "QskPanGestureRecognizer.h"
|
||||||
|
#include "QskQuick.h"
|
||||||
|
|
||||||
|
QSK_QT_PRIVATE_BEGIN
|
||||||
|
#include <private/qquickwindow_p.h>
|
||||||
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -95,6 +100,11 @@ namespace
|
||||||
class QskScrollBox::PrivateData
|
class QskScrollBox::PrivateData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
PrivateData()
|
||||||
|
: autoScrollFocusItem( true )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QPointF scrollPos;
|
QPointF scrollPos;
|
||||||
QSizeF scrollableSize = QSize( 0.0, 0.0 );
|
QSizeF scrollableSize = QSize( 0.0, 0.0 );
|
||||||
|
|
||||||
|
@ -105,6 +115,8 @@ class QskScrollBox::PrivateData
|
||||||
ScrollAnimator scroller;
|
ScrollAnimator scroller;
|
||||||
|
|
||||||
const qreal viewportPadding = 10;
|
const qreal viewportPadding = 10;
|
||||||
|
|
||||||
|
bool autoScrollFocusItem : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
QskScrollBox::QskScrollBox( QQuickItem* parent )
|
QskScrollBox::QskScrollBox( QQuickItem* parent )
|
||||||
|
@ -119,14 +131,52 @@ QskScrollBox::QskScrollBox( QQuickItem* parent )
|
||||||
|
|
||||||
setFiltersChildMouseEvents( true );
|
setFiltersChildMouseEvents( true );
|
||||||
|
|
||||||
|
setAcceptedMouseButtons( Qt::LeftButton );
|
||||||
setWheelEnabled( true );
|
setWheelEnabled( true );
|
||||||
|
|
||||||
setFocusPolicy( Qt::StrongFocus );
|
setFocusPolicy( Qt::StrongFocus );
|
||||||
|
|
||||||
|
connectWindow( window(), true );
|
||||||
}
|
}
|
||||||
|
|
||||||
QskScrollBox::~QskScrollBox()
|
QskScrollBox::~QskScrollBox()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QskScrollBox::setAutoScrollFocusedItem( bool on )
|
||||||
|
{
|
||||||
|
if ( m_data->autoScrollFocusItem != on )
|
||||||
|
{
|
||||||
|
m_data->autoScrollFocusItem = on;
|
||||||
|
connectWindow( window(), true );
|
||||||
|
Q_EMIT autoScrollFocusedItemChanged( on );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QskScrollBox::autoScrollFocusItem() const
|
||||||
|
{
|
||||||
|
return m_data->autoScrollFocusItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskScrollBox::onFocusItemChanged()
|
||||||
|
{
|
||||||
|
if ( window() )
|
||||||
|
{
|
||||||
|
auto reason = QQuickWindowPrivate::get( window() )->lastFocusReason;
|
||||||
|
if ( reason == Qt::TabFocusReason || reason == Qt::BacktabFocusReason )
|
||||||
|
ensureFocusItemVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskScrollBox::ensureFocusItemVisible()
|
||||||
|
{
|
||||||
|
if ( window() == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( const auto focusItem = window()->activeFocusItem() )
|
||||||
|
ensureItemVisible( focusItem );
|
||||||
|
}
|
||||||
|
|
||||||
void QskScrollBox::setFlickRecognizerTimeout( int timeout )
|
void QskScrollBox::setFlickRecognizerTimeout( int timeout )
|
||||||
{
|
{
|
||||||
if ( timeout < 0 )
|
if ( timeout < 0 )
|
||||||
|
@ -202,6 +252,17 @@ QRectF QskScrollBox::gestureRect() const
|
||||||
return viewContentsRect();
|
return viewContentsRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QskScrollBox::ensureItemVisible( const QQuickItem* item )
|
||||||
|
{
|
||||||
|
if ( qskIsAncestorOf( this, item ) )
|
||||||
|
{
|
||||||
|
auto pos = scrollPos() - viewContentsRect().topLeft();
|
||||||
|
pos += mapFromItem( item, QPointF() );
|
||||||
|
|
||||||
|
ensureVisible( QRectF( pos.x(), pos.y(), item->width(), item->height() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QskScrollBox::ensureVisible( const QPointF& pos )
|
void QskScrollBox::ensureVisible( const QPointF& pos )
|
||||||
{
|
{
|
||||||
const qreal margin = m_data->viewportPadding;
|
const qreal margin = m_data->viewportPadding;
|
||||||
|
@ -282,6 +343,14 @@ void QskScrollBox::ensureVisible( const QRectF& itemRect )
|
||||||
setScrollPos( newPos );
|
setScrollPos( newPos );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QskScrollBox::windowChangeEvent( QskWindowChangeEvent* event )
|
||||||
|
{
|
||||||
|
Inherited::windowChangeEvent( event );
|
||||||
|
|
||||||
|
connectWindow( event->oldWindow(), false );
|
||||||
|
connectWindow( event->window(), true );
|
||||||
|
}
|
||||||
|
|
||||||
void QskScrollBox::geometryChangeEvent( QskGeometryChangeEvent* event )
|
void QskScrollBox::geometryChangeEvent( QskGeometryChangeEvent* event )
|
||||||
{
|
{
|
||||||
if ( event->isResized() )
|
if ( event->isResized() )
|
||||||
|
@ -443,4 +512,21 @@ QPointF QskScrollBox::boundedScrollPos( const QPointF& pos ) const
|
||||||
return QPointF( qBound( 0.0, pos.x(), maxX ), qBound( 0.0, pos.y(), maxY ) );
|
return QPointF( qBound( 0.0, pos.x(), maxX ), qBound( 0.0, pos.y(), maxY ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QskScrollBox::connectWindow( const QQuickWindow* window, bool on )
|
||||||
|
{
|
||||||
|
if ( ( window == nullptr ) || ( on && !autoScrollFocusItem() ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( on )
|
||||||
|
{
|
||||||
|
QObject::connect( window, &QQuickWindow::activeFocusItemChanged,
|
||||||
|
this, &QskScrollBox::onFocusItemChanged, Qt::UniqueConnection );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QObject::disconnect( window, &QQuickWindow::activeFocusItemChanged,
|
||||||
|
this, &QskScrollBox::onFocusItemChanged );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_QskScrollBox.cpp"
|
#include "moc_QskScrollBox.cpp"
|
||||||
|
|
|
@ -18,12 +18,18 @@ class QSK_EXPORT QskScrollBox : public QskControl
|
||||||
Q_PROPERTY( Qt::Orientations flickableOrientations READ flickableOrientations
|
Q_PROPERTY( Qt::Orientations flickableOrientations READ flickableOrientations
|
||||||
WRITE setFlickableOrientations NOTIFY flickableOrientationsChanged FINAL )
|
WRITE setFlickableOrientations NOTIFY flickableOrientationsChanged FINAL )
|
||||||
|
|
||||||
|
Q_PROPERTY( bool autoScrollFocusedItem READ autoScrollFocusItem
|
||||||
|
WRITE setAutoScrollFocusedItem NOTIFY autoScrollFocusedItemChanged FINAL )
|
||||||
|
|
||||||
using Inherited = QskControl;
|
using Inherited = QskControl;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QskScrollBox( QQuickItem* parent = nullptr );
|
QskScrollBox( QQuickItem* parent = nullptr );
|
||||||
~QskScrollBox() override;
|
~QskScrollBox() override;
|
||||||
|
|
||||||
|
void setAutoScrollFocusedItem( bool on );
|
||||||
|
bool autoScrollFocusItem() const;
|
||||||
|
|
||||||
void setFlickableOrientations( Qt::Orientations );
|
void setFlickableOrientations( Qt::Orientations );
|
||||||
Qt::Orientations flickableOrientations() const;
|
Qt::Orientations flickableOrientations() const;
|
||||||
|
|
||||||
|
@ -43,17 +49,21 @@ class QSK_EXPORT QskScrollBox : public QskControl
|
||||||
void scrollPosChanged();
|
void scrollPosChanged();
|
||||||
void scrollableSizeChanged( const QSizeF& );
|
void scrollableSizeChanged( const QSizeF& );
|
||||||
|
|
||||||
|
void autoScrollFocusedItemChanged( bool );
|
||||||
void flickableOrientationsChanged();
|
void flickableOrientationsChanged();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void setScrollPos( const QPointF& );
|
void setScrollPos( const QPointF& );
|
||||||
void scrollTo( const QPointF& );
|
void scrollTo( const QPointF& );
|
||||||
|
|
||||||
|
void ensureItemVisible( const QQuickItem* );
|
||||||
|
void ensureFocusItemVisible();
|
||||||
void ensureVisible( const QPointF& );
|
void ensureVisible( const QPointF& );
|
||||||
void ensureVisible( const QRectF& );
|
void ensureVisible( const QRectF& );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
|
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
|
||||||
|
void windowChangeEvent( QskWindowChangeEvent* ) override;
|
||||||
void gestureEvent( QskGestureEvent* ) override;
|
void gestureEvent( QskGestureEvent* ) override;
|
||||||
|
|
||||||
#ifndef QT_NO_WHEELEVENT
|
#ifndef QT_NO_WHEELEVENT
|
||||||
|
@ -66,6 +76,8 @@ class QSK_EXPORT QskScrollBox : public QskControl
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPointF boundedScrollPos( const QPointF& ) const;
|
QPointF boundedScrollPos( const QPointF& ) const;
|
||||||
|
void onFocusItemChanged();
|
||||||
|
void connectWindow( const QQuickWindow*, bool on );
|
||||||
|
|
||||||
class PrivateData;
|
class PrivateData;
|
||||||
std::unique_ptr< PrivateData > m_data;
|
std::unique_ptr< PrivateData > m_data;
|
||||||
|
|
|
@ -38,7 +38,6 @@ QskScrollView::QskScrollView( QQuickItem* parent )
|
||||||
: Inherited( parent )
|
: Inherited( parent )
|
||||||
, m_data( new PrivateData() )
|
, m_data( new PrivateData() )
|
||||||
{
|
{
|
||||||
setAcceptedMouseButtons( Qt::LeftButton );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QskScrollView::~QskScrollView()
|
QskScrollView::~QskScrollView()
|
||||||
|
|
|
@ -5,9 +5,12 @@
|
||||||
|
|
||||||
#include "QskTabBar.h"
|
#include "QskTabBar.h"
|
||||||
#include "QskAspect.h"
|
#include "QskAspect.h"
|
||||||
|
#include "QskScrollBox.h"
|
||||||
#include "QskLinearBox.h"
|
#include "QskLinearBox.h"
|
||||||
#include "QskTabButton.h"
|
#include "QskTabButton.h"
|
||||||
#include "QskTextOptions.h"
|
#include "QskTextOptions.h"
|
||||||
|
#include "QskAnimationHint.h"
|
||||||
|
#include "QskQuick.h"
|
||||||
|
|
||||||
QSK_SUBCONTROL( QskTabBar, Panel )
|
QSK_SUBCONTROL( QskTabBar, Panel )
|
||||||
|
|
||||||
|
@ -21,8 +24,10 @@ static inline Qt::Orientation qskOrientation( int position )
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class ButtonBox : public QskLinearBox
|
class ButtonBox final : public QskLinearBox
|
||||||
{
|
{
|
||||||
|
using Inherited = QskLinearBox;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ButtonBox( Qt::Orientation orientation, QQuickItem* parent )
|
ButtonBox( Qt::Orientation orientation, QQuickItem* parent )
|
||||||
: QskLinearBox( orientation, parent )
|
: QskLinearBox( orientation, parent )
|
||||||
|
@ -48,6 +53,142 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ScrollBox final : public QskScrollBox
|
||||||
|
{
|
||||||
|
using Inherited = QskScrollBox;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScrollBox( QQuickItem* parent )
|
||||||
|
: QskScrollBox( parent )
|
||||||
|
{
|
||||||
|
setPolishOnResize( true );
|
||||||
|
enableAutoTranslation( true );
|
||||||
|
|
||||||
|
setFocusPolicy( Qt::NoFocus );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasFocusIndicatorClip() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QskAnimationHint flickHint() const override
|
||||||
|
{
|
||||||
|
if ( auto tabBar = qobject_cast< const QskTabBar* >( parentItem() ) )
|
||||||
|
{
|
||||||
|
return tabBar->effectiveAnimation( QskAspect::Metric,
|
||||||
|
QskTabBar::Panel, QskAspect::NoState );
|
||||||
|
}
|
||||||
|
|
||||||
|
return QskAnimationHint( 200, QEasingCurve::OutCubic );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF viewContentsRect() const override
|
||||||
|
{
|
||||||
|
return layoutRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOrientation( Qt::Orientation orientation )
|
||||||
|
{
|
||||||
|
setFlickableOrientations( orientation );
|
||||||
|
|
||||||
|
if ( orientation == Qt::Horizontal )
|
||||||
|
setSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::MinimumExpanding );
|
||||||
|
else
|
||||||
|
setSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::Ignored );
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensureItemVisible( const QQuickItem* item )
|
||||||
|
{
|
||||||
|
if ( qskIsAncestorOf( this, item ) )
|
||||||
|
{
|
||||||
|
const auto pos = mapFromItem( item, QPointF() );
|
||||||
|
ensureVisible( QRectF( pos.x(), pos.y(), item->width(), item->height() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool event( QEvent* event ) override
|
||||||
|
{
|
||||||
|
if ( event->type() == QEvent::LayoutRequest )
|
||||||
|
{
|
||||||
|
resetImplicitSize();
|
||||||
|
polish();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Inherited::event( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateLayout() override
|
||||||
|
{
|
||||||
|
auto scrolledItem = this->scrolledItem();
|
||||||
|
|
||||||
|
auto itemSize = viewContentsRect().size();
|
||||||
|
itemSize = qskConstrainedItemSize( scrolledItem, itemSize );
|
||||||
|
|
||||||
|
scrolledItem->setSize( itemSize );
|
||||||
|
|
||||||
|
enableAutoTranslation( false );
|
||||||
|
|
||||||
|
setScrollableSize( itemSize );
|
||||||
|
setScrollPos( scrollPos() );
|
||||||
|
|
||||||
|
enableAutoTranslation( true );
|
||||||
|
|
||||||
|
translateItem();
|
||||||
|
|
||||||
|
setClip( size().width() < itemSize.width()
|
||||||
|
|| size().height() < itemSize.height() );
|
||||||
|
}
|
||||||
|
|
||||||
|
QSizeF layoutSizeHint( Qt::SizeHint which, const QSizeF& constraint ) const override
|
||||||
|
{
|
||||||
|
auto hint = scrolledItem()->sizeConstraint( which, constraint );
|
||||||
|
|
||||||
|
if ( which == Qt::MinimumSize )
|
||||||
|
{
|
||||||
|
if ( sizePolicy().horizontalPolicy() & QskSizePolicy::ShrinkFlag )
|
||||||
|
hint.setWidth( -1 );
|
||||||
|
|
||||||
|
if ( sizePolicy().verticalPolicy() & QskSizePolicy::ShrinkFlag )
|
||||||
|
hint.setHeight( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
inline QskControl* scrolledItem() const
|
||||||
|
{
|
||||||
|
return qskControlCast( childItems().first() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void enableAutoTranslation( bool on )
|
||||||
|
{
|
||||||
|
if ( on )
|
||||||
|
{
|
||||||
|
connect( this, &QskScrollBox::scrollPosChanged,
|
||||||
|
this, &ScrollBox::translateItem );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
disconnect( this, &QskScrollBox::scrollPosChanged,
|
||||||
|
this, &ScrollBox::translateItem );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void translateItem()
|
||||||
|
{
|
||||||
|
if ( auto item = this->scrolledItem() )
|
||||||
|
{
|
||||||
|
const QPointF pos = viewContentsRect().topLeft() - scrollPos();
|
||||||
|
item->setPosition( pos );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class QskTabBar::PrivateData
|
class QskTabBar::PrivateData
|
||||||
|
@ -72,6 +213,7 @@ class QskTabBar::PrivateData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScrollBox* scrollBox = nullptr;
|
||||||
ButtonBox* buttonBox = nullptr;
|
ButtonBox* buttonBox = nullptr;
|
||||||
int currentIndex = -1;
|
int currentIndex = -1;
|
||||||
|
|
||||||
|
@ -97,9 +239,17 @@ QskTabBar::QskTabBar( Qsk::Position position, QQuickItem* parent )
|
||||||
else
|
else
|
||||||
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Preferred );
|
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Preferred );
|
||||||
|
|
||||||
m_data->buttonBox = new ButtonBox( orientation, this );
|
m_data->scrollBox = new ScrollBox( this );
|
||||||
|
m_data->scrollBox->setOrientation( orientation );
|
||||||
|
|
||||||
|
m_data->buttonBox = new ButtonBox( orientation, m_data->scrollBox );
|
||||||
m_data->buttonBox->setSpacing( metric( QskTabBar::Panel | QskAspect::Spacing ) );
|
m_data->buttonBox->setSpacing( metric( QskTabBar::Panel | QskAspect::Spacing ) );
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
// We might want to have a mode, where the buttons are stretched: TODO ...
|
||||||
|
m_data->buttonBox->setSizePolicy( QskSizePolicy::Maximum, QskSizePolicy::Maximum );
|
||||||
|
#endif
|
||||||
|
|
||||||
connect( this, &QskTabBar::currentIndexChanged,
|
connect( this, &QskTabBar::currentIndexChanged,
|
||||||
m_data->buttonBox, &ButtonBox::restack, Qt::QueuedConnection );
|
m_data->buttonBox, &ButtonBox::restack, Qt::QueuedConnection );
|
||||||
}
|
}
|
||||||
|
@ -120,6 +270,7 @@ void QskTabBar::setPosition( Qsk::Position position )
|
||||||
{
|
{
|
||||||
setSizePolicy( sizePolicy( Qt::Vertical ), sizePolicy( Qt::Horizontal ) );
|
setSizePolicy( sizePolicy( Qt::Vertical ), sizePolicy( Qt::Horizontal ) );
|
||||||
m_data->buttonBox->setOrientation( orientation );
|
m_data->buttonBox->setOrientation( orientation );
|
||||||
|
m_data->scrollBox->setOrientation( orientation );
|
||||||
}
|
}
|
||||||
|
|
||||||
resetImplicitSize();
|
resetImplicitSize();
|
||||||
|
@ -140,6 +291,20 @@ Qt::Orientation QskTabBar::orientation() const
|
||||||
return qskOrientation( m_data->position );
|
return qskOrientation( m_data->position );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QskTabBar::setAutoScrollFocusedButton( bool on )
|
||||||
|
{
|
||||||
|
if ( m_data->scrollBox->autoScrollFocusItem() != on )
|
||||||
|
{
|
||||||
|
m_data->scrollBox->setAutoScrollFocusedItem( on );
|
||||||
|
Q_EMIT autoScrollFocusedButtonChanged( on );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QskTabBar::autoScrollFocusButton() const
|
||||||
|
{
|
||||||
|
return m_data->scrollBox->autoScrollFocusItem();
|
||||||
|
}
|
||||||
|
|
||||||
void QskTabBar::setTextOptions( const QskTextOptions& options )
|
void QskTabBar::setTextOptions( const QskTextOptions& options )
|
||||||
{
|
{
|
||||||
if ( options != m_data->textOptions )
|
if ( options != m_data->textOptions )
|
||||||
|
@ -366,6 +531,11 @@ int QskTabBar::indexOf( QskTabButton* button ) const
|
||||||
return m_data->buttonBox->indexOf( button );
|
return m_data->buttonBox->indexOf( button );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QskTabBar::ensureButtonVisible( const QskTabButton* button )
|
||||||
|
{
|
||||||
|
m_data->scrollBox->ensureItemVisible( button );
|
||||||
|
}
|
||||||
|
|
||||||
void QskTabBar::componentComplete()
|
void QskTabBar::componentComplete()
|
||||||
{
|
{
|
||||||
Inherited::componentComplete();
|
Inherited::componentComplete();
|
||||||
|
|
|
@ -20,6 +20,9 @@ class QSK_EXPORT QskTabBar : public QskBox
|
||||||
|
|
||||||
Q_PROPERTY( Qt::Orientation orientation READ orientation )
|
Q_PROPERTY( Qt::Orientation orientation READ orientation )
|
||||||
|
|
||||||
|
Q_PROPERTY( bool autoScrollFocusButton READ autoScrollFocusButton
|
||||||
|
WRITE setAutoScrollFocusedButton NOTIFY autoScrollFocusedButtonChanged FINAL )
|
||||||
|
|
||||||
Q_PROPERTY( int count READ count NOTIFY countChanged FINAL )
|
Q_PROPERTY( int count READ count NOTIFY countChanged FINAL )
|
||||||
|
|
||||||
Q_PROPERTY( int currentIndex READ currentIndex
|
Q_PROPERTY( int currentIndex READ currentIndex
|
||||||
|
@ -43,6 +46,11 @@ class QSK_EXPORT QskTabBar : public QskBox
|
||||||
|
|
||||||
Qt::Orientation orientation() const;
|
Qt::Orientation orientation() const;
|
||||||
|
|
||||||
|
void setAutoScrollFocusedButton( bool on );
|
||||||
|
bool autoScrollFocusButton() const;
|
||||||
|
|
||||||
|
void ensureButtonVisible( const QskTabButton* );
|
||||||
|
|
||||||
void setTextOptions( const QskTextOptions& );
|
void setTextOptions( const QskTextOptions& );
|
||||||
QskTextOptions textOptions() const;
|
QskTextOptions textOptions() const;
|
||||||
|
|
||||||
|
@ -86,6 +94,7 @@ class QSK_EXPORT QskTabBar : public QskBox
|
||||||
void countChanged( int );
|
void countChanged( int );
|
||||||
void textOptionsChanged( const QskTextOptions& );
|
void textOptionsChanged( const QskTextOptions& );
|
||||||
void positionChanged( Qsk::Position );
|
void positionChanged( Qsk::Position );
|
||||||
|
void autoScrollFocusedButtonChanged( bool );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void componentComplete() override;
|
void componentComplete() override;
|
||||||
|
|
|
@ -210,12 +210,22 @@ QSizeF QskTabView::layoutSizeHint(
|
||||||
const auto& tabBar = m_data->tabBar;
|
const auto& tabBar = m_data->tabBar;
|
||||||
const auto& stackBox = m_data->stackBox;
|
const auto& stackBox = m_data->stackBox;
|
||||||
|
|
||||||
const auto barHint = tabBar->sizeConstraint( which );
|
auto barHint = tabBar->sizeConstraint( which );
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
/*
|
||||||
|
How to limit the constribution of the tabbar in a reasonable way ?
|
||||||
|
QTabWidget uses 200x200 - what is kind of random. TODO ...
|
||||||
|
*/
|
||||||
|
const qreal minBarSize = 200;
|
||||||
|
#endif
|
||||||
|
|
||||||
QSizeF hint;
|
QSizeF hint;
|
||||||
|
|
||||||
if ( orientation() == Qt::Vertical )
|
if ( orientation() == Qt::Vertical )
|
||||||
{
|
{
|
||||||
|
barHint.setWidth( qMin( barHint.width(), minBarSize ) );
|
||||||
|
|
||||||
if ( constraint.width() >= 0.0 )
|
if ( constraint.width() >= 0.0 )
|
||||||
{
|
{
|
||||||
qreal w = qMax( constraint.width(), barHint.width() );
|
qreal w = qMax( constraint.width(), barHint.width() );
|
||||||
|
@ -240,6 +250,8 @@ QSizeF QskTabView::layoutSizeHint(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
barHint.setHeight( qMin( barHint.height(), minBarSize ) );
|
||||||
|
|
||||||
if ( constraint.width() >= 0.0 )
|
if ( constraint.width() >= 0.0 )
|
||||||
{
|
{
|
||||||
qreal w = constraint.width() - barHint.width();
|
qreal w = constraint.width() - barHint.width();
|
||||||
|
|
Loading…
Reference in New Issue