1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtWidgets module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qtabwidget.h" |
41 | |
42 | #include "private/qapplication_p.h" |
43 | #include "private/qwidget_p.h" |
44 | #include "private/qtabbar_p.h" |
45 | #include "qapplication.h" |
46 | #include "qbitmap.h" |
47 | #include "qdesktopwidget.h" |
48 | #include <private/qdesktopwidget_p.h> |
49 | #include "qevent.h" |
50 | #include "qlayout.h" |
51 | #include "qstackedwidget.h" |
52 | #include "qstyle.h" |
53 | #include "qstyleoption.h" |
54 | #include "qstylepainter.h" |
55 | #include "qtabbar.h" |
56 | #include "qtoolbutton.h" |
57 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | /*! |
61 | \class QTabWidget |
62 | \brief The QTabWidget class provides a stack of tabbed widgets. |
63 | |
64 | \ingroup organizers |
65 | \ingroup basicwidgets |
66 | \inmodule QtWidgets |
67 | |
68 | \image windows-tabwidget.png |
69 | |
70 | A tab widget provides a tab bar (see QTabBar) and a "page area" |
71 | that is used to display pages related to each tab. By default, the |
72 | tab bar is shown above the page area, but different configurations |
73 | are available (see \l{TabPosition}). Each tab is associated with a |
74 | different widget (called a page). Only the current page is shown in |
75 | the page area; all the other pages are hidden. The user can show a |
76 | different page by clicking on its tab or by pressing its |
77 | Alt+\e{letter} shortcut if it has one. |
78 | |
79 | The normal way to use QTabWidget is to do the following: |
80 | \list 1 |
81 | \li Create a QTabWidget. |
82 | \li Create a QWidget for each of the pages in the tab dialog, but |
83 | do not specify parent widgets for them. |
84 | \li Insert child widgets into the page widget, using layouts to |
85 | position them as normal. |
86 | \li Call addTab() or insertTab() to put the page widgets into the |
87 | tab widget, giving each tab a suitable label with an optional |
88 | keyboard shortcut. |
89 | \endlist |
90 | |
91 | The position of the tabs is defined by \l tabPosition, their shape |
92 | by \l tabShape. |
93 | |
94 | The signal currentChanged() is emitted when the user selects a |
95 | page. |
96 | |
97 | The current page index is available as currentIndex(), the current |
98 | page widget with currentWidget(). You can retrieve a pointer to a |
99 | page widget with a given index using widget(), and can find the |
100 | index position of a widget with indexOf(). Use setCurrentWidget() |
101 | or setCurrentIndex() to show a particular page. |
102 | |
103 | You can change a tab's text and icon using setTabText() or |
104 | setTabIcon(). A tab and its associated page can be removed with |
105 | removeTab(). |
106 | |
107 | Each tab is either enabled or disabled at any given time (see |
108 | setTabEnabled()). If a tab is enabled, the tab text is drawn |
109 | normally and the user can select that tab. If it is disabled, the |
110 | tab is drawn in a different way and the user cannot select that |
111 | tab. Note that even if a tab is disabled, the page can still be |
112 | visible, for example if all of the tabs happen to be disabled. |
113 | |
114 | Tab widgets can be a very good way to split up a complex dialog. |
115 | An alternative is to use a QStackedWidget for which you provide some |
116 | means of navigating between pages, for example, a QToolBar or a |
117 | QListWidget. |
118 | |
119 | Most of the functionality in QTabWidget is provided by a QTabBar |
120 | (at the top, providing the tabs) and a QStackedWidget (most of the |
121 | area, organizing the individual pages). |
122 | |
123 | \sa QTabBar, QStackedWidget, QToolBox, {Tab Dialog Example} |
124 | */ |
125 | |
126 | /*! |
127 | \enum QTabWidget::TabPosition |
128 | |
129 | This enum type defines where QTabWidget draws the tab row: |
130 | |
131 | \value North The tabs are drawn above the pages. |
132 | \value South The tabs are drawn below the pages. |
133 | \value West The tabs are drawn to the left of the pages. |
134 | \value East The tabs are drawn to the right of the pages. |
135 | */ |
136 | |
137 | /*! |
138 | \enum QTabWidget::TabShape |
139 | |
140 | This enum type defines the shape of the tabs: |
141 | \value Rounded The tabs are drawn with a rounded look. This is the default |
142 | shape. |
143 | \value Triangular The tabs are drawn with a triangular look. |
144 | */ |
145 | |
146 | /*! |
147 | \fn void QTabWidget::currentChanged(int index) |
148 | |
149 | This signal is emitted whenever the current page index changes. |
150 | The parameter is the new current page \a index position, or -1 |
151 | if there isn't a new one (for example, if there are no widgets |
152 | in the QTabWidget) |
153 | |
154 | \sa currentWidget(), currentIndex |
155 | */ |
156 | |
157 | /*! |
158 | \fn void QTabWidget::tabCloseRequested(int index) |
159 | \since 4.5 |
160 | |
161 | This signal is emitted when the close button on a tab is clicked. |
162 | The \a index is the index that should be removed. |
163 | |
164 | \sa setTabsClosable() |
165 | */ |
166 | |
167 | /*! |
168 | \fn void QTabWidget::tabBarClicked(int index) |
169 | |
170 | This signal is emitted when user clicks on a tab at an \a index. |
171 | |
172 | \a index refers to the tab clicked, or -1 if no tab is under the cursor. |
173 | |
174 | \since 5.2 |
175 | */ |
176 | |
177 | /*! |
178 | \fn void QTabWidget::tabBarDoubleClicked(int index) |
179 | |
180 | This signal is emitted when the user double clicks on a tab at an \a index. |
181 | |
182 | \a index is the index of a clicked tab, or -1 if no tab is under the cursor. |
183 | |
184 | \since 5.2 |
185 | */ |
186 | |
187 | class QTabWidgetPrivate : public QWidgetPrivate |
188 | { |
189 | Q_DECLARE_PUBLIC(QTabWidget) |
190 | |
191 | public: |
192 | QTabWidgetPrivate(); |
193 | ~QTabWidgetPrivate(); |
194 | void updateTabBarPosition(); |
195 | void _q_showTab(int); |
196 | void _q_removeTab(int); |
197 | void _q_tabMoved(int from, int to); |
198 | void init(); |
199 | bool isAutoHidden() const |
200 | { |
201 | // see QTabBarPrivate::autoHideTabs() |
202 | return (tabs->autoHide() && tabs->count() <= 1); |
203 | } |
204 | |
205 | void initBasicStyleOption(QStyleOptionTabWidgetFrame *option) const; |
206 | |
207 | QTabBar *tabs; |
208 | QStackedWidget *stack; |
209 | QRect panelRect; |
210 | bool dirty; |
211 | QTabWidget::TabPosition pos; |
212 | QTabWidget::TabShape shape; |
213 | QWidget *leftCornerWidget; |
214 | QWidget *rightCornerWidget; |
215 | }; |
216 | |
217 | QTabWidgetPrivate::QTabWidgetPrivate() |
218 | : tabs(nullptr), stack(nullptr), dirty(true), |
219 | pos(QTabWidget::North), shape(QTabWidget::Rounded), |
220 | leftCornerWidget(nullptr), rightCornerWidget(nullptr) |
221 | {} |
222 | |
223 | QTabWidgetPrivate::~QTabWidgetPrivate() |
224 | {} |
225 | |
226 | void QTabWidgetPrivate::init() |
227 | { |
228 | Q_Q(QTabWidget); |
229 | |
230 | stack = new QStackedWidget(q); |
231 | stack->setObjectName(QLatin1String("qt_tabwidget_stackedwidget" )); |
232 | stack->setLineWidth(0); |
233 | // hack so that QMacStyle::layoutSpacing() can detect tab widget pages |
234 | stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::TabWidget)); |
235 | |
236 | QObject::connect(sender: stack, SIGNAL(widgetRemoved(int)), receiver: q, SLOT(_q_removeTab(int))); |
237 | QTabBar *tabBar = new QTabBar(q); |
238 | tabBar->setObjectName(QLatin1String("qt_tabwidget_tabbar" )); |
239 | tabBar->setDrawBase(false); |
240 | q->setTabBar(tabBar); |
241 | |
242 | q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, |
243 | QSizePolicy::TabWidget)); |
244 | #ifdef QT_KEYPAD_NAVIGATION |
245 | if (QApplicationPrivate::keypadNavigationEnabled()) |
246 | q->setFocusPolicy(Qt::NoFocus); |
247 | else |
248 | #endif |
249 | q->setFocusPolicy(Qt::TabFocus); |
250 | q->setFocusProxy(tabs); |
251 | q->setTabPosition(static_cast<QTabWidget::TabPosition> (q->style()->styleHint( |
252 | stylehint: QStyle::SH_TabWidget_DefaultTabPosition, opt: nullptr, widget: q ))); |
253 | |
254 | } |
255 | |
256 | /*! |
257 | \reimp |
258 | */ |
259 | |
260 | bool QTabWidget::hasHeightForWidth() const |
261 | { |
262 | Q_D(const QTabWidget); |
263 | bool has = d->size_policy.hasHeightForWidth(); |
264 | if (!has && d->stack) |
265 | has = d->stack->hasHeightForWidth(); |
266 | return has; |
267 | } |
268 | |
269 | /*! |
270 | \internal |
271 | |
272 | Initialize only time inexpensive parts of the style option |
273 | for QTabWidget::setUpLayout()'s non-visible code path. |
274 | */ |
275 | void QTabWidgetPrivate::initBasicStyleOption(QStyleOptionTabWidgetFrame *option) const |
276 | { |
277 | Q_Q(const QTabWidget); |
278 | option->initFrom(w: q); |
279 | |
280 | if (q->documentMode()) |
281 | option->lineWidth = 0; |
282 | else |
283 | option->lineWidth = q->style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth, option: nullptr, widget: q); |
284 | |
285 | switch (pos) { |
286 | case QTabWidget::North: |
287 | option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedNorth |
288 | : QTabBar::TriangularNorth; |
289 | break; |
290 | case QTabWidget::South: |
291 | option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedSouth |
292 | : QTabBar::TriangularSouth; |
293 | break; |
294 | case QTabWidget::West: |
295 | option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedWest |
296 | : QTabBar::TriangularWest; |
297 | break; |
298 | case QTabWidget::East: |
299 | option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedEast |
300 | : QTabBar::TriangularEast; |
301 | break; |
302 | } |
303 | |
304 | option->tabBarRect = q->tabBar()->geometry(); |
305 | } |
306 | |
307 | /*! |
308 | Initialize \a option with the values from this QTabWidget. This method is useful |
309 | for subclasses when they need a QStyleOptionTabWidgetFrame, but don't want to fill |
310 | in all the information themselves. |
311 | |
312 | \sa QStyleOption::initFrom(), QTabBar::initStyleOption() |
313 | */ |
314 | void QTabWidget::initStyleOption(QStyleOptionTabWidgetFrame *option) const |
315 | { |
316 | if (!option) |
317 | return; |
318 | |
319 | Q_D(const QTabWidget); |
320 | d->initBasicStyleOption(option); |
321 | |
322 | int exth = style()->pixelMetric(metric: QStyle::PM_TabBarBaseHeight, option: nullptr, widget: this); |
323 | QSize t(0, d->stack->frameWidth()); |
324 | if (d->tabs->isVisibleTo(const_cast<QTabWidget *>(this))) { |
325 | t = d->tabs->sizeHint(); |
326 | if (documentMode()) { |
327 | if (tabPosition() == East || tabPosition() == West) { |
328 | t.setHeight(height()); |
329 | } else { |
330 | t.setWidth(width()); |
331 | } |
332 | } |
333 | } |
334 | |
335 | if (d->rightCornerWidget) { |
336 | const QSize rightCornerSizeHint = d->rightCornerWidget->sizeHint(); |
337 | const QSize bounds(rightCornerSizeHint.width(), t.height() - exth); |
338 | option->rightCornerWidgetSize = rightCornerSizeHint.boundedTo(otherSize: bounds); |
339 | } else { |
340 | option->rightCornerWidgetSize = QSize(0, 0); |
341 | } |
342 | |
343 | if (d->leftCornerWidget) { |
344 | const QSize leftCornerSizeHint = d->leftCornerWidget->sizeHint(); |
345 | const QSize bounds(leftCornerSizeHint.width(), t.height() - exth); |
346 | option->leftCornerWidgetSize = leftCornerSizeHint.boundedTo(otherSize: bounds); |
347 | } else { |
348 | option->leftCornerWidgetSize = QSize(0, 0); |
349 | } |
350 | |
351 | option->tabBarSize = t; |
352 | |
353 | QRect selectedTabRect = tabBar()->tabRect(index: tabBar()->currentIndex()); |
354 | selectedTabRect.moveTopLeft(p: selectedTabRect.topLeft() + option->tabBarRect.topLeft()); |
355 | option->selectedTabRect = selectedTabRect; |
356 | } |
357 | |
358 | /*! |
359 | Constructs a tabbed widget with parent \a parent. |
360 | */ |
361 | QTabWidget::QTabWidget(QWidget *parent) |
362 | : QWidget(*new QTabWidgetPrivate, parent, { }) |
363 | { |
364 | Q_D(QTabWidget); |
365 | d->init(); |
366 | } |
367 | |
368 | |
369 | /*! |
370 | Destroys the tabbed widget. |
371 | */ |
372 | QTabWidget::~QTabWidget() |
373 | { |
374 | } |
375 | |
376 | /*! |
377 | \fn int QTabWidget::addTab(QWidget *page, const QString &label) |
378 | |
379 | Adds a tab with the given \a page and \a label to the tab widget, |
380 | and returns the index of the tab in the tab bar. Ownership of \a page |
381 | is passed on to the QTabWidget. |
382 | |
383 | If the tab's \a label contains an ampersand, the letter following |
384 | the ampersand is used as a shortcut for the tab, e.g. if the |
385 | label is "Bro\&wse" then Alt+W becomes a shortcut which will |
386 | move the focus to this tab. |
387 | |
388 | \note If you call addTab() after show(), the layout system will try |
389 | to adjust to the changes in its widgets hierarchy and may cause |
390 | flicker. To prevent this, you can set the QWidget::updatesEnabled |
391 | property to false prior to changes; remember to set the property |
392 | to true when the changes are done, making the widget receive paint |
393 | events again. |
394 | |
395 | \sa insertTab() |
396 | */ |
397 | int QTabWidget::addTab(QWidget *child, const QString &label) |
398 | { |
399 | return insertTab(index: -1, widget: child, label); |
400 | } |
401 | |
402 | |
403 | /*! |
404 | \fn int QTabWidget::addTab(QWidget *page, const QIcon &icon, const QString &label) |
405 | \overload |
406 | |
407 | Adds a tab with the given \a page, \a icon, and \a label to the tab |
408 | widget, and returns the index of the tab in the tab bar. Ownership |
409 | of \a page is passed on to the QTabWidget. |
410 | |
411 | This function is the same as addTab(), but with an additional \a |
412 | icon. |
413 | */ |
414 | int QTabWidget::addTab(QWidget *child, const QIcon& icon, const QString &label) |
415 | { |
416 | return insertTab(index: -1, widget: child, icon, label); |
417 | } |
418 | |
419 | |
420 | /*! |
421 | \fn int QTabWidget::insertTab(int index, QWidget *page, const QString &label) |
422 | |
423 | Inserts a tab with the given \a label and \a page into the tab |
424 | widget at the specified \a index, and returns the index of the |
425 | inserted tab in the tab bar. Ownership of \a page is passed on to the |
426 | QTabWidget. |
427 | |
428 | The label is displayed in the tab and may vary in appearance depending |
429 | on the configuration of the tab widget. |
430 | |
431 | If the tab's \a label contains an ampersand, the letter following |
432 | the ampersand is used as a shortcut for the tab, e.g. if the |
433 | label is "Bro\&wse" then Alt+W becomes a shortcut which will |
434 | move the focus to this tab. |
435 | |
436 | If \a index is out of range, the tab is simply appended. |
437 | Otherwise it is inserted at the specified position. |
438 | |
439 | If the QTabWidget was empty before this function is called, the |
440 | new page becomes the current page. Inserting a new tab at an index |
441 | less than or equal to the current index will increment the current |
442 | index, but keep the current page. |
443 | |
444 | \note If you call insertTab() after show(), the layout system will try |
445 | to adjust to the changes in its widgets hierarchy and may cause |
446 | flicker. To prevent this, you can set the QWidget::updatesEnabled |
447 | property to false prior to changes; remember to set the property |
448 | to true when the changes are done, making the widget receive paint |
449 | events again. |
450 | |
451 | \sa addTab() |
452 | */ |
453 | int QTabWidget::insertTab(int index, QWidget *w, const QString &label) |
454 | { |
455 | return insertTab(index, widget: w, icon: QIcon(), label); |
456 | } |
457 | |
458 | |
459 | /*! |
460 | \fn int QTabWidget::insertTab(int index, QWidget *page, const QIcon& icon, const QString &label) |
461 | \overload |
462 | |
463 | Inserts a tab with the given \a label, \a page, and \a icon into |
464 | the tab widget at the specified \a index, and returns the index of the |
465 | inserted tab in the tab bar. Ownership of \a page is passed on to the |
466 | QTabWidget. |
467 | |
468 | This function is the same as insertTab(), but with an additional |
469 | \a icon. |
470 | */ |
471 | int QTabWidget::insertTab(int index, QWidget *w, const QIcon& icon, const QString &label) |
472 | { |
473 | Q_D(QTabWidget); |
474 | if(!w) |
475 | return -1; |
476 | index = d->stack->insertWidget(index, w); |
477 | d->tabs->insertTab(index, icon, text: label); |
478 | setUpLayout(); |
479 | tabInserted(index); |
480 | |
481 | return index; |
482 | } |
483 | |
484 | |
485 | /*! |
486 | Defines a new \a label for the page at position \a index's tab. |
487 | |
488 | If the provided text contains an ampersand character ('&'), a |
489 | shortcut is automatically created for it. The character that |
490 | follows the '&' will be used as the shortcut key. Any previous |
491 | shortcut will be overwritten, or cleared if no shortcut is defined |
492 | by the text. See the \l {QShortcut#mnemonic}{QShortcut} |
493 | documentation for details (to display an actual ampersand, use |
494 | '&&'). |
495 | |
496 | */ |
497 | void QTabWidget::setTabText(int index, const QString &label) |
498 | { |
499 | Q_D(QTabWidget); |
500 | d->tabs->setTabText(index, text: label); |
501 | setUpLayout(); |
502 | } |
503 | |
504 | /*! |
505 | Returns the label text for the tab on the page at position \a index. |
506 | */ |
507 | |
508 | QString QTabWidget::tabText(int index) const |
509 | { |
510 | Q_D(const QTabWidget); |
511 | return d->tabs->tabText(index); |
512 | } |
513 | |
514 | /*! |
515 | Sets the \a icon for the tab at position \a index. |
516 | */ |
517 | void QTabWidget::setTabIcon(int index, const QIcon &icon) |
518 | { |
519 | Q_D(QTabWidget); |
520 | d->tabs->setTabIcon(index, icon); |
521 | setUpLayout(); |
522 | } |
523 | |
524 | /*! |
525 | Returns the icon for the tab on the page at position \a index. |
526 | */ |
527 | |
528 | QIcon QTabWidget::tabIcon(int index) const |
529 | { |
530 | Q_D(const QTabWidget); |
531 | return d->tabs->tabIcon(index); |
532 | } |
533 | |
534 | /*! |
535 | Returns \c true if the page at position \a index is enabled; otherwise returns \c false. |
536 | |
537 | \sa setTabEnabled(), QWidget::isEnabled() |
538 | */ |
539 | |
540 | bool QTabWidget::isTabEnabled(int index) const |
541 | { |
542 | Q_D(const QTabWidget); |
543 | return d->tabs->isTabEnabled(index); |
544 | } |
545 | |
546 | /*! |
547 | If \a enable is true, the page at position \a index is enabled; otherwise the page at |
548 | position \a index is disabled. The page's tab is redrawn appropriately. |
549 | |
550 | QTabWidget uses QWidget::setEnabled() internally, rather than |
551 | keeping a separate flag. |
552 | |
553 | Note that even a disabled tab/page may be visible. If the page is |
554 | visible already, QTabWidget will not hide it; if all the pages are |
555 | disabled, QTabWidget will show one of them. |
556 | |
557 | \sa isTabEnabled(), QWidget::setEnabled() |
558 | */ |
559 | |
560 | void QTabWidget::setTabEnabled(int index, bool enable) |
561 | { |
562 | Q_D(QTabWidget); |
563 | d->tabs->setTabEnabled(index, enabled: enable); |
564 | if (QWidget *widget = d->stack->widget(index)) |
565 | widget->setEnabled(enable); |
566 | } |
567 | |
568 | /*! |
569 | Returns true if the page at position \a index is visible; otherwise returns false. |
570 | |
571 | \sa setTabVisible() |
572 | \since 5.15 |
573 | */ |
574 | |
575 | bool QTabWidget::isTabVisible(int index) const |
576 | { |
577 | Q_D(const QTabWidget); |
578 | return d->tabs->isTabVisible(index); |
579 | } |
580 | |
581 | /*! |
582 | If \a visible is true, the page at position \a index is visible; otherwise the page at |
583 | position \a index is hidden. The page's tab is redrawn appropriately. |
584 | |
585 | \sa isTabVisible() |
586 | \since 5.15 |
587 | */ |
588 | |
589 | void QTabWidget::setTabVisible(int index, bool visible) |
590 | { |
591 | Q_D(QTabWidget); |
592 | QWidget *widget = d->stack->widget(index); |
593 | bool currentVisible = d->tabs->isTabVisible(index: d->tabs->currentIndex()); |
594 | d->tabs->setTabVisible(index, visible); |
595 | if (!visible) { |
596 | if (widget) |
597 | widget->setVisible(false); |
598 | } else if (!currentVisible) { |
599 | setCurrentIndex(index); |
600 | if (widget) |
601 | widget->setVisible(true); |
602 | } |
603 | setUpLayout(); |
604 | } |
605 | |
606 | /*! |
607 | \fn void QTabWidget::setCornerWidget(QWidget *widget, Qt::Corner corner) |
608 | |
609 | Sets the given \a widget to be shown in the specified \a corner of the |
610 | tab widget. The geometry of the widget is determined based on the widget's |
611 | sizeHint() and the style(). |
612 | |
613 | Only the horizontal element of the \a corner will be used. |
614 | |
615 | Passing \nullptr shows no widget in the corner. |
616 | |
617 | Any previously set corner widget is hidden. |
618 | |
619 | All widgets set here will be deleted by the tab widget when it is |
620 | destroyed unless you separately reparent the widget after setting |
621 | some other corner widget (or \nullptr). |
622 | |
623 | Note: Corner widgets are designed for \l North and \l South tab positions; |
624 | other orientations are known to not work properly. |
625 | |
626 | \sa cornerWidget(), setTabPosition() |
627 | */ |
628 | void QTabWidget::setCornerWidget(QWidget * widget, Qt::Corner corner) |
629 | { |
630 | Q_D(QTabWidget); |
631 | if (widget && widget->parentWidget() != this) |
632 | widget->setParent(this); |
633 | |
634 | if (corner & Qt::TopRightCorner) { |
635 | if (d->rightCornerWidget) |
636 | d->rightCornerWidget->hide(); |
637 | d->rightCornerWidget = widget; |
638 | } else { |
639 | if (d->leftCornerWidget) |
640 | d->leftCornerWidget->hide(); |
641 | d->leftCornerWidget = widget; |
642 | } |
643 | setUpLayout(); |
644 | } |
645 | |
646 | /*! |
647 | Returns the widget shown in the \a corner of the tab widget or \nullptr. |
648 | */ |
649 | QWidget * QTabWidget::cornerWidget(Qt::Corner corner) const |
650 | { |
651 | Q_D(const QTabWidget); |
652 | if (corner & Qt::TopRightCorner) |
653 | return d->rightCornerWidget; |
654 | return d->leftCornerWidget; |
655 | } |
656 | |
657 | /*! |
658 | Removes the tab at position \a index from this stack of widgets. |
659 | The page widget itself is not deleted. |
660 | |
661 | \sa addTab(), insertTab() |
662 | */ |
663 | void QTabWidget::removeTab(int index) |
664 | { |
665 | Q_D(QTabWidget); |
666 | if (QWidget *w = d->stack->widget(index)) |
667 | d->stack->removeWidget(w); |
668 | } |
669 | |
670 | /*! |
671 | Returns a pointer to the page currently being displayed by the tab |
672 | dialog. The tab dialog does its best to make sure that this value |
673 | is never 0 (but if you try hard enough, it can be). |
674 | |
675 | \sa currentIndex(), setCurrentWidget() |
676 | */ |
677 | |
678 | QWidget * QTabWidget::currentWidget() const |
679 | { |
680 | Q_D(const QTabWidget); |
681 | return d->stack->currentWidget(); |
682 | } |
683 | |
684 | /*! |
685 | Makes \a widget the current widget. The \a widget used must be a page in |
686 | this tab widget. |
687 | |
688 | \sa addTab(), setCurrentIndex(), currentWidget() |
689 | */ |
690 | void QTabWidget::setCurrentWidget(QWidget *widget) |
691 | { |
692 | Q_D(const QTabWidget); |
693 | d->tabs->setCurrentIndex(indexOf(widget)); |
694 | } |
695 | |
696 | |
697 | /*! |
698 | \property QTabWidget::currentIndex |
699 | \brief the index position of the current tab page |
700 | |
701 | The current index is -1 if there is no current widget. |
702 | |
703 | By default, this property contains a value of -1 because there are initially |
704 | no tabs in the widget. |
705 | */ |
706 | |
707 | int QTabWidget::currentIndex() const |
708 | { |
709 | Q_D(const QTabWidget); |
710 | return d->tabs->currentIndex(); |
711 | } |
712 | |
713 | void QTabWidget::setCurrentIndex(int index) |
714 | { |
715 | Q_D(QTabWidget); |
716 | d->tabs->setCurrentIndex(index); |
717 | } |
718 | |
719 | |
720 | /*! |
721 | Returns the index position of the page occupied by the widget \a |
722 | w, or -1 if the widget cannot be found. |
723 | */ |
724 | int QTabWidget::indexOf(QWidget* w) const |
725 | { |
726 | Q_D(const QTabWidget); |
727 | return d->stack->indexOf(w); |
728 | } |
729 | |
730 | |
731 | /*! |
732 | \reimp |
733 | */ |
734 | void QTabWidget::resizeEvent(QResizeEvent *e) |
735 | { |
736 | QWidget::resizeEvent(event: e); |
737 | setUpLayout(); |
738 | } |
739 | |
740 | /*! |
741 | Replaces the dialog's QTabBar heading with the tab bar \a tb. Note |
742 | that this must be called \e before any tabs have been added, or |
743 | the behavior is undefined. |
744 | |
745 | \sa tabBar() |
746 | */ |
747 | void QTabWidget::setTabBar(QTabBar* tb) |
748 | { |
749 | Q_D(QTabWidget); |
750 | Q_ASSERT(tb); |
751 | |
752 | if (tb->parentWidget() != this) { |
753 | tb->setParent(this); |
754 | tb->show(); |
755 | } |
756 | delete d->tabs; |
757 | d->tabs = tb; |
758 | setFocusProxy(d->tabs); |
759 | connect(sender: d->tabs, SIGNAL(currentChanged(int)), |
760 | receiver: this, SLOT(_q_showTab(int))); |
761 | connect(sender: d->tabs, SIGNAL(tabMoved(int,int)), |
762 | receiver: this, SLOT(_q_tabMoved(int,int))); |
763 | connect(sender: d->tabs, SIGNAL(tabBarClicked(int)), |
764 | receiver: this, SIGNAL(tabBarClicked(int))); |
765 | connect(sender: d->tabs, SIGNAL(tabBarDoubleClicked(int)), |
766 | receiver: this, SIGNAL(tabBarDoubleClicked(int))); |
767 | if (d->tabs->tabsClosable()) |
768 | connect(sender: d->tabs, SIGNAL(tabCloseRequested(int)), |
769 | receiver: this, SIGNAL(tabCloseRequested(int))); |
770 | tb->setExpanding(!documentMode()); |
771 | setUpLayout(); |
772 | } |
773 | |
774 | |
775 | /*! |
776 | Returns the current QTabBar. |
777 | |
778 | \sa setTabBar() |
779 | */ |
780 | QTabBar* QTabWidget::tabBar() const |
781 | { |
782 | Q_D(const QTabWidget); |
783 | return d->tabs; |
784 | } |
785 | |
786 | /* |
787 | Ensures that the selected tab's page is visible and appropriately |
788 | sized. |
789 | */ |
790 | |
791 | void QTabWidgetPrivate::_q_showTab(int index) |
792 | { |
793 | Q_Q(QTabWidget); |
794 | if (index < stack->count() && index >= 0) |
795 | stack->setCurrentIndex(index); |
796 | emit q->currentChanged(index); |
797 | } |
798 | |
799 | void QTabWidgetPrivate::_q_removeTab(int index) |
800 | { |
801 | Q_Q(QTabWidget); |
802 | tabs->removeTab(index); |
803 | q->setUpLayout(); |
804 | q->tabRemoved(index); |
805 | } |
806 | |
807 | void QTabWidgetPrivate::_q_tabMoved(int from, int to) |
808 | { |
809 | const QSignalBlocker blocker(stack); |
810 | QWidget *w = stack->widget(from); |
811 | stack->removeWidget(w); |
812 | stack->insertWidget(index: to, w); |
813 | } |
814 | |
815 | /* |
816 | Set up the layout. |
817 | Get subrect from the current style, and set the geometry for the |
818 | stack widget, tab bar and corner widgets. |
819 | */ |
820 | void QTabWidget::setUpLayout(bool onlyCheck) |
821 | { |
822 | Q_D(QTabWidget); |
823 | if (onlyCheck && !d->dirty) |
824 | return; // nothing to do |
825 | |
826 | if (!isVisible()) { |
827 | // this must be done immediately, because QWidgetItem relies on it (even if !isVisible()) |
828 | QStyleOptionTabWidgetFrame basicOption; |
829 | d->initBasicStyleOption(option: &basicOption); |
830 | d->setLayoutItemMargins(element: QStyle::SE_TabWidgetLayoutItem, opt: &basicOption); |
831 | d->dirty = true; |
832 | return; // we'll do it later |
833 | } |
834 | |
835 | QStyleOptionTabWidgetFrame option; |
836 | initStyleOption(option: &option); |
837 | d->setLayoutItemMargins(element: QStyle::SE_TabWidgetLayoutItem, opt: &option); |
838 | |
839 | QRect tabRect = style()->subElementRect(subElement: QStyle::SE_TabWidgetTabBar, option: &option, widget: this); |
840 | d->panelRect = style()->subElementRect(subElement: QStyle::SE_TabWidgetTabPane, option: &option, widget: this); |
841 | QRect contentsRect = style()->subElementRect(subElement: QStyle::SE_TabWidgetTabContents, option: &option, widget: this); |
842 | QRect leftCornerRect = style()->subElementRect(subElement: QStyle::SE_TabWidgetLeftCorner, option: &option, widget: this); |
843 | QRect rightCornerRect = style()->subElementRect(subElement: QStyle::SE_TabWidgetRightCorner, option: &option, widget: this); |
844 | |
845 | d->tabs->setGeometry(tabRect); |
846 | d->stack->setGeometry(contentsRect); |
847 | if (d->leftCornerWidget) |
848 | d->leftCornerWidget->setGeometry(leftCornerRect); |
849 | if (d->rightCornerWidget) |
850 | d->rightCornerWidget->setGeometry(rightCornerRect); |
851 | |
852 | if (!onlyCheck) |
853 | update(); |
854 | updateGeometry(); |
855 | } |
856 | |
857 | /*! |
858 | \internal |
859 | */ |
860 | static inline QSize basicSize( |
861 | bool horizontal, const QSize &lc, const QSize &rc, const QSize &s, const QSize &t) |
862 | { |
863 | return horizontal |
864 | ? QSize(qMax(a: s.width(), b: t.width() + rc.width() + lc.width()), |
865 | s.height() + (qMax(a: rc.height(), b: qMax(a: lc.height(), b: t.height())))) |
866 | : QSize(s.width() + (qMax(a: rc.width(), b: qMax(a: lc.width(), b: t.width()))), |
867 | qMax(a: s.height(), b: t.height() + rc.height() + lc.height())); |
868 | } |
869 | |
870 | /*! |
871 | \reimp |
872 | */ |
873 | QSize QTabWidget::sizeHint() const |
874 | { |
875 | Q_D(const QTabWidget); |
876 | QSize lc(0, 0), rc(0, 0); |
877 | QStyleOptionTabWidgetFrame opt; |
878 | initStyleOption(option: &opt); |
879 | opt.state = QStyle::State_None; |
880 | |
881 | if (d->leftCornerWidget) |
882 | lc = d->leftCornerWidget->sizeHint(); |
883 | if(d->rightCornerWidget) |
884 | rc = d->rightCornerWidget->sizeHint(); |
885 | if (!d->dirty) { |
886 | QTabWidget *that = const_cast<QTabWidget*>(this); |
887 | that->setUpLayout(true); |
888 | } |
889 | QSize s; |
890 | for (int i=0; i< d->stack->count(); ++i) { |
891 | if (const QWidget* w = d->stack->widget(i)) { |
892 | if (d->tabs->isTabVisible(index: i)) |
893 | s = s.expandedTo(otherSize: w->sizeHint()); |
894 | } |
895 | } |
896 | QSize t; |
897 | if (!d->isAutoHidden()) { |
898 | t = d->tabs->sizeHint(); |
899 | if (usesScrollButtons()) |
900 | t = t.boundedTo(otherSize: QSize(200,200)); |
901 | else |
902 | t = t.boundedTo(otherSize: QDesktopWidgetPrivate::size()); |
903 | } |
904 | |
905 | QSize sz = basicSize(horizontal: d->pos == North || d->pos == South, lc, rc, s, t); |
906 | |
907 | return style()->sizeFromContents(ct: QStyle::CT_TabWidget, opt: &opt, contentsSize: sz, w: this) |
908 | .expandedTo(otherSize: QApplication::globalStrut()); |
909 | } |
910 | |
911 | |
912 | /*! |
913 | \reimp |
914 | |
915 | Returns a suitable minimum size for the tab widget. |
916 | */ |
917 | QSize QTabWidget::minimumSizeHint() const |
918 | { |
919 | Q_D(const QTabWidget); |
920 | QSize lc(0, 0), rc(0, 0); |
921 | |
922 | if(d->leftCornerWidget) |
923 | lc = d->leftCornerWidget->minimumSizeHint(); |
924 | if(d->rightCornerWidget) |
925 | rc = d->rightCornerWidget->minimumSizeHint(); |
926 | if (!d->dirty) { |
927 | QTabWidget *that = const_cast<QTabWidget*>(this); |
928 | that->setUpLayout(true); |
929 | } |
930 | QSize s(d->stack->minimumSizeHint()); |
931 | QSize t; |
932 | if (!d->isAutoHidden()) |
933 | t = d->tabs->minimumSizeHint(); |
934 | |
935 | QSize sz = basicSize(horizontal: d->pos == North || d->pos == South, lc, rc, s, t); |
936 | |
937 | QStyleOptionTabWidgetFrame opt; |
938 | initStyleOption(option: &opt); |
939 | opt.palette = palette(); |
940 | opt.state = QStyle::State_None; |
941 | return style()->sizeFromContents(ct: QStyle::CT_TabWidget, opt: &opt, contentsSize: sz, w: this) |
942 | .expandedTo(otherSize: QApplication::globalStrut()); |
943 | } |
944 | |
945 | /*! |
946 | \reimp |
947 | */ |
948 | int QTabWidget::heightForWidth(int width) const |
949 | { |
950 | Q_D(const QTabWidget); |
951 | QStyleOptionTabWidgetFrame opt; |
952 | initStyleOption(option: &opt); |
953 | opt.state = QStyle::State_None; |
954 | |
955 | QSize zero(0,0); |
956 | const QSize padding = style()->sizeFromContents(ct: QStyle::CT_TabWidget, opt: &opt, contentsSize: zero, w: this) |
957 | .expandedTo(otherSize: QApplication::globalStrut()); |
958 | |
959 | QSize lc(0, 0), rc(0, 0); |
960 | if (d->leftCornerWidget) |
961 | lc = d->leftCornerWidget->sizeHint(); |
962 | if(d->rightCornerWidget) |
963 | rc = d->rightCornerWidget->sizeHint(); |
964 | if (!d->dirty) { |
965 | QTabWidget *that = const_cast<QTabWidget*>(this); |
966 | that->setUpLayout(true); |
967 | } |
968 | QSize t; |
969 | if (!d->isAutoHidden()) { |
970 | t = d->tabs->sizeHint(); |
971 | if (usesScrollButtons()) |
972 | t = t.boundedTo(otherSize: QSize(200,200)); |
973 | else |
974 | t = t.boundedTo(otherSize: QDesktopWidgetPrivate::size()); |
975 | } |
976 | |
977 | const bool tabIsHorizontal = (d->pos == North || d->pos == South); |
978 | const int contentsWidth = width - padding.width(); |
979 | int stackWidth = contentsWidth; |
980 | if (!tabIsHorizontal) |
981 | stackWidth -= qMax(a: t.width(), b: qMax(a: lc.width(), b: rc.width())); |
982 | |
983 | int stackHeight = d->stack->heightForWidth(stackWidth); |
984 | QSize s(stackWidth, stackHeight); |
985 | |
986 | QSize contentSize = basicSize(horizontal: tabIsHorizontal, lc, rc, s, t); |
987 | return (contentSize + padding).expandedTo(otherSize: QApplication::globalStrut()).height(); |
988 | } |
989 | |
990 | |
991 | /*! |
992 | \reimp |
993 | */ |
994 | void QTabWidget::showEvent(QShowEvent *) |
995 | { |
996 | setUpLayout(); |
997 | } |
998 | |
999 | void QTabWidgetPrivate::updateTabBarPosition() |
1000 | { |
1001 | Q_Q(QTabWidget); |
1002 | switch (pos) { |
1003 | case QTabWidget::North: |
1004 | tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedNorth |
1005 | : QTabBar::TriangularNorth); |
1006 | break; |
1007 | case QTabWidget::South: |
1008 | tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedSouth |
1009 | : QTabBar::TriangularSouth); |
1010 | break; |
1011 | case QTabWidget::West: |
1012 | tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedWest |
1013 | : QTabBar::TriangularWest); |
1014 | break; |
1015 | case QTabWidget::East: |
1016 | tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedEast |
1017 | : QTabBar::TriangularEast); |
1018 | break; |
1019 | } |
1020 | q->setUpLayout(); |
1021 | } |
1022 | |
1023 | /*! |
1024 | \property QTabWidget::tabPosition |
1025 | \brief the position of the tabs in this tab widget |
1026 | |
1027 | Possible values for this property are described by the TabPosition |
1028 | enum. |
1029 | |
1030 | By default, this property is set to \l North. |
1031 | |
1032 | \sa TabPosition |
1033 | */ |
1034 | QTabWidget::TabPosition QTabWidget::tabPosition() const |
1035 | { |
1036 | Q_D(const QTabWidget); |
1037 | return d->pos; |
1038 | } |
1039 | |
1040 | void QTabWidget::setTabPosition(TabPosition pos) |
1041 | { |
1042 | Q_D(QTabWidget); |
1043 | if (d->pos == pos) |
1044 | return; |
1045 | d->pos = pos; |
1046 | d->updateTabBarPosition(); |
1047 | } |
1048 | |
1049 | /*! |
1050 | \property QTabWidget::tabsClosable |
1051 | \brief whether close buttons are automatically added to each tab. |
1052 | |
1053 | \since 4.5 |
1054 | |
1055 | \sa QTabBar::tabsClosable() |
1056 | */ |
1057 | bool QTabWidget::tabsClosable() const |
1058 | { |
1059 | return tabBar()->tabsClosable(); |
1060 | } |
1061 | |
1062 | void QTabWidget::setTabsClosable(bool closeable) |
1063 | { |
1064 | if (tabsClosable() == closeable) |
1065 | return; |
1066 | |
1067 | tabBar()->setTabsClosable(closeable); |
1068 | if (closeable) |
1069 | connect(sender: tabBar(), SIGNAL(tabCloseRequested(int)), |
1070 | receiver: this, SIGNAL(tabCloseRequested(int))); |
1071 | else |
1072 | disconnect(sender: tabBar(), SIGNAL(tabCloseRequested(int)), |
1073 | receiver: this, SIGNAL(tabCloseRequested(int))); |
1074 | setUpLayout(); |
1075 | } |
1076 | |
1077 | /*! |
1078 | \property QTabWidget::movable |
1079 | \brief This property holds whether the user can move the tabs |
1080 | within the tabbar area. |
1081 | |
1082 | \since 4.5 |
1083 | |
1084 | By default, this property is \c false; |
1085 | */ |
1086 | |
1087 | bool QTabWidget::isMovable() const |
1088 | { |
1089 | return tabBar()->isMovable(); |
1090 | } |
1091 | |
1092 | void QTabWidget::setMovable(bool movable) |
1093 | { |
1094 | tabBar()->setMovable(movable); |
1095 | } |
1096 | |
1097 | /*! |
1098 | \property QTabWidget::tabShape |
1099 | \brief the shape of the tabs in this tab widget |
1100 | |
1101 | Possible values for this property are QTabWidget::Rounded |
1102 | (default) or QTabWidget::Triangular. |
1103 | |
1104 | \sa TabShape |
1105 | */ |
1106 | |
1107 | QTabWidget::TabShape QTabWidget::tabShape() const |
1108 | { |
1109 | Q_D(const QTabWidget); |
1110 | return d->shape; |
1111 | } |
1112 | |
1113 | void QTabWidget::setTabShape(TabShape s) |
1114 | { |
1115 | Q_D(QTabWidget); |
1116 | if (d->shape == s) |
1117 | return; |
1118 | d->shape = s; |
1119 | d->updateTabBarPosition(); |
1120 | } |
1121 | |
1122 | /*! |
1123 | \reimp |
1124 | */ |
1125 | bool QTabWidget::event(QEvent *ev) |
1126 | { |
1127 | if (ev->type() == QEvent::LayoutRequest) |
1128 | setUpLayout(); |
1129 | return QWidget::event(event: ev); |
1130 | } |
1131 | |
1132 | /*! |
1133 | \reimp |
1134 | */ |
1135 | void QTabWidget::changeEvent(QEvent *ev) |
1136 | { |
1137 | if (ev->type() == QEvent::StyleChange |
1138 | #ifdef Q_OS_MAC |
1139 | || ev->type() == QEvent::MacSizeChange |
1140 | #endif |
1141 | ) |
1142 | setUpLayout(); |
1143 | QWidget::changeEvent(ev); |
1144 | } |
1145 | |
1146 | |
1147 | /*! |
1148 | \reimp |
1149 | */ |
1150 | void QTabWidget::keyPressEvent(QKeyEvent *e) |
1151 | { |
1152 | Q_D(QTabWidget); |
1153 | if (((e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab) && |
1154 | count() > 1 && e->modifiers() & Qt::ControlModifier) |
1155 | #ifdef QT_KEYPAD_NAVIGATION |
1156 | || QApplicationPrivate::keypadNavigationEnabled() && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right) && count() > 1 |
1157 | #endif |
1158 | ) { |
1159 | int pageCount = d->tabs->count(); |
1160 | int page = currentIndex(); |
1161 | int dx = (e->key() == Qt::Key_Backtab || e->modifiers() & Qt::ShiftModifier) ? -1 : 1; |
1162 | #ifdef QT_KEYPAD_NAVIGATION |
1163 | if (QApplicationPrivate::keypadNavigationEnabled() && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right)) |
1164 | dx = e->key() == (isRightToLeft() ? Qt::Key_Right : Qt::Key_Left) ? -1 : 1; |
1165 | #endif |
1166 | for (int pass = 0; pass < pageCount; ++pass) { |
1167 | page+=dx; |
1168 | if (page < 0 |
1169 | #ifdef QT_KEYPAD_NAVIGATION |
1170 | && !e->isAutoRepeat() |
1171 | #endif |
1172 | ) { |
1173 | page = count() - 1; |
1174 | } else if (page >= pageCount |
1175 | #ifdef QT_KEYPAD_NAVIGATION |
1176 | && !e->isAutoRepeat() |
1177 | #endif |
1178 | ) { |
1179 | page = 0; |
1180 | } |
1181 | if (d->tabs->isTabEnabled(index: page)) { |
1182 | setCurrentIndex(page); |
1183 | break; |
1184 | } |
1185 | } |
1186 | if (!QApplication::focusWidget()) |
1187 | d->tabs->setFocus(); |
1188 | } else { |
1189 | e->ignore(); |
1190 | } |
1191 | } |
1192 | |
1193 | /*! |
1194 | Returns the tab page at index position \a index or \nullptr if the |
1195 | \a index is out of range. |
1196 | */ |
1197 | QWidget *QTabWidget::widget(int index) const |
1198 | { |
1199 | Q_D(const QTabWidget); |
1200 | return d->stack->widget(index); |
1201 | } |
1202 | |
1203 | /*! |
1204 | \property QTabWidget::count |
1205 | \brief the number of tabs in the tab bar |
1206 | |
1207 | By default, this property contains a value of 0. |
1208 | */ |
1209 | int QTabWidget::count() const |
1210 | { |
1211 | Q_D(const QTabWidget); |
1212 | return d->tabs->count(); |
1213 | } |
1214 | |
1215 | #ifndef QT_NO_TOOLTIP |
1216 | /*! |
1217 | Sets the tab tool tip for the page at position \a index to \a tip. |
1218 | |
1219 | \sa tabToolTip() |
1220 | */ |
1221 | void QTabWidget::setTabToolTip(int index, const QString & tip) |
1222 | { |
1223 | Q_D(QTabWidget); |
1224 | d->tabs->setTabToolTip(index, tip); |
1225 | } |
1226 | |
1227 | /*! |
1228 | Returns the tab tool tip for the page at position \a index or |
1229 | an empty string if no tool tip has been set. |
1230 | |
1231 | \sa setTabToolTip() |
1232 | */ |
1233 | QString QTabWidget::tabToolTip(int index) const |
1234 | { |
1235 | Q_D(const QTabWidget); |
1236 | return d->tabs->tabToolTip(index); |
1237 | } |
1238 | #endif // QT_NO_TOOLTIP |
1239 | |
1240 | #if QT_CONFIG(whatsthis) |
1241 | /*! |
1242 | \since 4.1 |
1243 | |
1244 | Sets the What's This help text for the page at position \a index |
1245 | to \a text. |
1246 | */ |
1247 | void QTabWidget::setTabWhatsThis(int index, const QString &text) |
1248 | { |
1249 | Q_D(QTabWidget); |
1250 | d->tabs->setTabWhatsThis(index, text); |
1251 | } |
1252 | |
1253 | /*! |
1254 | \since 4.1 |
1255 | |
1256 | Returns the What's This help text for the page at position \a index, |
1257 | or an empty string if no help text has been set. |
1258 | */ |
1259 | QString QTabWidget::tabWhatsThis(int index) const |
1260 | { |
1261 | Q_D(const QTabWidget); |
1262 | return d->tabs->tabWhatsThis(index); |
1263 | } |
1264 | #endif // QT_CONFIG(whatsthis) |
1265 | |
1266 | /*! |
1267 | This virtual handler is called after a new tab was added or |
1268 | inserted at position \a index. |
1269 | |
1270 | \sa tabRemoved() |
1271 | */ |
1272 | void QTabWidget::tabInserted(int index) |
1273 | { |
1274 | Q_UNUSED(index) |
1275 | } |
1276 | |
1277 | /*! |
1278 | This virtual handler is called after a tab was removed from |
1279 | position \a index. |
1280 | |
1281 | \sa tabInserted() |
1282 | */ |
1283 | void QTabWidget::tabRemoved(int index) |
1284 | { |
1285 | Q_UNUSED(index) |
1286 | } |
1287 | |
1288 | /*! |
1289 | \fn void QTabWidget::paintEvent(QPaintEvent *event) |
1290 | |
1291 | Paints the tab widget's tab bar in response to the paint \a event. |
1292 | */ |
1293 | void QTabWidget::paintEvent(QPaintEvent *) |
1294 | { |
1295 | Q_D(QTabWidget); |
1296 | if (documentMode()) { |
1297 | QStylePainter p(this, tabBar()); |
1298 | if (QWidget *w = cornerWidget(corner: Qt::TopLeftCorner)) { |
1299 | QStyleOptionTabBarBase opt; |
1300 | QTabBarPrivate::initStyleBaseOption(optTabBase: &opt, tabbar: tabBar(), size: w->size()); |
1301 | opt.rect.moveLeft(pos: w->x() + opt.rect.x()); |
1302 | opt.rect.moveTop(pos: w->y() + opt.rect.y()); |
1303 | p.drawPrimitive(pe: QStyle::PE_FrameTabBarBase, opt); |
1304 | } |
1305 | if (QWidget *w = cornerWidget(corner: Qt::TopRightCorner)) { |
1306 | QStyleOptionTabBarBase opt; |
1307 | QTabBarPrivate::initStyleBaseOption(optTabBase: &opt, tabbar: tabBar(), size: w->size()); |
1308 | opt.rect.moveLeft(pos: w->x() + opt.rect.x()); |
1309 | opt.rect.moveTop(pos: w->y() + opt.rect.y()); |
1310 | p.drawPrimitive(pe: QStyle::PE_FrameTabBarBase, opt); |
1311 | } |
1312 | return; |
1313 | } |
1314 | QStylePainter p(this); |
1315 | |
1316 | QStyleOptionTabWidgetFrame opt; |
1317 | initStyleOption(option: &opt); |
1318 | opt.rect = d->panelRect; |
1319 | p.drawPrimitive(pe: QStyle::PE_FrameTabWidget, opt); |
1320 | } |
1321 | |
1322 | /*! |
1323 | \property QTabWidget::iconSize |
1324 | \brief The size for icons in the tab bar |
1325 | \since 4.2 |
1326 | |
1327 | The default value is style-dependent. This is the maximum size |
1328 | that the icons will have. Icons are not scaled up if they are of |
1329 | smaller size. |
1330 | |
1331 | \sa QTabBar::iconSize |
1332 | */ |
1333 | QSize QTabWidget::iconSize() const |
1334 | { |
1335 | return d_func()->tabs->iconSize(); |
1336 | } |
1337 | |
1338 | void QTabWidget::setIconSize(const QSize &size) |
1339 | { |
1340 | d_func()->tabs->setIconSize(size); |
1341 | } |
1342 | |
1343 | /*! |
1344 | \property QTabWidget::elideMode |
1345 | \brief how to elide text in the tab bar |
1346 | \since 4.2 |
1347 | |
1348 | This property controls how items are elided when there is not |
1349 | enough space to show them for a given tab bar size. |
1350 | |
1351 | By default the value is style dependant. |
1352 | |
1353 | \sa QTabBar::elideMode, usesScrollButtons, QStyle::SH_TabBar_ElideMode |
1354 | */ |
1355 | Qt::TextElideMode QTabWidget::elideMode() const |
1356 | { |
1357 | return d_func()->tabs->elideMode(); |
1358 | } |
1359 | |
1360 | void QTabWidget::setElideMode(Qt::TextElideMode mode) |
1361 | { |
1362 | d_func()->tabs->setElideMode(mode); |
1363 | } |
1364 | |
1365 | /*! |
1366 | \property QTabWidget::usesScrollButtons |
1367 | \brief Whether or not a tab bar should use buttons to scroll tabs when it |
1368 | has many tabs. |
1369 | \since 4.2 |
1370 | |
1371 | When there are too many tabs in a tab bar for its size, the tab bar can either choose |
1372 | to expand its size or to add buttons that allow you to scroll through the tabs. |
1373 | |
1374 | By default the value is style dependant. |
1375 | |
1376 | \sa elideMode, QTabBar::usesScrollButtons, QStyle::SH_TabBar_PreferNoArrows |
1377 | */ |
1378 | bool QTabWidget::usesScrollButtons() const |
1379 | { |
1380 | return d_func()->tabs->usesScrollButtons(); |
1381 | } |
1382 | |
1383 | void QTabWidget::setUsesScrollButtons(bool useButtons) |
1384 | { |
1385 | d_func()->tabs->setUsesScrollButtons(useButtons); |
1386 | } |
1387 | |
1388 | /*! |
1389 | \property QTabWidget::documentMode |
1390 | \brief Whether or not the tab widget is rendered in a mode suitable for document |
1391 | pages. This is the same as document mode on \macos. |
1392 | \since 4.5 |
1393 | |
1394 | When this property is set the tab widget frame is not rendered. This mode is useful |
1395 | for showing document-type pages where the page covers most of the tab widget |
1396 | area. |
1397 | |
1398 | \sa elideMode, QTabBar::documentMode, QTabBar::usesScrollButtons, QStyle::SH_TabBar_PreferNoArrows |
1399 | */ |
1400 | bool QTabWidget::documentMode() const |
1401 | { |
1402 | Q_D(const QTabWidget); |
1403 | return d->tabs->documentMode(); |
1404 | } |
1405 | |
1406 | void QTabWidget::setDocumentMode(bool enabled) |
1407 | { |
1408 | Q_D(QTabWidget); |
1409 | d->tabs->setDocumentMode(enabled); |
1410 | d->tabs->setExpanding(!enabled); |
1411 | d->tabs->setDrawBase(enabled); |
1412 | setUpLayout(); |
1413 | } |
1414 | |
1415 | /*! |
1416 | \property QTabWidget::tabBarAutoHide |
1417 | \brief If true, the tab bar is automatically hidden when it contains less |
1418 | than 2 tabs. |
1419 | \since 5.4 |
1420 | |
1421 | By default, this property is false. |
1422 | |
1423 | \sa QWidget::visible |
1424 | */ |
1425 | |
1426 | bool QTabWidget::tabBarAutoHide() const |
1427 | { |
1428 | Q_D(const QTabWidget); |
1429 | return d->tabs->autoHide(); |
1430 | } |
1431 | |
1432 | void QTabWidget::setTabBarAutoHide(bool enabled) |
1433 | { |
1434 | Q_D(QTabWidget); |
1435 | return d->tabs->setAutoHide(enabled); |
1436 | } |
1437 | |
1438 | /*! |
1439 | Removes all the pages, but does not delete them. Calling this function |
1440 | is equivalent to calling removeTab() until the tab widget is empty. |
1441 | */ |
1442 | void QTabWidget::clear() |
1443 | { |
1444 | // ### optimize by introduce QStackedLayout::clear() |
1445 | while (count()) |
1446 | removeTab(index: 0); |
1447 | } |
1448 | |
1449 | QT_END_NAMESPACE |
1450 | |
1451 | #include "moc_qtabwidget.cpp" |
1452 | |