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 <QStackedLayout>
|
||||
#include <QStatusBar>
|
||||
#include <QStyleOption>
|
||||
#include <QToolTip>
|
||||
|
||||
using namespace Core;
|
||||
@@ -50,6 +51,8 @@ using namespace Utils;
|
||||
const int FancyTabBar::m_rounding = 22;
|
||||
const int FancyTabBar::m_textPadding = 4;
|
||||
|
||||
static const int kMenuButtonWidth = 16;
|
||||
|
||||
void FancyTab::fadeIn()
|
||||
{
|
||||
animator.stop();
|
||||
@@ -83,10 +86,6 @@ FancyTabBar::FancyTabBar(QWidget *parent)
|
||||
setAttribute(Qt::WA_Hover, true);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
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()
|
||||
@@ -104,7 +103,7 @@ QSize FancyTabBar::tabSizeHint(bool minimum) const
|
||||
int width = 60 + spacing + 2;
|
||||
int maxLabelwidth = 0;
|
||||
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)
|
||||
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)
|
||||
{
|
||||
e->accept();
|
||||
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 (m_tabs.at(index)->hasMenu && rect.right() - e->pos().x() <= kMenuButtonWidth) {
|
||||
// menu arrow clicked
|
||||
emit menuTriggered(index, e);
|
||||
} else {
|
||||
m_currentIndex = index;
|
||||
update();
|
||||
m_triggerTimer.start(0);
|
||||
// update tab bar before showing widget
|
||||
QTimer::singleShot(0, this, [this]() { emit currentChanged(m_currentIndex); });
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -290,6 +287,7 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
|
||||
}
|
||||
painter->save();
|
||||
|
||||
FancyTab *tab = m_tabs.at(tabIndex);
|
||||
QRect rect = tabRect(tabIndex);
|
||||
bool selected = (tabIndex == m_currentIndex);
|
||||
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);
|
||||
const bool drawIcon = rect.height() > 36;
|
||||
QRect tabIconRect(tabTextRect);
|
||||
@@ -334,7 +332,7 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
|
||||
tabIconRect.adjust(0, 4, 0, -textHeight);
|
||||
const QIcon::Mode iconMode = enabled ? (selected ? QIcon::Active : QIcon::Normal)
|
||||
: 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?
|
||||
@@ -350,6 +348,13 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
|
||||
painter->translate(0, -1);
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -479,6 +484,7 @@ FancyTabWidget::FancyTabWidget(QWidget *parent)
|
||||
setLayout(mainLayout);
|
||||
|
||||
connect(m_tabBar, &FancyTabBar::currentChanged, this, &FancyTabWidget::showWidget);
|
||||
connect(m_tabBar, &FancyTabBar::menuTriggered, this, &FancyTabWidget::menuTriggered);
|
||||
}
|
||||
|
||||
void FancyTabWidget::setSelectionWidgetVisible(bool visible)
|
||||
@@ -491,10 +497,11 @@ bool FancyTabWidget::isSelectionWidgetVisible() const
|
||||
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_tabBar->insertTab(index, icon, label);
|
||||
m_tabBar->insertTab(index, icon, label, hasMenu);
|
||||
}
|
||||
|
||||
void FancyTabWidget::removeTab(int index)
|
||||
|
||||
@@ -46,7 +46,7 @@ class FancyTab : public QObject
|
||||
|
||||
Q_PROPERTY(float fader READ fader WRITE setFader)
|
||||
public:
|
||||
FancyTab(QWidget *tabbar) : enabled(false), tabbar(tabbar), m_fader(0) {
|
||||
FancyTab(QWidget *tabbar) : tabbar(tabbar){
|
||||
animator.setPropertyName("fader");
|
||||
animator.setTargetObject(this);
|
||||
}
|
||||
@@ -59,12 +59,13 @@ public:
|
||||
QIcon icon;
|
||||
QString text;
|
||||
QString toolTip;
|
||||
bool enabled;
|
||||
bool enabled = false;
|
||||
bool hasMenu = false;
|
||||
|
||||
private:
|
||||
QPropertyAnimation animator;
|
||||
QWidget *tabbar;
|
||||
float m_fader;
|
||||
float m_fader = 0;
|
||||
};
|
||||
|
||||
class FancyTabBar : public QWidget
|
||||
@@ -91,10 +92,11 @@ public:
|
||||
void setTabEnabled(int index, bool enable);
|
||||
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);
|
||||
tab->icon = icon;
|
||||
tab->text = label;
|
||||
tab->hasMenu = hasMenu;
|
||||
m_tabs.insert(index, tab);
|
||||
updateGeometry();
|
||||
}
|
||||
@@ -110,16 +112,12 @@ public:
|
||||
void setTabToolTip(int index, QString toolTip) { m_tabs[index]->toolTip = 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(); }
|
||||
QRect tabRect(int index) const;
|
||||
|
||||
signals:
|
||||
void currentChanged(int);
|
||||
|
||||
public slots:
|
||||
void emitCurrentIndex();
|
||||
void currentChanged(int index);
|
||||
void menuTriggered(int index, QMouseEvent *event);
|
||||
|
||||
private:
|
||||
static const int m_rounding;
|
||||
@@ -128,7 +126,6 @@ private:
|
||||
int m_hoverIndex;
|
||||
int m_currentIndex;
|
||||
QList<FancyTab*> m_tabs;
|
||||
QTimer m_triggerTimer;
|
||||
QSize tabSizeHint(bool minimum = false) const;
|
||||
|
||||
};
|
||||
@@ -140,7 +137,7 @@ class FancyTabWidget : public QWidget
|
||||
public:
|
||||
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 setBackgroundBrush(const QBrush &brush);
|
||||
void addCornerWidget(QWidget *widget);
|
||||
@@ -161,6 +158,7 @@ public:
|
||||
signals:
|
||||
void currentAboutToShow(int index);
|
||||
void currentChanged(int index);
|
||||
void menuTriggered(int index, QMouseEvent *event);
|
||||
void topAreaClicked(Qt::MouseButton button, Qt::KeyboardModifiers modifiers);
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -32,6 +32,12 @@ IMode::IMode(QObject *parent)
|
||||
{
|
||||
}
|
||||
|
||||
IMode::~IMode()
|
||||
{
|
||||
if (m_menu)
|
||||
delete m_menu;
|
||||
}
|
||||
|
||||
void IMode::setEnabled(bool enabled)
|
||||
{
|
||||
if (m_isEnabled == enabled)
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "id.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QMenu>
|
||||
|
||||
namespace Core {
|
||||
|
||||
@@ -39,18 +40,21 @@ class CORE_EXPORT IMode : public IContext
|
||||
|
||||
public:
|
||||
IMode(QObject *parent = 0);
|
||||
~IMode();
|
||||
|
||||
QString displayName() const { return m_displayName; }
|
||||
QIcon icon() const { return m_icon; }
|
||||
int priority() const { return m_priority; }
|
||||
Id id() const { return m_id; }
|
||||
bool isEnabled() const;
|
||||
QMenu *menu() const { return m_menu; }
|
||||
|
||||
void setEnabled(bool enabled);
|
||||
void setDisplayName(const QString &displayName) { m_displayName = displayName; }
|
||||
void setIcon(const QIcon &icon) { m_icon = icon; }
|
||||
void setPriority(int priority) { m_priority = priority; }
|
||||
void setId(Id id) { m_id = id; }
|
||||
void setMenu(QMenu *menu) { m_menu = menu; }
|
||||
|
||||
signals:
|
||||
void enabledStateChanged(bool enabled);
|
||||
@@ -58,6 +62,7 @@ signals:
|
||||
private:
|
||||
QString m_displayName;
|
||||
QIcon m_icon;
|
||||
QMenu *m_menu = nullptr;
|
||||
int m_priority;
|
||||
Id m_id;
|
||||
bool m_isEnabled;
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <QAction>
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
#include <QMouseEvent>
|
||||
#include <QVector>
|
||||
|
||||
namespace Core {
|
||||
@@ -57,6 +58,8 @@ namespace Core {
|
||||
|
||||
struct ModeManagerPrivate
|
||||
{
|
||||
void showMenu(int index, QMouseEvent *event);
|
||||
|
||||
Internal::MainWindow *m_mainWindow;
|
||||
Internal::FancyTabWidget *m_modeStack;
|
||||
Internal::FancyActionBar *m_actionBar;
|
||||
@@ -81,6 +84,12 @@ static int indexOf(Id id)
|
||||
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,
|
||||
Internal::FancyTabWidget *modeStack)
|
||||
{
|
||||
@@ -98,6 +107,8 @@ ModeManager::ModeManager(Internal::MainWindow *mainWindow,
|
||||
this, &ModeManager::currentTabAboutToChange);
|
||||
connect(d->m_modeStack, &Internal::FancyTabWidget::currentChanged,
|
||||
this, &ModeManager::currentTabChanged);
|
||||
connect(d->m_modeStack, &Internal::FancyTabWidget::menuTriggered,
|
||||
this, [](int index, QMouseEvent *e) { d->showMenu(index, e); });
|
||||
}
|
||||
|
||||
void ModeManager::init()
|
||||
@@ -153,7 +164,8 @@ void ModeManager::objectAdded(QObject *obj)
|
||||
++index;
|
||||
|
||||
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());
|
||||
|
||||
// Register mode shortcut
|
||||
|
||||
Reference in New Issue
Block a user