QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskTabView.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskTabView.h"
7#include "QskAnimationHint.h"
8#include "QskAspect.h"
9#include "QskStackBox.h"
10#include "QskStackBoxAnimator.h"
11#include "QskTabBar.h"
12#include "QskTabButton.h"
13
14#include <QPointer>
15
16QSK_SUBCONTROL( QskTabView, TabBar )
17QSK_SUBCONTROL( QskTabView, Page )
18
19static inline Qt::Orientation qskTransposed( Qt::Orientation orientation )
20{
21 return ( orientation == Qt::Vertical ) ? Qt::Horizontal : Qt::Vertical;
22}
23
24class QskTabView::PrivateData
25{
26 public:
27 QskTabBar* tabBar = nullptr;
28 QskStackBox* stackBox = nullptr;
29};
30
31QskTabView::QskTabView( QQuickItem* parent )
32 : Inherited( parent )
33 , m_data( new PrivateData() )
34{
35 setPolishOnResize( true );
36
37 m_data->tabBar = new QskTabBar( this );
38
39 m_data->stackBox = new QskStackBox( this );
40 m_data->stackBox->setObjectName( QStringLiteral( "QskTabViewStackBox" ) );
41
42#if 1
43 const auto hint = animationHint( Page );
44 if ( hint.duration > 0 )
45 {
46 // When changing the skin, we have to update the animator. TODO ...
47
48 auto animator = new QskStackBoxAnimator3( m_data->stackBox );
49 animator->setDuration( hint.duration );
50 animator->setEasingCurve( hint.type );
51
52 m_data->stackBox->setAnimator( animator );
53 }
54#endif
55
56 connect( m_data->tabBar, &QskTabBar::currentIndexChanged,
57 m_data->stackBox, &QskStackBox::setCurrentIndex );
58
59 connect( m_data->tabBar, &QskTabBar::currentIndexChanged,
60 this, &QskTabView::currentIndexChanged );
61
62 connect( m_data->tabBar, &QskTabBar::countChanged,
63 this, &QskTabView::countChanged );
64
65 connect( m_data->tabBar, &QskTabBar::edgeChanged,
66 this, &QskTabView::tabBarEdgeChanged );
67
68 connect( m_data->tabBar, &QskTabBar::autoFitTabsChanged,
69 this, &QskTabView::autoFitTabsChanged );
70}
71
72QskTabView::~QskTabView()
73{
74}
75
76QskTabBar* QskTabView::tabBar()
77{
78 return m_data->tabBar;
79}
80
81const QskTabBar* QskTabView::tabBar() const
82{
83 return m_data->tabBar;
84}
85
86void QskTabView::setTabBarEdge( Qt::Edge edge )
87{
88 m_data->tabBar->setEdge( edge );
89}
90
91Qt::Edge QskTabView::tabBarEdge() const
92{
93 return m_data->tabBar->edge();
94}
95
96void QskTabView::setAutoFitTabs( bool on )
97{
98 m_data->tabBar->setAutoFitTabs( on );
99}
100
101bool QskTabView::autoFitTabs() const
102{
103 return m_data->tabBar->autoFitTabs();
104}
105
106Qt::Orientation QskTabView::orientation() const
107{
108 return qskTransposed( m_data->tabBar->orientation() );
109}
110
111int QskTabView::addTab( const QString& text, QQuickItem* page )
112{
113 return insertTab( -1, text, page );
114}
115
116int QskTabView::insertTab( int index, const QString& text, QQuickItem* page )
117{
118 index = m_data->tabBar->insertTab( index, text );
119
120 if ( page && page->parent() == nullptr )
121 page->setParent( this );
122
123 m_data->stackBox->insertItem( index, page );
124
125 return index;
126}
127
128void QskTabView::removeTab( int index )
129{
130 if ( index >= 0 && index < m_data->tabBar->count() )
131 {
132 QPointer< QQuickItem > page = m_data->stackBox->itemAtIndex( index );
133
134 /*
135 We have to remove the page from the stackBox first. Removing
136 the tab then will result in a currentIndexChanged, where the stack
137 box will be resynced.
138 */
139 m_data->stackBox->removeAt( index );
140 m_data->tabBar->removeTab( index );
141
142 if ( page )
143 {
144 if ( page->parent() == this )
145 delete page;
146 else
147 page->setParentItem( nullptr );
148 }
149 }
150}
151
152void QskTabView::clear( bool autoDelete )
153{
154 m_data->tabBar->clear( autoDelete );
155 m_data->stackBox->clear( autoDelete );
156}
157
158void QskTabView::setTabEnabled( int index, bool enabled )
159{
160 m_data->tabBar->setTabEnabled( index, enabled );
161 if ( auto page = pageAt( index ) )
162 page->setEnabled( enabled );
163}
164
165bool QskTabView::isTabEnabled( int index ) const
166{
167 return m_data->tabBar->isTabEnabled( index );
168}
169
170QQuickItem* QskTabView::pageAt( int index ) const
171{
172 return m_data->stackBox->itemAtIndex( index );
173}
174
175int QskTabView::pageIndex( const QQuickItem* page )
176{
177 return m_data->stackBox->indexOf( page );
178}
179
180QQuickItem* QskTabView::currentPage() const
181{
182 return pageAt( currentIndex() );
183}
184
185int QskTabView::currentIndex() const
186{
187 return m_data->tabBar->currentIndex();
188}
189
190int QskTabView::count() const
191{
192 return m_data->tabBar->count();
193}
194
196{
197 return m_data->tabBar->effectiveVariation();
198}
199
200QSizeF QskTabView::layoutSizeHint(
201 Qt::SizeHint which, const QSizeF& constraint ) const
202{
203 if ( which == Qt::MaximumSize )
204 return QSizeF();
205
206 const auto& tabBar = m_data->tabBar;
207 const auto& stackBox = m_data->stackBox;
208
209 auto barHint = tabBar->sizeConstraint( which );
210
211#if 1
212 /*
213 How to limit the contribution of the tabbar in a reasonable way ?
214 QTabWidget uses 200x200 - what is kind of random. TODO ...
215 */
216 const qreal minBarSize = 200;
217#endif
218
219 QSizeF hint;
220
221 if ( orientation() == Qt::Vertical )
222 {
223 barHint.setWidth( qMin( barHint.width(), minBarSize ) );
224
225 if ( constraint.width() >= 0.0 )
226 {
227 qreal w = qMax( constraint.width(), barHint.width() );
228 qreal h = stackBox->sizeConstraint( which, QSizeF( w, -1.0 ) ).height();
229
230 hint.rheight() = barHint.height() + h;
231 }
232 else if ( constraint.height() >= 0.0 )
233 {
234 qreal h = constraint.height() - barHint.height();
235 qreal w = stackBox->sizeConstraint( which, QSizeF( -1.0, h ) ).width();
236
237 hint.rwidth() = qMax( barHint.width(), w );
238 }
239 else
240 {
241 const auto boxHint = stackBox->sizeConstraint();
242
243 hint.rwidth() = qMax( barHint.width(), boxHint.width() );
244 hint.rheight() = barHint.height() + boxHint.height();
245 }
246 }
247 else
248 {
249 barHint.setHeight( qMin( barHint.height(), minBarSize ) );
250
251 if ( constraint.width() >= 0.0 )
252 {
253 qreal w = constraint.width() - barHint.width();
254 qreal h = stackBox->sizeConstraint( which, QSizeF( w, -1.0 ) ).height();
255
256 hint.rheight() = qMax( barHint.height(), h );
257 }
258 else if ( constraint.height() >= 0.0 )
259 {
260 qreal h = qMax( constraint.height(), barHint.height() );
261 qreal w = stackBox->sizeConstraint( which, QSizeF( -1.0, h ) ).width();
262
263 hint.rwidth() = barHint.width() + w;
264 }
265 else
266 {
267 const auto boxHint = stackBox->sizeConstraint( which );
268
269 hint.rwidth() = barHint.width() + boxHint.width();
270 hint.rheight() = qMax( barHint.height(), boxHint.height() );
271 }
272 }
273
274 return hint;
275}
276
277void QskTabView::setCurrentIndex( int index )
278{
279 m_data->tabBar->setCurrentIndex( index );
280}
281
282bool QskTabView::event( QEvent* event )
283{
284 if ( event->type() == QEvent::LayoutRequest )
285 {
287 polish();
288 update();
289 }
290
291 return Inherited::event( event );
292}
293
294void QskTabView::updateLayout()
295{
296 if ( maybeUnresized() )
297 return;
298
299 const auto cr = contentsRect();
300
301 m_data->tabBar->setGeometry( subControlRect( cr, TabBar ) );
302 m_data->stackBox->setGeometry( subControlContentsRect( cr, Page ) );
303}
304
305#if 1
306
307/*
308 QskTabBar will do scene graph node composition and QskTabButton will go away
309 see: https://github.com/uwerat/qskinny/issues/283
310 */
311
312int QskTabView::addTab( QskTabButton* button, QQuickItem* page )
313{
314 return insertTab( -1, button, page );
315}
316
317int QskTabView::insertTab( int index, QskTabButton* button, QQuickItem* page )
318{
319 if ( page && page->parent() == nullptr )
320 page->setParent( this );
321
322 index = m_data->tabBar->insertTab( index, button );
323 m_data->stackBox->insertItem( index, page );
324
325 return index;
326}
327
328QskTabButton* QskTabView::buttonAt( int index ) const
329{
330 return m_data->tabBar->buttonAt( index );
331}
332
333int QskTabView::buttonIndex( const QskTabButton* button )
334{
335 return m_data->tabBar->indexOf( button );
336}
337
338QskTabButton* QskTabView::currentButton() const
339{
340 return buttonAt( currentIndex() );
341}
342
343#endif
344
345#include "moc_QskTabView.cpp"
Variation
Some sort of variation.
Definition QskAspect.h:82
QRectF subControlRect(QskAspect::Subcontrol) const
QRectF subControlContentsRect(QskAspect::Subcontrol) const
QRectF contentsRect() const
QSizeF sizeConstraint
Definition QskControl.h:50
void resetImplicitSize()
Definition QskItem.cpp:721
bool maybeUnresized() const
Definition QskItem.cpp:583
QskAspect::Variation effectiveVariation() const override