1 /*
2  * Cantata
3  *
4  * Copyright (c) 2011-2020 Craig Drummond <craig.p.drummond@gmail.com>
5  */
6 
7 /**************************************************************************
8 **
9 ** This file is part of Qt Creator
10 **
11 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
12 **
13 ** Contact: Nokia Corporation (qt-info@nokia.com)
14 **
15 ** Commercial Usage
16 **
17 ** Licensees holding valid Qt Commercial licenses may use this file in
18 ** accordance with the Qt Commercial License Agreement provided with the
19 ** Software or, alternatively, in accordance with the terms contained in
20 ** a written agreement between you and Nokia.
21 **
22 ** GNU Lesser General Public License Usage
23 **
24 ** Alternatively, this file may be used under the terms of the GNU Lesser
25 ** General Public License version 2.1 as published by the Free Software
26 ** Foundation and appearing in the file LICENSE.LGPL included in the
27 ** packaging of this file.  Please review the following information to
28 ** ensure the GNU Lesser General Public License version 2.1 requirements
29 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
30 **
31 ** If you are unsure which license is appropriate for your use, please
32 ** contact the sales department at http://qt.nokia.com/contact.
33 **
34 **************************************************************************/
35 
36 #include "fancytabwidget.h"
37 #include "icon.h"
38 #include "action.h"
39 #include "utils.h"
40 #include "config.h"
41 #ifdef Q_OS_MAC
42 #include "osxstyle.h"
43 #endif
44 #include <QStyleOption>
45 #include <QHBoxLayout>
46 #include <QMouseEvent>
47 #include <QWheelEvent>
48 #include <QPainter>
49 #include <QSplitter>
50 #include <QStackedWidget>
51 #include <QToolButton>
52 #include <QToolTip>
53 #include <QVBoxLayout>
54 #include <QApplication>
55 #include <QSignalMapper>
56 #include <QMenu>
57 
sidebarSpacing(bool withText)58 static inline int sidebarSpacing(bool withText)
59 {
60     int sp=Utils::scaleForDpi(12);
61     if (!withText) {
62         sp*=1.25;
63     }
64     return sp;
65 }
66 
elideMode()67 static inline Qt::TextElideMode elideMode()
68 {
69     return Qt::LeftToRight==QApplication::layoutDirection() ? Qt::ElideRight : Qt::ElideLeft;
70 }
71 
72 static int largeIconSize=32;
73 static int smallIconSize=16;
setup()74 void FancyTabWidget::setup()
75 {
76     largeIconSize=Icon::stdSize(Utils::scaleForDpi(32));
77     smallIconSize=Icon::stdSize(Utils::scaleForDpi(16));
78 }
79 
iconSize(bool large)80 int FancyTabWidget::iconSize(bool large)
81 {
82     return large ? largeIconSize : smallIconSize;
83 }
84 
drawIcon(const QIcon & icon,const QRect & r,QPainter * p,const QSize & iconSize,bool selected)85 static void drawIcon(const QIcon &icon, const QRect &r, QPainter *p, const QSize &iconSize, bool selected)
86 {
87     #ifdef Q_OS_WIN
88     Q_UNUSED(selected);
89     QPixmap px = icon.pixmap(iconSize, QIcon::Normal);
90     #else
91     QPixmap px = icon.pixmap(iconSize, selected ? QIcon::Selected : QIcon::Normal);
92     #endif
93     QSize layoutSize = px.size() / px.DEVICE_PIXEL_RATIO();
94     p->drawPixmap(r.x()+(r.width()-layoutSize.width())/2.0, r.y()+(r.height()-layoutSize.height())/2.0, layoutSize.width(), layoutSize.height(), px);
95 }
96 
drawPrimitive(PrimitiveElement element,const QStyleOption * option,QPainter * p,const QWidget * widget) const97 void FancyTabProxyStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *p, const QWidget *widget) const
98 {
99     if (PE_FrameTabBarBase!=element) {
100         QProxyStyle::drawPrimitive(element, option, p, widget);
101     }
102 }
103 
drawControl(ControlElement element,const QStyleOption * option,QPainter * p,const QWidget * widget) const104 void FancyTabProxyStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *p, const QWidget *widget) const
105 {
106     const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab*>(option);
107 
108     if (element != CE_TabBarTab || !tabOpt) {
109         QProxyStyle::drawControl(element, option, p, widget);
110         return;
111     }
112 
113     const QRect rect = tabOpt->rect;
114     const bool selected = tabOpt->state&State_Selected;
115     const bool underMouse = tabOpt->state&State_MouseOver;
116     bool active = tabOpt->state&State_Active;
117     const bool verticalTabs = tabOpt->shape == QTabBar::RoundedWest;
118     const QString text = tabOpt->text;
119 
120     QTransform m;
121     if (verticalTabs) {
122         m = QTransform::fromTranslate(rect.left(), rect.bottom());
123         m.rotate(-90);
124     } else {
125         m = QTransform::fromTranslate(rect.left(), rect.top());
126     }
127 
128     const QRect draw_rect(QPoint(0, 0), m.mapRect(rect).size());
129 
130     p->save();
131     p->setTransform(m);
132 
133     QRect iconRect(QPoint(8, 0), tabOpt->iconSize);
134     QRect textRect(iconRect.topRight() + QPoint(4, 0), draw_rect.size());
135     textRect.setRight(draw_rect.width());
136     iconRect.translate(0, (draw_rect.height() - iconRect.height()) / 2);
137 
138     if (selected || underMouse) {
139         #ifdef Q_OS_MAC
140         QColor col = OSXStyle::self()->viewPalette().highlight().color();
141         #elif defined Q_OS_WIN
142         QColor col = active ? option->palette.highlight().color() : QColor(96, 96, 96);
143         col.setAlphaF(0.25);
144         #else
145         QColor col = option->palette.highlight().color();
146         #endif
147 
148         if (selected) {
149             #ifndef Q_OS_MAC
150             if (!active && option->palette.highlight().color()==QApplication::palette().color(QPalette::Active, QPalette::Highlight)) {
151                 active = true;
152             }
153             #endif
154         } else {
155             #if defined Q_OS_WIN
156             col.setAlphaF(0.1);
157             #else
158             col.setAlphaF(0.2);
159             #endif
160         }
161         p->fillRect(draw_rect, col);
162     }
163 
164     int textFlags = Qt::AlignTop | Qt::AlignVCenter;
165     #ifdef Q_OS_MAC
166     p->setPen(selected && active ? OSXStyle::self()->viewPalette().highlightedText().color() : OSXStyle::self()->viewPalette().windowText().color());
167     #elif defined Q_OS_WIN
168     p->setPen(QApplication::palette().windowText().color());
169     #else
170     p->setPen(selected && active ? QApplication::palette().highlightedText().color() : QApplication::palette().windowText().color());
171     #endif
172 
173     drawIcon(tabOpt->icon, iconRect, p, tabOpt->iconSize, selected && active);
174 
175     QString txt=text;
176     txt.replace("&", "");
177     txt=p->fontMetrics().elidedText(txt, elideMode(), textRect.width());
178     p->drawText(textRect.translated(0, -1), textFlags, txt);
179     p->restore();
180 }
181 
polish(QWidget * widget)182 void FancyTabProxyStyle::polish(QWidget* widget)
183 {
184     if (QLatin1String("QTabBar")==QString(widget->metaObject()->className())) {
185         widget->setMouseTracking(true);
186         widget->installEventFilter(this);
187     }
188     QProxyStyle::polish(widget);
189 }
190 
polish(QApplication * app)191 void FancyTabProxyStyle::polish(QApplication* app)
192 {
193     QProxyStyle::polish(app);
194 }
195 
polish(QPalette & palette)196 void FancyTabProxyStyle::polish(QPalette &palette)
197 {
198     QProxyStyle::polish(palette);
199 }
200 
eventFilter(QObject * o,QEvent * e)201 bool FancyTabProxyStyle::eventFilter(QObject* o, QEvent* e)
202 {
203     #ifndef Q_OS_MAC
204     QTabBar *bar = qobject_cast<QTabBar*>(o);
205     if (bar && (e->type() == QEvent::MouseMove || e->type() == QEvent::Leave)) {
206         QMouseEvent *event = static_cast<QMouseEvent*>(e);
207         const QString oldHoveredTab = bar->property("tab_hover").toString();
208         const QString hoveredTab = e->type() == QEvent::Leave ? QString() : bar->tabText(bar->tabAt(event->pos()));
209         bar->setProperty("tab_hover", hoveredTab);
210 
211         if (oldHoveredTab != hoveredTab) {
212             bar->update();
213         }
214     }
215     #endif
216 
217     return false;
218 }
219 
FancyTab(FancyTabBar * tabbar)220 FancyTab::FancyTab(FancyTabBar* tabbar)
221     : QWidget(tabbar), tabbar(tabbar), underMouse(false)
222 {
223     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
224     setAttribute(Qt::WA_Hover, true);
225 }
226 
FancyTabBar(QWidget * parent,bool text,int iSize,Pos pos)227 FancyTabBar::FancyTabBar(QWidget *parent, bool text, int iSize, Pos pos)
228     : QWidget(parent)
229     , withText(text)
230     , pos(pos)
231     , icnSize(iSize)
232 {
233     setFont(Utils::smallFont(font()));
234     setAttribute(Qt::WA_Hover, true);
235     setFocusPolicy(Qt::NoFocus);
236     setMouseTracking(true); // Needed for hover events
237     triggerTimer.setSingleShot(true);
238 
239     QBoxLayout* layout=nullptr;
240 
241     if (Side!=pos) {
242         setMinimumHeight(tabSizeHint().height());
243         setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
244         layout=new QHBoxLayout;
245     } else {
246         setMinimumWidth(tabSizeHint().width());
247         setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
248         layout=new QVBoxLayout;
249         layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::MinimumExpanding));
250     }
251 
252     layout->setSpacing(0);
253     layout->setContentsMargins(0, 0, 0, 0);
254     setLayout(layout);
255 
256     // We use a zerotimer to keep the sidebar responsive
257     connect(&triggerTimer, SIGNAL(timeout()), this, SLOT(emitCurrentIndex()));
258 }
259 
~FancyTabBar()260 FancyTabBar::~FancyTabBar()
261 {
262 }
263 
sizeHint() const264 QSize FancyTab::sizeHint() const
265 {
266     int iconSize = tabbar->iconSize();
267     bool withText = tabbar->showText();
268     int spacing = sidebarSpacing(withText);
269     int padding = FancyTabBar::Side==tabbar->position() ? Utils::scaleForDpi(12) : 0;
270     if (withText) {
271         QFontMetrics fm(font());
272         int textWidth = fm.horizontalAdvance(text)*1.1;
273         int width = qMax(iconSize, qMin(3*iconSize, textWidth)) + spacing;
274         return QSize(width, iconSize + spacing + fm.height() + padding);
275     } else {
276         return QSize(iconSize + spacing + padding, iconSize + spacing + padding);
277     }
278 }
279 
tabSizeHint() const280 QSize FancyTabBar::tabSizeHint() const
281 {
282     int spacing = sidebarSpacing(withText);
283     int padding = Side==pos ? Utils::scaleForDpi(12) : 0;
284     if (withText) {
285         QFontMetrics fm(font());
286         int maxTw=0;
287         for (FancyTab *tab: tabs) {
288             maxTw=qMax(maxTw, tab->sizeHint().width());
289         }
290         return QSize(qMax(icnSize + spacing, maxTw), icnSize + spacing + fm.height() + padding);
291     } else {
292         return QSize(icnSize + spacing + padding, icnSize + spacing + padding);
293     }
294 }
295 
paintEvent(QPaintEvent * event)296 void FancyTabBar::paintEvent(QPaintEvent *event)
297 {
298     Q_UNUSED(event)
299     QPainter p(this);
300 
301     for (int i = 0; i < count(); ++i) {
302         if (i != currentIndex()) {
303             paintTab(&p, i);
304         }
305     }
306 
307     // paint active tab last, since it overlaps the neighbors
308     if (currentIndex() != -1) {
309         paintTab(&p, currentIndex());
310     }
311 }
312 
enterEvent(QEvent *)313 void FancyTab::enterEvent(QEvent*)
314 {
315     underMouse = true;
316 }
317 
leaveEvent(QEvent *)318 void FancyTab::leaveEvent(QEvent*)
319 {
320     underMouse = false;
321 }
322 
sizeHint() const323 QSize FancyTabBar::sizeHint() const
324 {
325     QSize sh = tabSizeHint();
326     return Side!=pos
327             ? QSize(sh.width() * tabs.count(), sh.height())
328             : QSize(sh.width(), sh.height() * tabs.count());
329 }
330 
minimumSizeHint() const331 QSize FancyTabBar::minimumSizeHint() const
332 {
333     QSize sh = tabSizeHint();
334     return Side!=pos
335             ? QSize(sh.width() * tabs.count(), sh.height())
336             : QSize(sh.width(), sh.height() * tabs.count());
337 }
338 
tabRect(int index) const339 QRect FancyTabBar::tabRect(int index) const
340 {
341     return tabs[index]->geometry();
342 }
343 
tabToolTip(int index) const344 QString FancyTabBar::tabToolTip(int index) const
345 {
346     return tabs[index]->toolTip();
347 }
348 
setTabToolTip(int index,const QString & toolTip)349 void FancyTabBar::setTabToolTip(int index, const QString &toolTip)
350 {
351     tabs[index]->setToolTip(toolTip);
352 }
353 
354 // This keeps the sidebar responsive since
355 // we get a repaint before loading the
356 // mode itself
emitCurrentIndex()357 void FancyTabBar::emitCurrentIndex()
358 {
359     emit currentChanged(currentIdx);
360 }
361 
mousePressEvent(QMouseEvent * e)362 void FancyTabBar::mousePressEvent(QMouseEvent *e)
363 {
364     if (Qt::LeftButton!=e->button()) {
365         return;
366     }
367     e->accept();
368     for (int index = 0; index < tabs.count(); ++index) {
369         if (tabRect(index).contains(e->pos())) {
370             currentIdx = index;
371             update();
372             triggerTimer.start(0);
373             break;
374         }
375     }
376 }
377 
wheelEvent(QWheelEvent * ev)378 void FancyTabBar::wheelEvent(QWheelEvent *ev)
379 {
380     int numDegrees = ev->angleDelta().y() / 8;
381     int numSteps = numDegrees / -15;
382     int prevIndex = currentIdx;
383 
384     if (numSteps>0) {
385         currentIdx=qMin(currentIdx+numSteps, tabs.size()-1);
386     } else if (numSteps<0) {
387         currentIdx=qMax(currentIdx+numSteps, 0);
388     }
389     if (currentIdx!=prevIndex) {
390         update();
391         triggerTimer.start(0);
392     }
393     ev->accept();
394 }
395 
addTab(const QIcon & icon,const QString & label,const QString & tt)396 void FancyTabBar::addTab(const QIcon &icon, const QString &label, const QString &tt)
397 {
398     FancyTab *tab = new FancyTab(this);
399     tab->icon = icon;
400     tab->text = label;
401     tabs.append(tab);
402     if (!tt.isEmpty()) {
403         tab->setToolTip(tt);
404     } else if (!withText) {
405         tab->setToolTip(label);
406     }
407     qobject_cast<QBoxLayout*>(layout())->insertWidget(layout()->count()-(Side==pos ? 1 : 0), tab);
408 }
409 
addSpacer(int size)410 void FancyTabBar::addSpacer(int size)
411 {
412     qobject_cast<QVBoxLayout*>(layout())->insertSpacerItem(layout()->count()-1,
413                                                            new QSpacerItem(0, size, QSizePolicy::Fixed, QSizePolicy::Maximum));
414 }
415 
paintTab(QPainter * painter,int tabIndex) const416 void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
417 {
418     if (!validIndex(tabIndex)) {
419         qWarning("invalid index");
420         return;
421     }
422     painter->save();
423 
424     QRect rect = tabRect(tabIndex);
425     bool selected = (tabIndex == currentIdx);
426     bool underMouse = tabs[tabIndex]->underMouse;
427 
428     if (selected || underMouse) {
429         #ifdef Q_OS_MAC
430         QColor col = OSXStyle::self()->viewPalette().highlight().color();
431         #elif defined Q_OS_WIN
432         QColor col = palette().currentColorGroup()==QPalette::Active ? palette().highlight().color() : QColor(96, 96, 96);
433         col.setAlphaF(0.25);
434         #else
435         QColor col = palette().highlight().color();
436         #endif
437 
438         if (!selected) {
439             #if defined Q_OS_WIN
440             col.setAlphaF(0.1);
441             #else
442             col.setAlphaF(0.2);
443             #endif
444         }
445         painter->fillRect(rect, col);
446     }
447 
448     selected = selected && (palette().currentColorGroup()==QPalette::Active ||
449                            (palette().highlightedText().color()==palette().brush(QPalette::Active, QPalette::HighlightedText).color()));
450 
451     if (withText) {
452         QString tabText(painter->fontMetrics().elidedText(this->tabText(tabIndex), elideMode(), width()));
453         QRect tabTextRect(tabRect(tabIndex));
454         QRect tabIconRect(tabTextRect);
455         tabIconRect.adjust(+4, +4, -4, -4);
456         tabTextRect.translate(0, -2);
457 
458         #ifdef Q_OS_MAC
459         painter->setPen(selected ? OSXStyle::self()->viewPalette().highlightedText().color() : OSXStyle::self()->viewPalette().windowText().color());
460         #elif defined Q_OS_WIN
461         painter->setPen(QApplication::palette().windowText().color());
462         #else
463         painter->setPen(selected ? QApplication::palette().highlightedText().color() : QApplication::palette().windowText().color());
464         #endif
465         int textFlags = Qt::AlignCenter | Qt::AlignBottom;
466         painter->drawText(tabTextRect, textFlags, tabText);
467 
468         const int textHeight = painter->fontMetrics().height();
469         tabIconRect.adjust(0, 4, 0, -textHeight);
470         drawIcon(tabIcon(tabIndex), tabIconRect, painter, QSize(icnSize, icnSize), selected);
471     } else {
472         drawIcon(tabIcon(tabIndex), rect, painter, QSize(icnSize, icnSize), selected);
473     }
474 
475     painter->restore();
476 }
477 
setCurrentIndex(int index)478 void FancyTabBar::setCurrentIndex(int index)
479 {
480     currentIdx = index;
481     update();
482     emit currentChanged(currentIdx);
483 }
484 
FancyTabWidget(QWidget * parent)485 FancyTabWidget::FancyTabWidget(QWidget *parent)
486     : QWidget(parent)
487     , styleSetting(0)
488     , tabBar(nullptr)
489     , stack_(new QStackedWidget(this))
490     , sideWidget(new QWidget)
491     , sideLayout(new QVBoxLayout)
492     , topLayout(new QVBoxLayout)
493     , menu(nullptr)
494     , proxyStyle(new FancyTabProxyStyle)
495 {
496     sideLayout->setSpacing(0);
497     sideLayout->setMargin(0);
498     sideLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding));
499 
500     sideWidget->setLayout(sideLayout);
501     sideWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
502 
503     topLayout->setMargin(0);
504     topLayout->setSpacing(0);
505     topLayout->addWidget(stack_);
506 
507     QHBoxLayout *mainLayout = new QHBoxLayout;
508     mainLayout->setMargin(0);
509     mainLayout->setSpacing(0);
510     mainLayout->addWidget(sideWidget);
511     mainLayout->addLayout(topLayout);
512     setLayout(mainLayout);
513 }
514 
addTab(QWidget * tab,const QIcon & icon,const QString & label,const QString & tt,bool enabled)515 void FancyTabWidget::addTab(QWidget *tab, const QIcon &icon, const QString &label, const QString &tt, bool enabled)
516 {
517     stack_->addWidget(tab);
518     items << Item(icon, label, tt, enabled);
519     setMinimumWidth(128);
520 }
521 
currentIndex() const522 int FancyTabWidget::currentIndex() const
523 {
524     return stack_->currentIndex();
525 }
526 
currentWidget() const527 QWidget * FancyTabWidget::currentWidget() const
528 {
529     return stack_->currentWidget();
530 }
531 
widget(int index) const532 QWidget * FancyTabWidget::widget(int index) const
533 {
534     return stack_->widget(index);
535 }
536 
count() const537 int FancyTabWidget::count() const
538 {
539     return stack_->count();
540 }
541 
visibleCount() const542 int FancyTabWidget::visibleCount() const
543 {
544     int c=0;
545     for (const Item &i: items) {
546         if (i.enabled) {
547             c++;
548         }
549     }
550     return c;
551 }
552 
tabSize() const553 QSize FancyTabWidget::tabSize() const
554 {
555     if (FancyTabBar *bar = qobject_cast<FancyTabBar*>(tabBar)) {
556         return bar->tabSizeHint();
557     }
558     return QSize();
559 }
560 
setCurrentIndex(int idx)561 void FancyTabWidget::setCurrentIndex(int idx)
562 {
563     if (!isEnabled(idx)) {
564         return;
565     }
566     int index=IndexToTab(idx);
567     if (FancyTabBar* bar = qobject_cast<FancyTabBar*>(tabBar)) {
568         bar->setCurrentIndex(index);
569     } else if (QTabBar* bar = qobject_cast<QTabBar*>(tabBar)) {
570         bar->setCurrentIndex(index);
571         showWidget(index);
572     } else {
573         stack_->setCurrentIndex(idx); // ?? IS this *ever* called???
574     }
575 }
576 
showWidget(int index)577 void FancyTabWidget::showWidget(int index)
578 {
579     int idx=tabToIndex(index);
580     stack_->setCurrentIndex(idx);
581     emit currentChanged(idx);
582 }
583 
setStyle(int s)584 void FancyTabWidget::setStyle(int s)
585 {
586     if (s==styleSetting && tabBar) {
587         return;
588     }
589     // Remove previous tab bar
590     delete tabBar;
591     tabBar = nullptr;
592 
593     //   use_background_ = false;
594     // Create new tab bar
595     if (Tab==(s&Style_Mask) || (Small==(s&Style_Mask) && !(s&IconOnly))) {
596         switch (s&Position_Mask) {
597         default:
598         case Side:
599             makeTabBar(QApplication::isRightToLeft() ? QTabBar::RoundedEast : QTabBar::RoundedWest, !(s&IconOnly), true, Small==(s&Style_Mask));
600             break;
601         case Top:
602             makeTabBar(QTabBar::RoundedNorth, !(s&IconOnly), true, Small==(s&Style_Mask)); break;
603         case Bot:
604             makeTabBar(QTabBar::RoundedSouth, !(s&IconOnly), true, Small==(s&Style_Mask)); break;
605         }
606     } else {
607         FancyTabBar* bar = new FancyTabBar(this, !(s&IconOnly), Small==(s&Style_Mask) ? smallIconSize : largeIconSize,
608                                            Side==(s&Position_Mask) ? FancyTabBar::Side : (Top==(s&Position_Mask) ? FancyTabBar::Top : FancyTabBar::Bot));
609         switch (s&Position_Mask) {
610         default:
611         case Side: sideLayout->insertWidget(0, bar); break;
612         case Bot:  topLayout->insertWidget(1, bar); break;
613         case Top:  topLayout->insertWidget(0, bar); break;
614         }
615 
616         tabBar = bar;
617 
618         int index=0;
619         QList<Item>::Iterator it=items.begin();
620         QList<Item>::Iterator end=items.end();
621         for (; it!=end; ++it) {
622             if (!(*it).enabled) {
623                 (*it).index=-1;
624                 continue;
625             }
626             if (Item::Type_Spacer==(*it).type) {
627                 bar->addSpacer((*it).spacerSize);
628             } else {
629                 bar->addTab((*it).tabIcon, (*it).tabLabel, (*it).tabTooltip);
630             }
631             (*it).index=index++;
632         }
633 
634         bar->setCurrentIndex(IndexToTab(stack_->currentIndex()));
635         connect(bar, SIGNAL(currentChanged(int)), SLOT(showWidget(int)));
636     }
637     tabBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
638 
639     styleSetting = s;
640     emit styleChanged(s);
641     update();
642 }
643 
toggleTab(int tab,bool show)644 void FancyTabWidget::toggleTab(int tab, bool show)
645 {
646     if (tab>=0 && tab<items.count()) {
647         items[tab].enabled=show;
648         recreate();
649         emit tabToggled(tab);
650     }
651 }
652 
makeTabBar(QTabBar::Shape shape,bool text,bool icons,bool fancy)653 void FancyTabWidget::makeTabBar(QTabBar::Shape shape, bool text, bool icons, bool fancy)
654 {
655     QTabBar *bar = new QTabBar(this);
656     bar->setShape(shape);
657     bar->setDocumentMode(true);
658     bar->setUsesScrollButtons(true);
659 
660     if (QTabBar::RoundedWest==shape) {
661         bar->setIconSize(QSize(smallIconSize, smallIconSize));
662     }
663 
664     if (fancy) {
665         bar->setStyle(proxyStyle.data());
666     }
667 
668     if (QTabBar::RoundedNorth==shape) {
669         topLayout->insertWidget(0, bar);
670     } else if (QTabBar::RoundedSouth==shape) {
671         topLayout->insertWidget(1, bar);
672     } else {
673         sideLayout->insertWidget(0, bar);
674     }
675 
676     int index=0;
677     QList<Item>::Iterator it=items.begin();
678     QList<Item>::Iterator end=items.end();
679     for (; it!=end; ++it) {
680         if ((*it).type != Item::Type_Tab || !(*it).enabled) {
681             (*it).index=-1;
682             continue;
683         }
684 
685         QString label = (*it).tabLabel;
686         if (QTabBar::RoundedWest==shape) {
687             label = QFontMetrics(font()).elidedText(label, elideMode(), 120);
688         }
689 
690         int tabId = -1;
691         if (icons && text) {
692             tabId = bar->addTab((*it).tabIcon, label);
693         } else if (icons) {
694             tabId = bar->addTab((*it).tabIcon, QString());
695         } else if (text) {
696             tabId = bar->addTab(label);
697         }
698 
699         if (!(*it).tabTooltip.isEmpty()) {
700             bar->setTabToolTip(tabId, (*it).tabTooltip);
701         } else if (!text) {
702             bar->setTabToolTip(tabId, (*it).tabLabel);
703         }
704         (*it).index=index++;
705     }
706 
707     bar->setCurrentIndex(IndexToTab(stack_->currentIndex()));
708     connect(bar, SIGNAL(currentChanged(int)), SLOT(showWidget(int)));
709     tabBar = bar;
710 }
711 
tabToIndex(int tab) const712 int FancyTabWidget::tabToIndex(int tab) const
713 {
714     for (int i=0; i<items.count(); ++i) {
715         if (items[i].index==tab) {
716             return i;
717         }
718     }
719 
720     return 0;
721 }
722 
setIcon(int index,const QIcon & icon)723 void FancyTabWidget::setIcon(int index, const QIcon &icon)
724 {
725     if (index>-1 && index<items.count()) {
726         items[index].tabIcon=icon;
727     }
728 }
729 
setToolTip(int index,const QString & tt)730 void FancyTabWidget::setToolTip(int index, const QString &tt)
731 {
732     if (index>-1 && index<items.count()) {
733         Item &item=items[index];
734         item.tabTooltip=tt.isEmpty() ? item.tabLabel : tt;
735 
736         if (tabBar && -1!=item.index) {
737             if (qobject_cast<QTabBar *>(tabBar)) {
738                 static_cast<QTabBar *>(tabBar)->setTabToolTip(item.index, item.tabTooltip);
739             } else {
740                 static_cast<FancyTabBar *>(tabBar)->setTabToolTip(item.index, item.tabTooltip);
741             }
742         }
743     }
744 }
745 
recreate()746 void FancyTabWidget::recreate()
747 {
748     int s=styleSetting;
749     styleSetting=0;
750     setStyle(s);
751 }
752 
setHiddenPages(const QStringList & hidden)753 void FancyTabWidget::setHiddenPages(const QStringList &hidden)
754 {
755     QSet<QString> h=hidden.toSet();
756     if (h==hiddenPages().toSet()) {
757         return;
758     }
759     bool needToRecreate=false;
760     bool needToSetCurrent=false;
761     for (int i=0; i<count(); ++i) {
762         QWidget *w=widget(i);
763         if (w && items[i].enabled==hidden.contains(w->metaObject()->className())) {
764             items[i].enabled=!items[i].enabled;
765             emit tabToggled(i);
766             needToRecreate=true;
767             if (i==currentIndex()) {
768                 needToSetCurrent=true;
769             }
770         }
771     }
772     if (needToRecreate) {
773         recreate();
774     }
775     if (needToSetCurrent) {
776         for (int i=0; i<count(); ++i) {
777             QWidget *w=widget(i);
778             if (w && items[i].enabled) {
779                 setCurrentIndex(i);
780                 break;
781             }
782         }
783     }
784 }
785 
hiddenPages() const786 QStringList FancyTabWidget::hiddenPages() const
787 {
788     QStringList pages;
789     for (int i=0; i<count(); ++i) {
790         if (!isEnabled(i)) {
791             QWidget *w=widget(i);
792             if (w) {
793                 pages << w->metaObject()->className();
794             }
795         }
796     }
797     return pages;
798 }
799 
800 #include "moc_fancytabwidget.cpp"
801