diff --git a/clients/aurorae/src/aurorae.cpp b/clients/aurorae/src/aurorae.cpp index 19db4811df..9a6965cece 100644 --- a/clients/aurorae/src/aurorae.cpp +++ b/clients/aurorae/src/aurorae.cpp @@ -21,6 +21,7 @@ along with this program. If not, see . #include #include +#include #include #include @@ -99,6 +100,8 @@ bool AuroraeFactory::supports(Ability ability) const return m_theme->hasButton(HelpButton); case AbilityProvidesShadow: return true; // TODO: correct value from theme + case AbilityClientGrouping: + return true; default: return false; } @@ -125,6 +128,7 @@ AuroraeFactory *AuroraeFactory::s_instance = NULL; *******************************************************/ AuroraeClient::AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *factory) : KDecorationUnstable(bridge, factory) + , m_clickInProgress(false) { m_scene = new AuroraeScene(AuroraeFactory::instance()->theme(), options()->customButtonPositions() ? options()->titleButtonsLeft() : AuroraeFactory::instance()->theme()->defaultButtonsLeft(), @@ -148,6 +152,10 @@ AuroraeClient::AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *fact connect(m_scene, SIGNAL(titleMouseMoved(Qt::MouseButton,Qt::MouseButtons)), SLOT(titleMouseMoved(Qt::MouseButton,Qt::MouseButtons))); connect(m_scene, SIGNAL(wheelEvent(int)), SLOT(titlebarMouseWheelOperation(int))); + connect(m_scene, SIGNAL(tabMouseButtonPress(QGraphicsSceneMouseEvent*,int)), + SLOT(tabMouseButtonPress(QGraphicsSceneMouseEvent*,int))); + connect(m_scene, SIGNAL(tabMouseButtonRelease(QGraphicsSceneMouseEvent*,int)), + SLOT(tabMouseButtonRelease(QGraphicsSceneMouseEvent*,int))); connect(this, SIGNAL(keepAboveChanged(bool)), SLOT(keepAboveChanged(bool))); connect(this, SIGNAL(keepBelowChanged(bool)), SLOT(keepBelowChanged(bool))); } @@ -162,6 +170,7 @@ void AuroraeClient::init() createMainWidget(); widget()->setAttribute(Qt::WA_TranslucentBackground); widget()->setAttribute(Qt::WA_NoSystemBackground); + widget()->installEventFilter(this); m_view = new QGraphicsView(m_scene, widget()); m_view->setAttribute(Qt::WA_TranslucentBackground); m_view->setFrameShape(QFrame::NoFrame); @@ -181,7 +190,6 @@ void AuroraeClient::init() m_scene->setShade(isShade()); m_scene->setKeepAbove(keepAbove()); m_scene->setKeepBelow(keepBelow()); - m_scene->setCaption(caption()); AuroraeFactory::instance()->theme()->setCompositingActive(compositingActive()); } @@ -194,7 +202,7 @@ void AuroraeClient::activeChange() void AuroraeClient::captionChange() { - m_scene->setCaption(caption()); + checkTabs(true); } void AuroraeClient::iconChange() @@ -395,6 +403,55 @@ void AuroraeClient::titleMouseMoved(Qt::MouseButton button, Qt::MouseButtons but event = 0; } +void AuroraeClient::checkTabs(bool force) +{ + if (m_scene->tabCount() == 1 && clientGroupItems().count() == 1 && !force) { + return; + } + while (m_scene->tabCount() < clientGroupItems().count()) { + m_scene->addTab(QString()); + } + while (m_scene->tabCount() > clientGroupItems().count()) { + m_scene->removeLastTab(); + } + QStringList captions; + foreach (const ClientGroupItem &item, clientGroupItems()) { + captions << item.title(); + } + m_scene->setCaptions(captions); + m_scene->setFocusedTab(visibleClientGroupItem()); +} + +bool AuroraeClient::eventFilter(QObject *o, QEvent *e) +{ + if (o != widget()) { + return false; + } + if (e->type() == QEvent::Paint) { + checkTabs(); + } + return false; +} + +void AuroraeClient::tabMouseButtonPress(QGraphicsSceneMouseEvent *e, int index) +{ + if (buttonToWindowOperation(e->buttons()) == OperationsOp) { + displayClientMenu(index, e->screenPos()); + return; + } + titlePressed(e->button(), e->buttons()); + m_clickInProgress = true; +} + +void AuroraeClient::tabMouseButtonRelease(QGraphicsSceneMouseEvent *e, int index) +{ + if (m_clickInProgress) { + setVisibleClientGroupItem(index); + } + titleReleased(e->button(), e->buttons()); + m_clickInProgress = false; +} + } // namespace Aurorae extern "C" diff --git a/clients/aurorae/src/aurorae.h b/clients/aurorae/src/aurorae.h index 9821bacc7a..9336b81eba 100644 --- a/clients/aurorae/src/aurorae.h +++ b/clients/aurorae/src/aurorae.h @@ -23,6 +23,7 @@ along with this program. If not, see . #include #include +class QGraphicsSceneMouseEvent; class QGraphicsView; class QGraphicsScene; @@ -86,11 +87,18 @@ private slots: void titlePressed(Qt::MouseButton button, Qt::MouseButtons buttons); void titleReleased(Qt::MouseButton button, Qt::MouseButtons buttons); void titleMouseMoved(Qt::MouseButton button, Qt::MouseButtons buttons); + void tabMouseButtonPress(QGraphicsSceneMouseEvent *e, int index); + void tabMouseButtonRelease(QGraphicsSceneMouseEvent *e, int index); + +protected: + virtual bool eventFilter(QObject *o, QEvent *e); private: void updateWindowShape(); + void checkTabs(bool force = false); AuroraeScene *m_scene; QGraphicsView *m_view; + bool m_clickInProgress; }; } diff --git a/clients/aurorae/src/lib/auroraescene.cpp b/clients/aurorae/src/lib/auroraescene.cpp index c69b6fc4d7..48f69a426d 100644 --- a/clients/aurorae/src/lib/auroraescene.cpp +++ b/clients/aurorae/src/lib/auroraescene.cpp @@ -54,6 +54,7 @@ AuroraeScene::AuroraeScene(Aurorae::AuroraeTheme* theme, const QString& leftButt , m_rightButtonOrder(rightButtons) , m_dblClicked(false) , m_contextHelp(contextHelp) + , m_tabCount(0) { init(); connect(m_theme, SIGNAL(themeChanged()), SLOT(resetTheme())); @@ -69,6 +70,7 @@ void AuroraeScene::init() if (!m_theme->isValid()) { return; } + m_tabCount = 0; Qt::Orientation orientation = Qt::Horizontal; switch ((DecorationPosition)m_theme->themeConfig().decorationPosition()) { case DecorationLeft: // fall through @@ -109,12 +111,8 @@ void AuroraeScene::init() titleLayout->setContentsMargins(0, 0, 0, 0); titleLayout->setOrientation(orientation); m_title = new QGraphicsWidget; - AuroraeTab *tab = new AuroraeTab(m_theme, m_caption); - connect(this, SIGNAL(activeChanged()), tab, SLOT(activeChanged())); - titleLayout->addItem(tab); m_title->setLayout(titleLayout); addItem(m_title); - tab->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setActive(m_active, false); updateLayout(); @@ -759,16 +757,96 @@ void AuroraeScene::setButtons(const QString &left, const QString &right) resetTheme(); } -void AuroraeScene::setCaption(const QString &caption) +void AuroraeScene::setCaption(const QString &caption, int index) { - m_caption = caption; foreach (QGraphicsItem *item, items()) { if (AuroraeTab *tab = dynamic_cast(item)) { - tab->setCaption(caption); + if (tab->index() == index) { + tab->setCaption(caption); + } } } } +void AuroraeScene::setCaptions(const QStringList &captions) +{ + foreach (QGraphicsItem *item, items()) { + if (AuroraeTab *tab = dynamic_cast(item)) { + if (tab->index() < captions.size()) { + tab->setCaption(captions[tab->index()]); + } + } + } +} + +void AuroraeScene::addTab(const QString &caption) +{ + AuroraeTab *tab = new AuroraeTab(m_theme, caption, m_tabCount); + ++m_tabCount; + connect(this, SIGNAL(activeChanged()), tab, SLOT(activeChanged())); + connect(tab, SIGNAL(mouseButtonPress(QGraphicsSceneMouseEvent*,int)), + SIGNAL(tabMouseButtonPress(QGraphicsSceneMouseEvent*,int))); + connect(tab, SIGNAL(mouseButtonRelease(QGraphicsSceneMouseEvent*,int)), + SIGNAL(tabMouseButtonRelease(QGraphicsSceneMouseEvent*,int))); + connect(tab, SIGNAL(mouseDblClicked()), SIGNAL(titleDoubleClicked())); + connect(tab, SIGNAL(mouseMoved(Qt::MouseButton,Qt::MouseButtons)), + SIGNAL(titleMouseMoved(Qt::MouseButton,Qt::MouseButtons))); + static_cast(m_title->layout())->addItem(tab); + tab->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_title->layout()->invalidate(); +} + +void AuroraeScene::addTabs(const QStringList &captions) +{ + foreach (const QString &caption, captions) { + addTab(caption); + } +} + +void AuroraeScene::removeLastTab() +{ + if (m_tabCount < 2) { + return; + } + foreach (QGraphicsItem *item, items()) { + if (AuroraeTab *tab = dynamic_cast(item)) { + if (tab->index() == m_tabCount-1) { + m_title->layout()->removeAt(tab->index()); + removeItem(tab); + --m_tabCount; + m_title->layout()->invalidate(); + return; + } + } + } +} + +int AuroraeScene::tabCount() const +{ + return m_tabCount; +} + +int AuroraeScene::focusedTab() const +{ + return m_focusedTab; +} + +void AuroraeScene::setFocusedTab(int index) +{ + if (m_focusedTab != index) { + m_focusedTab = index; + m_title->update(); + } +} + +bool AuroraeScene::isFocusedTab(int index) const +{ + if (m_tabCount == 1) { + return true; + } + return (index == m_focusedTab); +} + void AuroraeScene::mousePressEvent(QGraphicsSceneMouseEvent* event) { QGraphicsScene::mousePressEvent(event); diff --git a/clients/aurorae/src/lib/auroraescene.h b/clients/aurorae/src/lib/auroraescene.h index 0e5a497a59..601f8347af 100644 --- a/clients/aurorae/src/lib/auroraescene.h +++ b/clients/aurorae/src/lib/auroraescene.h @@ -66,7 +66,39 @@ public: int rightButtonsWidth() const; void setButtons(const QString &left, const QString &right); - void setCaption(const QString &caption); + /** + * Updates the caption for the decoration with given index. + * @param caption The new caption + * @param index The index of the tab + */ + void setCaption(const QString &caption, int index = 0); + /** + * Updates the captions of all tabs. + * @param captions The new captions + */ + void setCaptions(const QStringList &captions); + /** + * Adds a tab with given caption to the end of the tab list. + */ + void addTab(const QString &caption); + /** + * Adds a tab for each of the given captions to the end of the tab list. + */ + void addTabs(const QStringList &captions); + /** + * Removes the last tab from the list, if there are at least two tabs. + */ + void removeLastTab(); + /** + * current number of tabs + */ + int tabCount() const; + void setFocusedTab(int index); + int focusedTab() const; + /** + * @returns true if the tab at given index is the focused one. + */ + bool isFocusedTab(int index) const; const QString &leftButtons() const; const QString &rightButtons() const; @@ -86,6 +118,8 @@ Q_SIGNALS: void titleDoubleClicked(); void titleMouseMoved(Qt::MouseButton, Qt::MouseButtons); void wheelEvent(int delta); + void tabMouseButtonPress(QGraphicsSceneMouseEvent*, int); + void tabMouseButtonRelease(QGraphicsSceneMouseEvent*, int); void activeChanged(); @@ -120,9 +154,10 @@ private: bool m_keepBelow; QString m_leftButtonOrder; QString m_rightButtonOrder; - QString m_caption; bool m_dblClicked; bool m_contextHelp; + int m_tabCount; + int m_focusedTab; }; } // namespace diff --git a/clients/aurorae/src/lib/auroraetab.cpp b/clients/aurorae/src/lib/auroraetab.cpp index b447e57016..c6ab26c049 100644 --- a/clients/aurorae/src/lib/auroraetab.cpp +++ b/clients/aurorae/src/lib/auroraetab.cpp @@ -28,21 +28,23 @@ #include #include #include +#include #include namespace Aurorae { -AuroraeTab::AuroraeTab(AuroraeTheme* theme, const QString& caption) +AuroraeTab::AuroraeTab(AuroraeTheme* theme, const QString& caption, int index) : QGraphicsWidget() , m_theme(theme) , m_caption(caption) + , m_index(index) + , m_dblClicked(false) { m_effect = new QGraphicsDropShadowEffect(this); if (m_theme->themeConfig().useTextShadow()) { setGraphicsEffect(m_effect); } - setAcceptedMouseButtons(Qt::NoButton); connect(m_theme, SIGNAL(buttonSizesChanged()), SLOT(buttonSizesChanged())); } @@ -72,6 +74,11 @@ void AuroraeTab::setCaption(const QString& caption) update(); } +void AuroraeTab::setIndex(int index) +{ + m_index = index; +} + void AuroraeTab::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) @@ -81,7 +88,47 @@ void AuroraeTab::paint(QPainter *painter, const QStyleOptionGraphicsItem *option painter->setCompositionMode(QPainter::CompositionMode_SourceOver); AuroraeScene *s = static_cast(scene()); const bool active = s->isActive(); + const bool useTabs = (s->tabCount() > 1); + const bool focused = s->isFocusedTab(m_index); const ThemeConfig &conf = m_theme->themeConfig(); + if (useTabs) { + painter->save(); + Plasma::FrameSvg *decoration = m_theme->decoration(); + if (!decoration->hasElementPrefix("tab-active-focused") && m_index < s->tabCount()-1) { + QColor color = active ? conf.activeTextColor(true, false) : conf.inactiveTextColor(true, false); + painter->setPen(color); + QPointF point1 = rect().topRight(); + QPointF point2 = rect().bottomRight(); + if (m_theme->decorationPosition() == DecorationLeft || + m_theme->decorationPosition() == DecorationRight) { + point1 = rect().topRight(); + point2 = rect().topLeft(); + } + painter->drawLine(point1, point2); + } else if (decoration->hasElementPrefix("tab-active-focused")) { + QString element = "tab-active-"; + if (!active && decoration->hasElementPrefix("tab-inactive-focused")) { + element = "tab-inactive-"; + } + bool useFocused = true; + if (!focused) { + if (element.startsWith(QLatin1String("tab-active")) && + decoration->hasElementPrefix("tab-active-unfocused")) { + useFocused = false; + } + if (element.startsWith(QLatin1String("tab-inactive")) && + decoration->hasElementPrefix("tab-inactive-unfocused")) { + useFocused = false; + } + } + element.append(useFocused ? "focused" : "unfocused"); + decoration->setElementPrefix(element); + decoration->setEnabledBorders(Plasma::FrameSvg::AllBorders); + decoration->resizeFrame(size()); + decoration->paintFrame(painter); + } + painter->restore(); + } Qt::Alignment align = conf.alignment(); if (align != Qt::AlignCenter && QApplication::layoutDirection() == Qt::RightToLeft) { // have to swap the alignment to be consistent with other kwin decos. @@ -124,14 +171,14 @@ void AuroraeTab::paint(QPainter *painter, const QStyleOptionGraphicsItem *option QPainter p(&pix); QColor color; if (active) { - color = conf.activeTextColor(); + color = conf.activeTextColor(useTabs, focused); if (s->isAnimating()) { - color = KColorUtils::mix(conf.inactiveTextColor(), conf.activeTextColor(), s->animationProgress()); + color = KColorUtils::mix(conf.inactiveTextColor(useTabs, focused), conf.activeTextColor(useTabs, focused), s->animationProgress()); } } else { - color = conf.inactiveTextColor(); + color = conf.inactiveTextColor(useTabs, focused); if (s->isAnimating()){ - color = KColorUtils::mix(conf.activeTextColor(), conf.inactiveTextColor(), s->animationProgress()); + color = KColorUtils::mix(conf.activeTextColor(useTabs, focused), conf.inactiveTextColor(useTabs, focused), s->animationProgress()); } } p.setPen(color); @@ -175,4 +222,31 @@ void AuroraeTab::buttonSizesChanged() updateGeometry(); } +void AuroraeTab::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + QGraphicsItem::mousePressEvent(event); + event->accept(); + emit mouseButtonPress(event, m_index); +} + +void AuroraeTab::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + QGraphicsItem::mouseReleaseEvent(event); + if (m_dblClicked && event->button() == Qt::LeftButton) { + // eat event + m_dblClicked = false; + return; + } + emit mouseButtonRelease(event, m_index); +} + +void AuroraeTab::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + QGraphicsItem::mouseDoubleClickEvent(event); + if (event->button() == Qt::LeftButton) { + m_dblClicked = true; + emit mouseDblClicked(); + } +} + } // namespace diff --git a/clients/aurorae/src/lib/auroraetab.h b/clients/aurorae/src/lib/auroraetab.h index 99138cba25..224e437095 100644 --- a/clients/aurorae/src/lib/auroraetab.h +++ b/clients/aurorae/src/lib/auroraetab.h @@ -31,21 +31,38 @@ class AuroraeTab : public QGraphicsWidget { Q_OBJECT public: - AuroraeTab(AuroraeTheme *theme, const QString &caption); + AuroraeTab(AuroraeTheme *theme, const QString &caption, int index); virtual ~AuroraeTab(); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); void setCaption(const QString &caption); + void setIndex(int index); + int index() const { + return m_index; + } + +Q_SIGNALS: + void mouseButtonPress(QGraphicsSceneMouseEvent *e, int index); + void mouseButtonRelease(QGraphicsSceneMouseEvent *e, int index); + void mouseDblClicked(); + void mouseMoved(Qt::MouseButton, Qt::MouseButtons); public Q_SLOTS: void activeChanged(); +protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); + private Q_SLOTS: void buttonSizesChanged(); private: AuroraeTheme *m_theme; QString m_caption; + int m_index; QGraphicsDropShadowEffect *m_effect; + bool m_dblClicked; }; } diff --git a/clients/aurorae/src/lib/themeconfig.cpp b/clients/aurorae/src/lib/themeconfig.cpp index fd903eda07..2268b2fedb 100644 --- a/clients/aurorae/src/lib/themeconfig.cpp +++ b/clients/aurorae/src/lib/themeconfig.cpp @@ -32,6 +32,10 @@ void ThemeConfig::load(const KConfig &conf) KConfigGroup general(&conf, "General"); m_activeTextColor = general.readEntry("ActiveTextColor", QColor(Qt::black)); m_inactiveTextColor = general.readEntry("InactiveTextColor", QColor(Qt::black)); + m_activeFocusedTextColor = general.readEntry("ActiveFocusedTabColor", m_activeTextColor); + m_activeUnfocusedTextColor = general.readEntry("ActiveUnfocusedTabColor", m_inactiveTextColor); + m_inactiveFocusedTextColor = general.readEntry("InactiveFocusedTabColor", m_inactiveTextColor); + m_inactiveUnfocusedTextColor = general.readEntry("InactiveUnfocusedTabColor", m_inactiveTextColor); m_useTextShadow = general.readEntry("UseTextShadow", false); m_activeTextShadowColor = general.readEntry("ActiveTextShadowColor", QColor(Qt::white)); m_inactiveTextShadowColor = general.readEntry("InactiveTextShadowColor", QColor(Qt::white)); @@ -105,4 +109,28 @@ void ThemeConfig::load(const KConfig &conf) m_paddingBottom = border.readEntry("PaddingBottom", 0); } +QColor ThemeConfig::activeTextColor(bool useTabs, bool focused) const +{ + if (!useTabs) { + return m_activeTextColor; + } + if (focused) { + return m_activeFocusedTextColor; + } else { + return m_activeUnfocusedTextColor; + } +} + +QColor ThemeConfig::inactiveTextColor(bool useTabs, bool focused) const +{ + if (!useTabs) { + return m_inactiveTextColor; + } + if (focused) { + return m_inactiveFocusedTextColor; + } else { + return m_inactiveUnfocusedTextColor; + } +} + } //namespace diff --git a/clients/aurorae/src/lib/themeconfig.h b/clients/aurorae/src/lib/themeconfig.h index 6dd73faa9e..48e05d547b 100644 --- a/clients/aurorae/src/lib/themeconfig.h +++ b/clients/aurorae/src/lib/themeconfig.h @@ -33,13 +33,9 @@ public: void load(const KConfig &conf); ~ThemeConfig() {}; // active window - QColor activeTextColor() const { - return m_activeTextColor; - } + QColor activeTextColor(bool useTabs = false, bool focused = true) const; // inactive window - QColor inactiveTextColor() const { - return m_inactiveTextColor; - } + QColor inactiveTextColor(bool useTabs = false, bool focused = true) const; QColor activeTextShadowColor() const { return m_activeTextShadowColor; } @@ -191,7 +187,11 @@ public: private: QColor m_activeTextColor; + QColor m_activeFocusedTextColor; + QColor m_activeUnfocusedTextColor; QColor m_inactiveTextColor; + QColor m_inactiveFocusedTextColor; + QColor m_inactiveUnfocusedTextColor; QColor m_activeTextShadowColor; QColor m_inactiveTextShadowColor; int m_textShadowOffsetX;