/* Library for Aurorae window decoration themes. Copyright (C) 2009, 2010 Martin Gräßlin 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 #include #include #include #include // KDE #include #include #include #include #include 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(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(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(scene()); if (s->isAnimating()) { animationPrefix = prefix; if (prefix.endsWith(QLatin1String("-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(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(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