Aurorae goes QML

What's working:
* background for active and inactive decorations inclusive transitions
* all buttons get loaded
* transition between button states
* all borders, paddings etc is working
* mouse interaction with buttons and title area

What's not yet working:
* special maximize mode
* mouse wheel on title area
* window tabs
* changing themes
* crash resistence (currently a not compiling QML file crashes KWin badly)
* window/blur mask (tricky - we need the alpha mask of the background SVG)

What's going to be dropped:
* special opaque mode
* decoration position at left/right/bottom instead of top
Why? Because nobody uses these features
This commit is contained in:
Martin Gräßlin 2012-01-07 17:25:21 +01:00
parent e8e4029a79
commit 5c36fcac36
9 changed files with 766 additions and 168 deletions

View file

@ -3,9 +3,6 @@ include_directories( ./lib )
set(kwin3_aurorae_PART_SRCS
aurorae.cpp
lib/auroraebutton.cpp
lib/auroraescene.cpp
lib/auroraetab.cpp
lib/auroraetheme.cpp
lib/themeconfig.cpp
)
@ -20,3 +17,11 @@ install(TARGETS kwin3_aurorae DESTINATION ${PLUGIN_INSTALL_DIR} )
install( FILES aurorae.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin )
install( FILES aurorae.knsrc DESTINATION ${CONFIG_INSTALL_DIR} )
install( FILES
qml/aurorae.qml
qml/AuroraeButton.qml
qml/AuroraeButtonGroup.qml
qml/Decoration.qml
qml/DecorationButton.qml
qml/MenuButton.qml
DESTINATION ${DATA_INSTALL_DIR}/kwin/aurorae )

View file

