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 ¤t) 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