forked from qt-creator/qt-creator
Support modes with context menus.
If modes provide a QMenu, a little arrow is shown next to the mode icon. If the user clicks there, the menu is shown instead of changing the mode. Limitations: Modes need to provide some QMenu instance already when they are added to the object pool. Setting or removing the menu later will not update the UI. Change-Id: Ic4ef709e6200afcff14f41054a5dd98c37b0b849 Reviewed-by: hjk <hjk@theqtcompany.com>
This commit is contained in:
@@ -41,6 +41,7 @@
|
|||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
#include <QStackedLayout>
|
#include <QStackedLayout>
|
||||||
#include <QStatusBar>
|
#include <QStatusBar>
|
||||||
|
#include <QStyleOption>
|
||||||
#include <QToolTip>
|
#include <QToolTip>
|
||||||
|
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
@@ -50,6 +51,8 @@ using namespace Utils;
|
|||||||
const int FancyTabBar::m_rounding = 22;
|
const int FancyTabBar::m_rounding = 22;
|
||||||
const int FancyTabBar::m_textPadding = 4;
|
const int FancyTabBar::m_textPadding = 4;
|
||||||
|
|
||||||
|
static const int kMenuButtonWidth = 16;
|
||||||
|
|
||||||
void FancyTab::fadeIn()
|
void FancyTab::fadeIn()
|
||||||
{
|
{
|
||||||
animator.stop();
|
animator.stop();
|
||||||
@@ -83,10 +86,6 @@ FancyTabBar::FancyTabBar(QWidget *parent)
|
|||||||
setAttribute(Qt::WA_Hover, true);
|
setAttribute(Qt::WA_Hover, true);
|
||||||
setFocusPolicy(Qt::NoFocus);
|
setFocusPolicy(Qt::NoFocus);
|
||||||
setMouseTracking(true); // Needed for hover events
|
setMouseTracking(true); // Needed for hover events
|
||||||
m_triggerTimer.setSingleShot(true);
|
|
||||||
|
|
||||||
// We use a zerotimer to keep the sidebar responsive
|
|
||||||
connect(&m_triggerTimer, &QTimer::timeout, this, &FancyTabBar::emitCurrentIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FancyTabBar::~FancyTabBar()
|
FancyTabBar::~FancyTabBar()
|
||||||
@@ -104,7 +103,7 @@ QSize FancyTabBar::tabSizeHint(bool minimum) const
|
|||||||
int width = 60 + spacing + 2;
|
int width = 60 + spacing + 2;
|
||||||
int maxLabelwidth = 0;
|
int maxLabelwidth = 0;
|
||||||
for (int tab=0 ; tab<count() ;++tab) {
|
for (int tab=0 ; tab<count() ;++tab) {
|
||||||
int width = fm.width(tabText(tab));
|
int width = fm.width(m_tabs.at(tab)->text);
|
||||||
if (width > maxLabelwidth)
|
if (width > maxLabelwidth)
|
||||||
maxLabelwidth = width;
|
maxLabelwidth = width;
|
||||||
}
|
}
|
||||||
@@ -211,24 +210,22 @@ QRect FancyTabBar::tabRect(int index) const
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This keeps the sidebar responsive since
|
|
||||||
// we get a repaint before loading the
|
|
||||||
// mode itself
|
|
||||||
void FancyTabBar::emitCurrentIndex()
|
|
||||||
{
|
|
||||||
emit currentChanged(m_currentIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FancyTabBar::mousePressEvent(QMouseEvent *e)
|
void FancyTabBar::mousePressEvent(QMouseEvent *e)
|
||||||
{
|
{
|
||||||
e->accept();
|
e->accept();
|
||||||
for (int index = 0; index < m_tabs.count(); ++index) {
|
for (int index = 0; index < m_tabs.count(); ++index) {
|
||||||
if (tabRect(index).contains(e->pos())) {
|
const QRect rect = tabRect(index);
|
||||||
|
if (rect.contains(e->pos())) {
|
||||||
if (isTabEnabled(index)) {
|
if (isTabEnabled(index)) {
|
||||||
|
if (m_tabs.at(index)->hasMenu && rect.right() - e->pos().x() <= kMenuButtonWidth) {
|
||||||
|
// menu arrow clicked
|
||||||
|
emit menuTriggered(index, e);
|
||||||
|
} else {
|
||||||
m_currentIndex = index;
|
m_currentIndex = index;
|
||||||
update();
|
update();
|
||||||
m_triggerTimer.start(0);
|
// update tab bar before showing widget
|
||||||
|
QTimer::singleShot(0, this, [this]() { emit currentChanged(m_currentIndex); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -290,6 +287,7 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
|
|||||||
}
|
}
|
||||||
painter->save();
|
painter->save();
|
||||||
|
|
||||||
|
FancyTab *tab = m_tabs.at(tabIndex);
|
||||||
QRect rect = tabRect(tabIndex);
|
QRect rect = tabRect(tabIndex);
|
||||||
bool selected = (tabIndex == m_currentIndex);
|
bool selected = (tabIndex == m_currentIndex);
|
||||||
bool enabled = isTabEnabled(tabIndex);
|
bool enabled = isTabEnabled(tabIndex);
|
||||||
@@ -303,7 +301,7 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString tabText(this->tabText(tabIndex));
|
QString tabText(tab->text);
|
||||||
QRect tabTextRect(rect);
|
QRect tabTextRect(rect);
|
||||||
const bool drawIcon = rect.height() > 36;
|
const bool drawIcon = rect.height() > 36;
|
||||||
QRect tabIconRect(tabTextRect);
|
QRect tabIconRect(tabTextRect);
|
||||||
@@ -334,7 +332,7 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
|
|||||||
tabIconRect.adjust(0, 4, 0, -textHeight);
|
tabIconRect.adjust(0, 4, 0, -textHeight);
|
||||||
const QIcon::Mode iconMode = enabled ? (selected ? QIcon::Active : QIcon::Normal)
|
const QIcon::Mode iconMode = enabled ? (selected ? QIcon::Active : QIcon::Normal)
|
||||||
: QIcon::Disabled;
|
: QIcon::Disabled;
|
||||||
StyleHelper::drawIconWithShadow(tabIcon(tabIndex), tabIconRect, painter, iconMode);
|
StyleHelper::drawIconWithShadow(tab->icon, tabIconRect, painter, iconMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
painter->setOpacity(1.0); //FIXME: was 0.7 before?
|
painter->setOpacity(1.0); //FIXME: was 0.7 before?
|
||||||
@@ -350,6 +348,13 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
|
|||||||
painter->translate(0, -1);
|
painter->translate(0, -1);
|
||||||
painter->drawText(tabTextRect, textFlags, tabText);
|
painter->drawText(tabTextRect, textFlags, tabText);
|
||||||
|
|
||||||
|
// menu arrow
|
||||||
|
if (tab->hasMenu) {
|
||||||
|
QStyleOption opt;
|
||||||
|
opt.initFrom(this);
|
||||||
|
opt.rect = rect.adjusted(rect.width() - kMenuButtonWidth, 0, -8, 0);
|
||||||
|
StyleHelper::drawArrow(QStyle::PE_IndicatorArrowRight, painter, &opt);
|
||||||
|
}
|
||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,6 +484,7 @@ FancyTabWidget::FancyTabWidget(QWidget *parent)
|
|||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
connect(m_tabBar, &FancyTabBar::currentChanged, this, &FancyTabWidget::showWidget);
|
connect(m_tabBar, &FancyTabBar::currentChanged, this, &FancyTabWidget::showWidget);
|
||||||
|
connect(m_tabBar, &FancyTabBar::menuTriggered, this, &FancyTabWidget::menuTriggered);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FancyTabWidget::setSelectionWidgetVisible(bool visible)
|
void FancyTabWidget::setSelectionWidgetVisible(bool visible)
|
||||||
@@ -491,10 +497,11 @@ bool FancyTabWidget::isSelectionWidgetVisible() const
|
|||||||
return m_selectionWidget->isVisible();
|
return m_selectionWidget->isVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FancyTabWidget::insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label)
|
void FancyTabWidget::insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label,
|
||||||
|
bool hasMenu)
|
||||||
{
|
{
|
||||||
m_modesStack->insertWidget(index, tab);
|
m_modesStack->insertWidget(index, tab);
|
||||||
m_tabBar->insertTab(index, icon, label);
|
m_tabBar->insertTab(index, icon, label, hasMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FancyTabWidget::removeTab(int index)
|
void FancyTabWidget::removeTab(int index)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class FancyTab : public QObject
|
|||||||
|
|
||||||
Q_PROPERTY(float fader READ fader WRITE setFader)
|
Q_PROPERTY(float fader READ fader WRITE setFader)
|
||||||
public:
|
public:
|
||||||
FancyTab(QWidget *tabbar) : enabled(false), tabbar(tabbar), m_fader(0) {
|
FancyTab(QWidget *tabbar) : tabbar(tabbar){
|
||||||
animator.setPropertyName("fader");
|
animator.setPropertyName("fader");
|
||||||
animator.setTargetObject(this);
|
animator.setTargetObject(this);
|
||||||
}
|
}
|
||||||
@@ -59,12 +59,13 @@ public:
|
|||||||
QIcon icon;
|
QIcon icon;
|
||||||
QString text;
|
QString text;
|
||||||
QString toolTip;
|
QString toolTip;
|
||||||
bool enabled;
|
bool enabled = false;
|
||||||
|
bool hasMenu = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPropertyAnimation animator;
|
QPropertyAnimation animator;
|
||||||
QWidget *tabbar;
|
QWidget *tabbar;
|
||||||
float m_fader;
|
float m_fader = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FancyTabBar : public QWidget
|
class FancyTabBar : public QWidget
|
||||||
@@ -91,10 +92,11 @@ public:
|
|||||||
void setTabEnabled(int index, bool enable);
|
void setTabEnabled(int index, bool enable);
|
||||||
bool isTabEnabled(int index) const;
|
bool isTabEnabled(int index) const;
|
||||||
|
|
||||||
void insertTab(int index, const QIcon &icon, const QString &label) {
|
void insertTab(int index, const QIcon &icon, const QString &label, bool hasMenu) {
|
||||||
FancyTab *tab = new FancyTab(this);
|
FancyTab *tab = new FancyTab(this);
|
||||||
tab->icon = icon;
|
tab->icon = icon;
|
||||||
tab->text = label;
|
tab->text = label;
|
||||||
|
tab->hasMenu = hasMenu;
|
||||||
m_tabs.insert(index, tab);
|
m_tabs.insert(index, tab);
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
@@ -110,16 +112,12 @@ public:
|
|||||||
void setTabToolTip(int index, QString toolTip) { m_tabs[index]->toolTip = toolTip; }
|
void setTabToolTip(int index, QString toolTip) { m_tabs[index]->toolTip = toolTip; }
|
||||||
QString tabToolTip(int index) const { return m_tabs.at(index)->toolTip; }
|
QString tabToolTip(int index) const { return m_tabs.at(index)->toolTip; }
|
||||||
|
|
||||||
QIcon tabIcon(int index) const { return m_tabs.at(index)->icon; }
|
|
||||||
QString tabText(int index) const { return m_tabs.at(index)->text; }
|
|
||||||
int count() const {return m_tabs.count(); }
|
int count() const {return m_tabs.count(); }
|
||||||
QRect tabRect(int index) const;
|
QRect tabRect(int index) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void currentChanged(int);
|
void currentChanged(int index);
|
||||||
|
void menuTriggered(int index, QMouseEvent *event);
|
||||||
public slots:
|
|
||||||
void emitCurrentIndex();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int m_rounding;
|
static const int m_rounding;
|
||||||
@@ -128,7 +126,6 @@ private:
|
|||||||
int m_hoverIndex;
|
int m_hoverIndex;
|
||||||
int m_currentIndex;
|
int m_currentIndex;
|
||||||
QList<FancyTab*> m_tabs;
|
QList<FancyTab*> m_tabs;
|
||||||
QTimer m_triggerTimer;
|
|
||||||
QSize tabSizeHint(bool minimum = false) const;
|
QSize tabSizeHint(bool minimum = false) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -140,7 +137,7 @@ class FancyTabWidget : public QWidget
|
|||||||
public:
|
public:
|
||||||
FancyTabWidget(QWidget *parent = 0);
|
FancyTabWidget(QWidget *parent = 0);
|
||||||
|
|
||||||
void insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label);
|
void insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label, bool hasMenu);
|
||||||
void removeTab(int index);
|
void removeTab(int index);
|
||||||
void setBackgroundBrush(const QBrush &brush);
|
void setBackgroundBrush(const QBrush &brush);
|
||||||
void addCornerWidget(QWidget *widget);
|
void addCornerWidget(QWidget *widget);
|
||||||
@@ -161,6 +158,7 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void currentAboutToShow(int index);
|
void currentAboutToShow(int index);
|
||||||
void currentChanged(int index);
|
void currentChanged(int index);
|
||||||
|
void menuTriggered(int index, QMouseEvent *event);
|
||||||
void topAreaClicked(Qt::MouseButton button, Qt::KeyboardModifiers modifiers);
|
void topAreaClicked(Qt::MouseButton button, Qt::KeyboardModifiers modifiers);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ IMode::IMode(QObject *parent)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IMode::~IMode()
|
||||||
|
{
|
||||||
|
if (m_menu)
|
||||||
|
delete m_menu;
|
||||||
|
}
|
||||||
|
|
||||||
void IMode::setEnabled(bool enabled)
|
void IMode::setEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
if (m_isEnabled == enabled)
|
if (m_isEnabled == enabled)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "id.h"
|
#include "id.h"
|
||||||
|
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
@@ -39,18 +40,21 @@ class CORE_EXPORT IMode : public IContext
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
IMode(QObject *parent = 0);
|
IMode(QObject *parent = 0);
|
||||||
|
~IMode();
|
||||||
|
|
||||||
QString displayName() const { return m_displayName; }
|
QString displayName() const { return m_displayName; }
|
||||||
QIcon icon() const { return m_icon; }
|
QIcon icon() const { return m_icon; }
|
||||||
int priority() const { return m_priority; }
|
int priority() const { return m_priority; }
|
||||||
Id id() const { return m_id; }
|
Id id() const { return m_id; }
|
||||||
bool isEnabled() const;
|
bool isEnabled() const;
|
||||||
|
QMenu *menu() const { return m_menu; }
|
||||||
|
|
||||||
void setEnabled(bool enabled);
|
void setEnabled(bool enabled);
|
||||||
void setDisplayName(const QString &displayName) { m_displayName = displayName; }
|
void setDisplayName(const QString &displayName) { m_displayName = displayName; }
|
||||||
void setIcon(const QIcon &icon) { m_icon = icon; }
|
void setIcon(const QIcon &icon) { m_icon = icon; }
|
||||||
void setPriority(int priority) { m_priority = priority; }
|
void setPriority(int priority) { m_priority = priority; }
|
||||||
void setId(Id id) { m_id = id; }
|
void setId(Id id) { m_id = id; }
|
||||||
|
void setMenu(QMenu *menu) { m_menu = menu; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void enabledStateChanged(bool enabled);
|
void enabledStateChanged(bool enabled);
|
||||||
@@ -58,6 +62,7 @@ signals:
|
|||||||
private:
|
private:
|
||||||
QString m_displayName;
|
QString m_displayName;
|
||||||
QIcon m_icon;
|
QIcon m_icon;
|
||||||
|
QMenu *m_menu = nullptr;
|
||||||
int m_priority;
|
int m_priority;
|
||||||
Id m_id;
|
Id m_id;
|
||||||
bool m_isEnabled;
|
bool m_isEnabled;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QMouseEvent>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@@ -57,6 +58,8 @@ namespace Core {
|
|||||||
|
|
||||||
struct ModeManagerPrivate
|
struct ModeManagerPrivate
|
||||||
{
|
{
|
||||||
|
void showMenu(int index, QMouseEvent *event);
|
||||||
|
|
||||||
Internal::MainWindow *m_mainWindow;
|
Internal::MainWindow *m_mainWindow;
|
||||||
Internal::FancyTabWidget *m_modeStack;
|
Internal::FancyTabWidget *m_modeStack;
|
||||||
Internal::FancyActionBar *m_actionBar;
|
Internal::FancyActionBar *m_actionBar;
|
||||||
@@ -81,6 +84,12 @@ static int indexOf(Id id)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModeManagerPrivate::showMenu(int index, QMouseEvent *event)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_modes.at(index)->menu(), return);
|
||||||
|
m_modes.at(index)->menu()->popup(event->globalPos());
|
||||||
|
}
|
||||||
|
|
||||||
ModeManager::ModeManager(Internal::MainWindow *mainWindow,
|
ModeManager::ModeManager(Internal::MainWindow *mainWindow,
|
||||||
Internal::FancyTabWidget *modeStack)
|
Internal::FancyTabWidget *modeStack)
|
||||||
{
|
{
|
||||||
@@ -98,6 +107,8 @@ ModeManager::ModeManager(Internal::MainWindow *mainWindow,
|
|||||||
this, &ModeManager::currentTabAboutToChange);
|
this, &ModeManager::currentTabAboutToChange);
|
||||||
connect(d->m_modeStack, &Internal::FancyTabWidget::currentChanged,
|
connect(d->m_modeStack, &Internal::FancyTabWidget::currentChanged,
|
||||||
this, &ModeManager::currentTabChanged);
|
this, &ModeManager::currentTabChanged);
|
||||||
|
connect(d->m_modeStack, &Internal::FancyTabWidget::menuTriggered,
|
||||||
|
this, [](int index, QMouseEvent *e) { d->showMenu(index, e); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModeManager::init()
|
void ModeManager::init()
|
||||||
@@ -153,7 +164,8 @@ void ModeManager::objectAdded(QObject *obj)
|
|||||||
++index;
|
++index;
|
||||||
|
|
||||||
d->m_modes.insert(index, mode);
|
d->m_modes.insert(index, mode);
|
||||||
d->m_modeStack->insertTab(index, mode->widget(), mode->icon(), mode->displayName());
|
d->m_modeStack->insertTab(index, mode->widget(), mode->icon(), mode->displayName(),
|
||||||
|
mode->menu() != nullptr);
|
||||||
d->m_modeStack->setTabEnabled(index, mode->isEnabled());
|
d->m_modeStack->setTabEnabled(index, mode->isEnabled());
|
||||||
|
|
||||||
// Register mode shortcut
|
// Register mode shortcut
|
||||||
|
|||||||
Reference in New Issue
Block a user