LP-56 - Better txpid option namings, fix tabs-spaces, tooltips. headers, variable...
[librepilot.git] / ground / openpilotgcs / src / plugins / coreplugin / fancytabwidget.cpp
blob9b247b8c4190a776e446cc8750c07564de2e3369
1 /**
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
8 * @{
9 * @addtogroup CorePlugin Core Plugin
10 * @{
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
22 * for more details.
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>
34 #include <QDebug>
36 #include <QColorDialog>
37 #include <QHBoxLayout>
38 #include <QVBoxLayout>
39 #include <QMouseEvent>
40 #include <QStyleFactory>
41 #include <QPainter>
42 #include <QStackedLayout>
43 #include <QStatusBar>
44 #include <QToolTip>
46 using namespace Core;
47 using namespace Internal;
49 const int FancyTabBar::m_rounding = 22;
50 const int FancyTabBar::m_textPadding = 4;
52 void FancyTab::fadeIn()
54 animator.stop();
55 animator.setDuration(80);
56 animator.setEndValue(40);
57 animator.start();
60 void FancyTab::fadeOut()
62 animator.stop();
63 animator.setDuration(160);
64 animator.setEndValue(0);
65 animator.start();
68 void FancyTab::setFader(float value)
70 m_fader = value;
71 tabbar->update();
74 FancyTabBar::FancyTabBar(QWidget *parent)
75 : QWidget(parent)
77 m_hoverIndex = -1;
78 m_currentIndex = -1;
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()
93 delete style();
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);
103 int spacing = 8;
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)
118 Q_UNUSED(event)
119 QPainter p(this);
121 for (int i = 0; i < count(); ++i) {
122 if (i != currentIndex()) {
123 paintTab(&p, i);
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)
136 int newHover = -1;
138 for (int i = 0; i < count(); ++i) {
139 QRect area = tabRect(i);
140 if (area.contains(e->pos())) {
141 newHover = i;
142 break;
145 if (newHover == m_hoverIndex) {
146 return;
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);
166 if (!tt.isEmpty()) {
167 QToolTip::showText(static_cast<QHelpEvent *>(event)->globalPos(), tt, this);
168 return true;
172 return QWidget::event(event);
175 // Resets hover animation on mouse enter
176 void FancyTabBar::enterEvent(QEvent *e)
178 Q_UNUSED(e)
179 m_hoverRect = QRect();
180 m_hoverIndex = -1;
183 // Resets hover animation on mouse enter
184 void FancyTabBar::leaveEvent(QEvent *e)
186 Q_UNUSED(e)
187 m_hoverIndex = -1;
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
221 // mode itself
222 void FancyTabBar::emitCurrentIndex()
224 emit currentChanged(m_currentIndex);
227 void FancyTabBar::mousePressEvent(QMouseEvent *e)
229 e->accept();
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;
234 update();
235 m_triggerTimer.start(0);
237 break;
242 void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
244 if (!validIndex(tabIndex)) {
245 qWarning("invalid index");
246 return;
248 painter->save();
250 QRect rect = tabRect(tabIndex);
251 bool selected = (tabIndex == m_currentIndex);
252 bool enabled = isTabEnabled(tabIndex);
254 if (selected) {
255 // background
256 painter->save();
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);
261 painter->restore();
263 // shadows
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());
270 // highlights
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;
291 if (enabled) {
292 painter->drawText(tabTextRect, textFlags, tabText);
293 painter->setPen(selected ? QColor(60, 60, 60) : Utils::StyleHelper::panelTextColor());
294 } else {
295 painter->setPen(selected ? Utils::StyleHelper::panelTextColor() : QColor(255, 255, 255, 120));
297 if (!Utils::HostOsInfo::isMacHost() && !selected && enabled) {
298 painter->save();
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());
308 painter->restore();
311 if (!enabled) {
312 painter->setOpacity(0.7);
315 if (drawIcon) {
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);
323 painter->restore();
326 void FancyTabBar::setCurrentIndex(int index)
328 if (isTabEnabled(index)) {
329 m_currentIndex = index;
330 update();
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;
355 return false;
359 //////
360 // FancyColorButton
361 //////
363 class FancyColorButton : public QWidget {
364 public:
365 FancyColorButton(QWidget *parent)
366 : m_parent(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);
380 private:
381 QWidget *m_parent;
384 //////
385 // FancyTabWidget
386 //////
388 FancyTabWidget::FancyTabWidget(QWidget *parent)
389 : 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)
476 Q_UNUSED(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
516 return m_statusBar;
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);