2 ******************************************************************************
4 * @file fancytabwidget.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
7 * @addtogroup GCSPlugins GCS Plugins
9 * @addtogroup CorePlugin Core Plugin
11 * @brief The Core GCS plugin
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "fancytabwidget.h"
30 #include <utils/hostosinfo.h>
31 #include <utils/stylehelper.h>
32 #include <utils/styledbar.h>
36 #include <QColorDialog>
37 #include <QHBoxLayout>
38 #include <QVBoxLayout>
39 #include <QMouseEvent>
40 #include <QStyleFactory>
42 #include <QStackedLayout>
47 using namespace Internal
;
49 const int FancyTabBar::m_rounding
= 22;
50 const int FancyTabBar::m_textPadding
= 4;
52 void FancyTab::fadeIn()
55 animator
.setDuration(80);
56 animator
.setEndValue(40);
60 void FancyTab::fadeOut()
63 animator
.setDuration(160);
64 animator
.setEndValue(0);
68 void FancyTab::setFader(float value
)
74 FancyTabBar::FancyTabBar(QWidget
*parent
)
79 setSizePolicy(QSizePolicy::Preferred
, QSizePolicy::Expanding
);
80 setStyle(QStyleFactory::create(QLatin1String("windows")));
81 setMinimumWidth(qMax(2 * m_rounding
, 40));
82 setAttribute(Qt::WA_Hover
, true);
83 setFocusPolicy(Qt::NoFocus
);
84 setMouseTracking(true); // Needed for hover events
85 m_triggerTimer
.setSingleShot(true);
87 // We use a zerotimer to keep the sidebar responsive
88 connect(&m_triggerTimer
, SIGNAL(timeout()), this, SLOT(emitCurrentIndex()));
91 FancyTabBar::~FancyTabBar()
96 QSize
FancyTabBar::tabSizeHint(bool minimum
) const
98 QFont
boldFont(font());
100 boldFont
.setPointSizeF(Utils::StyleHelper::sidebarFontSize());
101 boldFont
.setBold(true);
102 QFontMetrics
fm(boldFont
);
104 int width
= 60 + spacing
+ 2;
105 int maxLabelwidth
= 0;
106 for (int tab
= 0; tab
< count(); ++tab
) {
107 int width
= fm
.width(tabText(tab
));
108 if (width
> maxLabelwidth
) {
109 maxLabelwidth
= width
;
112 int iconHeight
= minimum
? 0 : 32;
113 return QSize(qMax(width
, maxLabelwidth
+ 4), iconHeight
+ spacing
+ fm
.height());
116 void FancyTabBar::paintEvent(QPaintEvent
*event
)
121 for (int i
= 0; i
< count(); ++i
) {
122 if (i
!= currentIndex()) {
127 // paint active tab last, since it overlaps the neighbors
128 if (currentIndex() != -1) {
129 paintTab(&p
, currentIndex());
133 // Handle hover events for mouse fade ins
134 void FancyTabBar::mouseMoveEvent(QMouseEvent
*e
)
138 for (int i
= 0; i
< count(); ++i
) {
139 QRect area
= tabRect(i
);
140 if (area
.contains(e
->pos())) {
145 if (newHover
== m_hoverIndex
) {
149 if (validIndex(m_hoverIndex
)) {
150 m_tabs
[m_hoverIndex
]->fadeOut();
153 m_hoverIndex
= newHover
;
155 if (validIndex(m_hoverIndex
)) {
156 m_tabs
[m_hoverIndex
]->fadeIn();
157 m_hoverRect
= tabRect(m_hoverIndex
);
161 bool FancyTabBar::event(QEvent
*event
)
163 if (event
->type() == QEvent::ToolTip
) {
164 if (validIndex(m_hoverIndex
)) {
165 QString tt
= tabToolTip(m_hoverIndex
);
167 QToolTip::showText(static_cast<QHelpEvent
*>(event
)->globalPos(), tt
, this);
172 return QWidget::event(event
);
175 // Resets hover animation on mouse enter
176 void FancyTabBar::enterEvent(QEvent
*e
)
179 m_hoverRect
= QRect();
183 // Resets hover animation on mouse enter
184 void FancyTabBar::leaveEvent(QEvent
*e
)
188 m_hoverRect
= QRect();
189 for (int i
= 0; i
< m_tabs
.count(); ++i
) {
190 m_tabs
[i
]->fadeOut();
194 QSize
FancyTabBar::sizeHint() const
196 QSize sh
= tabSizeHint();
198 return QSize(sh
.width(), sh
.height() * m_tabs
.count());
201 QSize
FancyTabBar::minimumSizeHint() const
203 QSize sh
= tabSizeHint(true);
205 return QSize(sh
.width(), sh
.height() * m_tabs
.count());
208 QRect
FancyTabBar::tabRect(int index
) const
210 QSize sh
= tabSizeHint();
212 if (sh
.height() * m_tabs
.count() > height()) {
213 sh
.setHeight(height() / m_tabs
.count());
216 return QRect(0, index
* sh
.height(), sh
.width(), sh
.height());
219 // This keeps the sidebar responsive since
220 // we get a repaint before loading the
222 void FancyTabBar::emitCurrentIndex()
224 emit
currentChanged(m_currentIndex
);
227 void FancyTabBar::mousePressEvent(QMouseEvent
*e
)
230 for (int index
= 0; index
< m_tabs
.count(); ++index
) {
231 if (tabRect(index
).contains(e
->pos())) {
232 if (isTabEnabled(index
)) {
233 m_currentIndex
= index
;
235 m_triggerTimer
.start(0);
242 void FancyTabBar::paintTab(QPainter
*painter
, int tabIndex
) const
244 if (!validIndex(tabIndex
)) {
245 qWarning("invalid index");
250 QRect rect
= tabRect(tabIndex
);
251 bool selected
= (tabIndex
== m_currentIndex
);
252 bool enabled
= isTabEnabled(tabIndex
);
257 QLinearGradient
grad(rect
.topLeft(), rect
.topRight());
258 grad
.setColorAt(0, QColor(255, 255, 255, 140));
259 grad
.setColorAt(1, QColor(255, 255, 255, 210));
260 painter
->fillRect(rect
.adjusted(0, 0, 0, -1), grad
);
264 painter
->setPen(QColor(0, 0, 0, 110));
265 painter
->drawLine(rect
.topLeft() + QPoint(1, -1), rect
.topRight() - QPoint(0, 1));
266 painter
->drawLine(rect
.bottomLeft(), rect
.bottomRight());
267 painter
->setPen(QColor(0, 0, 0, 40));
268 painter
->drawLine(rect
.topLeft(), rect
.bottomLeft());
271 painter
->setPen(QColor(255, 255, 255, 50));
272 painter
->drawLine(rect
.topLeft() + QPoint(0, -2), rect
.topRight() - QPoint(0, 2));
273 painter
->drawLine(rect
.bottomLeft() + QPoint(0, 1), rect
.bottomRight() + QPoint(0, 1));
274 painter
->setPen(QColor(255, 255, 255, 40));
275 painter
->drawLine(rect
.topLeft() + QPoint(0, 0), rect
.topRight());
276 painter
->drawLine(rect
.topRight() + QPoint(0, 1), rect
.bottomRight() - QPoint(0, 1));
277 painter
->drawLine(rect
.bottomLeft() + QPoint(0, -1), rect
.bottomRight() - QPoint(0, 1));
280 QString
tabText(this->tabText(tabIndex
));
281 QRect
tabTextRect(rect
);
282 const bool drawIcon
= rect
.height() > 36;
283 QRect
tabIconRect(tabTextRect
);
284 tabTextRect
.translate(0, drawIcon
? -2 : 1);
285 QFont
boldFont(painter
->font());
286 boldFont
.setPointSizeF(Utils::StyleHelper::sidebarFontSize());
287 boldFont
.setBold(true);
288 painter
->setFont(boldFont
);
289 painter
->setPen(selected
? QColor(255, 255, 255, 160) : QColor(0, 0, 0, 110));
290 const int textFlags
= Qt::AlignCenter
| (drawIcon
? Qt::AlignBottom
: Qt::AlignVCenter
) | Qt::TextWordWrap
;
292 painter
->drawText(tabTextRect
, textFlags
, tabText
);
293 painter
->setPen(selected
? QColor(60, 60, 60) : Utils::StyleHelper::panelTextColor());
295 painter
->setPen(selected
? Utils::StyleHelper::panelTextColor() : QColor(255, 255, 255, 120));
297 if (!Utils::HostOsInfo::isMacHost() && !selected
&& enabled
) {
299 int fader
= int(m_tabs
[tabIndex
]->fader());
300 QLinearGradient
grad(rect
.topLeft(), rect
.topRight());
301 grad
.setColorAt(0, Qt::transparent
);
302 grad
.setColorAt(0.5, QColor(255, 255, 255, fader
));
303 grad
.setColorAt(1, Qt::transparent
);
304 painter
->fillRect(rect
, grad
);
305 painter
->setPen(QPen(grad
, 1.0));
306 painter
->drawLine(rect
.topLeft(), rect
.topRight());
307 painter
->drawLine(rect
.bottomLeft(), rect
.bottomRight());
312 painter
->setOpacity(0.7);
316 int textHeight
= painter
->fontMetrics().boundingRect(QRect(0, 0, width(), height()), Qt::TextWordWrap
, tabText
).height();
317 tabIconRect
.adjust(0, 4, 0, -textHeight
);
318 Utils::StyleHelper::drawIconWithShadow(tabIcon(tabIndex
), tabIconRect
, painter
, enabled
? QIcon::Normal
: QIcon::Disabled
);
321 painter
->translate(0, -1);
322 painter
->drawText(tabTextRect
, textFlags
, tabText
);
326 void FancyTabBar::setCurrentIndex(int index
)
328 if (isTabEnabled(index
)) {
329 m_currentIndex
= index
;
331 emit
currentChanged(m_currentIndex
);
335 void FancyTabBar::setTabEnabled(int index
, bool enable
)
337 Q_ASSERT(index
< m_tabs
.size());
338 Q_ASSERT(index
>= 0);
340 if (index
< m_tabs
.size() && index
>= 0) {
341 m_tabs
[index
]->enabled
= enable
;
342 update(tabRect(index
));
346 bool FancyTabBar::isTabEnabled(int index
) const
348 Q_ASSERT(index
< m_tabs
.size());
349 Q_ASSERT(index
>= 0);
351 if (index
< m_tabs
.size() && index
>= 0) {
352 return m_tabs
[index
]->enabled
;
363 class FancyColorButton
: public QWidget
{
365 FancyColorButton(QWidget
*parent
)
368 setSizePolicy(QSizePolicy::MinimumExpanding
, QSizePolicy::Preferred
);
371 void mousePressEvent(QMouseEvent
*ev
)
373 if (ev
->modifiers() & Qt::ShiftModifier
) {
374 QColor color
= QColorDialog::getColor(Utils::StyleHelper::requestedBaseColor(), m_parent
);
375 if (color
.isValid()) {
376 Utils::StyleHelper::setBaseColor(color
);
388 FancyTabWidget::FancyTabWidget(QWidget
*parent
)
391 m_tabBar
= new FancyTabBar(this);
393 m_selectionWidget
= new QWidget(this);
394 QVBoxLayout
*selectionLayout
= new QVBoxLayout
;
395 selectionLayout
->setSpacing(0);
396 selectionLayout
->setMargin(0);
398 Utils::StyledBar
*bar
= new Utils::StyledBar
;
399 QHBoxLayout
*layout
= new QHBoxLayout(bar
);
400 layout
->setMargin(0);
401 layout
->setSpacing(0);
402 layout
->addWidget(new FancyColorButton(this));
403 selectionLayout
->addWidget(bar
);
405 selectionLayout
->addWidget(m_tabBar
, 1);
406 m_selectionWidget
->setLayout(selectionLayout
);
407 m_selectionWidget
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Expanding
);
409 m_cornerWidgetContainer
= new QWidget(this);
410 m_cornerWidgetContainer
->setSizePolicy(QSizePolicy::Minimum
, QSizePolicy::Preferred
);
411 m_cornerWidgetContainer
->setAutoFillBackground(false);
413 QVBoxLayout
*cornerWidgetLayout
= new QVBoxLayout
;
414 cornerWidgetLayout
->setSpacing(0);
415 cornerWidgetLayout
->setMargin(0);
416 cornerWidgetLayout
->addStretch();
417 m_cornerWidgetContainer
->setLayout(cornerWidgetLayout
);
419 selectionLayout
->addWidget(m_cornerWidgetContainer
, 0);
421 m_modesStack
= new QStackedLayout
;
422 m_statusBar
= new QStatusBar
;
423 m_statusBar
->setSizePolicy(QSizePolicy::Ignored
, QSizePolicy::Fixed
);
425 QVBoxLayout
*vlayout
= new QVBoxLayout
;
426 vlayout
->setMargin(0);
427 vlayout
->setSpacing(0);
428 vlayout
->addLayout(m_modesStack
);
429 vlayout
->addWidget(m_statusBar
);
431 QHBoxLayout
*mainLayout
= new QHBoxLayout
;
432 mainLayout
->setMargin(0);
433 mainLayout
->setSpacing(1);
434 mainLayout
->addWidget(m_selectionWidget
);
435 mainLayout
->addLayout(vlayout
);
436 setLayout(mainLayout
);
438 connect(m_tabBar
, SIGNAL(currentChanged(int)), this, SLOT(showWidget(int)));
441 void FancyTabWidget::setSelectionWidgetVisible(bool visible
)
443 m_selectionWidget
->setVisible(visible
);
446 bool FancyTabWidget::isSelectionWidgetVisible() const
448 return m_selectionWidget
->isVisible();
451 void FancyTabWidget::insertTab(int index
, QWidget
*tab
, const QIcon
&icon
, const QString
&label
)
453 m_modesStack
->insertWidget(index
, tab
);
454 m_tabBar
->insertTab(index
, icon
, label
);
457 void FancyTabWidget::removeTab(int index
)
459 m_modesStack
->removeWidget(m_modesStack
->widget(index
));
460 m_tabBar
->removeTab(index
);
463 void FancyTabWidget::setBackgroundBrush(const QBrush
&brush
)
465 QPalette pal
= m_tabBar
->palette();
467 pal
.setBrush(QPalette::Mid
, brush
);
468 m_tabBar
->setPalette(pal
);
469 pal
= m_cornerWidgetContainer
->palette();
470 pal
.setBrush(QPalette::Mid
, brush
);
471 m_cornerWidgetContainer
->setPalette(pal
);
474 void FancyTabWidget::paintEvent(QPaintEvent
*event
)
477 if (m_selectionWidget
->isVisible()) {
478 QPainter
painter(this);
480 QRect rect
= m_selectionWidget
->rect().adjusted(0, 0, 1, 0);
481 rect
= style()->visualRect(layoutDirection(), geometry(), rect
);
482 Utils::StyleHelper::verticalGradient(&painter
, rect
, rect
);
483 painter
.setPen(Utils::StyleHelper::borderColor());
484 painter
.drawLine(rect
.topRight(), rect
.bottomRight());
486 QColor light
= Utils::StyleHelper::sidebarHighlight();
487 painter
.setPen(light
);
488 painter
.drawLine(rect
.bottomLeft(), rect
.bottomRight());
492 void FancyTabWidget::insertCornerWidget(int pos
, QWidget
*widget
)
494 QVBoxLayout
*layout
= static_cast<QVBoxLayout
*>(m_cornerWidgetContainer
->layout());
496 layout
->insertWidget(pos
, widget
);
499 int FancyTabWidget::cornerWidgetCount() const
501 return m_cornerWidgetContainer
->layout()->count();
504 void FancyTabWidget::addCornerWidget(QWidget
*widget
)
506 m_cornerWidgetContainer
->layout()->addWidget(widget
);
509 int FancyTabWidget::currentIndex() const
511 return m_tabBar
->currentIndex();
514 QStatusBar
*FancyTabWidget::statusBar() const
519 void FancyTabWidget::setCurrentIndex(int index
)
521 if (m_tabBar
->isTabEnabled(index
)) {
522 m_tabBar
->setCurrentIndex(index
);
526 void FancyTabWidget::showWidget(int index
)
528 emit
currentAboutToShow(index
);
530 m_modesStack
->setCurrentIndex(index
);
531 emit
currentChanged(index
);
534 void FancyTabWidget::setTabToolTip(int index
, const QString
&toolTip
)
536 m_tabBar
->setTabToolTip(index
, toolTip
);
539 void FancyTabWidget::setTabEnabled(int index
, bool enable
)
541 m_tabBar
->setTabEnabled(index
, enable
);
544 bool FancyTabWidget::isTabEnabled(int index
) const
546 return m_tabBar
->isTabEnabled(index
);