Commit 685bc2cc authored by Eike Ziller's avatar Eike Ziller

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: default avatarhjk <hjk@theqtcompany.com>
parent d984a836
......@@ -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)) {
m_currentIndex = index;
update();
m_triggerTimer.start(0);
if (m_tabs.at(index)->hasMenu && rect.right() - e->pos().x() <= kMenuButtonWidth) {
// menu arrow clicked
emit menuTriggered(index, e);
} else {
m_currentIndex = index;
update();
// 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment