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