kwin/clients/aurorae/src/lib/auroraetab.cpp
Martin Gräßlin abcef60190 Forward port revision 1169086: Update text shadow information whenever Tabs are added/removed in Aurorae.
Fixes incorrect initial text shadow position in Aurorae. Unfortunately
QGraphicsDropShadowEffect seems to be not side effect free. Updates to the scene
are not propagated leaving the tabs in a wrong visual state. Therefore text shadow
is disabled for window tabbing. I will investigate further to see if it gets fixed
in Qt 4.7.
CCBUG: 248754

svn path=/trunk/KDE/kdebase/workspace/; revision=1169087
2010-08-28 12:00:03 +00:00

300 lines
10 KiB
C++

/*
Library for Aurorae window decoration themes.
Copyright (C) 2009, 2010 Martin Gräßlin <kde@martin-graesslin.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "auroraetab.h"
#include "auroraescene.h"
#include "auroraetheme.h"
#include "themeconfig.h"
#include <QtGui/QGraphicsDropShadowEffect>
#include <QtGui/QGraphicsSceneMouseEvent>
#include <QtGui/QPainter>
#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, int index)
: QGraphicsWidget()
, m_theme(theme)
, m_caption(caption)
, m_index(index)
, m_dblClicked(false)
, m_uid(-1)
, m_dragAllowed(true)
, m_clickInProgress(false)
{
m_effect = new QGraphicsDropShadowEffect(this);
if (m_theme->themeConfig().useTextShadow()) {
setGraphicsEffect(m_effect);
}
connect(m_theme, SIGNAL(buttonSizesChanged()), SLOT(buttonSizesChanged()));
}
AuroraeTab::~AuroraeTab()
{
}
void AuroraeTab::activeChanged()
{
if (scene() == NULL) {
return;
}
const ThemeConfig &config = m_theme->themeConfig();
if (!config.useTextShadow()) {
return;
}
AuroraeScene *s = static_cast<AuroraeScene*>(scene());
if (s->tabCount() > 1) {
// graphics effect seems to be not side effect free and drops scheduled updates
// rendering tabs unreadable, therefore disabled.
m_effect->setEnabled(false);
} else {
m_effect->setEnabled(true);
}
const bool active = s->isActive();
m_effect->setXOffset(config.textShadowOffsetX());
m_effect->setYOffset(config.textShadowOffsetY());
m_effect->setColor(active ? config.activeTextShadowColor() : config.inactiveTextShadowColor());
}
void AuroraeTab::setCaption(const QString& caption)
{
if (m_caption == caption) {
return;
}
m_caption = caption;
updateGeometry();
update();
}
void AuroraeTab::setIndex(int index)
{
m_index = index;
}
void AuroraeTab::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
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();
const DecorationPosition decoPos = s->isShade() ? DecorationTop : m_theme->decorationPosition();
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 (decoPos == DecorationLeft || decoPos == 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.
// Decorations do not change in RTL mode
if (align == Qt::AlignLeft) {
align = Qt::AlignRight;
} else {
align = Qt::AlignLeft;
}
}
qreal w = rect().width();
qreal h = rect().height();
if (decoPos == DecorationLeft || decoPos == DecorationRight) {
h = rect().width();
w = rect().height();
}
const QRect textRect = painter->fontMetrics().boundingRect(QRect(rect().x(), rect().y(), w, h),
align | conf.verticalAlignment() | Qt::TextSingleLine,
m_caption);
if ((active && conf.haloActive()) ||
(!active && conf.haloInactive())) {
QRect haloRect = textRect;
if (haloRect.width() > w) {
haloRect.setWidth(w);
}
painter->save();
if (decoPos == DecorationLeft) {
painter->translate(rect().bottomLeft());
painter->rotate(270);
} else if (decoPos == DecorationRight) {
painter->translate(rect().topRight());
painter->rotate(90);
}
Plasma::PaintUtils::drawHalo(painter, haloRect);
painter->restore();
}
QPixmap pix(w, h);
pix.fill(Qt::transparent);
QPainter p(&pix);
QColor color;
if (active) {
color = conf.activeTextColor(useTabs, focused);
if (s->isAnimating()) {
color = KColorUtils::mix(conf.inactiveTextColor(useTabs, focused), conf.activeTextColor(useTabs, focused), s->animationProgress());
}
} else {
color = conf.inactiveTextColor(useTabs, focused);
if (s->isAnimating()){
color = KColorUtils::mix(conf.activeTextColor(useTabs, focused), conf.inactiveTextColor(useTabs, focused), s->animationProgress());
}
}
p.setPen(color);
p.drawText(pix.rect(), align | conf.verticalAlignment() | Qt::TextSingleLine, m_caption);
if (textRect.width() > w) {
// Fade out effect
// based on fadeout of tasks applet in Plasma/desktop/applets/tasks/abstracttaskitem.cpp by
// Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
// Copyright (C) 2008 by Alexis Ménard <darktears31@gmail.com>
// Copyright (C) 2008 by Marco Martin <notmart@gmail.com>
QLinearGradient alphaGradient(0, 0, 1, 0);
alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
if (QApplication::layoutDirection() == Qt::LeftToRight) {
alphaGradient.setColorAt(0, QColor(0, 0, 0, 255));
alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
} else {
alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
alphaGradient.setColorAt(1, QColor(0, 0, 0, 255));
}
int fadeWidth = 30;
int x = pix.width() - fadeWidth;
QRect r = QStyle::visualRect(QApplication::layoutDirection(), pix.rect(),
QRect(x, 0, fadeWidth, pix.height()));
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.fillRect(r, alphaGradient);
}
p.end();
if (decoPos == DecorationLeft) {
painter->translate(rect().bottomLeft());
painter->rotate(270);
} else if (decoPos == DecorationRight) {
painter->translate(rect().topRight());
painter->rotate(90);
}
painter->drawPixmap(pix.rect(), pix);
painter->restore();
}
void AuroraeTab::buttonSizesChanged()
{
updateGeometry();
}
void AuroraeTab::setUniqueTabId(long int id)
{
m_uid = id;
if (m_clickInProgress) {
m_dragAllowed = true;
}
}
void AuroraeTab::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsItem::mousePressEvent(event);
event->accept();
m_clickPos = event->pos();
m_clickInProgress = true;
m_dragAllowed = false;
emit mouseButtonPress(event, m_index);
}
void AuroraeTab::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsItem::mouseReleaseEvent(event);
m_dragAllowed = false;
m_clickInProgress = false;
if (m_dblClicked && event->button() == Qt::LeftButton) {
// eat event
m_dblClicked = false;
return;
}
emit mouseButtonRelease(event, m_index);
}
void AuroraeTab::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
m_clickInProgress = false;
if (event->button() == Qt::LeftButton) {
m_dblClicked = true;
emit mouseDblClicked();
}
}
void AuroraeTab::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
AuroraeScene *s = static_cast<AuroraeScene*>(scene());
if (s->tabCount() >= 1 && m_dragAllowed &&
(event->pos() - m_clickPos).manhattanLength() >= KGlobalSettings::dndEventDelay()) {
QDrag *drag = new QDrag(event->widget());
QMimeData *data = new QMimeData;
QString itemData = QString().setNum(m_uid) + '/' + QString().setNum(m_index);
data->setData(m_theme->tabDragMimeType(), itemData.toAscii());
drag->setMimeData(data);
QPixmap pix(size().toSize());
pix.fill(Qt::transparent);
QPainter painter(&pix);
s->render(&painter, pix.rect(), sceneBoundingRect());
drag->setPixmap(pix);
drag->exec();
if (!drag->target() && s->tabCount() > 1) {
emit tabRemoved(m_index);
}
}
}
} // namespace