kwin/clients/aurorae/src/lib/auroraebutton.cpp

507 lines
15 KiB
C++
Raw Normal View History

/*
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 "auroraebutton.h"
#include "auroraescene.h"
#include "auroraetheme.h"
#include "themeconfig.h"
// Qt
#include <QtCore/QEasingCurve>
#include <QtCore/QPropertyAnimation>
#include <QtCore/QTimer>
#include <QtGui/QGraphicsSceneEvent>
#include <QtGui/QPainter>
// KDE
#include <KDE/KIcon>
#include <KDE/KIconLoader>
#include <KDE/KIconEffect>
#include <KDE/Plasma/FrameSvg>
#include <KDE/Plasma/PaintUtils>
namespace Aurorae {
AuroraeButtonGroup::AuroraeButtonGroup(AuroraeTheme *theme, AuroraeButtonGroup::ButtonGroup group)
: QGraphicsWidget()
, m_theme(theme)
, m_group(group)
{
}
void AuroraeButtonGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
Plasma::FrameSvg *decoration = m_theme->decoration();
QString basePrefix;
QString prefix;
AuroraeScene *s = static_cast<AuroraeScene*>(scene());
switch (m_group) {
case LeftGroup:
basePrefix = "buttongroup-left";
break;
case RightGroup:
basePrefix = "buttongroup-right";
break;
}
if (!decoration->hasElementPrefix(basePrefix)) {
return;
}
if (!s->isActive() && decoration->hasElementPrefix(basePrefix + "-inactive")) {
prefix = basePrefix + "-inactive";
} else {
prefix = basePrefix;
}
decoration->setElementPrefix(prefix);
decoration->setEnabledBorders(Plasma::FrameSvg::AllBorders);
decoration->resizeFrame(size());
if (s->isAnimating() && decoration->hasElementPrefix(basePrefix + "-inactive")) {
QPixmap target = decoration->framePixmap();
decoration->setElementPrefix(basePrefix + "-inactive");
if (!s->isActive()) {
decoration->setElementPrefix(basePrefix);
}
decoration->resizeFrame(size());
QPixmap result = Plasma::PaintUtils::transition(decoration->framePixmap(),
target, s->animationProgress());
painter->drawPixmap(0, 0, result);
} else {
decoration->paintFrame(painter);
}
}
AuroraeButton::AuroraeButton(AuroraeTheme* theme, AuroraeButtonType type)
: QGraphicsWidget()
, m_theme(theme)
, m_type(type)
, m_pressed(false)
, m_hovered(false)
, m_animationProgress(0.0)
, m_animation(new QPropertyAnimation(this, "animation", this))
, m_checkable(false)
, m_checked(false)
{
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setAcceptHoverEvents(true);
setAcceptedMouseButtons(Qt::LeftButton);
connect(m_theme, SIGNAL(buttonSizesChanged()), SLOT(buttonSizesChanged()));
}
AuroraeButton::~AuroraeButton()
{
}
void AuroraeButton::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
if (m_theme->hasButton(m_type)) {
ButtonStates state;
if (static_cast<AuroraeScene*>(scene())->isActive()) {
state |= Active;
}
if (m_hovered) {
state |= Hover;
}
if (m_pressed) {
state |= Pressed;
}
if (isCheckable() && isChecked()) {
state |= Pressed;
}
paintButton(painter, m_theme->button(currentType()), state);
}
}
AuroraeButtonType AuroraeButton::currentType() const
{
return m_type;
}
QSizeF AuroraeButton::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
{
Q_UNUSED(which)
Q_UNUSED(constraint)
const qreal factor = m_theme->buttonSizeFactor();
qreal width = m_theme->themeConfig().buttonWidth()*factor;
qreal height = m_theme->themeConfig().buttonHeight()*factor;
switch (m_type) {
case MinimizeButton:
width = m_theme->themeConfig().buttonWidthMinimize()*factor;
break;
case MaximizeButton:
case RestoreButton:
width = m_theme->themeConfig().buttonWidthMaximizeRestore()*factor;
break;
case CloseButton:
width = m_theme->themeConfig().buttonWidthClose()*factor;
break;
case AllDesktopsButton:
width = m_theme->themeConfig().buttonWidthAllDesktops()*factor;
break;
case KeepAboveButton:
width = m_theme->themeConfig().buttonWidthKeepAbove()*factor;
break;
case KeepBelowButton:
width = m_theme->themeConfig().buttonWidthKeepBelow()*factor;
break;
case ShadeButton:
width = m_theme->themeConfig().buttonWidthShade()*factor;
break;
case HelpButton:
width = m_theme->themeConfig().buttonWidthHelp()*factor;
break;
default:
break; // nothing
}
if (m_theme->themeConfig().decorationPosition() == DecorationLeft ||
m_theme->themeConfig().decorationPosition() == DecorationRight) {
qSwap(width, height);
}
return QSizeF(width, height);
}
void AuroraeButton::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
Q_UNUSED(event)
m_pressed = true;
update();
}
void AuroraeButton::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
Q_UNUSED(event)
if (m_pressed) {
emit clicked();
}
m_pressed = false;
update();
QGraphicsItem::mouseReleaseEvent(event);
}
void AuroraeButton::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
{
Q_UNUSED(event)
m_hovered = true;
if (isAnimating()) {
m_animation->stop();
}
m_animationProgress = 0.0;
int time = m_theme->themeConfig().animationTime();
if (time != 0) {
m_animation->setDuration(time);
m_animation->setEasingCurve(QEasingCurve::InQuad);
m_animation->setStartValue(0.0);
m_animation->setEndValue(1.0);
m_animation->start();
}
update();
}
void AuroraeButton::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
{
Q_UNUSED(event)
m_hovered = false;
if (isAnimating()) {
m_animation->stop();
}
m_animationProgress = 0.0;
int time = m_theme->themeConfig().animationTime();
if (time != 0) {
m_animation->setDuration(time);
m_animation->setEasingCurve(QEasingCurve::OutQuad);
m_animation->setStartValue(0.0);
m_animation->setEndValue(1.0);
m_animation->start();
}
update();
}
void AuroraeButton::paintButton(QPainter *painter, Plasma::FrameSvg *frame, ButtonStates states)
{
QString prefix = "active";
QString animationPrefix = "active";
bool hasInactive = false;
// check for inactive prefix
if (!states.testFlag(Active) && frame->hasElementPrefix("inactive")) {
// we have inactive, so we use it
hasInactive = true;
prefix = "inactive";
animationPrefix = "inactive";
}
if (states.testFlag(Hover)) {
if (states.testFlag(Active)) {
if (frame->hasElementPrefix("hover")) {
prefix = "hover";
}
} else {
if (hasInactive) {
if (frame->hasElementPrefix("hover-inactive")) {
prefix = "hover-inactive";
}
} else {
if (frame->hasElementPrefix("hover")) {
prefix = "hover";
}
}
}
}
if (states.testFlag(Pressed)) {
if (states.testFlag(Active)) {
if (frame->hasElementPrefix("pressed")) {
prefix = "pressed";
}
} else {
if (hasInactive) {
if (frame->hasElementPrefix("pressed-inactive")) {
prefix = "pressed-inactive";
}
} else {
if (frame->hasElementPrefix("pressed")) {
prefix = "pressed";
}
}
}
}
if (states.testFlag(Deactivated)) {
if (states.testFlag(Active)) {
if (frame->hasElementPrefix("deactivated")) {
prefix = "deactivated";
}
} else {
if (hasInactive) {
if (frame->hasElementPrefix("deactivated-inactive")) {
prefix = "deactivated-inactive";
}
} else {
if (frame->hasElementPrefix("deactivated")) {
prefix = "deactivated";
}
}
}
}
frame->setElementPrefix(prefix);
frame->resizeFrame(size());
if (isAnimating()) {
// there is an animation so we have to use it
// the animation is definately a hover animation as currently nothing else is supported
if (!states.testFlag(Hover)) {
// only have to set for not hover state as animationPrefix is set to (in)active by default
if (states.testFlag(Active)) {
if (frame->hasElementPrefix("hover")) {
animationPrefix = "hover";
}
} else {
if (hasInactive) {
if (frame->hasElementPrefix("hover-inactive")) {
animationPrefix = "hover-inactive";
}
} else {
if (frame->hasElementPrefix("hover")) {
animationPrefix = "hover";
}
}
}
}
QPixmap target = frame->framePixmap();
frame->setElementPrefix(animationPrefix);
frame->resizeFrame(size());
QPixmap result = Plasma::PaintUtils::transition(frame->framePixmap(),
target, m_animationProgress);
painter->drawPixmap(QRect(QPoint(0, 0), size().toSize()), result);
} else {
bool animation = false;
AuroraeScene *s = static_cast<AuroraeScene*>(scene());
if (s->isAnimating()) {
animationPrefix = prefix;
if (prefix.endsWith("-inactive")) {
animationPrefix.remove("-inactive");
} else {
animationPrefix = animationPrefix + "-inactive";
}
if (frame->hasElementPrefix(animationPrefix)) {
animation = true;
QPixmap target = frame->framePixmap();
frame->setElementPrefix(animationPrefix);
frame->resizeFrame(size());
QPixmap result = Plasma::PaintUtils::transition(frame->framePixmap(),
target, s->animationProgress());
painter->drawPixmap(0, 0, result);
}
}
if (!animation) {
frame->paintFrame(painter);
}
}
}
bool AuroraeButton::isAnimating() const
{
return (m_animation->state() == QAbstractAnimation::Running);
}
qreal AuroraeButton::animationProgress() const
{
return m_animationProgress;
}
void AuroraeButton::setAnimationProgress(qreal progress)
{
m_animationProgress = progress;
update();
}
void AuroraeButton::buttonSizesChanged()
{
updateGeometry();
static_cast<AuroraeScene*>(scene())->updateLayout();
}
/***********************************************
* AuroraeMaximizeButton
***********************************************/
AuroraeMaximizeButton::AuroraeMaximizeButton(AuroraeTheme* theme)
: AuroraeButton(theme, MaximizeButton)
, m_maximizeMode(KDecorationDefines::MaximizeRestore)
{
setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton|Qt::MidButton);
}
void AuroraeMaximizeButton::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
AuroraeButton::mousePressEvent(event);
m_pressedButton = event->button();
}
void AuroraeMaximizeButton::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
if (isPressed() && m_pressedButton == event->button()) {
emit clicked(m_pressedButton);
}
setPressed(false);
update();
QGraphicsItem::mouseReleaseEvent(event);
}
AuroraeButtonType AuroraeMaximizeButton::currentType() const
{
if (m_maximizeMode == KDecorationDefines::MaximizeFull &&
theme()->hasButton(RestoreButton)) {
return RestoreButton;
} else {
return MaximizeButton;
}
}
void AuroraeMaximizeButton::setMaximizeMode(KDecorationDefines::MaximizeMode mode)
{
m_maximizeMode = mode;
update();
}
/************************************************
* AuroraeMenuButton
************************************************/
AuroraeMenuButton::AuroraeMenuButton(AuroraeTheme* theme)
: AuroraeButton(theme, MenuButton)
{
m_timer = new QTimer(this);
m_timer->setSingleShot(true);
m_timer->setInterval(QApplication::doubleClickInterval());
connect(m_timer, SIGNAL(timeout()), SIGNAL(clicked()));
}
void AuroraeMenuButton::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
if (m_icon.isNull()) {
return;
}
QPixmap iconPix = m_icon;
KIconEffect *effect = KIconLoader::global()->iconEffect();
AuroraeScene *s = static_cast<AuroraeScene*>(scene());
if (s->isActive()) {
if (isHovered()) {
iconPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::ActiveState);
}
} else {
iconPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::DisabledState);
}
if (s->isAnimating()) {
// animation
QPixmap oldPix = m_icon;
if (!s->isActive()) {
if (isHovered()) {
oldPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::ActiveState);
}
} else {
oldPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::DisabledState);
}
iconPix = Plasma::PaintUtils::transition(oldPix, iconPix, s->animationProgress());
}
painter->drawPixmap(0, 0, iconPix);
}
void AuroraeMenuButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
{
Q_UNUSED(event)
emit doubleClicked();
}
void AuroraeMenuButton::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
Q_UNUSED(event)
if (isPressed()) {
if (m_timer->isActive()) {
m_timer->stop();
} else {
m_timer->start();
}
}
setPressed(false);
update();
QGraphicsItem::mouseReleaseEvent(event);
}
void AuroraeMenuButton::setIcon(const QPixmap& icon)
{
m_icon = icon;
update();
}
/************************************************
* AuroraeSpacer
************************************************/
AuroraeSpacer::AuroraeSpacer(AuroraeTheme *theme)
: QGraphicsWidget()
, m_theme(theme)
{
}
QSizeF AuroraeSpacer::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
Q_UNUSED(which)
Q_UNUSED(constraint)
return QSizeF(m_theme->themeConfig().explicitButtonSpacer(),
m_theme->themeConfig().buttonHeight());
}
} // namespace