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 #ifndef QTABBAR_P_H
41 #define QTABBAR_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtWidgets/private/qtwidgetsglobal_p.h>
55 #include "qtabbar.h"
56 #include "private/qwidget_p.h"
57 
58 #include <qicon.h>
59 #include <qtoolbutton.h>
60 #include <qdebug.h>
61 #if QT_CONFIG(animation)
62 #include <qvariantanimation.h>
63 #endif
64 
65 #define ANIMATION_DURATION 250
66 
67 #include <qstyleoption.h>
68 
69 QT_REQUIRE_CONFIG(tabbar);
70 
71 QT_BEGIN_NAMESPACE
72 
73 class QMovableTabWidget : public QWidget
74 {
75 public:
76     explicit QMovableTabWidget(QWidget *parent = nullptr);
77     void setPixmap(const QPixmap &pixmap);
78 
79 protected:
80     void paintEvent(QPaintEvent *e) override;
81 
82 private:
83     QPixmap m_pixmap;
84 };
85 
86 class Q_WIDGETS_EXPORT QTabBarPrivate : public QWidgetPrivate
87 {
Q_DECLARE_PUBLIC(QTabBar)88     Q_DECLARE_PUBLIC(QTabBar)
89 public:
90     QTabBarPrivate()
91         :currentIndex(-1), pressedIndex(-1), firstVisible(0), lastVisible(-1), shape(QTabBar::RoundedNorth), layoutDirty(false),
92         drawBase(true), scrollOffset(0), hoverIndex(-1), elideModeSetByUser(false), useScrollButtonsSetByUser(false), expanding(true), closeButtonOnTabs(false),
93         selectionBehaviorOnRemove(QTabBar::SelectRightTab), paintWithOffsets(true), movable(false),
94         dragInProgress(false), documentMode(false), autoHide(false), changeCurrentOnDrag(false),
95         switchTabCurrentIndex(-1), switchTabTimerId(0), movingTab(nullptr)
96         {}
97 
98     int currentIndex;
99     int pressedIndex;
100     int firstVisible;
101     int lastVisible;
102     QTabBar::Shape shape;
103     bool layoutDirty;
104     bool drawBase;
105     int scrollOffset;
106 
107     struct Tab {
TabTab108         inline Tab(const QIcon &ico, const QString &txt)
109             : enabled(true) , visible(true), shortcutId(0), text(txt), icon(ico),
110             leftWidget(nullptr), rightWidget(nullptr), lastTab(-1), dragOffset(0)
111 #if QT_CONFIG(animation)
112             , animation(nullptr)
113 #endif // animation
114         {}
115         bool operator==(const Tab &other) const { return &other == this; }
116         bool enabled;
117         bool visible;
118         int shortcutId;
119         QString text;
120 #ifndef QT_NO_TOOLTIP
121         QString toolTip;
122 #endif
123 #if QT_CONFIG(whatsthis)
124         QString whatsThis;
125 #endif
126         QIcon icon;
127         QRect rect;
128         QRect minRect;
129         QRect maxRect;
130 
131         QColor textColor;
132         QVariant data;
133         QWidget *leftWidget;
134         QWidget *rightWidget;
135         int lastTab;
136         int dragOffset;
137 #ifndef QT_NO_ACCESSIBILITY
138         QString accessibleName;
139 #endif
140 
141 #if QT_CONFIG(animation)
~TabTab142         ~Tab() { delete animation; }
143         struct TabBarAnimation : public QVariantAnimation {
TabBarAnimationTab::TabBarAnimation144             TabBarAnimation(Tab *t, QTabBarPrivate *_priv) : tab(t), priv(_priv)
145             { setEasingCurve(QEasingCurve::InOutQuad); }
146 
147             void updateCurrentValue(const QVariant &current) override;
148 
149             void updateState(State newState, State) override;
150         private:
151             //these are needed for the callbacks
152             Tab *tab;
153             QTabBarPrivate *priv;
154         } *animation;
155 
startAnimationTab156         void startAnimation(QTabBarPrivate *priv, int duration) {
157             if (!priv->isAnimated()) {
158                 priv->moveTabFinished(priv->tabList.indexOf(*this));
159                 return;
160             }
161             if (!animation)
162                 animation = new TabBarAnimation(this, priv);
163             animation->setStartValue(dragOffset);
164             animation->setEndValue(0);
165             animation->setDuration(duration);
166             animation->start();
167         }
168 #else
startAnimationTab169         void startAnimation(QTabBarPrivate *priv, int duration)
170         { Q_UNUSED(duration); priv->moveTabFinished(priv->tabList.indexOf(*this)); }
171 #endif // animation
172     };
173     QList<Tab> tabList;
174     mutable QHash<QString, QSize> textSizes;
175 
176     void calculateFirstLastVisible(int index, bool visible, bool remove);
177     int selectNewCurrentIndexFrom(int currentIndex);
178     int calculateNewPosition(int from, int to, int index) const;
179     void slide(int from, int to);
180     void init();
181 
182     Tab *at(int index);
183     const Tab *at(int index) const;
184 
185     int indexAtPos(const QPoint &p) const;
186 
isAnimated()187     inline bool isAnimated() const { Q_Q(const QTabBar); return q->style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, q) > 0; }
validIndex(int index)188     inline bool validIndex(int index) const { return index >= 0 && index < tabList.count(); }
189     void setCurrentNextEnabledIndex(int offset);
190 
191     QToolButton* rightB; // right or bottom
192     QToolButton* leftB; // left or top
193 
194     void _q_scrollTabs();
195     void _q_closeTab();
196     void moveTab(int index, int offset);
197     void moveTabFinished(int index);
198     QRect hoverRect;
199     int hoverIndex;
200 
201     void refresh();
202     void layoutTabs();
203     void layoutWidgets(int start = 0);
204     void layoutTab(int index);
205     void updateMacBorderMetrics();
206     bool isTabInMacUnifiedToolbarArea() const;
207     void setupMovableTab();
208     void autoHideTabs();
209     QRect normalizedScrollRect(int index = -1);
210     int hoveredTabIndex() const;
211 
212     void initBasicStyleOption(QStyleOptionTab *option, int tabIndex) const;
213 
214     void makeVisible(int index);
215     QSize iconSize;
216     Qt::TextElideMode elideMode;
217     bool elideModeSetByUser;
218     bool useScrollButtons;
219     bool useScrollButtonsSetByUser;
220 
221     bool expanding;
222     bool closeButtonOnTabs;
223     QTabBar::SelectionBehavior selectionBehaviorOnRemove;
224 
225     QPoint dragStartPosition;
226     bool paintWithOffsets;
227     bool movable;
228     bool dragInProgress;
229     bool documentMode;
230     bool autoHide;
231     bool changeCurrentOnDrag;
232 
233     int switchTabCurrentIndex;
234     int switchTabTimerId;
235 
236     QMovableTabWidget *movingTab;
237     // shared by tabwidget and qtabbar
initStyleBaseOption(QStyleOptionTabBarBase * optTabBase,QTabBar * tabbar,QSize size)238     static void initStyleBaseOption(QStyleOptionTabBarBase *optTabBase, QTabBar *tabbar, QSize size)
239     {
240         QStyleOptionTab tabOverlap;
241         tabOverlap.shape = tabbar->shape();
242         int overlap = tabbar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap, tabbar);
243         QWidget *theParent = tabbar->parentWidget();
244         optTabBase->init(tabbar);
245         optTabBase->shape = tabbar->shape();
246         optTabBase->documentMode = tabbar->documentMode();
247         if (theParent && overlap > 0) {
248             QRect rect;
249             switch (tabOverlap.shape) {
250             case QTabBar::RoundedNorth:
251             case QTabBar::TriangularNorth:
252                 rect.setRect(0, size.height()-overlap, size.width(), overlap);
253                 break;
254             case QTabBar::RoundedSouth:
255             case QTabBar::TriangularSouth:
256                 rect.setRect(0, 0, size.width(), overlap);
257                 break;
258             case QTabBar::RoundedEast:
259             case QTabBar::TriangularEast:
260                 rect.setRect(0, 0, overlap, size.height());
261                 break;
262             case QTabBar::RoundedWest:
263             case QTabBar::TriangularWest:
264                 rect.setRect(size.width() - overlap, 0, overlap, size.height());
265                 break;
266             }
267             optTabBase->rect = rect;
268         }
269     }
270 
271     void killSwitchTabTimer();
272 
273 };
274 
275 QT_END_NAMESPACE
276 
277 #endif
278