diff --git a/src/plugins/projectexplorer/doubletabwidget.cpp b/src/plugins/projectexplorer/doubletabwidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05e5fbaa07e96b139bda23b3f573c100485bf2e7 --- /dev/null +++ b/src/plugins/projectexplorer/doubletabwidget.cpp @@ -0,0 +1,267 @@ +#include "doubletabwidget.h" +#include "ui_doubletabwidget.h" + +#include <utils/stylehelper.h> + +#include <QtCore/QRect> +#include <QtGui/QPainter> +#include <QtGui/QFont> +#include <QtGui/QMouseEvent> + +using namespace ProjectExplorer::Internal; + +static const int MIN_LEFT_MARGIN = 50; +static const int MARGIN = 12; +static const int OTHER_HEIGHT = 38; +static const int SELECTION_IMAGE_WIDTH = 10; +static const int SELECTION_IMAGE_HEIGHT = 20; + +static void drawFirstLevelSeparator(QPainter *painter, QPoint top, QPoint bottom) +{ + QLinearGradient grad(top, bottom); + grad.setColorAt(0, QColor(255, 255, 255, 20)); + grad.setColorAt(0.4, QColor(255, 255, 255, 60)); + grad.setColorAt(0.7, QColor(255, 255, 255, 50)); + grad.setColorAt(1, QColor(255, 255, 255, 40)); + painter->setPen(QPen(grad, 0)); + painter->drawLine(top, bottom); + grad.setColorAt(0, QColor(0, 0, 0, 30)); + grad.setColorAt(0.4, QColor(0, 0, 0, 70)); + grad.setColorAt(0.7, QColor(0, 0, 0, 70)); + grad.setColorAt(1, QColor(0, 0, 0, 40)); + painter->setPen(QPen(grad, 0)); + painter->drawLine(top - QPoint(1,0), bottom - QPoint(1,0)); +} + +static void drawSecondLevelSeparator(QPainter *painter, QPoint top, QPoint bottom) +{ + QLinearGradient grad(top, bottom); + grad.setColorAt(0, QColor(255, 255, 255, 0)); + grad.setColorAt(0.4, QColor(255, 255, 255, 100)); + grad.setColorAt(0.7, QColor(255, 255, 255, 100)); + grad.setColorAt(1, QColor(255, 255, 255, 0)); + painter->setPen(QPen(grad, 0)); + painter->drawLine(top, bottom); + grad.setColorAt(0, QColor(0, 0, 0, 0)); + grad.setColorAt(0.4, QColor(0, 0, 0, 100)); + grad.setColorAt(0.7, QColor(0, 0, 0, 100)); + grad.setColorAt(1, QColor(0, 0, 0, 0)); + painter->setPen(QPen(grad, 0)); + painter->drawLine(top - QPoint(1,0), bottom - QPoint(1,0)); +} + +DoubleTabWidget::DoubleTabWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::DoubleTabWidget), + m_currentIndex(-1) +{ + ui->setupUi(this); +} + +DoubleTabWidget::~DoubleTabWidget() +{ + delete ui; +} + +void DoubleTabWidget::setTitle(const QString &title) +{ + m_title = title; + update(); +} + +QSize DoubleTabWidget::minimumSizeHint() const +{ + return QSize(0, Utils::StyleHelper::navigationWidgetHeight() + OTHER_HEIGHT + 1); +} + +void DoubleTabWidget::addTab(const QString &name, const QStringList &subTabs) +{ + Tab tab; + tab.name = name; + tab.subTabs = subTabs; + tab.currentSubTab = tab.subTabs.isEmpty() ? -1 : 0; + m_tabs.append(tab); + if (m_currentIndex == -1) { + m_currentIndex = m_tabs.size()-1; + emit currentIndexChanged(m_currentIndex, m_tabs.at(m_currentIndex).currentSubTab); + } + update(); +} + +void DoubleTabWidget::mousePressEvent(QMouseEvent *event) +{ + if (event->y() < Utils::StyleHelper::navigationWidgetHeight()) { + int eventX = event->x(); + // clicked on the top level part of the bar + QFontMetrics fm(font()); + int x = 2 * MARGIN + qMax(fm.width(m_title), MIN_LEFT_MARGIN); + if (eventX <= x) + return; + int i; + for (i = 0; i < m_tabs.size(); ++i) { + int otherX = x + 2 * MARGIN + fm.width(m_tabs.at(i).name); + if (eventX > x && eventX < otherX) { + break; + } + x = otherX; + } + if (i < m_tabs.size()) { + if (m_currentIndex != i) { + m_currentIndex = i; + update(); + emit currentIndexChanged(m_currentIndex, m_tabs.at(m_currentIndex).currentSubTab); + } + event->accept(); + return; + } + } else if (event->y() < Utils::StyleHelper::navigationWidgetHeight() + OTHER_HEIGHT) { + int diff = (OTHER_HEIGHT - SELECTION_IMAGE_HEIGHT) / 2; + if (event->y() < Utils::StyleHelper::navigationWidgetHeight() + diff + || event->y() > Utils::StyleHelper::navigationWidgetHeight() + OTHER_HEIGHT - diff) + return; + if (m_currentIndex == -1) + return; + Tab currentTab = m_tabs.at(m_currentIndex); + QStringList subTabs = currentTab.subTabs; + if (subTabs.isEmpty()) + return; + int eventX = event->x(); + QFontMetrics fm(font()); + // clicked on the lower level part of the bar + int x = MARGIN; + int i; + for (i = 0; i < subTabs.size(); ++i) { + int otherX = x + 2 * SELECTION_IMAGE_WIDTH + fm.width(subTabs.at(i)); + if (eventX > x && eventX < otherX) { + break; + } + x = otherX + 2 * MARGIN; + } + if (i < subTabs.size()) { + if (m_tabs[m_currentIndex].currentSubTab != i) { + m_tabs[m_currentIndex].currentSubTab = i; + update(); + } + event->accept(); + emit currentIndexChanged(m_currentIndex, m_tabs.at(m_currentIndex).currentSubTab); + return; + } + + } + event->ignore(); +} + +void DoubleTabWidget::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + QPainter painter(this); + QRect r = rect(); + + // draw top level tab bar + r.setHeight(Utils::StyleHelper::navigationWidgetHeight()); + + QPoint offset = window()->mapToGlobal(QPoint(0, 0)) - mapToGlobal(r.topLeft()); + QRect gradientSpan = QRect(offset, window()->size()); + Utils::StyleHelper::horizontalGradient(&painter, gradientSpan, r); + + painter.setPen(Utils::StyleHelper::borderColor()); + + QColor lighter(255, 255, 255, 40); + painter.drawLine(r.bottomLeft(), r.bottomRight()); + painter.setPen(lighter); + painter.drawLine(r.topLeft(), r.topRight()); + + QFontMetrics fm(font()); + int baseline = (r.height() + fm.ascent()) / 2 - 1; + + // top level title + painter.setPen(Utils::StyleHelper::panelTextColor()); + painter.drawText(MARGIN, baseline, m_title); + + QLinearGradient grad(QPoint(0, 0), QPoint(0, r.height() + OTHER_HEIGHT - 1)); + grad.setColorAt(0, QColor(247, 247, 247)); + grad.setColorAt(1, QColor(205, 205, 205)); + + // draw background of second bar + painter.fillRect(QRect(0, r.height(), r.width(), OTHER_HEIGHT), grad); + painter.setPen(Qt::black); + painter.drawLine(0, r.height() + OTHER_HEIGHT, + r.width(), r.height() + OTHER_HEIGHT); + painter.setPen(Qt::white); + painter.drawLine(0, r.height(), + r.width(), r.height()); + + // top level tabs + int x = 2 * MARGIN + qMax(fm.width(m_title), MIN_LEFT_MARGIN); + for (int i = 0; i < m_tabs.size(); ++i) { + if (i == m_currentIndex) { + painter.setPen(Utils::StyleHelper::borderColor()); + painter.drawLine(x - 1, 0, x - 1, r.height() - 1); + painter.fillRect(QRect(x, 0, + 2 * MARGIN + fm.width(m_tabs.at(i).name), + r.height() + 1), + grad); + x += MARGIN; + painter.setPen(Qt::black); + painter.drawText(x, baseline, m_tabs.at(i).name); + x += fm.width(m_tabs.at(i).name); + x += MARGIN; + painter.setPen(Utils::StyleHelper::borderColor()); + painter.drawLine(x, 0, x, r.height() - 1); + } else { + if (i == 0) + drawFirstLevelSeparator(&painter, QPoint(x, 0), QPoint(x, r.height()-1)); + x += MARGIN; + painter.setPen(Utils::StyleHelper::panelTextColor()); + painter.drawText(x + 1, baseline, m_tabs.at(i).name); + x += fm.width(m_tabs.at(i).name); + x += MARGIN; + drawFirstLevelSeparator(&painter, QPoint(x, 0), QPoint(x, r.height()-1)); + } + if (x >= r.width()) // TODO: do something useful... + break; + } + + // second level tabs + static QPixmap left(":/projectexplorer/leftselection.png"); + static QPixmap mid(":/projectexplorer/midselection.png"); + static QPixmap right(":/projectexplorer/rightselection.png"); + if (m_currentIndex != -1) { + int y = r.height() + (OTHER_HEIGHT - left.height()) / 2.; + int imageHeight = left.height(); + Tab currentTab = m_tabs.at(m_currentIndex); + QStringList subTabs = currentTab.subTabs; + x = 0; + for (int i = 0; i < subTabs.size(); ++i) { + x += MARGIN; + int textWidth = fm.width(subTabs.at(i)); + if (currentTab.currentSubTab == i) { + painter.setPen(Qt::white); + painter.drawPixmap(x, y, left); + painter.drawPixmap(QRect(x + SELECTION_IMAGE_WIDTH, y, + textWidth, imageHeight), + mid, QRect(0, 0, mid.width(), mid.height())); + painter.drawPixmap(x + SELECTION_IMAGE_WIDTH + textWidth, y, right); + } else { + painter.setPen(Qt::black); + } + x += SELECTION_IMAGE_WIDTH; + painter.drawText(x, y + (imageHeight + fm.ascent()) / 2. - 1, + subTabs.at(i)); + x += textWidth + SELECTION_IMAGE_WIDTH + MARGIN; + drawSecondLevelSeparator(&painter, QPoint(x, y), QPoint(x, y + imageHeight)); + } + } +} + +void DoubleTabWidget::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} diff --git a/src/plugins/projectexplorer/doubletabwidget.h b/src/plugins/projectexplorer/doubletabwidget.h new file mode 100644 index 0000000000000000000000000000000000000000..a77366aa32d506c18e1849f3bb959a347f5feb0f --- /dev/null +++ b/src/plugins/projectexplorer/doubletabwidget.h @@ -0,0 +1,50 @@ +#ifndef DOUBLETABWIDGET_H +#define DOUBLETABWIDGET_H + +#include <QtGui/QWidget> + +namespace ProjectExplorer { +namespace Internal { + +namespace Ui { + class DoubleTabWidget; +} + +class DoubleTabWidget : public QWidget { + Q_OBJECT +public: + DoubleTabWidget(QWidget *parent = 0); + ~DoubleTabWidget(); + + void setTitle(const QString &title); + QString title() const { return m_title; } + + void addTab(const QString &name, const QStringList &subTabs); + +signals: + void currentIndexChanged(int index, int subIndex); + +protected: + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + void changeEvent(QEvent *e); + QSize minimumSizeHint() const; + +private: + struct Tab { + QString name; + QStringList subTabs; + int currentSubTab; + }; + + Ui::DoubleTabWidget *ui; + + QString m_title; + QList<Tab> m_tabs; + int m_currentIndex; +}; + +} // namespace Internal +} // namespace ProjectExplorer + +#endif // DOUBLETABWIDGET_H diff --git a/src/plugins/projectexplorer/doubletabwidget.ui b/src/plugins/projectexplorer/doubletabwidget.ui new file mode 100644 index 0000000000000000000000000000000000000000..dafad3344c7c8018542c3fddc98824f28602850d --- /dev/null +++ b/src/plugins/projectexplorer/doubletabwidget.ui @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ProjectExplorer::Internal::DoubleTabWidget</class> + <widget class="QWidget" name="ProjectExplorer::Internal::DoubleTabWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>400</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>DoubleTabWidget</string> + </property> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections/> +</ui> diff --git a/src/plugins/projectexplorer/images/leftselection.png b/src/plugins/projectexplorer/images/leftselection.png new file mode 100644 index 0000000000000000000000000000000000000000..8b787ca4e6e54f7b80d9abfabc925ad0466c79eb Binary files /dev/null and b/src/plugins/projectexplorer/images/leftselection.png differ diff --git a/src/plugins/projectexplorer/images/midselection.png b/src/plugins/projectexplorer/images/midselection.png new file mode 100644 index 0000000000000000000000000000000000000000..d6db82e1680701be6287e1e3f1f114189be9c697 Binary files /dev/null and b/src/plugins/projectexplorer/images/midselection.png differ diff --git a/src/plugins/projectexplorer/images/rightselection.png b/src/plugins/projectexplorer/images/rightselection.png new file mode 100644 index 0000000000000000000000000000000000000000..26b181cf342a7ee7c4a771bcc75625ac2f2f59b3 Binary files /dev/null and b/src/plugins/projectexplorer/images/rightselection.png differ diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index 981a42da11a9d60f0e7c883fc8b83cc8fe982685..d752fb82443bec2d74d0d8a1e79231d41003424d 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -68,7 +68,8 @@ HEADERS += projectexplorer.h \ projectwelcomepagewidget.h \ baseprojectwizarddialog.h \ targetselector.h \ - targetsettingswidget.h + targetsettingswidget.h \ + doubletabwidget.h SOURCES += projectexplorer.cpp \ projectwindow.cpp \ buildmanager.cpp \ @@ -124,7 +125,8 @@ SOURCES += projectexplorer.cpp \ corelistenercheckingforrunningbuild.cpp \ baseprojectwizarddialog.cpp \ targetselector.cpp \ - targetsettingswidget.cpp + targetsettingswidget.cpp \ + doubletabwidget.cpp FORMS += processstep.ui \ editorsettingspropertiespage.ui \ runsettingspropertiespage.ui \ @@ -133,7 +135,8 @@ FORMS += processstep.ui \ removefiledialog.ui \ projectexplorersettingspage.ui \ projectwelcomepagewidget.ui \ - targetsettingswidget.ui + targetsettingswidget.ui \ + doubletabwidget.ui win32 { SOURCES += applicationlauncher_win.cpp \ diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc index 2c1f8f1683e701b02b882971fd9ed6366b78863e..83aaae39de50884fc0219f4c77fce6170c6582b9 100644 --- a/src/plugins/projectexplorer/projectexplorer.qrc +++ b/src/plugins/projectexplorer/projectexplorer.qrc @@ -23,5 +23,8 @@ <file>images/targetrunselected.png</file> <file>images/targetseparatorbackground.png</file> <file>images/targetunselected.png</file> + <file>images/leftselection.png</file> + <file>images/rightselection.png</file> + <file>images/midselection.png</file> </qresource> </RCC>