@ -16,17 +16,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "aurorae.h"
#include "auroraescene.h"
#include "auroraetheme.h"
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsSceneMouseEvent>
#include <QtDeclarative/QDeclarativeView>
#include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtDeclarative/QDeclarativeView>
#include <KConfig>
#include <KConfigGroup>
#include <KStandardDirs>
#include <Plasma/FrameSvg>
namespace Aurorae
@ -135,46 +134,15 @@ AuroraeFactory *AuroraeFactory::s_instance = NULL;
*******************************************************/
AuroraeClient::AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *factory)
: KDecorationUnstable(bridge, factory)
, m_clickInProgress(false)
{
m_scene = new AuroraeScene(AuroraeFactory::instance()->theme(),
options()->customButtonPositions() ? options()->titleButtonsLeft() : AuroraeFactory::instance()->theme()->defaultButtonsLeft(),
options()->customButtonPositions() ? options()->titleButtonsRight() : AuroraeFactory::instance()->theme()->defaultButtonsRight(),
providesContextHelp(), NULL);
connect(m_scene, SIGNAL(closeWindow()), SLOT(closeWindow()), Qt::QueuedConnection);
connect(m_scene, SIGNAL(maximize(Qt::MouseButtons)), SLOT(maximize(Qt::MouseButtons)), Qt::QueuedConnection);
connect(m_scene, SIGNAL(showContextHelp()), SLOT(showContextHelp()), Qt::QueuedConnection);
connect(m_scene, SIGNAL(minimizeWindow()), SLOT(minimize()), Qt::QueuedConnection);
connect(m_scene, SIGNAL(menuClicked()), SLOT(menuClicked()), Qt::QueuedConnection);
connect(m_scene, SIGNAL(menuDblClicked()), SLOT(closeWindow()), Qt::QueuedConnection);
connect(m_scene, SIGNAL(toggleOnAllDesktops()), SLOT(toggleOnAllDesktops()), Qt::QueuedConnection);
connect(m_scene, SIGNAL(toggleShade()), SLOT(toggleShade()), Qt::QueuedConnection);
connect(m_scene, SIGNAL(toggleKeepAbove()), SLOT(toggleKeepAbove()), Qt::QueuedConnection);
connect(m_scene, SIGNAL(toggleKeepBelow()), SLOT(toggleKeepBelow()), Qt::QueuedConnection);
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(m_scene, SIGNAL(tabMouseButtonPress(QGraphicsSceneMouseEvent*,int)),
SLOT(tabMouseButtonPress(QGraphicsSceneMouseEvent*,int)));
connect(m_scene, SIGNAL(tabMouseButtonRelease(QGraphicsSceneMouseEvent*,int)),
SLOT(tabMouseButtonRelease(QGraphicsSceneMouseEvent*,int)));
connect(m_scene, SIGNAL(tabRemoved(int)), SLOT(tabRemoved(int)));
connect(m_scene, SIGNAL(tabMoved(int,int)), SLOT(tabMoved(int,int)));
connect(m_scene, SIGNAL(tabMovedToGroup(long int,int)), SLOT(tabMovedToGroup(long int,int)));
connect(this, SIGNAL(keepAboveChanged(bool)), SLOT(slotKeepAboveChanged(bool)));
connect(this, SIGNAL(keepBelowChanged(bool)), SLOT(slotKeepBelowChanged(bool)));
connect(this, SIGNAL(keepAboveChanged(bool)), SIGNAL(keepAboveChangedWrapper()));
connect(this, SIGNAL(keepBelowChanged(bool)), SIGNAL(keepBelowChangedWrapper()));
}
AuroraeClient::~AuroraeClient()
{
m_view->setParent(NULL);
m_view->deleteLater();
m_scene->deleteLater();
}
void AuroraeClient::init()
@ -187,7 +155,6 @@ void AuroraeClient::init()
createMainWidget();
widget()->setAttribute(Qt::WA_TranslucentBackground);
widget()->setAttribute(Qt::WA_NoSystemBackground);
widget()->installEventFilter(this);
m_view = new QDeclarativeView(widget());
m_view->setResizeMode(QDeclarativeView::SizeRootObjectToView);
m_view->setAttribute(Qt::WA_TranslucentBackground);
@ -198,58 +165,46 @@ void AuroraeClient::init()
QPalette pal2 = widget()->palette();
pal2.setColor(widget()->backgroundRole(), Qt::transparent);
widget()->setPalette(pal2);
// setup the QML engine
foreach (const QString &importPath, KGlobal::dirs()->findDirs("module", "imports")) {
m_view->engine()->addImportPath(importPath);
}
m_view->rootContext()->setContextProperty("decoration", this);
// 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->setFont(KDecoration::options()->font(true), true);
m_scene->setFont(KDecoration::options()->font(false), false);
m_view->rootContext()->setContextProperty("auroraeTheme", AuroraeFactory::instance()->theme());
m_view->setSource(QUrl(KStandardDirs::locate("data", "kwin/aurorae/aurorae.qml")));
AuroraeFactory::instance()->theme()->setCompositingActive(compositingActive());
}
void AuroraeClient::activeChange()
{
if (m_scene->isActive() != isActive()) {
m_scene->setActive(isActive());
}
emit activeChanged();
}
void AuroraeClient::captionChange()
{
checkTabs(true);
emit captionChanged();
}
void AuroraeClient::iconChange()
{
m_scene->setIcon(icon());
emit iconChanged();
}
void AuroraeClient::desktopChange()
{
m_scene->setAllDesktops(isOnAllDesktops());
emit desktopChanged();
}
void AuroraeClient::maximizeChange()
{
if (!options()->moveResizeMaximizedWindows()) {
m_scene->setMaximizeMode(maximizeMode());
emit maximizeChanged();
}
emit maximizeChanged();
}
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();
@ -257,19 +212,31 @@ void AuroraeClient::resize(const QSize &s)
void AuroraeClient::shadeChange()
{
m_scene->setShade(isShade());
emit shadeChanged();
}
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);
if (maximized) {
left = m_view->rootObject()->property("borderLeftMaximized").toInt();
right = m_view->rootObject()->property("borderRightMaximized").toInt();
top = m_view->rootObject()->property("borderTopMaximized").toInt();
bottom = m_view->rootObject()->property("borderBottomMaximized").toInt();
} else {
left = m_view->rootObject()->property("borderLeft").toInt();
right = m_view->rootObject()->property("borderRight").toInt();
top = m_view->rootObject()->property("borderTop").toInt();
bottom = m_view->rootObject()->property("borderBottom").toInt();
}
}
void AuroraeClient::padding(int &left, int &right, int &top, int &bottom) const
{
AuroraeFactory::instance()->theme()->padding(left, top, right, bottom);
left = m_view->rootObject()->property("paddingLeft").toInt();
right = m_view->rootObject()->property("paddingRight").toInt();
top = m_view->rootObject()->property("paddingTop").toInt();
bottom = m_view->rootObject()->property("paddingBottom").toInt();
}
QSize AuroraeClient::minimumSize() const
@ -330,12 +297,10 @@ void AuroraeClient::reset(long unsigned int changed)
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());
// TODO: update buttons
}
if (changed & SettingFont) {
m_scene->setFont(KDecoration::options()->font(true), true);
m_scene->setFont(KDecoration::options()->font(false), false);
// TODO: set font
}
KDecoration::reset(changed);
}
@ -350,22 +315,6 @@ void AuroraeClient::toggleShade()
setShade(!isShade());
}
void AuroraeClient::slotKeepAboveChanged(bool above)
{
if (above && m_scene->isKeepBelow()) {
m_scene->setKeepBelow(false);
}
m_scene->setKeepAbove(above);
}
void AuroraeClient::slotKeepBelowChanged(bool below)
{
if (below && m_scene->isKeepAbove()) {
m_scene->setKeepAbove(false);
}
m_scene->setKeepBelow(below);
}
void AuroraeClient::toggleKeepAbove()
{
setKeepAbove(!keepAbove());
@ -447,72 +396,6 @@ void AuroraeClient::titleMouseMoved(Qt::MouseButton button, Qt::MouseButtons but
event = 0;
}
void AuroraeClient::checkTabs(bool force)
{
if (m_scene->tabCount() == 1 && clientGroupItems().count() == 1 && !force) {
return;
}
while (m_scene->tabCount() < clientGroupItems().count()) {
m_scene->addTab(QString());
}
while (m_scene->tabCount() > clientGroupItems().count()) {
m_scene->removeLastTab();
}
QList<AuroraeTabData> data;
foreach (const ClientGroupItem &item, clientGroupItems()) {
data << AuroraeTabData(item.title(), item.icon());
}
m_scene->setAllTabData(data);
m_scene->setFocusedTab(visibleClientGroupItem());
}
bool AuroraeClient::eventFilter(QObject *o, QEvent *e)
{
if (o != widget()) {
return false;
}
if (e->type() == QEvent::Paint) {
checkTabs();
}
return false;
}
void AuroraeClient::tabMouseButtonPress(QGraphicsSceneMouseEvent *e, int index)
{
if (buttonToWindowOperation(e->buttons()) == OperationsOp) {
displayClientMenu(index, e->screenPos());
return;
} else if (buttonToWindowOperation(e->buttons()) == ClientGroupDragOp) {
m_scene->setUniqueTabDragId(index, itemId(index));
}
titlePressed(e->button(), e->buttons());
m_clickInProgress = true;
}
void AuroraeClient::tabMouseButtonRelease(QGraphicsSceneMouseEvent *e, int index)
{
if (m_clickInProgress) {
setVisibleClientGroupItem(index);
}
titleReleased(e->button(), e->buttons());
m_clickInProgress = false;
}
void AuroraeClient::tabRemoved(int index)
{
removeFromClientGroup(index);
}
void AuroraeClient::tabMoved(int index, int before)
{
moveItemInClientGroup(index, before);
}
void AuroraeClient::tabMovedToGroup(long int uid, int before)
{
moveItemToClientGroup(uid, before);
}
QString AuroraeClient::rightButtons() const
{
// TODO: make independent of Aurorae

View file

@ -30,7 +30,6 @@ class QGraphicsScene;
namespace Aurorae
{
class AuroraeTheme;
class AuroraeScene;
class AuroraeFactory : public QObject, public KDecorationFactoryUnstable
{
@ -77,8 +76,8 @@ class AuroraeClient : public KDecorationUnstable
Q_PROPERTY(bool setShade READ isSetShade NOTIFY shadeChanged)
Q_PROPERTY(bool shade READ isShade WRITE setShade NOTIFY shadeChanged)
Q_PROPERTY(bool shadeable READ isShadeable)
Q_PROPERTY(bool keepAbove READ keepAbove WRITE setKeepAbove NOTIFY keepAboveChanged)
Q_PROPERTY(bool keepBelow READ keepBelow WRITE setKeepBelow NOTIFY keepBelowChanged)
Q_PROPERTY(bool keepAbove READ keepAbove WRITE setKeepAbove NOTIFY keepAboveChangedWrapper)
Q_PROPERTY(bool keepBelow READ keepBelow WRITE setKeepBelow NOTIFY keepBelowChangedWrapper)
// TODO: maximize mode
Q_PROPERTY(bool providesContextHelp READ providesContextHelp)
Q_PROPERTY(QRect transparentRect READ transparentRect)
@ -114,14 +113,12 @@ Q_SIGNALS:
void iconChanged();
void maximizeChanged();
void shadeChanged();
void keepAboveChanged();
void keepBelowChanged();
void keepAboveChangedWrapper();
void keepBelowChangedWrapper();
public slots:
void menuClicked();
void toggleShade();
void slotKeepAboveChanged(bool above);
void slotKeepBelowChanged(bool below);
void toggleKeepAbove();
void toggleKeepBelow();
void titlePressed(int button, int buttons);
@ -130,21 +127,10 @@ public slots:
void titlePressed(Qt::MouseButton button, Qt::MouseButtons buttons);
void titleReleased(Qt::MouseButton button, Qt::MouseButtons buttons);
void titleMouseMoved(Qt::MouseButton button, Qt::MouseButtons buttons);
void tabMouseButtonPress(QGraphicsSceneMouseEvent *e, int index);
void tabMouseButtonRelease(QGraphicsSceneMouseEvent *e, int index);
void tabRemoved(int index);
void tabMoved(int index, int before);
void tabMovedToGroup(long int uid, int before);
protected:
virtual bool eventFilter(QObject *o, QEvent *e);
private:
void updateWindowShape();
void checkTabs(bool force = false);
AuroraeScene *m_scene;
QDeclarativeView *m_view;
bool m_clickInProgress;
};
}

View file

@ -0,0 +1,329 @@
/********************************************************************
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
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, see <http://www.gnu.org/licenses/>.
*********************************************************************/
import QtQuick 1.1
import org.kde.plasma.core 0.1 as PlasmaCore
DecorationButton {
function widthForButton() {
switch (buttonType) {
case "M":
// menu
return auroraeTheme.buttonWidthMenu;
case "S":
// all desktops
return auroraeTheme.buttonWidthAllDesktops;
case "H":
// help
return auroraeTheme.buttonWidthHelp;
case "I":
// minimize
return auroraeTheme.buttonWidthMinimize;
case "A":
// maximize
return auroraeTheme.buttonWidthMaximizeRestore;
case "X":
// close
return auroraeTheme.buttonWidthClose;
case "F":
// keep above
return auroraeTheme.buttonWidthKeepAbove;
case "B":
// keep below
return auroraeTheme.buttonWidthKeepBelow;
case "L":
// shade
return auroraeTheme.buttonWidthShade;
default:
return auroraeTheme.buttonWidth;
}
}
function pathForButton() {
switch (buttonType) {
case "S":
// all desktops
return auroraeTheme.allDesktopsButtonPath;
case "H":
// help
return auroraeTheme.helpButtonPath;
case "I":
// minimize
return auroraeTheme.minimizeButtonPath;
case "A":
// maximize
return auroraeTheme.maximizeButtonPath;
case "X":
// close
return auroraeTheme.closeButtonPath;
case "F":
// keep above
return auroraeTheme.keepAboveButtonPath;
case "B":
// keep below
return auroraeTheme.keepBelowButtonPath;
case "L":
// shade
return auroraeTheme.shadeButtonPath;
default:
return "";
}
}
function toggledPressedStatusChange() {
if (pressed || toggled) {
// pressed comes after hovered (if supported)
if (!decoration.active && buttonSvg.supportsInactivePressed) {
// if inactive and the buttons supports pressed, we use it
// in case we have an inactive-hover but no pressed we stay in hovered state
state = "inactive-pressed";
} else if (decoration.active && state != "inactive-hover" && buttonSvg.supportsPressed) {
state = "active-pressed";
}
} else {
if (!decoration.active && hovered && buttonSvg.supportsInactiveHover) {
state = "inactive-hover";
} else if (!decoration.active && buttonSvg.supportsInactive) {
state = "inactive";
} else if (hovered && buttonSvg.supportsHover) {
state = "active-hover";
} else {
state = "active";
}
}
}
width: widthForButton() * auroraeTheme.buttonSizeFactor
height: auroraeTheme.buttonHeight * auroraeTheme.buttonSizeFactor
PlasmaCore.FrameSvg {
property bool supportsHover: hasElementPrefix("hover")
property bool supportsPressed: hasElementPrefix("pressed")
property bool supportsDeactivated: hasElementPrefix("deactivated")
property bool supportsInactive: hasElementPrefix("inactive")
property bool supportsInactiveHover: hasElementPrefix("hover-inactive")
property bool supportsInactivePressed: hasElementPrefix("pressed-inactive")
property bool supportsInactiveDeactivated: hasElementPrefix("deactivated-inactive")
id: buttonSvg
imagePath: pathForButton()
}
PlasmaCore.FrameSvgItem {
id: buttonActive
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "active"
}
PlasmaCore.FrameSvgItem {
id: buttonActiveHover
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "hover"
opacity: 0
}
PlasmaCore.FrameSvgItem {
id: buttonActivePressed
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "pressed"
opacity: 0
}
PlasmaCore.FrameSvgItem {
id: buttonActiveDeactivated
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "deactivated"
opacity: 0
}
PlasmaCore.FrameSvgItem {
id: buttonInactive
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "inactive"
opacity: 0
}
PlasmaCore.FrameSvgItem {
id: buttonInactiveHover
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "hover-inactive"
opacity: 0
}
PlasmaCore.FrameSvgItem {
id: buttonInactivePressed
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "pressed-inactive"
opacity: 0
}
PlasmaCore.FrameSvgItem {
id: buttonInactiveDeactivated
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "deactivated-inactive"
opacity: 0
}
Component.onCompleted: {
if (!decoration.active && !enabled && buttonSvg.supportsInactiveDeactivated) {
state = "inactive-deactivated";
} else if (!enabled && buttonSvg.supportsDeactivated) {
state = "active-deactivated";
} else if (!decoration.active && (toggled || pressed) && buttonSvg.supportsInactivePressed) {
state = "inactive-pressed";
} else if ((toggled || pressed) && buttonSvg.supportsPressed) {
state = "active-pressed";
} else if (!decoration.active && buttonSvg.supportsInactive) {
state = "inactive";
} else {
state = "active";
}
if (buttonType == "H" && !decoration.providesContextHelp) {
visible = false;
} else {
visible = buttonSvg.imagePath != "";
}
}
onHoveredChanged: {
if (state == "active-pressed" || state == "inactive-pressed") {
// state change of hovered does not matter as the button is currently pressed
return;
}
if (hovered) {
if (state == "active" && buttonSvg.supportsHover) {
state = "active-hover";
} else if (state == "inactive" && buttonSvg.supportsInactiveHover) {
state = "inactive-hover";
}
} else {
if (!decoration.active && buttonSvg.supportsInactive) {
state = "inactive";
} else {
state = "active";
}
}
}
onPressedChanged: toggledPressedStatusChange()
onToggledChanged: toggledPressedStatusChange()
states: [
State { name: "active" },
State { name: "active-hover" },
State { name: "active-pressed" },
State { name: "active-deactivated" },
State { name: "inactive" },
State { name: "inactive-hover" },
State { name: "inactive-pressed" },
State { name: "inactive-deactivated" }
]
transitions: [
Transition {
to: "active"
// Cross fade from somewhere to active
ParallelAnimation {
NumberAnimation { target: buttonActive; property: "opacity"; to: 1; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonActiveHover; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonActivePressed; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
}
},
Transition {
to: "active-hover"
// Cross fade from active to hover
ParallelAnimation {
NumberAnimation { target: buttonActive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonActiveHover; property: "opacity"; to: 1; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonActivePressed; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactiveHover; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactivePressed; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
}
},
Transition {
to: "active-pressed"
// Cross fade to pressed state
ParallelAnimation {
NumberAnimation { target: buttonActive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonActiveHover; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonActivePressed; property: "opacity"; to: 1; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactiveHover; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactivePressed; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
}
},
Transition {
to: "inactive"
// Cross fade from hover/pressed/active to inactive
ParallelAnimation {
NumberAnimation { target: buttonActive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactive; property: "opacity"; to: 1; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactiveHover; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactivePressed; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
}
},
Transition {
to: "inactive-hover"
// Cross fade from inactive to hover
ParallelAnimation {
NumberAnimation { target: buttonActiveHover; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactiveHover; property: "opacity"; to: 1; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactivePressed; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
}
},
Transition {
to: "inactive-pressed"
// Cross fade to inactive pressed state
ParallelAnimation {
NumberAnimation { target: buttonActivePressed; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactiveHover; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactivePressed; property: "opacity"; to: 1; duration: auroraeTheme.animationTime }
}
},
Transition {
to: "active-deactivated"
ParallelAnimation {
NumberAnimation { target: buttonActive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonActiveDeactivated; property: "opacity"; to: 1; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactiveDeactivated; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
}
},
Transition {
to: "inactive-deactivated"
ParallelAnimation {
NumberAnimation { target: buttonActive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonActiveDeactivated; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: buttonInactiveDeactivated; property: "opacity"; to: 1; duration: auroraeTheme.animationTime }
}
}
]
Connections {
target: decoration
onActiveChanged: {
if (!decoration.active && !enabled && buttonSvg.supportsInactiveDeactivated) {
state = "inactive-deactivated";
} else if (!enabled && buttonSvg.supportsDeactivated) {
state = "active-deactivated";
} else if (!decoration.active && (pressed || toggled) && buttonSvg.supportsInactivePressed) {
state = "inactive-pressed";
} else if (!decoration.active && hovered && buttonSvg.supportsInactiveHover) {
state = "inactive-hover";
} else if (!decoration.active && buttonSvg.supportsInactive) {
state = "inactive";
} else if ((pressed || toggled) && buttonSvg.supportsPressed) {
state = "active-pressed";
} else if (hovered && buttonSvg.supportsHover) {
state = "active-hover";
} else {
state = "active";
}
}
}
}

View file

@ -0,0 +1,42 @@
/********************************************************************
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
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, see <http://www.gnu.org/licenses/>.
*********************************************************************/
import QtQuick 1.1
import org.kde.plasma.core 0.1 as PlasmaCore
Item {
id: group
property string buttons
Component.onCompleted: {
var component = Qt.createComponent("AuroraeButton.qml");
for (var i=0; i<buttons.length; i++) {
if (buttons.charAt(i) == "_") {
Qt.createQmlObject("import QtQuick 1.1; Item { width: auroraeTheme.explicitButtonSpacer; height: auroraeTheme.buttonHeight }",
groupRow, "explicitSpacer" + buttons + i);
} else if (buttons.charAt(i) == "M") {
Qt.createQmlObject("import QtQuick 1.1; MenuButton { width: auroraeTheme.buttonWidthMenu; height: auroraeTheme.buttonHeight }",
groupRow, "menuButton" + buttons + i);
} else {
component.createObject(groupRow, {buttonType: buttons.charAt(i)});
}
}
}
Row {
id: groupRow
spacing: auroraeTheme.buttonSpacing
}
}

View file

@ -0,0 +1,37 @@
/********************************************************************
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
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, see <http://www.gnu.org/licenses/>.
*********************************************************************/
import QtQuick 1.1
Item {
property int paddingLeft
property int paddingRight
property int paddingTop
property int paddingBottom
property int borderLeft
property int borderRight
property int borderTop
property int borderBottom
property int borderLeftMaximized
property int borderRightMaximized
property int borderTopMaximized
property int borderBottomMaximized
MouseArea {
anchors.fill: parent
hoverEnabled: true
onPositionChanged: decoration.titleMouseMoved(mouse.button, mouse.buttons)
}
}

View file

@ -0,0 +1,147 @@
/********************************************************************
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
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, see <http://www.gnu.org/licenses/>.
*********************************************************************/
import QtQuick 1.1
Item {
id: button
property string buttonType : ""
property bool hovered: false
property bool pressed: false
property bool toggled: false
enabled: {
switch (button.buttonType) {
case "X":
return decoration.closeable;
case "A":
return decoration.maximizeable;
case "I":
return decoration.minimizeable;
case "_":
return false;
default:
return true;
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: {
switch (button.buttonType) {
case "M":
return Qt.LeftButton | Qt.RightButton;
case "A":
return Qt.LeftButton | Qt.RightButton | Qt.MiddleButton;
default:
return Qt.LeftButton;
}
}
hoverEnabled: true
onEntered: button.hovered = true
onPositionChanged: decoration.titleMouseMoved(mouse.button, mouse.buttons)
onExited: button.hovered = false
onPressed: button.pressed = true
onReleased: button.pressed = false
onClicked: {
switch (button.buttonType) {
case "M":
// menu
decoration.menuClicked();
break;
case "S":
// all desktops
decoration.toggleOnAllDesktops();
break;
case "H":
// help
decoration.showContextHelp();
break;
case "I":
// minimize
decoration.minimize();
break;
case "A":
// maximize
decoration.maximize(mouse.buttons);
break;
case "X":
// close
decoration.closeWindow();
break;
case "F":
// keep above
decoration.toggleKeepAbove();
break;
case "B":
// keep below
decoration.toggleKeepBelow();
break;
case "L":
// shade
decoration.toggleShade();
break;
}
}
onDoubleClicked: {
if (button.buttonType == "M") {
decoration.closeWindow();
}
}
Component.onCompleted: {
switch (button.buttonType) {
case "S":
// all desktops
button.toggled = decoration.onAllDesktops;
break;
case "F":
button.toggled = decoration.keepAbove;
break;
case "B":
button.toggled = decoration.keepBelow;
break;
case "L":
button.toggled = decoration.shade;
break;
}
}
Connections {
target: decoration
onShadeChanged: {
if (button.buttonType != "L") {
return;
}
button.toggled = decoration.shade;
}
onKeepBelowChanged: {
if (button.buttonType != "B") {
return;
}
button.toggled = decoration.keepBelow;
}
onKeepAboveChanged: {
if (button.buttonType != "F") {
return;
}
button.toggled = decoration.keepAbove;
}
onDesktopChanged: {
if (button.buttonType != "S") {
return;
}
button.toggled = decoration.onAllDesktops;
}
}
}
}

View file

@ -0,0 +1,26 @@
/********************************************************************
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
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, see <http://www.gnu.org/licenses/>.
*********************************************************************/
import QtQuick 1.1
import org.kde.qtextracomponents 0.1 as QtExtra
DecorationButton {
buttonType: "M"
QtExtra.QIconItem {
icon: decoration.icon
anchors.fill: parent
}
}

View file

@ -0,0 +1,143 @@
/********************************************************************
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
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, see <http://www.gnu.org/licenses/>.
*********************************************************************/
import QtQuick 1.1
import org.kde.plasma.core 0.1 as PlasmaCore
Decoration {
id: root
borderLeft: auroraeTheme.borderLeft
borderRight: auroraeTheme.borderRight
borderTop: auroraeTheme.borderTop
borderBottom: auroraeTheme.borderBottom
borderLeftMaximized: auroraeTheme.borderLeftMaximized
borderRightMaximized: auroraeTheme.borderRightMaximized
borderBottomMaximized: auroraeTheme.borderBottomMaximized
borderTopMaximized: auroraeTheme.borderTopMaximized
paddingLeft: auroraeTheme.paddingLeft
paddingRight: auroraeTheme.paddingRight
paddingBottom: auroraeTheme.paddingBottom
paddingTop: auroraeTheme.paddingTop
Component.onCompleted: {
if (decoration.active) {
root.state = "active";
} else {
if (backgroundSvg.supportsInactive) {
root.state = "inactive";
} else {
root.state = "active";
}
}
}
PlasmaCore.FrameSvg {
property bool supportsInactive: hasElementPrefix("decoration-inactive")
id: backgroundSvg
imagePath: auroraeTheme.decorationPath
}
PlasmaCore.FrameSvgItem {
id: decorationActive
anchors.fill: parent
imagePath: backgroundSvg.imagePath
prefix: "decoration"
}
PlasmaCore.FrameSvgItem {
id: decorationInactive
anchors.fill: parent
imagePath: backgroundSvg.imagePath
prefix: "decoration-inactive"
opacity: 0
}
AuroraeButtonGroup {
id: leftButtonGroup
buttons: decoration.leftButtons
width: childrenRect.width
anchors {
top: parent.top
left: parent.left
leftMargin: auroraeTheme.titleEdgeLeft + root.paddingLeft
topMargin: root.paddingTop + auroraeTheme.titleEdgeTop + auroraeTheme.buttonMarginTop
}
}
AuroraeButtonGroup {
id: rightButtonGroup
buttons: decoration.rightButtons
width: childrenRect.width
anchors {
top: parent.top
right: parent.right
rightMargin: auroraeTheme.titleEdgeRight + root.paddingRight
topMargin: root.paddingTop + auroraeTheme.titleEdgeTop + auroraeTheme.buttonMarginTop
}
}
Text {
id: caption
text: decoration.caption
horizontalAlignment: auroraeTheme.horizontalAlignment
verticalAlignment: auroraeTheme.verticalAlignment
elide: Text.ElideRight
anchors {
left: leftButtonGroup.right
right: rightButtonGroup.left
top: root.top
topMargin: root.paddingTop + auroraeTheme.titleEdgeTop
leftMargin: auroraeTheme.titleBorderLeft
rightMargin: auroraeTheme.titleBorderRight
}
MouseArea {
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
anchors.fill: parent
onDoubleClicked: decoration.titlebarDblClickOperation()
onPressed: decoration.titlePressed(mouse.button, mouse.buttons)
onReleased: decoration.titleReleased(mouse.button, mouse.buttons)
}
}
states: [
State { name: "active" },
State { name: "inactive" }
]
transitions: [
Transition {
to: "active"
// Cross fade from inactive to active
ParallelAnimation {
NumberAnimation { target: decorationActive; property: "opacity"; to: 1; duration: auroraeTheme.animationTime }
NumberAnimation { target: decorationInactive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
ColorAnimation { target: caption; property: "color"; to: auroraeTheme.activeTextColor; duration: auroraeTheme.animationTime }
}
},
Transition {
to: "inactive"
// Cross fade from active to inactive
ParallelAnimation {
NumberAnimation { target: decorationActive; property: "opacity"; to: 0; duration: auroraeTheme.animationTime }
NumberAnimation { target: decorationInactive; property: "opacity"; to: 1; duration: auroraeTheme.animationTime }
ColorAnimation { target: caption; property: "color"; to: auroraeTheme.inactiveTextColor; duration: auroraeTheme.animationTime }
}
}
]
Connections {
target: decoration
onActiveChanged: {
if (decoration.active) {
root.state = "active";
} else {
if (backgroundSvg.supportsInactive) {
root.state = "inactive";
}
}
}
}
}