Aurorae supports window tabbing.

svn path=/trunk/KDE/kdebase/workspace/; revision=1124521
This commit is contained in:
Martin Gräßlin 2010-05-09 09:08:09 +00:00
parent 3e9377e6b4
commit a1fa419ea6
8 changed files with 321 additions and 24 deletions

View file

@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsSceneMouseEvent>
#include <KConfig>
#include <KConfigGroup>
@ -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"

View file

@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kdecoration.h>
#include <kdecorationfactory.h>
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;
};
}

View file

@ -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<AuroraeTab*>(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<AuroraeTab*>(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<QGraphicsLinearLayout*>(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<AuroraeTab*>(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);

View file

@ -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

View file

@ -28,21 +28,23 @@
#include <QtGui/QStyle>
#include <KDE/KColorUtils>
#include <KDE/KGlobalSettings>
#include <KDE/Plasma/FrameSvg>
#include <KDE/Plasma/PaintUtils>
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<AuroraeScene*>(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

View file

@ -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;
};
}

View file

@ -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

View file

@ -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;