diff --git a/clients/aurorae/src/CMakeLists.txt b/clients/aurorae/src/CMakeLists.txt index 0d410e416d..fcc2d209b9 100644 --- a/clients/aurorae/src/CMakeLists.txt +++ b/clients/aurorae/src/CMakeLists.txt @@ -1,6 +1,14 @@ ########### decoration ############### +include_directories( ./lib ) -set(kwin3_aurorae_PART_SRCS aurorae.cpp themeconfig.cpp) +set(kwin3_aurorae_PART_SRCS + aurorae.cpp + lib/auroraebutton.cpp + lib/auroraescene.cpp + lib/auroraetab.cpp + lib/auroraetheme.cpp + lib/themeconfig.cpp +) kde4_add_plugin(kwin3_aurorae ${kwin3_aurorae_PART_SRCS}) diff --git a/clients/aurorae/src/aurorae.cpp b/clients/aurorae/src/aurorae.cpp index 24ad997b21..a9202244ae 100644 --- a/clients/aurorae/src/aurorae.cpp +++ b/clients/aurorae/src/aurorae.cpp @@ -1,5 +1,5 @@ /******************************************************************** -Copyright (C) 2009 Martin Gräßlin +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 @@ -16,19 +16,15 @@ along with this program. If not, see . *********************************************************************/ #include "aurorae.h" +#include "auroraescene.h" +#include "auroraetheme.h" -#include -#include -#include +#include +#include #include #include -#include -#include -#include - -#include -#include +#include namespace Aurorae { @@ -36,7 +32,7 @@ namespace Aurorae AuroraeFactory::AuroraeFactory() : QObject() , KDecorationFactoryUnstable() - , m_valid(false) + , m_theme(new AuroraeTheme(this)) { init(); } @@ -46,42 +42,10 @@ void AuroraeFactory::init() KConfig conf("auroraerc"); KConfigGroup group(&conf, "Engine"); - m_themeName = group.readEntry("ThemeName", "example-deco"); - - QString file("aurorae/themes/" + m_themeName + "/decoration.svg"); - QString path = KGlobal::dirs()->findResource("data", file); - if (path.isEmpty()) { - file += 'z'; - path = KGlobal::dirs()->findResource("data", file); - } - if (path.isEmpty()) { - kDebug(1216) << "Could not find decoration svg: aborting"; - return; - } - m_frame.setImagePath(path); - m_frame.setCacheAllRenderedFrames(true); - m_frame.setEnabledBorders(Plasma::FrameSvg::AllBorders); - - // load the buttons - initButtonFrame("minimize"); - initButtonFrame("maximize"); - initButtonFrame("restore"); - initButtonFrame("close"); - initButtonFrame("alldesktops"); - initButtonFrame("keepabove"); - initButtonFrame("keepbelow"); - initButtonFrame("shade"); - initButtonFrame("help"); - - readThemeConfig(); - m_valid = true; -} - -void AuroraeFactory::readThemeConfig() -{ - // read config values - KConfig conf("aurorae/themes/" + m_themeName + '/' + m_themeName + "rc", KConfig::FullConfig, "data"); - m_themeConfig.load(&conf); + const QString themeName = group.readEntry("ThemeName", "example-deco"); + KConfig config("aurorae/themes/" + themeName + '/' + themeName + "rc", KConfig::FullConfig, "data"); + m_theme->loadTheme(themeName, config); + m_theme->setBorderSize(KDecoration::options()->preferredBorderSize(this)); } AuroraeFactory::~AuroraeFactory() @@ -100,9 +64,6 @@ AuroraeFactory *AuroraeFactory::instance() bool AuroraeFactory::reset(unsigned long changed) { - // re-read config - m_frame.clearCache(); - m_buttons.clear(); init(); resetDecorations(changed); return false; // need hard reset @@ -118,23 +79,23 @@ bool AuroraeFactory::supports(Ability ability) const case AbilityExtendIntoClientArea: return true; case AbilityButtonMinimize: - return m_buttons.contains("minimize"); + return m_theme->hasButton(MinimizeButton); case AbilityButtonMaximize: - return m_buttons.contains("maximize") || m_buttons.contains("restore"); + return m_theme->hasButton(MaximizeButton) || m_theme->hasButton(RestoreButton); case AbilityButtonClose: - return m_buttons.contains("close"); + return m_theme->hasButton(CloseButton); case AbilityButtonAboveOthers: - return m_buttons.contains("keepabove"); + return m_theme->hasButton(KeepAboveButton); case AbilityButtonBelowOthers: - return m_buttons.contains("keepbelow"); + return m_theme->hasButton(KeepBelowButton); case AbilityButtonShade: - return m_buttons.contains("shade"); + return m_theme->hasButton(ShadeButton); case AbilityButtonOnAllDesktops: - return m_buttons.contains("alldesktops"); + return m_theme->hasButton(AllDesktopsButton); case AbilityButtonHelp: - return m_buttons.contains("help"); + return m_theme->hasButton(HelpButton); case AbilityProvidesShadow: - return m_themeConfig.shadow(); + return true; // TODO: correct value from theme default: return false; } @@ -143,36 +104,7 @@ bool AuroraeFactory::supports(Ability ability) const KDecoration *AuroraeFactory::createDecoration(KDecorationBridge *bridge) { AuroraeClient *client = new AuroraeClient(bridge, this); - return client->decoration(); -} - -void AuroraeFactory::initButtonFrame(const QString &button) -{ - QString file("aurorae/themes/" + m_themeName + '/' + button + ".svg"); - QString path = KGlobal::dirs()->findResource("data", file); - if (path.isEmpty()) { - // let's look for svgz - file.append("z"); - path = KGlobal::dirs()->findResource("data", file); - } - if (!path.isEmpty()) { - Plasma::FrameSvg *frame = new Plasma::FrameSvg(this); - frame->setImagePath(path); - frame->setCacheAllRenderedFrames(true); - frame->setEnabledBorders(Plasma::FrameSvg::NoBorder); - m_buttons[ button ] = frame; - } else { - kDebug(1216) << "No button for: " << button; - } -} - -Plasma::FrameSvg *AuroraeFactory::button(const QString &b) -{ - if (hasButton(b)) { - return m_buttons[ b ]; - } else { - return NULL; - } + return client; } QList< KDecorationDefines::BorderSize > AuroraeFactory::borderSizes() const @@ -185,771 +117,207 @@ QList< KDecorationDefines::BorderSize > AuroraeFactory::borderSizes() const AuroraeFactory *AuroraeFactory::s_instance = NULL; -/******************************************************* -* Button -*******************************************************/ -AuroraeButton::AuroraeButton(ButtonType type, KCommonDecoration *parent) - : KCommonDecorationButton(type, parent) - , m_animationProgress(0.0) - , m_pressed(false) -{ - m_animation = new QPropertyAnimation(this, "animation", this); - setAttribute(Qt::WA_NoSystemBackground); -} - -void AuroraeButton::reset(unsigned long changed) -{ - Q_UNUSED(changed) -} - -void AuroraeButton::enterEvent(QEvent *event) -{ - Q_UNUSED(event) - if (isAnimating()) { - m_animation->stop(); - } - m_animationProgress = 0.0; - int time = AuroraeFactory::instance()->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::leaveEvent(QEvent *event) -{ - Q_UNUSED(event) - if (isAnimating()) { - m_animation->stop(); - } - m_animationProgress = 0.0; - int time = AuroraeFactory::instance()->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::mousePressEvent(QMouseEvent *e) -{ - m_pressed = true; - update(); - KCommonDecorationButton::mousePressEvent(e); -} - -void AuroraeButton::mouseReleaseEvent(QMouseEvent *e) -{ - m_pressed = false; - update(); - KCommonDecorationButton::mouseReleaseEvent(e); -} - -void AuroraeButton::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event) - if (decoration()->isPreview() || !AuroraeFactory::instance()->isValid()) { - return; - } - - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - - bool active = decoration()->isActive(); - - if (type() == MenuButton) { - const QIcon icon = decoration()->icon(); - ThemeConfig config = AuroraeFactory::instance()->themeConfig(); - int iconSize = qMin(config.buttonWidthMenu(), config.buttonHeight()); - const QSize size = icon.actualSize(QSize(iconSize, iconSize)); - QPixmap iconPix = icon.pixmap(size); - KIconEffect *effect = KIconLoader::global()->iconEffect(); - if (active) { - if (underMouse()) { - iconPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::ActiveState); - } - } else { - iconPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::DisabledState); - } - AuroraeClient *deco = dynamic_cast(decoration()); - if (deco && deco->isAnimating()) { - // animation - QPixmap oldPix = icon.pixmap(size); - if (!active) { - if (underMouse()) { - oldPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::ActiveState); - } - } else { - oldPix = effect->apply(iconPix, KIconLoader::Desktop, KIconLoader::DisabledState); - } - iconPix = Plasma::PaintUtils::transition(oldPix, iconPix, deco->animationProgress()); - } - painter.drawPixmap(0, 0, iconPix); - return; - } - - ButtonStates states; - if (active) { - states |= Active; - } - if (underMouse()) { - states |= Hover; - } - if (m_pressed) { - states |= Pressed; - } - QString buttonName = ""; - switch (type()) { - case MinButton: - if (!decoration()->isMinimizable()) { - states |= Deactivated; - } - buttonName = "minimize"; - break; - case CloseButton: - if (!decoration()->isCloseable()) { - states |= Deactivated; - } - buttonName = "close"; - break; - case MaxButton: { - if (!decoration()->isMaximizable()) { - states |= Deactivated; - } - buttonName = "maximize"; - if (decoration()->maximizeMode() == KDecorationDefines::MaximizeFull && - !decoration()->options()->moveResizeMaximizedWindows()) { - buttonName = "restore"; - if (!AuroraeFactory::instance()->hasButton(buttonName)) { - buttonName = "maximize"; - } - } - break; - } - case OnAllDesktopsButton: - if (decoration()->isOnAllDesktops()) { - states |= Hover; - } - buttonName = "alldesktops"; - break; - case AboveButton: - buttonName = "keepabove"; - break; - case BelowButton: - buttonName = "keepbelow"; - break; - case ShadeButton: - if (!decoration()->isShadeable()) { - states |= Deactivated; - } - if (decoration()->isShade()) { - states |= Hover; - } - buttonName = "shade"; - break; - case HelpButton: - buttonName = "help"; - break; - default: - buttonName.clear(); - } - - if (!buttonName.isEmpty()) { - if (AuroraeFactory::instance()->hasButton(buttonName)) { - Plasma::FrameSvg *button = AuroraeFactory::instance()->button(buttonName); - paintButton(painter, button, states); - } - } -} - -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(rect(), result); - } else { - bool animation = false; - AuroraeClient *deco = dynamic_cast(decoration()); - if (deco && deco->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, deco->animationProgress()); - painter.drawPixmap(rect(), 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(); -} - /******************************************************* * Client *******************************************************/ - AuroraeClient::AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *factory) - : KCommonDecorationUnstable(bridge, factory) -{ - m_animation = new QPropertyAnimation(this, "animation", this); -} - -AuroraeClient::~AuroraeClient() + : KDecorationUnstable(bridge, factory) { + m_scene = new AuroraeScene(AuroraeFactory::instance()->theme(), + options()->customButtonPositions() ? options()->titleButtonsLeft() : AuroraeFactory::instance()->theme()->defaultButtonsLeft(), + options()->customButtonPositions() ? options()->titleButtonsRight() : AuroraeFactory::instance()->theme()->defaultButtonsRight(), + providesContextHelp(), this); + connect(m_scene, SIGNAL(closeWindow()), SLOT(closeWindow())); + connect(m_scene, SIGNAL(maximize(Qt::MouseButtons)), SLOT(maximize(Qt::MouseButtons))); + connect(m_scene, SIGNAL(showContextHelp()), SLOT(showContextHelp())); + connect(m_scene, SIGNAL(minimizeWindow()), SLOT(minimize())); + connect(m_scene, SIGNAL(menuClicked()), SLOT(menuClicked())); + connect(m_scene, SIGNAL(menuDblClicked()), SLOT(closeWindow())); + connect(m_scene, SIGNAL(toggleOnAllDesktops()), SLOT(toggleOnAllDesktops())); + connect(m_scene, SIGNAL(toggleShade()), SLOT(toggleShade())); + connect(m_scene, SIGNAL(toggleKeepAbove()), SLOT(toggleKeepAbove())); + connect(m_scene, SIGNAL(toggleKeepBelow()), SLOT(toggleKeepBelow())); + connect(m_scene, SIGNAL(titlePressed(Qt::MouseButton,Qt::MouseButtons)), + SLOT(titlePressed(Qt::MouseButton,Qt::MouseButtons))); + connect(m_scene, SIGNAL(titleReleased(Qt::MouseButton,Qt::MouseButtons)), + SLOT(titleReleased(Qt::MouseButton,Qt::MouseButtons))); + connect(m_scene, SIGNAL(titleDoubleClicked()), SLOT(titlebarDblClickOperation())); + 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(this, SIGNAL(keepAboveChanged(bool)), SLOT(keepAboveChanged(bool))); + connect(this, SIGNAL(keepBelowChanged(bool)), SLOT(keepBelowChanged(bool))); } void AuroraeClient::init() { - KCommonDecoration::init(); + // HACK: we need to add the GraphicsView as a child widget to a normal widget + // the GraphicsView eats the mouse release event and by that kwin core starts to move + // the decoration each time the decoration is clicked + // therefore we use two widgets and inject an own mouse release event to the parent widget + // when the graphics view eats a mouse event + createMainWidget(); + widget()->setAttribute(Qt::WA_TranslucentBackground); + widget()->setAttribute(Qt::WA_NoSystemBackground); + m_view = new QGraphicsView(m_scene, widget()); + m_view->setAttribute(Qt::WA_TranslucentBackground); + m_view->setFrameShape(QFrame::NoFrame); + QPalette pal = m_view->palette(); + pal.setColor(m_view->backgroundRole(), Qt::transparent); + m_view->setPalette(pal); + QPalette pal2 = widget()->palette(); + pal2.setColor(widget()->backgroundRole(), Qt::transparent); + widget()->setPalette(pal2); + m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + // scene initialisation + m_scene->setActive(isActive(), false); + m_scene->setIcon(icon()); + m_scene->setAllDesktops(isOnAllDesktops()); + m_scene->setMaximizeMode(options()->moveResizeMaximizedWindows() ? MaximizeRestore : maximizeMode()); + m_scene->setShade(isShade()); + m_scene->setKeepAbove(keepAbove()); + m_scene->setKeepBelow(keepBelow()); + m_scene->setCaption(caption()); + AuroraeFactory::instance()->theme()->setCompositingActive(compositingActive()); } -void AuroraeClient::reset(unsigned long changed) +void AuroraeClient::activeChange() { - if (changed & SettingCompositing) { - updateWindowShape(); + if (m_scene->isActive() != isActive()) { + m_scene->setActive(isActive()); } - widget()->update(); - - KCommonDecoration::reset(changed); -} - -QString AuroraeClient::visibleName() const -{ - return i18n("Aurorae Theme Engine"); -} - -QString AuroraeClient::defaultButtonsLeft() const -{ - return AuroraeFactory::instance()->themeConfig().defaultButtonsLeft(); -} - -QString AuroraeClient::defaultButtonsRight() const -{ - return AuroraeFactory::instance()->themeConfig().defaultButtonsRight(); -} - -bool AuroraeClient::decorationBehaviour(DecorationBehaviour behavior) const -{ - switch (behavior) { - case DB_MenuClose: - return true; // Close on double click - - case DB_WindowMask: - case DB_ButtonHide: - return false; - default: - return false; - } -} - -int AuroraeClient::layoutMetric(LayoutMetric lm, bool respectWindowState, - const KCommonDecorationButton *button) const -{ - if (!AuroraeFactory::instance()->isValid()) { - return KCommonDecoration::layoutMetric(lm, respectWindowState, button); - } - bool maximized = maximizeMode() == MaximizeFull && - !options()->moveResizeMaximizedWindows(); - const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig(); - qreal left, top, right, bottom; - AuroraeFactory::instance()->frame()->getMargins(left, top, right, bottom); - int borderLeft, borderRight, borderBottom;; - switch (KDecoration::options()->preferredBorderSize(AuroraeFactory::instance())) { - case BorderTiny: - if (compositingActive()) { - borderLeft = qMin(0, (int)left - conf.borderLeft() - conf.paddingLeft()); - borderRight = qMin(0, (int)right - conf.borderRight() - conf.paddingRight()); - borderBottom = qMin(0, (int)bottom - conf.borderBottom() - conf.paddingBottom()); - } else { - borderLeft = qMin(0, (int)left - conf.borderLeft()); - borderRight = qMin(0, (int)right - conf.borderRight()); - borderBottom = qMin(0, (int)bottom - conf.borderBottom()); - } - break; - case BorderLarge: - borderLeft = borderRight = borderBottom = 4; - break; - case BorderVeryLarge: - borderLeft = borderRight = borderBottom = 8; - break; - case BorderHuge: - borderLeft = borderRight = borderBottom = 12; - break; - case BorderVeryHuge: - borderLeft = borderRight = borderBottom = 23; - break; - case BorderOversized: - borderLeft = borderRight = borderBottom = 36; - break; - case BorderNormal: - default: - borderLeft = borderRight = borderBottom = 0; - } - switch (lm) { - case LM_BorderLeft: - return maximized && respectWindowState ? 0 : conf.borderLeft() + borderLeft; - case LM_BorderRight: - return maximized && respectWindowState ? 0 : conf.borderRight() + borderRight; - case LM_BorderBottom: - return maximized && respectWindowState ? 0 : conf.borderBottom() + borderBottom; - - case LM_OuterPaddingLeft: - return conf.paddingLeft(); - case LM_OuterPaddingRight: - return conf.paddingRight(); - case LM_OuterPaddingTop: - return conf.paddingTop(); - case LM_OuterPaddingBottom: - return conf.paddingBottom(); - - case LM_TitleEdgeLeft: - return maximized && respectWindowState ? conf.titleEdgeLeftMaximized() : conf.titleEdgeLeft(); - case LM_TitleEdgeRight: - return maximized && respectWindowState ? conf.titleEdgeRightMaximized() : conf.titleBorderRight(); - case LM_TitleEdgeTop: - return maximized && respectWindowState ? conf.titleEdgeTopMaximized() : conf.titleEdgeTop(); - case LM_TitleEdgeBottom: - return maximized && respectWindowState ? conf.titleEdgeBottomMaximized() : conf.titleEdgeBottom(); - - case LM_ButtonMarginTop: - return conf.buttonMarginTop(); - - case LM_TitleBorderLeft: - return conf.titleBorderLeft(); - case LM_TitleBorderRight: - return conf.titleBorderRight(); - case LM_TitleHeight: - return conf.titleHeight(); - - case LM_ButtonWidth: - switch (button->type()) { - case MinButton: - return conf.buttonWidthMinimize(); - case MaxButton: - return conf.buttonWidthMaximizeRestore(); - case CloseButton: - return conf.buttonWidthClose(); - case OnAllDesktopsButton: - return conf.buttonWidthAllDesktops(); - case AboveButton: - return conf.buttonWidthKeepAbove(); - case BelowButton: - return conf.buttonWidthKeepBelow(); - case ShadeButton: - return conf.buttonWidthShade(); - case MenuButton: - return conf.buttonWidthMenu(); - case HelpButton: - return conf.buttonWidthHelp(); - default: - return conf.buttonWidth(); - } - case LM_ButtonHeight: - return conf.buttonHeight(); - case LM_ButtonSpacing: - return conf.buttonSpacing(); - case LM_ExplicitButtonSpacer: - return conf.explicitButtonSpacer(); - - default: - return KCommonDecoration::layoutMetric(lm, respectWindowState, button); - } -} - -KCommonDecorationButton *AuroraeClient::createButton(ButtonType type) -{ - AuroraeFactory *factory = AuroraeFactory::instance(); - switch (type) { - case MenuButton: - return new AuroraeButton(type, this); - case MinButton: - if (factory->hasButton("minimize")) { - return new AuroraeButton(type, this); - } else { - return NULL; - } - case MaxButton: - if (factory->hasButton("maximize") || factory->hasButton("restore")) { - return new AuroraeButton(type, this); - } else { - return NULL; - } - case CloseButton: - if (factory->hasButton("close")) { - return new AuroraeButton(type, this); - } else { - return NULL; - } - case OnAllDesktopsButton: - if (factory->hasButton("alldesktops")) { - return new AuroraeButton(type, this); - } else { - return NULL; - } - case HelpButton: - if (factory->hasButton("help")) { - return new AuroraeButton(type, this); - } else { - return NULL; - } - case AboveButton: - if (factory->hasButton("keepabove")) { - return new AuroraeButton(type, this); - } else { - return NULL; - } - case BelowButton: - if (factory->hasButton("keepbelow")) { - return new AuroraeButton(type, this); - } else { - return NULL; - } - case ShadeButton: - if (factory->hasButton("shade")) { - return new AuroraeButton(type, this); - } else { - return NULL; - } - default: - return NULL; - } -} - -void AuroraeClient::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event); - if (isPreview() || !AuroraeFactory::instance()->isValid()) { - return; - } - bool maximized = maximizeMode() == MaximizeFull && - !options()->moveResizeMaximizedWindows(); - - QPainter painter(widget()); - painter.setRenderHint(QPainter::Antialiasing); - painter.setCompositionMode(QPainter::CompositionMode_Source); - - const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig(); - Plasma::FrameSvg *frame = AuroraeFactory::instance()->frame(); - - frame->setElementPrefix("decoration"); - if (!isActive() && frame->hasElementPrefix("decoration-inactive")) { - frame->setElementPrefix("decoration-inactive"); - } - if (!compositingActive() && frame->hasElementPrefix("decoration-opaque")) { - frame->setElementPrefix("decoration-opaque"); - if (!isActive() && frame->hasElementPrefix("decoration-opaque-inactive")) { - frame->setElementPrefix("decoration-opaque-inactive"); - } - } - if (maximized) { - if (frame->hasElementPrefix("decoration-maximized")) { - frame->setElementPrefix("decoration-maximized"); - } - if (!isActive() && frame->hasElementPrefix("decoration-maximized-inactive")) { - frame->setElementPrefix("decoration-maximized-inactive"); - } - if (!compositingActive() && frame->hasElementPrefix("decoration-maximized-opaque")) { - frame->setElementPrefix("decoration-maximized-opaque"); - if (!isActive() && frame->hasElementPrefix("decoration-maximized-opaque-inactive")) { - frame->setElementPrefix("decoration-maximized-opaque-inactive"); - } - } - } - - // restrict painting on the decoration - no need to paint behind the window - int left, right, top, bottom; - decoration()->borders(left, right, top, bottom); - if (!compositingActive() || (compositingActive() && !transparentRect().isNull())) { - // only clip when compositing is not active and we don't extend into the client - painter.setClipping(true); - painter.setClipRect(0, 0, - left + conf.paddingLeft(), - height() + conf.paddingTop() + conf.paddingBottom(), - Qt::ReplaceClip); - painter.setClipRect(0, 0, - width() + conf.paddingLeft() + conf.paddingRight(), - top + conf.paddingTop(), - Qt::UniteClip); - painter.setClipRect(width() - right + conf.paddingLeft(), 0, - right + conf.paddingRight(), - height() + conf.paddingTop() + conf.paddingBottom(), - Qt::UniteClip); - painter.setClipRect(0, height() - bottom + conf.paddingTop(), - width() + conf.paddingLeft() + conf.paddingRight(), - bottom + conf.paddingBottom(), - Qt::UniteClip); - } - - // top - if (maximized) { - frame->setEnabledBorders(Plasma::FrameSvg::NoBorder); - } else { - frame->setEnabledBorders(Plasma::FrameSvg::AllBorders); - } - QRectF rect = QRectF(0.0, 0.0, widget()->width(), widget()->height()); - if (maximized) { - rect = QRectF(conf.paddingLeft(), conf.paddingTop(), - widget()->width() - conf.paddingRight(), - widget()->height() - conf.paddingBottom()); - if (transparentRect().isNull()) { - rect = QRectF(conf.paddingLeft(), conf.paddingTop(), - widget()->width() - conf.paddingRight(), - layoutMetric(LM_TitleEdgeTop) + layoutMetric(LM_TitleHeight) + layoutMetric(LM_TitleEdgeBottom)); - } - } - QRectF sourceRect = rect; - if (!compositingActive()) { - if (frame->hasElementPrefix("decoration-opaque")) { - rect = QRectF(conf.paddingLeft(), conf.paddingTop(), - widget()->width()-conf.paddingRight()-conf.paddingLeft(), - widget()->height()-conf.paddingBottom()-conf.paddingTop()); - sourceRect = QRectF(0.0, 0.0, rect.width(), rect.height()); - } - else { - rect = QRectF(conf.paddingLeft(), conf.paddingTop(), widget()->width(), widget()->height()); - sourceRect = rect; - } - } - frame->resizeFrame(rect.size()); - - // animation - if (isAnimating() && frame->hasElementPrefix("decoration-inactive")) { - QPixmap target = frame->framePixmap(); - frame->setElementPrefix("decoration-inactive"); - if (!isActive()) { - frame->setElementPrefix("decoration"); - } - if (!compositingActive() && frame->hasElementPrefix("decoration-opaque-inactive")) { - frame->setElementPrefix("decoration-opaque-inactive"); - if (!isActive()) { - frame->setElementPrefix("decoration-opaque"); - } - } - if (maximized && frame->hasElementPrefix("decoration-maximized-inactive")) { - frame->setElementPrefix("decoration-maximized-inactive"); - if (!isActive()) { - frame->setElementPrefix("decoration-maximized"); - } - if (!compositingActive() && frame->hasElementPrefix("decoration-maximized-opaque-inactive")) { - frame->setElementPrefix("decoration-maximized-opaque-inactive"); - if (!isActive()) { - frame->setElementPrefix("decoration-maximized-opaque"); - } - } - } else if (maximized && frame->hasElementPrefix("decoration-maximized")) { - frame->setElementPrefix("decoration-maximized"); - } - frame->resizeFrame(rect.size()); - QPixmap result = Plasma::PaintUtils::transition(frame->framePixmap(), - target, m_animationProgress); - painter.drawPixmap(rect.toRect(), result, sourceRect); - } else { - frame->paintFrame(&painter, rect, sourceRect); - } - - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - if (isAnimating()) { - QPixmap result; - if (isActive()) { - result = Plasma::PaintUtils::transition(m_inactiveText, m_activeText, m_animationProgress); - } else { - result = Plasma::PaintUtils::transition(m_activeText, m_inactiveText, m_animationProgress); - } - painter.drawPixmap(0, 0, result); - } else { - if (isActive()) { - painter.drawPixmap(0, 0, m_activeText); - } else { - painter.drawPixmap(0, 0, m_inactiveText); - } - } -} - -void AuroraeClient::generateTextPixmap(QPixmap& pixmap, bool active) -{ - QPainter painter(&pixmap); - pixmap.fill(Qt::transparent); - if (!AuroraeFactory::instance()->isValid()) { - return; - } - const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig(); - painter.setFont(options()->font(active)); - if ((active && conf.haloActive()) || (!active && conf.haloInactive())) { - QRectF haloRect = painter.fontMetrics().boundingRect(titleRect(), - conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine, - caption()); - if (haloRect.width() > titleRect().width()) { - haloRect.setWidth(titleRect().width()); - } - Plasma::PaintUtils::drawHalo(&painter, haloRect); - } - if (conf.useTextShadow()) { - // shadow code is inspired by Qt FAQ: How can I draw shadows behind text? - // see http://www.qtsoftware.com/developer/faqs/faq.2007-07-27.3052836051 - const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig(); - painter.save(); - if (active) { - painter.setPen(conf.activeTextShadowColor()); - } - else { - painter.setPen(conf.inactiveTextShadowColor()); - } - int dx = conf.textShadowOffsetX(); - int dy = conf.textShadowOffsetY(); - painter.setOpacity(0.5); - painter.drawText(pixmap.rect().translated(dx, dy), - conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine, - caption()); - painter.setOpacity(0.2); - painter.drawText(pixmap.rect().translated(dx+1, dy), - conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine, - caption()); - painter.drawText(pixmap.rect().translated(dx-1, dy), - conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine, - caption()); - painter.drawText(pixmap.rect().translated(dx, dy+1), - conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine, - caption()); - painter.drawText(pixmap.rect().translated(dx, dy-1), - conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine, - caption()); - painter.restore(); - } - if (active) { - painter.setPen(conf.activeTextColor()); - } else { - painter.setPen(conf.inactiveTextColor()); - } - painter.drawText(titleRect(), conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine, - caption()); - painter.end(); } void AuroraeClient::captionChange() { - generateTextPixmap(m_activeText, true); - generateTextPixmap(m_inactiveText, false); - KCommonDecoration::captionChange(); + m_scene->setCaption(caption()); +} + +void AuroraeClient::iconChange() +{ + m_scene->setIcon(icon()); +} + +void AuroraeClient::desktopChange() +{ + m_scene->setAllDesktops(isOnAllDesktops()); +} + +void AuroraeClient::maximizeChange() +{ + if (!options()->moveResizeMaximizedWindows()) { + m_scene->setMaximizeMode(maximizeMode()); + } +} + +void AuroraeClient::resize(const QSize &s) +{ + m_scene->setSceneRect(QRectF(QPoint(0, 0), s)); + m_scene->updateLayout(); + m_view->resize(s); + widget()->resize(s); + updateWindowShape(); +} + +void AuroraeClient::shadeChange() +{ + m_scene->setShade(isShade()); +} + +void AuroraeClient::borders(int &left, int &right, int &top, int &bottom) const +{ + const bool maximized = maximizeMode() == MaximizeFull && !options()->moveResizeMaximizedWindows(); + AuroraeFactory::instance()->theme()->borders(left, top, right, bottom, maximized); +} + +void AuroraeClient::padding(int &left, int &right, int &top, int &bottom) const +{ + AuroraeFactory::instance()->theme()->padding(left, top, right, bottom); +} + +QSize AuroraeClient::minimumSize() const +{ + return widget()->minimumSize(); +} + +KDecorationDefines::Position AuroraeClient::mousePosition(const QPoint &point) const +{ + // based on the code from deKorator + int pos = PositionCenter; + if (isShade()) { + return Position(pos); + } + + int borderLeft, borderTop, borderRight, borderBottom; + borders(borderLeft, borderRight, borderTop, borderBottom); + int paddingLeft, paddingTop, paddingRight, paddingBottom; + padding(paddingLeft, paddingRight, paddingTop, paddingBottom); + if (point.x() >= (width() - borderRight)) { + pos |= PositionRight; + } else if (point.x() <= borderLeft + paddingLeft) { + pos |= PositionLeft; + } + + const bool maximized = maximizeMode() == MaximizeFull && !options()->moveResizeMaximizedWindows(); + int titleEdgeLeft, titleEdgeRight, titleEdgeTop, titleEdgeBottom; + AuroraeFactory::instance()->theme()->titleEdges(titleEdgeLeft, titleEdgeTop, titleEdgeRight, titleEdgeBottom, maximized); + if (point.y() >= height() - borderBottom) { + pos |= PositionBottom; + } else if (point.y() <= titleEdgeTop + paddingTop ) { + pos |= PositionTop; + } + + return Position(pos); +} + +void AuroraeClient::reset(long unsigned int changed) +{ + if (changed & SettingCompositing) { + updateWindowShape(); + AuroraeFactory::instance()->theme()->setCompositingActive(compositingActive()); + } + if (changed & SettingButtons) { + m_scene->setButtons(options()->customButtonPositions() ? options()->titleButtonsLeft() : AuroraeFactory::instance()->theme()->defaultButtonsLeft(), + options()->customButtonPositions() ? options()->titleButtonsRight() : AuroraeFactory::instance()->theme()->defaultButtonsRight()); + } + KDecoration::reset(changed); +} + +void AuroraeClient::menuClicked() +{ + showWindowMenu(QCursor::pos()); +} + +void AuroraeClient::toggleShade() +{ + setShade(!isShade()); +} + +void AuroraeClient::keepAboveChanged(bool above) +{ + if (above && m_scene->isKeepBelow()) { + m_scene->setKeepBelow(false); + } + m_scene->setKeepAbove(above); +} + +void AuroraeClient::keepBelowChanged(bool below) +{ + if (below && m_scene->isKeepAbove()) { + m_scene->setKeepAbove(false); + } + m_scene->setKeepBelow(below); +} + +void AuroraeClient::toggleKeepAbove() +{ + setKeepAbove(!keepAbove()); +} + +void AuroraeClient::toggleKeepBelow() +{ + setKeepBelow(!keepBelow()); } void AuroraeClient::updateWindowShape() @@ -958,70 +326,54 @@ void AuroraeClient::updateWindowShape() int w=widget()->width(); int h=widget()->height(); - if (maximized || compositingActive() || !AuroraeFactory::instance()->isValid()) { + if (maximized || compositingActive()) { QRegion mask(0,0,w,h); setMask(mask); return; } - const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig(); - Plasma::FrameSvg *deco = AuroraeFactory::instance()->frame(); + int pl, pt, pr, pb; + padding(pl, pr, pt, pb); + Plasma::FrameSvg *deco = AuroraeFactory::instance()->theme()->decoration(); if (!deco->hasElementPrefix("decoration-opaque")) { // opaque element is missing: set generic mask - w = w - conf.paddingLeft() - conf.paddingRight(); - h = h - conf.paddingTop() - conf.paddingBottom(); - QRegion mask(conf.paddingLeft(),conf.paddingTop(),w,h); + w = w - pl - pr; + h = h - pt - pb; + QRegion mask(pl, pt, w, h); setMask(mask); return; } deco->setElementPrefix("decoration-opaque"); - deco->resizeFrame(QSize(w-conf.paddingLeft()-conf.paddingRight(), - h-conf.paddingTop()-conf.paddingBottom())); - QRegion mask = deco->mask().translated(conf.paddingLeft(), conf.paddingTop()); + deco->resizeFrame(QSize(w-pl-pr, h-pt-pb)); + QRegion mask = deco->mask().translated(pl, pt); setMask(mask); } -void AuroraeClient::activeChange() +void AuroraeClient::titlePressed(Qt::MouseButton button, Qt::MouseButtons buttons) { - if (isAnimating()) { - m_animation->stop(); - } - m_animationProgress = 0.0; - int time = AuroraeFactory::instance()->themeConfig().animationTime(); - if (time != 0) { - m_animation->setDuration(time); - m_animation->setEasingCurve(QEasingCurve::InOutQuad); - m_animation->setStartValue(0.0); - m_animation->setEndValue(1.0); - m_animation->start(); - } - KCommonDecoration::activeChange(); + QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress, widget()->mapFromGlobal(QCursor::pos()), + QCursor::pos(), button, buttons, Qt::NoModifier); + processMousePressEvent(event); + delete event; + event = 0; } -void AuroraeClient::resize(const QSize& s) +void AuroraeClient::titleReleased(Qt::MouseButton button, Qt::MouseButtons buttons) { - KCommonDecoration::resize(s); - m_activeText = QPixmap(QSize(widget()->width(), titleRect().height() + titleRect().y())); - m_activeText.fill(Qt::transparent); - m_inactiveText = QPixmap(QSize(widget()->width(), titleRect().height() + titleRect().y())); - m_inactiveText.fill(Qt::transparent); - captionChange(); + QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonRelease, widget()->mapFromGlobal(QCursor::pos()), + QCursor::pos(), button, buttons, Qt::NoModifier); + QApplication::sendEvent(widget(), event); + delete event; + event = 0; } -bool AuroraeClient::isAnimating() const +void AuroraeClient::titleMouseMoved(Qt::MouseButton button, Qt::MouseButtons buttons) { - return (m_animation->state() == QAbstractAnimation::Running); -} - -qreal AuroraeClient::animationProgress() const -{ - return m_animationProgress; -} - -void AuroraeClient::setAnimationProgress(qreal progress) -{ - m_animationProgress = progress; - widget()->update(); + QMouseEvent *event = new QMouseEvent(QEvent::MouseMove, widget()->mapFromGlobal(QCursor::pos()), + QCursor::pos(), button, buttons, Qt::NoModifier); + QApplication::sendEvent(widget(), event); + delete event; + event = 0; } } // namespace Aurorae diff --git a/clients/aurorae/src/aurorae.h b/clients/aurorae/src/aurorae.h index 722e62fa48..9821bacc7a 100644 --- a/clients/aurorae/src/aurorae.h +++ b/clients/aurorae/src/aurorae.h @@ -1,5 +1,5 @@ /******************************************************************** -Copyright (C) 2009 Martin Gräßlin +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 @@ -20,14 +20,16 @@ along with this program. If not, see . #include "themeconfig.h" +#include #include -#include -#include -class QPropertyAnimation; +class QGraphicsView; +class QGraphicsScene; namespace Aurorae { +class AuroraeTheme; +class AuroraeScene; class AuroraeFactory : public QObject, public KDecorationFactoryUnstable { @@ -40,113 +42,55 @@ public: bool supports(Ability ability) const; virtual QList< BorderSize > borderSizes() const; - Plasma::FrameSvg *frame() { - return &m_frame; - } - Plasma::FrameSvg *button(const QString& b); - bool hasButton(const QString& button) { - return m_buttons.contains(button); - } - ThemeConfig &themeConfig() { - return m_themeConfig; - } - bool isValid() const { - return m_valid; + AuroraeTheme *theme() const { + return m_theme; } private: AuroraeFactory(); void init(); - void initButtonFrame(const QString& button); - void readThemeConfig(); private: static AuroraeFactory *s_instance; - // theme name - QString m_themeName; - ThemeConfig m_themeConfig; - // deco - Plasma::FrameSvg m_frame; - - // buttons - QHash< QString, Plasma::FrameSvg* > m_buttons; - bool m_valid; + AuroraeTheme *m_theme; }; -class AuroraeButton : public KCommonDecorationButton +class AuroraeClient : public KDecorationUnstable { Q_OBJECT - Q_PROPERTY(qreal animation READ animationProgress WRITE setAnimationProgress) - public: - AuroraeButton(ButtonType type, KCommonDecoration *parent); - void reset(unsigned long changed); - void enterEvent(QEvent *event); - void leaveEvent(QEvent *event); - void paintEvent(QPaintEvent *event); - qreal animationProgress() const; - void setAnimationProgress(qreal progress); - -protected: - void mousePressEvent(QMouseEvent *e); - void mouseReleaseEvent(QMouseEvent *e); - -private: - enum ButtonState { - Active = 0x1, - Hover = 0x2, - Pressed = 0x4, - Deactivated = 0x8 - }; - Q_DECLARE_FLAGS(ButtonStates, ButtonState) - void paintButton(QPainter& painter, Plasma::FrameSvg* frame, ButtonStates states); - bool isAnimating() const; - -private: - qreal m_animationProgress; - bool m_pressed; - QPropertyAnimation *m_animation; -}; - - -class AuroraeClient : public KCommonDecorationUnstable -{ - Q_OBJECT - Q_PROPERTY(qreal animation READ animationProgress WRITE setAnimationProgress) -public: - AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *factory); - ~AuroraeClient(); - - virtual void init(); - - virtual QString visibleName() const; - virtual QString defaultButtonsLeft() const; - virtual QString defaultButtonsRight() const; - virtual bool decorationBehaviour(DecorationBehaviour behaviour) const; - virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, - const KCommonDecorationButton * = 0) const; - virtual KCommonDecorationButton *createButton(ButtonType type); - virtual void updateWindowShape(); + AuroraeClient(KDecorationBridge* bridge, KDecorationFactory* factory); virtual void activeChange(); + virtual void borders(int& left, int& right, int& top, int& bottom) const; virtual void captionChange(); + virtual void desktopChange(); + virtual void iconChange(); + virtual void init(); + virtual void maximizeChange(); + virtual QSize minimumSize() const; + virtual Position mousePosition(const QPoint& p) const; virtual void resize(const QSize& s); + virtual void shadeChange(); + // optional overrides + virtual void padding(int &left, int &right, int &top, int &bottom) const; + virtual void reset(long unsigned int changed); - bool isAnimating() const; - qreal animationProgress() const; - void setAnimationProgress(qreal progress); - -protected: - void reset(unsigned long changed); - void paintEvent(QPaintEvent *event); +private slots: + void menuClicked(); + void toggleShade(); + void keepAboveChanged(bool above); + void keepBelowChanged(bool below); + void toggleKeepAbove(); + void toggleKeepBelow(); + void titlePressed(Qt::MouseButton button, Qt::MouseButtons buttons); + void titleReleased(Qt::MouseButton button, Qt::MouseButtons buttons); + void titleMouseMoved(Qt::MouseButton button, Qt::MouseButtons buttons); private: - void generateTextPixmap(QPixmap& pixmap, bool active); - qreal m_animationProgress; - QPixmap m_activeText; - QPixmap m_inactiveText; - QPropertyAnimation *m_animation; - + void updateWindowShape(); + AuroraeScene *m_scene; + QGraphicsView *m_view; }; } diff --git a/clients/aurorae/src/lib/auroraebutton.cpp b/clients/aurorae/src/lib/auroraebutton.cpp new file mode 100644 index 0000000000..4215469a1d --- /dev/null +++ b/clients/aurorae/src/lib/auroraebutton.cpp @@ -0,0 +1,442 @@ +/* + 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 { + +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); +} + +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) + switch (m_type) { + case MinimizeButton: + return QSizeF(m_theme->themeConfig().buttonWidthMinimize(), + m_theme->themeConfig().buttonHeight()); + case MaximizeButton: + case RestoreButton: + return QSizeF(m_theme->themeConfig().buttonWidthMaximizeRestore(), + m_theme->themeConfig().buttonHeight()); + case CloseButton: + return QSizeF(m_theme->themeConfig().buttonWidthClose(), + m_theme->themeConfig().buttonHeight()); + case AllDesktopsButton: + return QSizeF(m_theme->themeConfig().buttonWidthAllDesktops(), + m_theme->themeConfig().buttonHeight()); + case KeepAboveButton: + return QSizeF(m_theme->themeConfig().buttonWidthKeepAbove(), + m_theme->themeConfig().buttonHeight()); + case KeepBelowButton: + return QSizeF(m_theme->themeConfig().buttonWidthKeepBelow(), + m_theme->themeConfig().buttonHeight()); + case ShadeButton: + return QSizeF(m_theme->themeConfig().buttonWidthShade(), + m_theme->themeConfig().buttonHeight()); + case HelpButton: + return QSizeF(m_theme->themeConfig().buttonWidthHelp(), + m_theme->themeConfig().buttonHeight()); + default: + return QSizeF(m_theme->themeConfig().buttonWidth(), m_theme->themeConfig().buttonHeight()); + } +} +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("-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(); +} + +/*********************************************** +* 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 diff --git a/clients/aurorae/src/lib/auroraebutton.h b/clients/aurorae/src/lib/auroraebutton.h new file mode 100644 index 0000000000..de9af51bfe --- /dev/null +++ b/clients/aurorae/src/lib/auroraebutton.h @@ -0,0 +1,168 @@ +/* + 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. + +*/ + +#ifndef AURORAE_AURORAEBUTTON_H +#define AURORAE_AURORAEBUTTON_H + +#include "auroraetheme.h" +#include +#include + +class QTimer; +class QPropertyAnimation; + +namespace Plasma { +class FrameSvg; +} + +namespace Aurorae { + +class AuroraeTheme; + +class AuroraeButton : public QGraphicsWidget +{ + Q_OBJECT + Q_PROPERTY(qreal animation READ animationProgress WRITE setAnimationProgress) + +public: + AuroraeButton(AuroraeTheme *theme, AuroraeButtonType type ); + virtual ~AuroraeButton(); + virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); + + AuroraeButtonType buttonType() const { + return m_type; + } + virtual void mousePressEvent(QGraphicsSceneMouseEvent* event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event); + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event); + virtual int type() const { + return m_type; + } + + qreal animationProgress() const; + void setAnimationProgress(qreal progress); + void setCheckable(bool checkable) { + m_checkable = checkable; + } + bool isCheckable() const { + return m_checkable; + } + void setChecked(bool checked) { + m_checked = checked; + } + bool isChecked() const { + return m_checked; + } + +Q_SIGNALS: + void clicked(); + +protected: + enum ButtonState { + Active = 0x1, + Hover = 0x2, + Pressed = 0x4, + Deactivated = 0x8 + }; + Q_DECLARE_FLAGS(ButtonStates, ButtonState) + virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint = QSizeF()) const; + virtual void paintButton(QPainter *painter, Plasma::FrameSvg *frame, ButtonStates states); + virtual bool isAnimating() const; + virtual AuroraeButtonType currentType() const; + + AuroraeTheme *theme() const { + return m_theme; + } + + bool isHovered() const { + return m_hovered; + } + + bool isPressed() const { + return m_pressed; + } + void setPressed(bool pressed) { + m_pressed = pressed; + } + +private: + AuroraeTheme *m_theme; + AuroraeButtonType m_type; + bool m_pressed; + bool m_hovered; + qreal m_animationProgress; + QPropertyAnimation *m_animation; + bool m_checkable; + bool m_checked; +}; + +class AuroraeMaximizeButton : public AuroraeButton +{ + Q_OBJECT +public: + AuroraeMaximizeButton(AuroraeTheme* theme); + virtual void mousePressEvent(QGraphicsSceneMouseEvent* event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); + void setMaximizeMode(KDecorationDefines::MaximizeMode mode); + +Q_SIGNALS: + void clicked(Qt::MouseButtons button); + +protected: + virtual AuroraeButtonType currentType() const; + +private: + Qt::MouseButton m_pressedButton; + KDecorationDefines::MaximizeMode m_maximizeMode; +}; + +class AuroraeMenuButton : public AuroraeButton +{ + Q_OBJECT +public: + AuroraeMenuButton(AuroraeTheme *theme); + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); + + void setIcon(const QPixmap &icon); + +Q_SIGNALS: + void doubleClicked(); + +private: + QPixmap m_icon; + QTimer *m_timer; +}; + +class AuroraeSpacer : public QGraphicsWidget +{ +public: + AuroraeSpacer(AuroraeTheme *theme); + virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint = QSizeF()) const; + +private: + AuroraeTheme *m_theme; +}; + +} // namespace Aurorae + +#endif // AURORAE_AURORAEBUTTON_H diff --git a/clients/aurorae/src/lib/auroraescene.cpp b/clients/aurorae/src/lib/auroraescene.cpp new file mode 100644 index 0000000000..7f0cfb7cc9 --- /dev/null +++ b/clients/aurorae/src/lib/auroraescene.cpp @@ -0,0 +1,607 @@ +/* + 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 "auroraescene.h" +#include "auroraebutton.h" +#include "auroraetab.h" +#include "auroraetheme.h" +#include "themeconfig.h" +// Qt +#include +#include +#include +#include +#include +// KDE +#include +#include + +namespace Aurorae { + +AuroraeScene::AuroraeScene(Aurorae::AuroraeTheme* theme, const QString& leftButtons, + const QString& rightButtons, bool contextHelp, QObject* parent) + : QGraphicsScene(parent) + , m_theme(theme) + , m_leftButtons(0) + , m_rightButtons(0) + , m_title(0) + , m_active(false) + , m_animationProgress(0.0) + , m_animation(new QPropertyAnimation(this, "animation", this)) + , m_maximizeMode(KDecorationDefines::MaximizeRestore) + , m_allDesktops(false) + , m_shade(false) + , m_keepAbove(false) + , m_keepBelow(false) + , m_leftButtonOrder(leftButtons) + , m_rightButtonOrder(rightButtons) + , m_dblClicked(false) + , m_contextHelp(contextHelp) +{ + init(); + connect(m_theme, SIGNAL(themeChanged()), SLOT(resetTheme())); +} + +AuroraeScene::~AuroraeScene() +{ +} + +void AuroraeScene::init() +{ + if (!m_theme->isValid()) { + return; + } + // left buttons + QGraphicsLinearLayout *leftButtonsLayout = new QGraphicsLinearLayout; + leftButtonsLayout->setSpacing(m_theme->themeConfig().buttonSpacing()); + leftButtonsLayout->setContentsMargins(0, 0, 0, 0); + initButtons(leftButtonsLayout, m_leftButtonOrder); + + m_leftButtons = new QGraphicsWidget; + m_leftButtons->setLayout(leftButtonsLayout); + addItem(m_leftButtons); + + // right buttons + QGraphicsLinearLayout *rightButtonsLayout = new QGraphicsLinearLayout; + rightButtonsLayout->setSpacing(m_theme->themeConfig().buttonSpacing()); + rightButtonsLayout->setContentsMargins(0, 0, 0, 0); + initButtons(rightButtonsLayout, m_rightButtonOrder); + + m_rightButtons = new QGraphicsWidget; + m_rightButtons->setLayout(rightButtonsLayout); + addItem(m_rightButtons); + + // title area + QGraphicsLinearLayout *titleLayout = new QGraphicsLinearLayout; + titleLayout->setSpacing(0); + titleLayout->setContentsMargins(0, 0, 0, 0); + 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::Fixed); + + setActive(m_active, false); + updateLayout(); + // reset the icon + setIcon(m_iconPixmap); + update(sceneRect()); +} + +void AuroraeScene::resetTheme() +{ + clear(); + init(); +} + +void AuroraeScene::drawBackground(QPainter *painter, const QRectF &rect) +{ + if (!m_theme->isValid()) { + return; + } + painter->setClipRect(rect); + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + + bool maximized = m_maximizeMode == KDecorationDefines::MaximizeFull; // TODO: check option + const ThemeConfig &conf = m_theme->themeConfig(); + + Plasma::FrameSvg *frame = m_theme->decoration(); + frame->setElementPrefix("decoration"); + if (!isActive() && frame->hasElementPrefix("decoration-inactive")) { + frame->setElementPrefix("decoration-inactive"); + } + if (!m_theme->isCompositingActive() && frame->hasElementPrefix("decoration-opaque")) { + frame->setElementPrefix("decoration-opaque"); + if (!isActive() && frame->hasElementPrefix("decoration-opaque-inactive")) { + frame->setElementPrefix("decoration-opaque-inactive"); + } + } + if (maximized) { + if (frame->hasElementPrefix("decoration-maximized")) { + frame->setElementPrefix("decoration-maximized"); + } + if (!isActive() && frame->hasElementPrefix("decoration-maximized-inactive")) { + frame->setElementPrefix("decoration-maximized-inactive"); + } + if (!m_theme->isCompositingActive() && frame->hasElementPrefix("decoration-maximized-opaque")) { + frame->setElementPrefix("decoration-maximized-opaque"); + if (!isActive() && frame->hasElementPrefix("decoration-maximized-opaque-inactive")) { + frame->setElementPrefix("decoration-maximized-opaque-inactive"); + } + } + } + + // restrict painting on the decoration - no need to paint behind the window + /*int left, right, top, bottom; + decoration()->borders(left, right, top, bottom); + if (!compositingActive() || (compositingActive() && !transparentRect().isNull())) { + // only clip when compositing is not active and we don't extend into the client + painter.setClipping(true); + painter.setClipRect(0, 0, + left + conf.paddingLeft(), + height() + conf.paddingTop() + conf.paddingBottom(), + Qt::ReplaceClip); + painter.setClipRect(0, 0, + width() + conf.paddingLeft() + conf.paddingRight(), + top + conf.paddingTop(), + Qt::UniteClip); + painter.setClipRect(width() - right + conf.paddingLeft(), 0, + right + conf.paddingRight(), + height() + conf.paddingTop() + conf.paddingBottom(), + Qt::UniteClip); + painter.setClipRect(0, height() - bottom + conf.paddingTop(), + width() + conf.paddingLeft() + conf.paddingRight(), + bottom + conf.paddingBottom(), + Qt::UniteClip); + }*/ + + // top + if (maximized) { + frame->setEnabledBorders(Plasma::FrameSvg::NoBorder); + } else { + frame->setEnabledBorders(Plasma::FrameSvg::AllBorders); + } + QRectF r = sceneRect(); + if (maximized) { + r = QRectF(conf.paddingLeft(), conf.paddingTop(), + sceneRect().width() - conf.paddingRight() - conf.paddingLeft(), + sceneRect().height() - conf.paddingBottom() - conf.paddingTop()); + if (true/*transparentRect().isNull()*/) { + r = QRectF(conf.paddingLeft(), conf.paddingTop(), + sceneRect().width() - conf.paddingRight() - conf.paddingLeft(), + conf.titleEdgeTopMaximized() + conf.titleHeight() + conf.titleEdgeBottomMaximized()); + } + } + QRectF sourceRect = QRectF(QPointF(0, 0), r.size()); + if (!m_theme->isCompositingActive()) { + if (frame->hasElementPrefix("decoration-opaque")) { + r = QRectF(conf.paddingLeft(), conf.paddingTop(), + sceneRect().width()-conf.paddingRight()-conf.paddingLeft(), + sceneRect().height()-conf.paddingBottom()-conf.paddingTop()); + sourceRect = QRectF(0.0, 0.0, r.width(), r.height()); + } + else { + r = QRectF(conf.paddingLeft(), conf.paddingTop(), + sceneRect().width(), sceneRect().height()); + sourceRect = r; + } + } + frame->resizeFrame(r.size()); + + // animation + if (isAnimating() && frame->hasElementPrefix("decoration-inactive")) { + QPixmap target = frame->framePixmap(); + frame->setElementPrefix("decoration-inactive"); + if (!isActive()) { + frame->setElementPrefix("decoration"); + } + if (!m_theme->isCompositingActive() && frame->hasElementPrefix("decoration-opaque-inactive")) { + frame->setElementPrefix("decoration-opaque-inactive"); + if (!isActive()) { + frame->setElementPrefix("decoration-opaque"); + } + } + if (maximized && frame->hasElementPrefix("decoration-maximized-inactive")) { + frame->setElementPrefix("decoration-maximized-inactive"); + if (!isActive()) { + frame->setElementPrefix("decoration-maximized"); + } + if (!m_theme->isCompositingActive() && frame->hasElementPrefix("decoration-maximized-opaque-inactive")) { + frame->setElementPrefix("decoration-maximized-opaque-inactive"); + if (!isActive()) { + frame->setElementPrefix("decoration-maximized-opaque"); + } + } + } else if (maximized && frame->hasElementPrefix("decoration-maximized")) { + frame->setElementPrefix("decoration-maximized"); + } + frame->resizeFrame(r.size()); + QPixmap result = Plasma::PaintUtils::transition(frame->framePixmap(), + target, m_animationProgress); + painter->drawPixmap(r.toRect(), result, sourceRect); + } else { + frame->paintFrame(painter, r, sourceRect); + } + painter->restore(); +} + +void AuroraeScene::updateLayout() +{ + if (!m_theme->isValid()) { + return; + } + const ThemeConfig &config = m_theme->themeConfig(); + int marginTop = qMin(config.buttonMarginTop(), config.titleHeight() - config.buttonHeight()); + marginTop = qMax(marginTop, 0); + const int left = config.paddingLeft(); + const int genericTop = config.paddingTop() + marginTop; + const int right = sceneRect().width() - m_rightButtons->preferredWidth() - config.paddingRight(); + if (m_maximizeMode == KDecorationDefines::MaximizeFull) { // TODO: check option + const int top = genericTop + config.titleEdgeTopMaximized(); + m_leftButtons->setGeometry(QRectF(QPointF(left + config.titleEdgeLeftMaximized(), top), + m_leftButtons->size())); + m_rightButtons->setGeometry(QRectF(QPointF(right - config.titleEdgeRightMaximized(), top), + m_rightButtons->size())); + // title + const int leftTitle = m_leftButtons->geometry().right() + config.titleBorderLeft(); + const int titleWidth = m_rightButtons->geometry().left() - config.titleBorderRight() - leftTitle; + m_title->setGeometry(leftTitle, config.paddingTop() + config.titleEdgeTopMaximized(), + titleWidth, config.titleHeight()); + m_title->layout()->invalidate(); + } else { + const int top = genericTop + config.titleEdgeTop(); + m_leftButtons->setGeometry(QRectF(QPointF(left + config.titleEdgeLeft(), top), m_leftButtons->size())); + m_rightButtons->setGeometry(QRectF(QPointF(right - config.titleEdgeRight(), top), m_rightButtons->size())); + // title + const int leftTitle = m_leftButtons->geometry().right() + config.titleBorderLeft(); + const int titleWidth = m_rightButtons->geometry().left() - config.titleBorderRight() - leftTitle; + m_title->setGeometry(leftTitle, config.paddingTop() + config.titleEdgeTop(), + titleWidth, config.titleHeight()); + m_title->layout()->invalidate(); + } +} + +void AuroraeScene::initButtons(QGraphicsLinearLayout* layout, const QString& buttons) const +{ + if (!m_theme->isValid()) { + return; + } + foreach (const QChar &button, buttons) { + switch (button.toAscii()) { + case 'M': { + AuroraeMenuButton *button = new AuroraeMenuButton(m_theme); + connect(button, SIGNAL(clicked()), SIGNAL(menuClicked())); + connect(button, SIGNAL(doubleClicked()), SIGNAL(menuDblClicked())); + layout->addItem(button); + break; + } + case 'S': + if (m_theme->hasButton(AllDesktopsButton)) { + AuroraeButton *button = new AuroraeButton(m_theme, AllDesktopsButton); + button->setCheckable(true); + button->setChecked(m_allDesktops); + connect(button, SIGNAL(clicked()), SIGNAL(toggleOnAllDesktops())); + layout->addItem(button); + } + break; + case 'H': + if (m_contextHelp && m_theme->hasButton(HelpButton)) { + AuroraeButton *button = new AuroraeButton(m_theme, HelpButton); + connect(button, SIGNAL(clicked()), SIGNAL(showContextHelp())); + layout->addItem(button); + } + break; + case 'I': + if (m_theme->hasButton(MinimizeButton)) { + AuroraeButton *button = new AuroraeButton(m_theme, MinimizeButton); + connect(button, SIGNAL(clicked()), SIGNAL(minimizeWindow())); + layout->addItem(button); + } + break; + case 'A': + if (m_theme->hasButton(MaximizeButton) || m_theme->hasButton(RestoreButton)) { + AuroraeMaximizeButton *button = new AuroraeMaximizeButton(m_theme); + button->setMaximizeMode(m_maximizeMode); + connect(button, SIGNAL(clicked(Qt::MouseButtons)), SIGNAL(maximize(Qt::MouseButtons))); + layout->addItem(button); + } + break; + case 'X': + if (m_theme->hasButton(CloseButton)){ + AuroraeButton *button = new AuroraeButton(m_theme, CloseButton); + connect(button, SIGNAL(clicked()), SIGNAL(closeWindow())); + layout->addItem(button); + } + break; + case 'F': + if (m_theme->hasButton(KeepAboveButton)) { + AuroraeButton *button = new AuroraeButton(m_theme, KeepAboveButton); + button->setCheckable(true); + button->setChecked(m_keepAbove); + connect(button, SIGNAL(clicked()), SIGNAL(toggleKeepAbove())); + layout->addItem(button); + } + break; + case 'B': + if (m_theme->hasButton(KeepBelowButton)) { + AuroraeButton *button = new AuroraeButton(m_theme, KeepBelowButton); + button->setCheckable(true); + button->setChecked(m_keepBelow); + connect(button, SIGNAL(clicked()), SIGNAL(toggleKeepBelow())); + layout->addItem(button); + } + break; + case 'L': + if (m_theme->hasButton(ShadeButton)) { + AuroraeButton *button = new AuroraeButton(m_theme, ShadeButton); + button->setCheckable(true); + button->setChecked(m_shade); + connect(button, SIGNAL(clicked()), SIGNAL(toggleShade())); + layout->addItem(button); + } + break; + case '_': + layout->addItem(new AuroraeSpacer(m_theme)); + break; + default: + break; // nothing + } + } +} + +void AuroraeScene::setIcon(const QIcon &icon) +{ + m_iconPixmap = icon; + foreach (QGraphicsItem *item, items()) { + if (AuroraeMenuButton *button = dynamic_cast< AuroraeMenuButton* >(item)) { + const int iconSize = qMin(button->size().width(), button->size().height()); + const QSize size = icon.actualSize(QSize(iconSize, iconSize)); + QPixmap pix = icon.pixmap(size); + button->setIcon(pix); + } + } +} + +bool AuroraeScene::isActive() const +{ + return m_active; +} + +void AuroraeScene::setActive(bool active, bool animate) +{ + m_active = active; + if (isAnimating()) { + m_animation->stop(); + } + m_animationProgress = 0.0; + int time = m_theme->themeConfig().animationTime(); + if (time != 0 && animate) { + m_animation->setDuration(time); + m_animation->setEasingCurve(QEasingCurve::InOutQuad); + m_animation->setStartValue(0.0); + m_animation->setEndValue(1.0); + m_animation->start(); + } + emit activeChanged(); + update(sceneRect()); +} + +KDecorationDefines::MaximizeMode AuroraeScene::maximizeMode() const +{ + return m_maximizeMode; +} + +void AuroraeScene::setMaximizeMode(KDecorationDefines::MaximizeMode mode) +{ + m_maximizeMode = mode; + foreach (QGraphicsItem *item, items()) { + if (AuroraeMaximizeButton *button = dynamic_cast< AuroraeMaximizeButton* >(item)) { + button->setMaximizeMode(mode); + } + } + updateLayout(); + update(sceneRect()); +} + +bool AuroraeScene::isAnimating() const +{ + return (m_animation->state() == QAbstractAnimation::Running); +} + +qreal AuroraeScene::animationProgress() const +{ + return m_animationProgress; +} + +void AuroraeScene::setAnimationProgress(qreal progress) +{ + m_animationProgress = progress; + update(sceneRect()); +} + +bool AuroraeScene::isAllDesktops() const +{ + return m_allDesktops; +} + +void AuroraeScene::setAllDesktops(bool all) +{ + if (m_allDesktops == all) { + return; + } + m_allDesktops = all; + foreach (QGraphicsItem *item, items()) { + if (AuroraeButton *button = dynamic_cast< AuroraeButton* >(item)) { + if (button->type() == AllDesktopsButton) { + button->setChecked(m_allDesktops); + button->update(); + } + } + } +} + +bool AuroraeScene::isKeepAbove() const +{ + return m_keepAbove; +} + +void AuroraeScene::setKeepAbove(bool keep) +{ + if (m_keepAbove == keep) { + return; + } + m_keepAbove = keep; + foreach (QGraphicsItem *item, items()) { + if (AuroraeButton *button = dynamic_cast< AuroraeButton* >(item)) { + if (button->type() == KeepAboveButton) { + button->setChecked(m_keepAbove); + button->update(); + } + } + } +} + +bool AuroraeScene::isKeepBelow() const +{ + return m_keepBelow; +} + +void AuroraeScene::setKeepBelow(bool keep) +{ + if (m_keepBelow == keep) { + return; + } + m_keepBelow = keep; + foreach (QGraphicsItem *item, items()) { + if (AuroraeButton *button = dynamic_cast< AuroraeButton* >(item)) { + if (button->type() == KeepBelowButton) { + button->setChecked(m_keepBelow); + button->update(); + } + } + } +} + +bool AuroraeScene::isShade() const +{ + return m_shade; +} + +void AuroraeScene::setShade(bool shade) +{ + if (m_shade == shade) { + return; + } + m_shade = shade; + foreach (QGraphicsItem *item, items()) { + if (AuroraeButton *button = dynamic_cast< AuroraeButton* >(item)) { + if (button->type() == ShadeButton) { + button->setChecked(m_shade); + button->update(); + } + } + } +} + +int AuroraeScene::leftButtonsWidth() const +{ + if (!m_leftButtons) { + return 0; + } + return m_leftButtons->preferredWidth(); +} + +int AuroraeScene::rightButtonsWidth() const +{ + if (!m_rightButtons) { + return 0; + } + return m_rightButtons->preferredWidth(); +} + +void AuroraeScene::setButtons(const QString &left, const QString &right) +{ + m_leftButtonOrder = left; + m_rightButtonOrder = right; + resetTheme(); +} + +void AuroraeScene::setCaption(const QString &caption) +{ + m_caption = caption; + foreach (QGraphicsItem *item, items()) { + if (AuroraeTab *tab = dynamic_cast(item)) { + tab->setCaption(caption); + } + } +} + +void AuroraeScene::mousePressEvent(QGraphicsSceneMouseEvent* event) +{ + QGraphicsScene::mousePressEvent(event); + if (!event->isAccepted()) { + event->accept(); + emit titlePressed(event->button(), event->buttons()); + } +} + +void AuroraeScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) +{ + QGraphicsScene::mouseReleaseEvent(event); + if (!event->isAccepted()) { + if (m_dblClicked && event->button() == Qt::LeftButton) { + // eat event + m_dblClicked = false; + return; + } + emit titleReleased(event->button(), event->buttons()); + } +} + +void AuroraeScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) +{ + QGraphicsScene::mouseDoubleClickEvent(event); + if (!event->isAccepted() && event->button() == Qt::LeftButton) { + m_dblClicked = true; + emit titleDoubleClicked(); + } +} + +void AuroraeScene::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + QGraphicsScene::mouseMoveEvent(event); + if (!event->isAccepted()) { + emit titleMouseMoved(event->button(), event->buttons()); + } +} + +void AuroraeScene::wheelEvent(QGraphicsSceneWheelEvent* event) +{ + QGraphicsScene::wheelEvent(event); + if (!event->isAccepted()) { + emit wheelEvent(event->delta()); + } +} + + +} // namespace diff --git a/clients/aurorae/src/lib/auroraescene.h b/clients/aurorae/src/lib/auroraescene.h new file mode 100644 index 0000000000..f8aba3da32 --- /dev/null +++ b/clients/aurorae/src/lib/auroraescene.h @@ -0,0 +1,126 @@ +/* + 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. + +*/ + +#ifndef AURORAE_AURORAESCENE_H +#define AURORAE_AURORAESCENE_H +// #include "libaurorae_export.h" + +#include +#include + +class QGraphicsLayout; +class QGraphicsLinearLayout; +class QIcon; +class QPropertyAnimation; + +namespace Aurorae { +class AuroraeTheme; + +class /*LIBAURORAE_EXPORT*/ AuroraeScene : public QGraphicsScene +{ + Q_OBJECT + Q_PROPERTY(qreal animation READ animationProgress WRITE setAnimationProgress) + +public: + AuroraeScene(AuroraeTheme *theme, const QString &leftButtons, const QString &rightButtons, bool contextHelp, QObject* parent = 0); + virtual ~AuroraeScene(); + void updateLayout(); + + void setActive(bool active, bool animate = true); + bool isActive() const; + void setIcon(const QIcon &icon); + void setAllDesktops(bool all); + bool isAllDesktops() const; + void setKeepAbove(bool keep); + bool isKeepAbove() const; + void setKeepBelow(bool keep); + bool isKeepBelow() const; + void setShade(bool shade); + bool isShade() const; + + void setMaximizeMode(KDecorationDefines::MaximizeMode mode); + KDecorationDefines::MaximizeMode maximizeMode() const; + + bool isAnimating() const; + qreal animationProgress() const; + void setAnimationProgress(qreal progress); + + int leftButtonsWidth() const; + int rightButtonsWidth() const; + void setButtons(const QString &left, const QString &right); + + void setCaption(const QString &caption); + +Q_SIGNALS: + void menuClicked(); + void menuDblClicked(); + void showContextHelp(); + void maximize(Qt::MouseButtons button); + void minimizeWindow(); + void closeWindow(); + void toggleOnAllDesktops(); + void toggleKeepAbove(); + void toggleKeepBelow(); + void toggleShade(); + void titlePressed(Qt::MouseButton, Qt::MouseButtons); + void titleReleased(Qt::MouseButton, Qt::MouseButtons); + void titleDoubleClicked(); + void titleMouseMoved(Qt::MouseButton, Qt::MouseButtons); + void wheelEvent(int delta); + + void activeChanged(); + +protected: + virtual void drawBackground(QPainter* painter, const QRectF& rect); + virtual void mousePressEvent(QGraphicsSceneMouseEvent* event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event); + virtual void wheelEvent(QGraphicsSceneWheelEvent* event); + +private Q_SLOTS: + void resetTheme(); + +private: + void init(); + void initButtons(QGraphicsLinearLayout *layout, const QString &buttons) const; + AuroraeTheme *m_theme; + QGraphicsWidget *m_leftButtons; + QGraphicsWidget *m_rightButtons; + QGraphicsWidget *m_title; + bool m_active; + qreal m_animationProgress; + QPropertyAnimation *m_animation; + KDecorationDefines::MaximizeMode m_maximizeMode; + QIcon m_iconPixmap; + bool m_allDesktops; + bool m_shade; + bool m_keepAbove; + bool m_keepBelow; + QString m_leftButtonOrder; + QString m_rightButtonOrder; + QString m_caption; + bool m_dblClicked; + bool m_contextHelp; +}; + +} // namespace + +#endif // AURORAE_AURORAESCENE_H diff --git a/clients/aurorae/src/lib/auroraetab.cpp b/clients/aurorae/src/lib/auroraetab.cpp new file mode 100644 index 0000000000..fedae78f89 --- /dev/null +++ b/clients/aurorae/src/lib/auroraetab.cpp @@ -0,0 +1,157 @@ +/* + 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 "auroraetab.h" +#include "auroraescene.h" +#include "auroraetheme.h" +#include "themeconfig.h" +#include +#include +#include +#include +#include +#include +#include + +namespace Aurorae +{ + +AuroraeTab::AuroraeTab(AuroraeTheme* theme, const QString& caption) + : QGraphicsWidget() + , m_theme(theme) + , m_caption(caption) +{ + m_effect = new QGraphicsDropShadowEffect(this); + if (m_theme->themeConfig().useTextShadow()) { + setGraphicsEffect(m_effect); + } + setAcceptedMouseButtons(Qt::NoButton); +} + +AuroraeTab::~AuroraeTab() +{ +} + +void AuroraeTab::activeChanged() +{ + const ThemeConfig &config = m_theme->themeConfig(); + if (!config.useTextShadow()) { + return; + } + const bool active = static_cast(scene())->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::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(scene()); + const bool active = s->isActive(); + const ThemeConfig &conf = m_theme->themeConfig(); + const QRect textRect = painter->fontMetrics().boundingRect(rect().toRect(), + conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine, + m_caption); + if ((active && conf.haloActive()) || + (!active && conf.haloInactive())) { + QRect haloRect = textRect; + if (haloRect.width() > rect().width()) { + haloRect.setWidth(rect().width()); + } + Plasma::PaintUtils::drawHalo(painter, haloRect); + } + QPixmap pix(rect().size().toSize()); + pix.fill(Qt::transparent); + QPainter p(&pix); + QColor color; + if (active) { + color = conf.activeTextColor(); + if (s->isAnimating()) { + color = KColorUtils::mix(conf.inactiveTextColor(), conf.activeTextColor(), s->animationProgress()); + } + } else { + color = conf.inactiveTextColor(); + if (s->isAnimating()){ + color = KColorUtils::mix(conf.activeTextColor(), conf.inactiveTextColor(), s->animationProgress()); + } + } + p.setPen(color); + p.drawText(pix.rect(), conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine, m_caption); + if (textRect.width() > rect().width()) { + // Fade out effect + // based on fadeout of tasks applet in Plasma/desktop/applets/tasks/abstracttaskitem.cpp by + // Copyright (C) 2007 by Robert Knight + // Copyright (C) 2008 by Alexis Ménard + // Copyright (C) 2008 by Marco Martin + 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(); + painter->drawPixmap(rect().toRect(), pix); + painter->restore(); +} + +QSizeF AuroraeTab::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + QFont titleFont = KGlobalSettings::windowTitleFont(); + QFontMetricsF fm(titleFont); + switch (which) { + case Qt::MinimumSize: + fm.boundingRect(m_caption.left(3)).size(); + break; + case Qt::PreferredSize: + return fm.boundingRect(m_caption).size(); + case Qt::MaximumSize: + return QSizeF(scene()->sceneRect().width(), m_theme->themeConfig().titleHeight()); + default: + return QGraphicsWidget::sizeHint(which, constraint); + } + return QGraphicsWidget::sizeHint(which, constraint); +} + +} // namespace diff --git a/clients/aurorae/src/lib/auroraetab.h b/clients/aurorae/src/lib/auroraetab.h new file mode 100644 index 0000000000..0d4e6ae3ef --- /dev/null +++ b/clients/aurorae/src/lib/auroraetab.h @@ -0,0 +1,53 @@ +/* + 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. + +*/ + +#ifndef AURORAE_AURORAETAB_H +#define AURORAE_AURORAETAB_H + +#include + +class QGraphicsDropShadowEffect; +namespace Aurorae { +class AuroraeTheme; + +class AuroraeTab : public QGraphicsWidget +{ + Q_OBJECT +public: + AuroraeTab(AuroraeTheme *theme, const QString &caption); + virtual ~AuroraeTab(); + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + void setCaption(const QString &caption); + +public Q_SLOTS: + void activeChanged(); + +protected: + virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint = QSizeF()) const; + +private: + AuroraeTheme *m_theme; + QString m_caption; + QGraphicsDropShadowEffect *m_effect; +}; + +} + +#endif // AURORAE_AURORAETAB_H diff --git a/clients/aurorae/src/lib/auroraetheme.cpp b/clients/aurorae/src/lib/auroraetheme.cpp new file mode 100644 index 0000000000..9e826a3254 --- /dev/null +++ b/clients/aurorae/src/lib/auroraetheme.cpp @@ -0,0 +1,324 @@ +/* + 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 "auroraetheme.h" +#include "themeconfig.h" +// Qt +#include +// KDE +#include +#include +#include +#include +#include +#include + +namespace Aurorae { + +/************************************************ +* AuroraeThemePrivate +************************************************/ +class AuroraeThemePrivate +{ +public: + AuroraeThemePrivate(); + ~AuroraeThemePrivate(); + void initButtonFrame(AuroraeButtonType type); + void reset(); + QString themeName; + Aurorae::ThemeConfig themeConfig; + Plasma::FrameSvg *decoration; + QHash< AuroraeButtonType, Plasma::FrameSvg* > buttons; + bool activeCompositing; + KDecorationDefines::BorderSize borderSize; +}; + +AuroraeThemePrivate::AuroraeThemePrivate() + : decoration(0) + , activeCompositing(true) + , borderSize(KDecoration::BorderNormal) +{ +} + +AuroraeThemePrivate::~AuroraeThemePrivate() +{ + while (!buttons.isEmpty()) { + Plasma::FrameSvg *button = buttons.begin().value(); + delete button; + button = 0; + buttons.remove(buttons.begin().key()); + } +} + +void AuroraeThemePrivate::initButtonFrame(AuroraeButtonType type) +{ + QString file("aurorae/themes/" + themeName + '/' + AuroraeTheme::mapButtonToName(type) + ".svg"); + QString path = KGlobal::dirs()->findResource("data", file); + if (path.isEmpty()) { + // let's look for svgz + file.append("z"); + path = KGlobal::dirs()->findResource("data", file); + } + if (!path.isEmpty()) { + Plasma::FrameSvg *frame = new Plasma::FrameSvg(); + frame->setImagePath(path); + frame->setCacheAllRenderedFrames(true); + frame->setEnabledBorders(Plasma::FrameSvg::NoBorder); + buttons[ type ] = frame; + } else { + kDebug(1216) << "No button for: " << AuroraeTheme::mapButtonToName(type); + } +} + +void AuroraeThemePrivate::reset() +{ + decoration->clearCache(); + delete decoration; + decoration = 0; + while (!buttons.isEmpty()) { + Plasma::FrameSvg *button = buttons.begin().value(); + button->clearCache(); + delete button; + button = 0; + buttons.remove(buttons.begin().key()); + } +} + +/************************************************ +* AuroraeTheme +************************************************/ +AuroraeTheme::AuroraeTheme(QObject* parent) + : QObject(parent) + , d(new AuroraeThemePrivate) +{ +} + +AuroraeTheme::~AuroraeTheme() +{ + delete d; +} + +bool AuroraeTheme::isValid() const +{ + return !d->themeName.isNull(); +} + +void AuroraeTheme::loadTheme(const QString &name, const KConfig &config) +{ + if (!d->themeName.isNull()) { + // only reset if the theme has been initialized at least once + d->reset(); + } + d->themeName = name; + QString file("aurorae/themes/" + d->themeName + "/decoration.svg"); + QString path = KGlobal::dirs()->findResource("data", file); + if (path.isEmpty()) { + file += 'z'; + path = KGlobal::dirs()->findResource("data", file); + } + if (path.isEmpty()) { + kDebug(1216) << "Could not find decoration svg: aborting"; + d->themeName = QString(); + return; + } + d->decoration = new Plasma::FrameSvg(this); + d->decoration->setImagePath(path); + d->decoration->setCacheAllRenderedFrames(true); + d->decoration->setEnabledBorders(Plasma::FrameSvg::AllBorders); + + // load the buttons + d->initButtonFrame(MinimizeButton); + d->initButtonFrame(MaximizeButton); + d->initButtonFrame(RestoreButton); + d->initButtonFrame(CloseButton); + d->initButtonFrame(AllDesktopsButton); + d->initButtonFrame(KeepAboveButton); + d->initButtonFrame(KeepBelowButton); + d->initButtonFrame(ShadeButton); + d->initButtonFrame(HelpButton); + + d->themeConfig.load(config); + emit themeChanged(); +} + +void AuroraeTheme::readThemeConfig(const KConfig &config) +{ + // read config values + d->themeConfig.load(config); + emit themeChanged(); +} + +Plasma::FrameSvg *AuroraeTheme::button(AuroraeButtonType b) const +{ + if (hasButton(b)) { + return d->buttons[ b ]; + } else { + return NULL; + } +} + +Plasma::FrameSvg *AuroraeTheme::decoration() const +{ + return d->decoration; +} + +bool AuroraeTheme::hasButton(AuroraeButtonType button) const +{ + return d->buttons.contains(button); +} + +QLatin1String AuroraeTheme::mapButtonToName(AuroraeButtonType type) +{ + switch(type) { + case MinimizeButton: + return QLatin1String("minimize"); + case MaximizeButton: + return QLatin1String("maximize"); + case RestoreButton: + return QLatin1String("restore"); + case CloseButton: + return QLatin1String("close"); + case AllDesktopsButton: + return QLatin1String("alldesktops"); + case KeepAboveButton: + return QLatin1String("keepabove"); + case KeepBelowButton: + return QLatin1String("keepbelow"); + case ShadeButton: + return QLatin1String("shade"); + case HelpButton: + return QLatin1String("help"); + default: + return QLatin1String(""); + } +} + +const QString &AuroraeTheme::themeName() const +{ + return d->themeName; +} +const Aurorae::ThemeConfig &AuroraeTheme::themeConfig() const +{ + return d->themeConfig; +} + +void AuroraeTheme::borders(int& left, int& top, int& right, int& bottom, bool maximized) const +{ + if (maximized) { + left = 0; + right = 0; + bottom = 0; + top = d->themeConfig.titleHeight() + d->themeConfig.titleEdgeTopMaximized() + d->themeConfig.titleEdgeBottomMaximized(); + } else { + switch (d->borderSize) { + case KDecoration::BorderTiny: + if (isCompositingActive()) { + left = qMin(0, (int)left - d->themeConfig.borderLeft() - d->themeConfig.paddingLeft()); + right = qMin(0, (int)right - d->themeConfig.borderRight() - d->themeConfig.paddingRight()); + bottom = qMin(0, (int)bottom - d->themeConfig.borderBottom() - d->themeConfig.paddingBottom()); + } else { + left = qMin(0, (int)left - d->themeConfig.borderLeft()); + right = qMin(0, (int)right - d->themeConfig.borderRight()); + bottom = qMin(0, (int)bottom - d->themeConfig.borderBottom()); + } + break; + case KDecoration::BorderLarge: + left = right = bottom = 4; + break; + case KDecoration::BorderVeryLarge: + left = right = bottom = 8; + break; + case KDecoration::BorderHuge: + left = right = bottom = 12; + break; + case KDecoration::BorderVeryHuge: + left = right = bottom = 23; + break; + case KDecoration::BorderOversized: + left = right = bottom = 36; + break; + case KDecoration::BorderNormal: + default: + left = right = bottom = 0; + } + left += d->themeConfig.borderLeft(); + right += d->themeConfig.borderRight(); + bottom += d->themeConfig.borderBottom(); + top = d->themeConfig.titleHeight() + d->themeConfig.titleEdgeTop() + d->themeConfig.titleEdgeBottom(); + } +} + +void AuroraeTheme::padding(int& left, int& top, int& right, int& bottom) const +{ + left = d->themeConfig.paddingLeft(); + top = d->themeConfig.paddingTop(); + right = d->themeConfig.paddingRight(); + bottom = d->themeConfig.paddingBottom(); +} + +void AuroraeTheme::titleEdges(int &left, int &top, int &right, int &bottom, bool maximized) const +{ + if (maximized) { + left = d->themeConfig.titleEdgeLeftMaximized(); + top = d->themeConfig.titleEdgeTopMaximized(); + right = d->themeConfig.titleEdgeRightMaximized(); + bottom = d->themeConfig.titleEdgeBottomMaximized(); + } else { + left = d->themeConfig.titleEdgeLeft(); + top = d->themeConfig.titleEdgeTop(); + right = d->themeConfig.titleEdgeRight(); + bottom = d->themeConfig.titleEdgeBottom(); + } +} + +void AuroraeTheme::buttonMargins(int &left, int &top, int &right) const +{ + left = d->themeConfig.titleBorderLeft(); + top = d->themeConfig.buttonMarginTop(); + right = d->themeConfig.titleBorderRight(); +} + +bool AuroraeTheme::isCompositingActive() const +{ + return d->activeCompositing; +} + +void AuroraeTheme::setCompositingActive(bool active) +{ + d->activeCompositing = active; +} + +QString AuroraeTheme::defaultButtonsLeft() const +{ + return d->themeConfig.defaultButtonsLeft(); +} + +QString AuroraeTheme::defaultButtonsRight() const +{ + return d->themeConfig.defaultButtonsRight(); +} + +void AuroraeTheme::setBorderSize(KDecorationDefines::BorderSize size) +{ + d->borderSize = size; +} + + +} // namespace diff --git a/clients/aurorae/src/lib/auroraetheme.h b/clients/aurorae/src/lib/auroraetheme.h new file mode 100644 index 0000000000..8cef60e8e2 --- /dev/null +++ b/clients/aurorae/src/lib/auroraetheme.h @@ -0,0 +1,127 @@ +/* + 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. + +*/ + +#ifndef AURORAETHEME_H +#define AURORAETHEME_H + +// #include "libaurorae_export.h" + +#include +#include +#include + +namespace Plasma { +class FrameSvg; +} +class KConfig; + +namespace Aurorae { +class AuroraeThemePrivate; +class AuroraeTab; +class AuroraeScene; +class AuroraeButton; +class AuroraeMaximizeButton; +class AuroraeSpacer; +class ThemeConfig; + +enum AuroraeButtonType { + MinimizeButton = QGraphicsItem::UserType+1, + MaximizeButton, + RestoreButton, + CloseButton, + AllDesktopsButton, + KeepAboveButton, + KeepBelowButton, + ShadeButton, + HelpButton, + MenuButton +}; + +class /*LIBAURORAE_EXPORT*/ AuroraeTheme : public QObject +{ + Q_OBJECT +public: + AuroraeTheme(QObject* parent = 0); + virtual ~AuroraeTheme(); + // TODO: KSharedConfigPtr + void loadTheme(const QString &name, const KConfig &config); + bool isValid() const; + void readThemeConfig(const KConfig& config); + const QString &themeName() const; + /** + * Sets the borders according to maximized state. + * Borders are global to all windows. + */ + void borders(int &left, int &top, int &right, int &bottom, bool maximized) const; + /** + * Sets the padding according. + * Padding is global to all windows. + */ + void padding(int &left, int &top, int &right, int &bottom) const; + /** + * Sets the title edges according to maximized state. + * Title edges are global to all windows. + */ + void titleEdges(int &left, int &top, int &right, int &bottom, bool maximized) const; + /** + * Sets the button margins. + * Button margins are global to all windows. There is no button margin bottom. + */ + void buttonMargins(int& left, int& top, int& right) const; + void setCompositingActive(bool active); + bool isCompositingActive() const; + + /** + * @returns The FrameSvg containing the decoration. + */ + Plasma::FrameSvg *decoration() const; + /** + * @returns The FrameSvg for the specified button or NULL if there is no such button. + */ + Plasma::FrameSvg *button(AuroraeButtonType button) const; + /** + * @returns true if the theme contains a FrameSvg for specified button. + */ + bool hasButton(AuroraeButtonType button) const; + QString defaultButtonsLeft() const; + QString defaultButtonsRight() const; + void setBorderSize(KDecorationDefines::BorderSize size); + + // TODO: move to namespace + static QLatin1String mapButtonToName(AuroraeButtonType type); + +Q_SIGNALS: + void themeChanged(); + +private: + const ThemeConfig &themeConfig() const; + + AuroraeThemePrivate* const d; + + friend class Aurorae::AuroraeButton; + friend class Aurorae::AuroraeMaximizeButton; + friend class Aurorae::AuroraeSpacer; + friend class Aurorae::AuroraeScene; + friend class Aurorae::AuroraeTab; +}; + +} // namespace + +#endif // AURORAETHEME_H diff --git a/clients/aurorae/src/themeconfig.cpp b/clients/aurorae/src/lib/themeconfig.cpp similarity index 97% rename from clients/aurorae/src/themeconfig.cpp rename to clients/aurorae/src/lib/themeconfig.cpp index 104d1120b7..3bb7588ab4 100644 --- a/clients/aurorae/src/themeconfig.cpp +++ b/clients/aurorae/src/lib/themeconfig.cpp @@ -27,9 +27,9 @@ ThemeConfig::ThemeConfig() { } -void ThemeConfig::load(KConfig *conf) +void ThemeConfig::load(const KConfig &conf) { - KConfigGroup general(conf, "General"); + KConfigGroup general(&conf, "General"); m_activeTextColor = general.readEntry("ActiveTextColor", QColor(Qt::black)); m_inactiveTextColor = general.readEntry("InactiveTextColor", QColor(Qt::black)); m_useTextShadow = general.readEntry("UseTextShadow", false); @@ -64,7 +64,7 @@ void ThemeConfig::load(KConfig *conf) m_defaultButtonsRight = general.readEntry("RightButtons", KDecorationOptions::defaultTitleButtonsRight()); m_shadow = general.readEntry("Shadow", true); - KConfigGroup border(conf, "Layout"); + KConfigGroup border(&conf, "Layout"); // default values taken from KCommonDecoration::layoutMetric() in kcommondecoration.cpp m_borderLeft = border.readEntry("BorderLeft", 5); m_borderRight = border.readEntry("BorderRight", 5); diff --git a/clients/aurorae/src/themeconfig.h b/clients/aurorae/src/lib/themeconfig.h similarity index 99% rename from clients/aurorae/src/themeconfig.h rename to clients/aurorae/src/lib/themeconfig.h index a75327d25a..e87bd8f8b8 100644 --- a/clients/aurorae/src/themeconfig.h +++ b/clients/aurorae/src/lib/themeconfig.h @@ -30,7 +30,7 @@ class ThemeConfig { public: ThemeConfig(); - void load(KConfig *conf); + void load(const KConfig &conf); ~ThemeConfig() {}; // active window QColor activeTextColor() const { diff --git a/kcmkwin/kwindecoration/CMakeLists.txt b/kcmkwin/kwindecoration/CMakeLists.txt index 407ccaee94..6014197168 100644 --- a/kcmkwin/kwindecoration/CMakeLists.txt +++ b/kcmkwin/kwindecoration/CMakeLists.txt @@ -1,6 +1,6 @@ # need a header file from Aurorae sources include_directories( - ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/clients/aurorae/src/ + ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/clients/aurorae/src/lib ) set(kcm_kwindecoration_PART_SRCS @@ -12,7 +12,7 @@ set(kcm_kwindecoration_PART_SRCS decorationdelegate.cpp decorationmodel.cpp auroraepreview.cpp - ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/clients/aurorae/src/themeconfig.cpp + ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/clients/aurorae/src/lib/themeconfig.cpp ) kde4_add_ui_files(kcm_kwindecoration_PART_SRCS buttons.ui config.ui decoration.ui) diff --git a/kcmkwin/kwindecoration/auroraepreview.cpp b/kcmkwin/kwindecoration/auroraepreview.cpp index 118b30152e..1a2e009698 100644 --- a/kcmkwin/kwindecoration/auroraepreview.cpp +++ b/kcmkwin/kwindecoration/auroraepreview.cpp @@ -54,7 +54,7 @@ AuroraePreview::AuroraePreview( const QString& name, const QString& packageName, m_themeConfig = new Aurorae::ThemeConfig(); KConfig conf( "aurorae/themes/" + packageName + '/' + packageName + "rc", KConfig::FullConfig, "data" ); - m_themeConfig->load( &conf ); + m_themeConfig->load( conf ); initButtonFrame( "minimize", packageName ); initButtonFrame( "maximize", packageName );