From 1bcd9fe4f6003738a988953256a452633d3d8e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 12 Apr 2010 19:28:58 +0000 Subject: [PATCH] Import of new Aurorae based on QGraphicsView and KDecoration instead of KCommonDecoration. It should support everything the old engine supported. Only known regression is the lack of tooltips. Now finally Aurorae is ready to get window tab support \o/ svn path=/trunk/KDE/kdebase/workspace/; revision=1114115 --- clients/aurorae/src/CMakeLists.txt | 10 +- clients/aurorae/src/aurorae.cpp | 1112 ++++------------- clients/aurorae/src/aurorae.h | 126 +- clients/aurorae/src/lib/auroraebutton.cpp | 442 +++++++ clients/aurorae/src/lib/auroraebutton.h | 168 +++ clients/aurorae/src/lib/auroraescene.cpp | 607 +++++++++ clients/aurorae/src/lib/auroraescene.h | 126 ++ clients/aurorae/src/lib/auroraetab.cpp | 157 +++ clients/aurorae/src/lib/auroraetab.h | 53 + clients/aurorae/src/lib/auroraetheme.cpp | 324 +++++ clients/aurorae/src/lib/auroraetheme.h | 127 ++ clients/aurorae/src/{ => lib}/themeconfig.cpp | 6 +- clients/aurorae/src/{ => lib}/themeconfig.h | 2 +- kcmkwin/kwindecoration/CMakeLists.txt | 4 +- kcmkwin/kwindecoration/auroraepreview.cpp | 2 +- 15 files changed, 2287 insertions(+), 979 deletions(-) create mode 100644 clients/aurorae/src/lib/auroraebutton.cpp create mode 100644 clients/aurorae/src/lib/auroraebutton.h create mode 100644 clients/aurorae/src/lib/auroraescene.cpp create mode 100644 clients/aurorae/src/lib/auroraescene.h create mode 100644 clients/aurorae/src/lib/auroraetab.cpp create mode 100644 clients/aurorae/src/lib/auroraetab.h create mode 100644 clients/aurorae/src/lib/auroraetheme.cpp create mode 100644 clients/aurorae/src/lib/auroraetheme.h rename clients/aurorae/src/{ => lib}/themeconfig.cpp (97%) rename clients/aurorae/src/{ => lib}/themeconfig.h (99%) 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 );