Initial import of Aurorae Kwin decoration theme engine.
This theme engine uses SVG files to theme the decoration like the themes for Plasma desktop shell. svn path=/trunk/playground/artwork/aurorae/; revision=983819
This commit is contained in:
parent
19495c6cd0
commit
2d24bce243
22 changed files with 2113 additions and 0 deletions
1
clients/aurorae/AUTHORS
Normal file
1
clients/aurorae/AUTHORS
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Martin Gräßlin kde [at] martin [minus] graesslin [dot] com Developer and Maintainer
|
14
clients/aurorae/CMakeLists.txt
Normal file
14
clients/aurorae/CMakeLists.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
project(aurorae)
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
|
||||||
|
|
||||||
|
find_package(KDE4 4.2.92 REQUIRED)
|
||||||
|
find_package(KDE4Workspace REQUIRED)
|
||||||
|
include (KDE4Defaults)
|
||||||
|
include (MacroLibrary)
|
||||||
|
|
||||||
|
add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
|
||||||
|
include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES})
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
add_subdirectory(themes/example-deco)
|
||||||
|
|
6
clients/aurorae/README
Normal file
6
clients/aurorae/README
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Aurorae is a themeable window decoration for KWin.
|
||||||
|
|
||||||
|
It supports theme files consisting of several SVG files for decoration and buttons. Themes can be
|
||||||
|
installed and selected directly in the configuration module of KWin decorations.
|
||||||
|
|
||||||
|
Please have a look at theme-description on how to write a theme file.
|
3
clients/aurorae/TODO
Normal file
3
clients/aurorae/TODO
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
* Button positions are not updated after theme change
|
||||||
|
* Delete themes from selection
|
||||||
|
* Get Hot New Stuff support
|
24
clients/aurorae/src/CMakeLists.txt
Normal file
24
clients/aurorae/src/CMakeLists.txt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
########### decoration ###############
|
||||||
|
|
||||||
|
set(kwin3_aurorae_PART_SRCS aurorae.cpp themeconfig.cpp)
|
||||||
|
|
||||||
|
kde4_add_plugin(kwin3_aurorae ${kwin3_aurorae_PART_SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(kwin3_aurorae ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${KDE4WORKSPACE_KDECORATIONS_LIBS})
|
||||||
|
|
||||||
|
install(TARGETS kwin3_aurorae DESTINATION ${PLUGIN_INSTALL_DIR} )
|
||||||
|
|
||||||
|
########### install files ###############
|
||||||
|
|
||||||
|
install( FILES aurorae.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin )
|
||||||
|
|
||||||
|
########### config ###############
|
||||||
|
set(kwin_aurorae_config_PART_SRCS config/config.cpp themeconfig.cpp )
|
||||||
|
|
||||||
|
kde4_add_ui_files(kwin_aurorae_config_PART_SRCS config/config.ui)
|
||||||
|
|
||||||
|
kde4_add_plugin(kwin_aurorae_config ${kwin_aurorae_config_PART_SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(kwin_aurorae_config ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS} ${QT_QTGUI_LIBRARY})
|
||||||
|
|
||||||
|
install(TARGETS kwin_aurorae_config DESTINATION ${PLUGIN_INSTALL_DIR} )
|
714
clients/aurorae/src/aurorae.cpp
Normal file
714
clients/aurorae/src/aurorae.cpp
Normal file
|
@ -0,0 +1,714 @@
|
||||||
|
/********************************************************************
|
||||||
|
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "aurorae.h"
|
||||||
|
|
||||||
|
#include <kglobal.h>
|
||||||
|
#include <kstandarddirs.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
|
||||||
|
#include <KConfig>
|
||||||
|
#include <KConfigGroup>
|
||||||
|
#include <KDE/Plasma/Animator>
|
||||||
|
#include <KDE/Plasma/PaintUtils>
|
||||||
|
#include <KIconEffect>
|
||||||
|
#include <KIconLoader>
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
namespace Aurorae
|
||||||
|
{
|
||||||
|
|
||||||
|
AuroraeFactory::AuroraeFactory()
|
||||||
|
: QObject()
|
||||||
|
, KDecorationFactoryUnstable()
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeFactory::readThemeConfig()
|
||||||
|
{
|
||||||
|
// read config values
|
||||||
|
KConfig conf("aurorae/themes/" + m_themeName + "/" + m_themeName + "rc", KConfig::FullConfig, "data");
|
||||||
|
m_themeConfig.load(&conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
AuroraeFactory::~AuroraeFactory()
|
||||||
|
{
|
||||||
|
s_instance = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuroraeFactory *AuroraeFactory::instance()
|
||||||
|
{
|
||||||
|
if (!s_instance) {
|
||||||
|
s_instance = new AuroraeFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AuroraeFactory::reset(unsigned long changed)
|
||||||
|
{
|
||||||
|
// re-read config
|
||||||
|
m_frame.clearCache();
|
||||||
|
m_buttons.clear();
|
||||||
|
init();
|
||||||
|
resetDecorations(changed);
|
||||||
|
return false; // need hard reset
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AuroraeFactory::supports(Ability ability) const
|
||||||
|
{
|
||||||
|
switch (ability) {
|
||||||
|
case AbilityAnnounceButtons:
|
||||||
|
case AbilityUsesAlphaChannel:
|
||||||
|
case AbilityButtonMenu:
|
||||||
|
case AbilityButtonSpacer:
|
||||||
|
return true;
|
||||||
|
case AbilityButtonMinimize:
|
||||||
|
return m_buttons.contains("minimize");
|
||||||
|
case AbilityButtonMaximize:
|
||||||
|
return m_buttons.contains("maximize") || m_buttons.contains("restore");
|
||||||
|
case AbilityButtonClose:
|
||||||
|
return m_buttons.contains("close");
|
||||||
|
case AbilityButtonAboveOthers:
|
||||||
|
return m_buttons.contains("keepabove");
|
||||||
|
case AbilityButtonBelowOthers:
|
||||||
|
return m_buttons.contains("keepbelow");
|
||||||
|
case AbilityButtonShade:
|
||||||
|
return m_buttons.contains("shade");
|
||||||
|
case AbilityButtonOnAllDesktops:
|
||||||
|
return m_buttons.contains("alldesktops");
|
||||||
|
case AbilityButtonHelp:
|
||||||
|
return m_buttons.contains("help");
|
||||||
|
case AbilityProvidesShadow:
|
||||||
|
return m_themeConfig.shadow();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AuroraeFactory *AuroraeFactory::s_instance = NULL;
|
||||||
|
|
||||||
|
/*******************************************************
|
||||||
|
* Button
|
||||||
|
*******************************************************/
|
||||||
|
AuroraeButton::AuroraeButton(ButtonType type, KCommonDecoration *parent)
|
||||||
|
: KCommonDecorationButton(type, parent)
|
||||||
|
, m_animationId(0)
|
||||||
|
, m_animationProgress(0.0)
|
||||||
|
, m_pressed(false)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_NoSystemBackground);
|
||||||
|
connect(Plasma::Animator::self(), SIGNAL(customAnimationFinished(int)), this, SLOT(animationFinished(int)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeButton::reset(unsigned long changed)
|
||||||
|
{
|
||||||
|
Q_UNUSED(changed)
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeButton::enterEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event)
|
||||||
|
if (m_animationId != 0) {
|
||||||
|
Plasma::Animator::self()->stopCustomAnimation(m_animationId);
|
||||||
|
}
|
||||||
|
m_animationProgress = 0.0;
|
||||||
|
int time = AuroraeFactory::instance()->themeConfig().animationTime();
|
||||||
|
if (time != 0) {
|
||||||
|
m_animationId = Plasma::Animator::self()->customAnimation(40 / (1000.0 / qreal(time)),
|
||||||
|
time, Plasma::Animator::EaseInCurve, this, "animationUpdate");
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeButton::leaveEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event)
|
||||||
|
if (m_animationId != 0) {
|
||||||
|
Plasma::Animator::self()->stopCustomAnimation(m_animationId);
|
||||||
|
}
|
||||||
|
m_animationProgress = 0.0;
|
||||||
|
int time = AuroraeFactory::instance()->themeConfig().animationTime();
|
||||||
|
if (time != 0) {
|
||||||
|
m_animationId = Plasma::Animator::self()->customAnimation(40 / (1000.0 / qreal(time)),
|
||||||
|
time, Plasma::Animator::EaseOutCurve, this, "animationUpdate");
|
||||||
|
}
|
||||||
|
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::animationUpdate(double progress, int id)
|
||||||
|
{
|
||||||
|
Q_UNUSED(id)
|
||||||
|
m_animationProgress = progress;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeButton::animationFinished(int id)
|
||||||
|
{
|
||||||
|
if (m_animationId == id) {
|
||||||
|
m_animationId = 0;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeButton::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event)
|
||||||
|
if (decoration()->isPreview()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
bool active = decoration()->isActive();
|
||||||
|
|
||||||
|
if (type() == MenuButton) {
|
||||||
|
const QIcon icon = decoration()->icon();
|
||||||
|
const QSize size = icon.actualSize(QSize(16, 16));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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 = QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (m_animationId != 0) {
|
||||||
|
// 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 {
|
||||||
|
frame->paintFrame(&painter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************
|
||||||
|
* Client
|
||||||
|
*******************************************************/
|
||||||
|
|
||||||
|
AuroraeClient::AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *factory)
|
||||||
|
: KCommonDecorationUnstable(bridge, factory)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AuroraeClient::~AuroraeClient()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeClient::init()
|
||||||
|
{
|
||||||
|
KCommonDecoration::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeClient::reset(unsigned long changed)
|
||||||
|
{
|
||||||
|
widget()->update();
|
||||||
|
|
||||||
|
KCommonDecoration::reset(changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AuroraeClient::visibleName() const
|
||||||
|
{
|
||||||
|
return QString("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
|
||||||
|
{
|
||||||
|
bool maximized = maximizeMode() == MaximizeFull &&
|
||||||
|
!options()->moveResizeMaximizedWindows();
|
||||||
|
const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig();
|
||||||
|
switch (lm) {
|
||||||
|
case LM_BorderLeft:
|
||||||
|
return maximized && respectWindowState ? 0 : conf.borderLeft();
|
||||||
|
case LM_BorderRight:
|
||||||
|
return maximized && respectWindowState ? 0 : conf.borderRight();
|
||||||
|
case LM_BorderBottom:
|
||||||
|
return maximized && respectWindowState ? 0 : conf.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 conf.titleEdgeLeft();
|
||||||
|
case LM_TitleEdgeRight:
|
||||||
|
return conf.titleBorderRight();
|
||||||
|
case LM_TitleEdgeTop:
|
||||||
|
return conf.titleEdgeTop();
|
||||||
|
case LM_TitleEdgeBottom:
|
||||||
|
return 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:
|
||||||
|
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()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool maximized = maximizeMode() == MaximizeFull &&
|
||||||
|
!options()->moveResizeMaximizedWindows();
|
||||||
|
|
||||||
|
QPainter painter(widget());
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
QRectF sourceRect = rect;
|
||||||
|
if (!compositingActive()) {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
frame->resizeFrame(rect.size());
|
||||||
|
frame->paintFrame(&painter, rect, sourceRect);
|
||||||
|
|
||||||
|
if (isActive()) {
|
||||||
|
painter.setPen(conf.activeTextColor());
|
||||||
|
} else {
|
||||||
|
painter.setPen(conf.inactiveTextColor());
|
||||||
|
}
|
||||||
|
painter.setFont(options()->font(isActive()));
|
||||||
|
painter.drawText(titleRect(), conf.alignment() | conf.verticalAlignment() | Qt::TextSingleLine,
|
||||||
|
caption());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeClient::updateWindowShape()
|
||||||
|
{
|
||||||
|
bool maximized = maximizeMode()==KDecorationDefines::MaximizeFull && !options()->moveResizeMaximizedWindows();
|
||||||
|
int w=widget()->width();
|
||||||
|
int h=widget()->height();
|
||||||
|
|
||||||
|
if (maximized) {
|
||||||
|
QRegion mask(0,0,w,h);
|
||||||
|
setMask(mask);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThemeConfig &conf = AuroraeFactory::instance()->themeConfig();
|
||||||
|
Plasma::FrameSvg *deco = AuroraeFactory::instance()->frame();
|
||||||
|
if (!deco->hasElementPrefix("decoration-opaque")) {
|
||||||
|
// opaque element is missing: set generic mask
|
||||||
|
QRegion mask(0,0,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());
|
||||||
|
setMask(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Aurorae
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
KDE_EXPORT KDecorationFactory *create_factory() {
|
||||||
|
return Aurorae::AuroraeFactory::instance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "aurorae.moc"
|
3
clients/aurorae/src/aurorae.desktop
Normal file
3
clients/aurorae/src/aurorae.desktop
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=Aurorae Decoration Theme Engine
|
||||||
|
X-KDE-Library=kwin3_aurorae
|
132
clients/aurorae/src/aurorae.h
Normal file
132
clients/aurorae/src/aurorae.h
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/********************************************************************
|
||||||
|
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef AURORAE_H
|
||||||
|
#define AURORAE_H
|
||||||
|
|
||||||
|
#include "themeconfig.h"
|
||||||
|
|
||||||
|
#include <kdecorationfactory.h>
|
||||||
|
#include <kcommondecoration.h>
|
||||||
|
#include <KDE/Plasma/FrameSvg>
|
||||||
|
|
||||||
|
class KComponentData;
|
||||||
|
|
||||||
|
namespace Aurorae
|
||||||
|
{
|
||||||
|
|
||||||
|
class AuroraeFactory : public QObject, public KDecorationFactoryUnstable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~AuroraeFactory();
|
||||||
|
|
||||||
|
static AuroraeFactory* instance();
|
||||||
|
bool reset(unsigned long changed);
|
||||||
|
KDecoration *createDecoration(KDecorationBridge*);
|
||||||
|
bool supports(Ability ability) 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AuroraeButton : public KCommonDecorationButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AuroraeButton(ButtonType type, KCommonDecoration *parent);
|
||||||
|
void reset(unsigned long changed);
|
||||||
|
void enterEvent(QEvent *event);
|
||||||
|
void leaveEvent(QEvent *event);
|
||||||
|
void paintEvent(QPaintEvent *event);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void animationUpdate(qreal progress, int id);
|
||||||
|
void animationFinished(int id);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_animationId;
|
||||||
|
qreal m_animationProgress;
|
||||||
|
bool m_pressed;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AuroraeClient : public KCommonDecorationUnstable
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void reset(unsigned long changed);
|
||||||
|
void paintEvent(QPaintEvent *event);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
570
clients/aurorae/src/config/config.cpp
Normal file
570
clients/aurorae/src/config/config.cpp
Normal file
|
@ -0,0 +1,570 @@
|
||||||
|
/********************************************************************
|
||||||
|
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "themeconfig.h"
|
||||||
|
|
||||||
|
#include <klocalizedstring.h>
|
||||||
|
#include <KAboutApplicationDialog>
|
||||||
|
#include <KAboutData>
|
||||||
|
#include <KColorScheme>
|
||||||
|
#include <KConfig>
|
||||||
|
#include <KConfigGroup>
|
||||||
|
#include <KDesktopFile>
|
||||||
|
#include <KGlobal>
|
||||||
|
#include <KIO/NetAccess>
|
||||||
|
#include <KMessageBox>
|
||||||
|
#include <KStandardDirs>
|
||||||
|
#include <KTar>
|
||||||
|
#include <KUrlRequesterDialog>
|
||||||
|
#include <KDE/Plasma/FrameSvg>
|
||||||
|
|
||||||
|
#include <QAbstractItemView>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
KDE_EXPORT QObject *allocate_config(KConfig *conf, QWidget *parent)
|
||||||
|
{
|
||||||
|
return (new Aurorae::AuroraeConfig(conf, parent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Aurorae
|
||||||
|
{
|
||||||
|
|
||||||
|
//Theme selector code by Andre Duffeck (modified to add package description)
|
||||||
|
ThemeModel::ThemeModel(QObject *parent)
|
||||||
|
: QAbstractListModel(parent)
|
||||||
|
{
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThemeModel::~ThemeModel()
|
||||||
|
{
|
||||||
|
clearThemeList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThemeModel::clearThemeList()
|
||||||
|
{
|
||||||
|
foreach(const ThemeInfo &themeInfo, m_themes) {
|
||||||
|
delete themeInfo.svg;
|
||||||
|
}
|
||||||
|
m_themes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThemeModel::reload()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
clearThemeList();
|
||||||
|
|
||||||
|
// get all desktop themes
|
||||||
|
QStringList themes = KGlobal::dirs()->findAllResources("data",
|
||||||
|
"aurorae/themes/*/metadata.desktop",
|
||||||
|
KStandardDirs::NoDuplicates);
|
||||||
|
foreach(const QString &theme, themes) {
|
||||||
|
int themeSepIndex = theme.lastIndexOf('/', -1);
|
||||||
|
QString themeRoot = theme.left(themeSepIndex);
|
||||||
|
int themeNameSepIndex = themeRoot.lastIndexOf('/', -1);
|
||||||
|
QString packageName = themeRoot.right(themeRoot.length() - themeNameSepIndex - 1);
|
||||||
|
|
||||||
|
KDesktopFile df(theme);
|
||||||
|
QString name = df.readName();
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
name = packageName;
|
||||||
|
}
|
||||||
|
QString comment = df.readComment();
|
||||||
|
QString author = df.desktopGroup().readEntry("X-KDE-PluginInfo-Author", QString());
|
||||||
|
QString email = df.desktopGroup().readEntry("X-KDE-PluginInfo-Email", QString());
|
||||||
|
QString version = df.desktopGroup().readEntry("X-KDE-PluginInfo-Version", QString());
|
||||||
|
QString license = df.desktopGroup().readEntry("X-KDE-PluginInfo-License", QString());
|
||||||
|
QString website = df.desktopGroup().readEntry("X-KDE-PluginInfo-Website", QString());
|
||||||
|
|
||||||
|
|
||||||
|
Plasma::FrameSvg *svg = new Plasma::FrameSvg(this);
|
||||||
|
QString svgFile = themeRoot + "/decoration.svg";
|
||||||
|
if (QFile::exists(svgFile)) {
|
||||||
|
svg->setImagePath(svgFile);
|
||||||
|
} else {
|
||||||
|
svg->setImagePath(svgFile + "z");
|
||||||
|
}
|
||||||
|
svg->setEnabledBorders(Plasma::FrameSvg::AllBorders);
|
||||||
|
|
||||||
|
ThemeConfig *config = new ThemeConfig();
|
||||||
|
KConfig conf("aurorae/themes/" + packageName + "/" + packageName + "rc", KConfig::FullConfig, "data");
|
||||||
|
config->load(&conf);
|
||||||
|
|
||||||
|
// buttons
|
||||||
|
QHash<QString, Plasma::FrameSvg*> *buttons = new QHash<QString, Plasma::FrameSvg*>();
|
||||||
|
initButtonFrame("minimize", packageName, buttons);
|
||||||
|
initButtonFrame("maximize", packageName, buttons);
|
||||||
|
initButtonFrame("restore", packageName, buttons);
|
||||||
|
initButtonFrame("close", packageName, buttons);
|
||||||
|
initButtonFrame("alldesktops", packageName, buttons);
|
||||||
|
initButtonFrame("keepabove", packageName, buttons);
|
||||||
|
initButtonFrame("keepbelow", packageName, buttons);
|
||||||
|
initButtonFrame("shade", packageName, buttons);
|
||||||
|
initButtonFrame("help", packageName, buttons);
|
||||||
|
|
||||||
|
ThemeInfo info;
|
||||||
|
info.package = packageName;
|
||||||
|
info.description = comment;
|
||||||
|
info.author = author;
|
||||||
|
info.email = email;
|
||||||
|
info.version = version;
|
||||||
|
info.website = website;
|
||||||
|
info.license = license;
|
||||||
|
info.svg = svg;
|
||||||
|
info.themeRoot = themeRoot;
|
||||||
|
info.themeConfig = config;
|
||||||
|
info.buttons = buttons;
|
||||||
|
m_themes[name] = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
beginInsertRows(QModelIndex(), 0, m_themes.size());
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ThemeModel::rowCount(const QModelIndex &) const
|
||||||
|
{
|
||||||
|
return m_themes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ThemeModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid()) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index.row() >= m_themes.size()) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, ThemeInfo>::const_iterator it = m_themes.constBegin();
|
||||||
|
for (int i = 0; i < index.row(); ++i) {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
return it.key();
|
||||||
|
case PackageNameRole:
|
||||||
|
return (*it).package;
|
||||||
|
case SvgRole:
|
||||||
|
return qVariantFromValue((void*)(*it).svg);
|
||||||
|
case PackageDescriptionRole:
|
||||||
|
return (*it).description;
|
||||||
|
case PackageAuthorRole:
|
||||||
|
return (*it).author;
|
||||||
|
case PackageVersionRole:
|
||||||
|
return (*it).version;
|
||||||
|
case PackageEmailRole:
|
||||||
|
return (*it).email;
|
||||||
|
case PackageLicenseRole:
|
||||||
|
return (*it).license;
|
||||||
|
case PackageWebsiteRole:
|
||||||
|
return (*it).website;
|
||||||
|
case ThemeConfigRole:
|
||||||
|
return qVariantFromValue((void*)(*it).themeConfig);
|
||||||
|
case ButtonsRole:
|
||||||
|
return qVariantFromValue((void*)(*it).buttons);
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ThemeModel::indexOf(const QString &name) const
|
||||||
|
{
|
||||||
|
QMapIterator<QString, ThemeInfo> it(m_themes);
|
||||||
|
int i = -1;
|
||||||
|
while (it.hasNext()) {
|
||||||
|
++i;
|
||||||
|
if (it.next().value().package == name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThemeModel::initButtonFrame(const QString &button, const QString &themeName, QHash<QString, Plasma::FrameSvg*> *buttons)
|
||||||
|
{
|
||||||
|
QString file("aurorae/themes/" + 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);
|
||||||
|
buttons->insert(button, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// ThemeDelegate
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
ThemeDelegate::ThemeDelegate(QObject* parent)
|
||||||
|
: QAbstractItemDelegate(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThemeDelegate::paint(QPainter *painter,
|
||||||
|
const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QString title = index.model()->data(index, Qt::DisplayRole).toString();
|
||||||
|
|
||||||
|
// highlight selected item
|
||||||
|
painter->save();
|
||||||
|
if (option.state & QStyle::State_Selected) {
|
||||||
|
painter->setBrush(option.palette.color(QPalette::Highlight));
|
||||||
|
} else {
|
||||||
|
painter->setBrush(Qt::gray);
|
||||||
|
}
|
||||||
|
painter->drawRect(option.rect);
|
||||||
|
painter->restore();
|
||||||
|
|
||||||
|
ThemeConfig *themeConfig = static_cast<ThemeConfig *>(
|
||||||
|
index.model()->data(index, ThemeModel::ThemeConfigRole).value<void *>());
|
||||||
|
painter->save();
|
||||||
|
paintDeco(painter, false, option, index, 5 + themeConfig->paddingLeft() + themeConfig->borderLeft(),
|
||||||
|
5, 5, 5 + themeConfig->paddingBottom() + themeConfig->borderBottom() );
|
||||||
|
painter->restore();
|
||||||
|
painter->save();
|
||||||
|
int activeLeft = 5;
|
||||||
|
int activeTop = 5 + themeConfig->paddingTop() + themeConfig->titleEdgeTop() +
|
||||||
|
themeConfig->titleEdgeBottom() + themeConfig->titleHeight();
|
||||||
|
int activeRight = 5 + themeConfig->paddingRight() + themeConfig->borderRight();
|
||||||
|
int activeBottom = 5;
|
||||||
|
paintDeco(painter, true, option, index, activeLeft, activeTop, activeRight, activeBottom);
|
||||||
|
painter->restore();
|
||||||
|
|
||||||
|
// paint title
|
||||||
|
painter->save();
|
||||||
|
QFont font = painter->font();
|
||||||
|
font.setWeight(QFont::Bold);
|
||||||
|
painter->setPen(themeConfig->activeTextColor());
|
||||||
|
painter->setFont(font);
|
||||||
|
painter->drawText(QRect(option.rect.topLeft() + QPoint(activeLeft, activeTop),
|
||||||
|
option.rect.bottomRight() - QPoint(activeRight, activeBottom)),
|
||||||
|
Qt::AlignCenter | Qt::TextWordWrap, title);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThemeDelegate::paintDeco(QPainter *painter, bool active, const QStyleOptionViewItem &option, const QModelIndex &index,
|
||||||
|
int leftMargin, int topMargin,
|
||||||
|
int rightMargin, int bottomMargin) const
|
||||||
|
{
|
||||||
|
Plasma::FrameSvg *svg = static_cast<Plasma::FrameSvg *>(
|
||||||
|
index.model()->data(index, ThemeModel::SvgRole).value<void *>());
|
||||||
|
svg->setElementPrefix("decoration");
|
||||||
|
if (!active && svg->hasElementPrefix("decoration-inactive")) {
|
||||||
|
svg->setElementPrefix("decoration-inactive");
|
||||||
|
}
|
||||||
|
svg->resizeFrame(QSize(option.rect.width() - leftMargin - rightMargin, option.rect.height() - topMargin - bottomMargin));
|
||||||
|
svg->paintFrame(painter, option.rect.topLeft() + QPoint(leftMargin, topMargin));
|
||||||
|
|
||||||
|
ThemeConfig *themeConfig = static_cast<ThemeConfig *>(
|
||||||
|
index.model()->data(index, ThemeModel::ThemeConfigRole).value<void *>());
|
||||||
|
|
||||||
|
QHash<QString, Plasma::FrameSvg*> *buttons = static_cast<QHash<QString, Plasma::FrameSvg*> *>(
|
||||||
|
index.model()->data(index, ThemeModel::ButtonsRole).value<void *>());
|
||||||
|
int y = option.rect.top() + topMargin + themeConfig->paddingTop() + themeConfig->titleEdgeTop() + themeConfig->buttonMarginTop();
|
||||||
|
int x = option.rect.left() + leftMargin + themeConfig->paddingLeft() + themeConfig->titleEdgeLeft();
|
||||||
|
int buttonWidth = themeConfig->buttonWidth();
|
||||||
|
int buttonHeight = themeConfig->buttonHeight();
|
||||||
|
foreach (const QChar &character, themeConfig->defaultButtonsLeft()) {
|
||||||
|
QString buttonName;
|
||||||
|
if (character == '_'){
|
||||||
|
x += themeConfig->explicitButtonSpacer() + themeConfig->buttonSpacing();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (character == 'M') {
|
||||||
|
KIcon icon = KIcon( "xorg" );
|
||||||
|
QSize buttonSize(buttonWidth,buttonHeight);
|
||||||
|
painter->drawPixmap(QPoint(x,y), icon.pixmap(buttonSize));
|
||||||
|
x += buttonWidth;
|
||||||
|
}
|
||||||
|
else if (character == 'S') {
|
||||||
|
buttonName = "alldesktops";
|
||||||
|
}
|
||||||
|
else if (character == 'H') {
|
||||||
|
buttonName = "help";
|
||||||
|
}
|
||||||
|
else if (character == 'I') {
|
||||||
|
buttonName = "minimize";
|
||||||
|
}
|
||||||
|
else if (character == 'A') {
|
||||||
|
buttonName = "restore";
|
||||||
|
if (!buttons->contains(buttonName)) {
|
||||||
|
buttonName = "maximize";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (character == 'X') {
|
||||||
|
buttonName = "close";
|
||||||
|
}
|
||||||
|
else if (character == 'F') {
|
||||||
|
buttonName = "keepabove";
|
||||||
|
}
|
||||||
|
else if (character == 'B') {
|
||||||
|
buttonName = "keepbelow";
|
||||||
|
}
|
||||||
|
else if (character == 'L') {
|
||||||
|
buttonName = "shade";
|
||||||
|
}
|
||||||
|
if (!buttonName.isEmpty() && buttons->contains(buttonName)) {
|
||||||
|
Plasma::FrameSvg *frame = buttons->value(buttonName);
|
||||||
|
frame->setElementPrefix("active");
|
||||||
|
if (!active && frame->hasElementPrefix("inactive")) {
|
||||||
|
frame->setElementPrefix("inactive");
|
||||||
|
}
|
||||||
|
frame->resizeFrame(QSize(buttonWidth,buttonHeight));
|
||||||
|
frame->paintFrame(painter, QPoint(x, y));
|
||||||
|
x += buttonWidth;
|
||||||
|
}
|
||||||
|
x += themeConfig->buttonSpacing();
|
||||||
|
}
|
||||||
|
if (!themeConfig->defaultButtonsLeft().isEmpty()) {
|
||||||
|
x -= themeConfig->buttonSpacing();
|
||||||
|
}
|
||||||
|
int titleLeft = x;
|
||||||
|
|
||||||
|
x = option.rect.right() - rightMargin - themeConfig->paddingRight() - themeConfig->titleEdgeRight() - buttonWidth;
|
||||||
|
QString rightButtons;
|
||||||
|
foreach (const QChar &character, themeConfig->defaultButtonsRight()) {
|
||||||
|
rightButtons.prepend(character);
|
||||||
|
}
|
||||||
|
foreach (const QChar &character, rightButtons) {
|
||||||
|
QString buttonName;
|
||||||
|
if (character == '_'){
|
||||||
|
x -= themeConfig->explicitButtonSpacer() + themeConfig->buttonSpacing();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (character == 'M') {
|
||||||
|
KIcon icon = KIcon( "xorg" );
|
||||||
|
QSize buttonSize(buttonWidth,buttonHeight);
|
||||||
|
painter->drawPixmap(QPoint(x,y), icon.pixmap(buttonSize));
|
||||||
|
x -= buttonWidth;
|
||||||
|
}
|
||||||
|
else if (character == 'S') {
|
||||||
|
buttonName = "alldesktops";
|
||||||
|
}
|
||||||
|
else if (character == 'H') {
|
||||||
|
buttonName = "help";
|
||||||
|
}
|
||||||
|
else if (character == 'I') {
|
||||||
|
buttonName = "minimize";
|
||||||
|
}
|
||||||
|
else if (character == 'A') {
|
||||||
|
buttonName = "restore";
|
||||||
|
if (!buttons->contains(buttonName)) {
|
||||||
|
buttonName = "maximize";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (character == 'X') {
|
||||||
|
buttonName = "close";
|
||||||
|
}
|
||||||
|
else if (character == 'F') {
|
||||||
|
buttonName = "keepabove";
|
||||||
|
}
|
||||||
|
else if (character == 'B') {
|
||||||
|
buttonName = "keepbelow";
|
||||||
|
}
|
||||||
|
else if (character == 'L') {
|
||||||
|
buttonName = "shade";
|
||||||
|
}
|
||||||
|
if (!buttonName.isEmpty() && buttons->contains(buttonName)) {
|
||||||
|
Plasma::FrameSvg *frame = buttons->value(buttonName);
|
||||||
|
frame->setElementPrefix("active");
|
||||||
|
if (!active && frame->hasElementPrefix("inactive")) {
|
||||||
|
frame->setElementPrefix("inactive");
|
||||||
|
}
|
||||||
|
frame->resizeFrame(QSize(buttonWidth,buttonHeight));
|
||||||
|
frame->paintFrame(painter, QPoint(x, y));
|
||||||
|
x -= buttonWidth;
|
||||||
|
}
|
||||||
|
x -= themeConfig->buttonSpacing();
|
||||||
|
}
|
||||||
|
x += buttonWidth;
|
||||||
|
if (!rightButtons.isEmpty()){
|
||||||
|
x += themeConfig->buttonSpacing();
|
||||||
|
}
|
||||||
|
int titleRight = x;
|
||||||
|
|
||||||
|
// draw text
|
||||||
|
painter->save();
|
||||||
|
if (active) {
|
||||||
|
painter->setPen(themeConfig->activeTextColor());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
painter->setPen(themeConfig->inactiveTextColor());
|
||||||
|
}
|
||||||
|
y = option.rect.top() + topMargin + themeConfig->paddingTop() + themeConfig->titleEdgeTop();
|
||||||
|
QRectF titleRect(QPointF(titleLeft, y), QPointF(titleRight, y + themeConfig->titleHeight()));
|
||||||
|
QString caption = i18n("Active Window");
|
||||||
|
if (!active) {
|
||||||
|
caption = i18n("Inactive Window");
|
||||||
|
}
|
||||||
|
painter->drawText(titleRect,
|
||||||
|
themeConfig->alignment() | themeConfig->verticalAlignment() | Qt::TextSingleLine,
|
||||||
|
caption);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize ThemeDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
|
||||||
|
{
|
||||||
|
return QSize(400, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// AuroraeConfig
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AuroraeConfig::AuroraeConfig(KConfig* conf, QWidget* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_parent(parent)
|
||||||
|
{
|
||||||
|
Q_UNUSED(conf)
|
||||||
|
m_ui = new AuroraeConfigUI(parent);
|
||||||
|
m_ui->aboutPushButton->setIcon(KIcon("dialog-information"));
|
||||||
|
|
||||||
|
m_themeModel = new ThemeModel(this);
|
||||||
|
m_ui->theme->setModel(m_themeModel);
|
||||||
|
m_ui->theme->setItemDelegate(new ThemeDelegate(m_ui->theme->view()));
|
||||||
|
m_ui->theme->setMinimumSize(400, m_ui->theme->sizeHint().height());
|
||||||
|
|
||||||
|
m_config = new KConfig("auroraerc");
|
||||||
|
KConfigGroup group(m_config, "Engine");
|
||||||
|
load(group);
|
||||||
|
|
||||||
|
connect(m_ui->theme, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed()));
|
||||||
|
connect(m_ui->installNewThemeButton, SIGNAL(clicked(bool)), this, SLOT(slotInstallNewTheme()));
|
||||||
|
connect(m_ui->aboutPushButton, SIGNAL(clicked(bool)), this, SLOT(slotAboutClicked()));
|
||||||
|
m_ui->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
AuroraeConfig::AuroraeConfig::~AuroraeConfig()
|
||||||
|
{
|
||||||
|
delete m_ui;
|
||||||
|
delete m_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeConfig::defaults()
|
||||||
|
{
|
||||||
|
m_ui->theme->setCurrentIndex(m_themeModel->indexOf("example-deco"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeConfig::load(const KConfigGroup &conf)
|
||||||
|
{
|
||||||
|
QString theme = conf.readEntry("ThemeName", "example-deco");
|
||||||
|
m_ui->theme->setCurrentIndex(m_themeModel->indexOf(theme));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeConfig::save(KConfigGroup &conf)
|
||||||
|
{
|
||||||
|
Q_UNUSED(conf)
|
||||||
|
KConfigGroup group(m_config, "Engine");
|
||||||
|
int index = m_ui->theme->currentIndex();
|
||||||
|
QString theme = m_ui->theme->itemData(index, ThemeModel::PackageNameRole).toString();
|
||||||
|
group.writeEntry("ThemeName", theme);
|
||||||
|
group.sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeConfig::slotAboutClicked()
|
||||||
|
{
|
||||||
|
int index = m_ui->theme->currentIndex();
|
||||||
|
const QString name = m_ui->theme->itemData(index, Qt::DisplayRole).toString();
|
||||||
|
const QString comment = m_ui->theme->itemData(index, ThemeModel::PackageDescriptionRole).toString();
|
||||||
|
const QString author = m_ui->theme->itemData(index, ThemeModel::PackageAuthorRole).toString();
|
||||||
|
const QString email = m_ui->theme->itemData(index, ThemeModel::PackageEmailRole).toString();
|
||||||
|
const QString website = m_ui->theme->itemData(index, ThemeModel::PackageWebsiteRole).toString();
|
||||||
|
const QString version = m_ui->theme->itemData(index, ThemeModel::PackageVersionRole).toString();
|
||||||
|
const QString license = m_ui->theme->itemData(index, ThemeModel::PackageLicenseRole).toString();
|
||||||
|
|
||||||
|
KAboutData aboutData(name.toUtf8(), name.toUtf8(), ki18n(name.toUtf8()), version.toUtf8(), ki18n(comment.toUtf8()), KAboutLicense::byKeyword(license).key(), ki18n(QByteArray()), ki18n(QByteArray()), website.toLatin1());
|
||||||
|
aboutData.setProgramIconName("preferences-system-windows-action");
|
||||||
|
const QStringList authors = author.split(',');
|
||||||
|
const QStringList emails = email.split(',');
|
||||||
|
int i = 0;
|
||||||
|
if (authors.count() == emails.count()) {
|
||||||
|
foreach(const QString &author, authors) {
|
||||||
|
if (!author.isEmpty()) {
|
||||||
|
aboutData.addAuthor(ki18n(author.toUtf8()), ki18n(QByteArray()), emails[i].toUtf8(), 0);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KAboutApplicationDialog aboutPlugin(&aboutData, m_parent);
|
||||||
|
aboutPlugin.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuroraeConfig::slotInstallNewTheme()
|
||||||
|
{
|
||||||
|
KUrl themeURL = KUrlRequesterDialog::getUrl(QString(), m_parent,
|
||||||
|
i18n("Drag or Type Theme URL"));
|
||||||
|
if (themeURL.url().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// themeTmpFile contains the name of the downloaded file
|
||||||
|
QString themeTmpFile;
|
||||||
|
|
||||||
|
if (!KIO::NetAccess::download(themeURL, themeTmpFile, m_parent)) {
|
||||||
|
QString sorryText;
|
||||||
|
if (themeURL.isLocalFile()) {
|
||||||
|
sorryText = i18n("Unable to find the theme archive %1.", themeURL.prettyUrl());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sorryText = i18n("Unable to download theme archive;\n"
|
||||||
|
"please check that address %1 is correct.", themeURL.prettyUrl());
|
||||||
|
}
|
||||||
|
KMessageBox::sorry(m_parent, sorryText);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if archive contains a valid theme
|
||||||
|
// TODO: show a progress dialog
|
||||||
|
KTar archive(themeTmpFile);
|
||||||
|
archive.open(QIODevice::ReadOnly);
|
||||||
|
const KArchiveDirectory* themeDir = archive.directory();
|
||||||
|
QString localThemesDir = KStandardDirs::locateLocal("data", "aurorae/themes/");
|
||||||
|
foreach(const QString& entry, themeDir->entries()) {
|
||||||
|
// entry has to be a directory to contain a theme
|
||||||
|
const KArchiveEntry* possibleEntry = themeDir->entry(entry);
|
||||||
|
if (possibleEntry->isDirectory()) {
|
||||||
|
const KArchiveDirectory* dir = dynamic_cast<const KArchiveDirectory*>(possibleEntry);
|
||||||
|
if (dir) {
|
||||||
|
dir->copyTo(localThemesDir + dir->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// and reload
|
||||||
|
int index = m_ui->theme->currentIndex();
|
||||||
|
const QString themeName = m_ui->theme->itemData(index, ThemeModel::PackageNameRole).toString();
|
||||||
|
m_themeModel->reload();
|
||||||
|
m_ui->theme->setCurrentIndex(m_themeModel->indexOf(themeName));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#include "config.moc"
|
132
clients/aurorae/src/config/config.h
Normal file
132
clients/aurorae/src/config/config.h
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/********************************************************************
|
||||||
|
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef AURORAE_CONFIG_H
|
||||||
|
#define AURORAE_CONFIG_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QAbstractItemDelegate>
|
||||||
|
#include <KConfig>
|
||||||
|
|
||||||
|
#include "ui_config.h"
|
||||||
|
|
||||||
|
namespace Plasma
|
||||||
|
{
|
||||||
|
class FrameSvg;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Aurorae
|
||||||
|
{
|
||||||
|
class ThemeConfig;
|
||||||
|
|
||||||
|
//Theme selector code by Andre Duffeck (modified to add package description)
|
||||||
|
class ThemeInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString package;
|
||||||
|
Plasma::FrameSvg *svg;
|
||||||
|
QString description;
|
||||||
|
QString author;
|
||||||
|
QString email;
|
||||||
|
QString version;
|
||||||
|
QString website;
|
||||||
|
QString license;
|
||||||
|
QString themeRoot;
|
||||||
|
ThemeConfig *themeConfig;
|
||||||
|
QHash<QString, Plasma::FrameSvg*> *buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ThemeModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum { PackageNameRole = Qt::UserRole,
|
||||||
|
SvgRole = Qt::UserRole + 1,
|
||||||
|
PackageDescriptionRole = Qt::UserRole + 2,
|
||||||
|
PackageAuthorRole = Qt::UserRole + 3,
|
||||||
|
PackageVersionRole = Qt::UserRole + 4,
|
||||||
|
PackageLicenseRole = Qt::UserRole + 5,
|
||||||
|
PackageEmailRole = Qt::UserRole + 6,
|
||||||
|
PackageWebsiteRole = Qt::UserRole + 7,
|
||||||
|
ThemeConfigRole = Qt::UserRole + 8,
|
||||||
|
ButtonsRole = Qt::UserRole + 9
|
||||||
|
};
|
||||||
|
|
||||||
|
ThemeModel(QObject *parent = 0);
|
||||||
|
virtual ~ThemeModel();
|
||||||
|
|
||||||
|
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||||
|
int indexOf(const QString &name) const;
|
||||||
|
void reload();
|
||||||
|
void clearThemeList();
|
||||||
|
void initButtonFrame(const QString &button, const QString &path, QHash<QString, Plasma::FrameSvg*> *buttons);
|
||||||
|
private:
|
||||||
|
QMap<QString, ThemeInfo> m_themes;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ThemeDelegate : public QAbstractItemDelegate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ThemeDelegate(QObject *parent = 0);
|
||||||
|
|
||||||
|
virtual void paint(QPainter *painter,
|
||||||
|
const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &index) const;
|
||||||
|
virtual QSize sizeHint(const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &index) const;
|
||||||
|
private:
|
||||||
|
void paintDeco(QPainter *painter, bool active, const QStyleOptionViewItem &option, const QModelIndex &index,
|
||||||
|
int leftMargin, int topMargin,
|
||||||
|
int rightMargin, int bottomMargin) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AuroraeConfigUI : public QWidget, public Ui::ConfigUI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AuroraeConfigUI(QWidget *parent) : QWidget(parent)
|
||||||
|
{
|
||||||
|
setupUi(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AuroraeConfig: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
AuroraeConfig(KConfig *conf, QWidget *parent);
|
||||||
|
~AuroraeConfig();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void changed();
|
||||||
|
public slots:
|
||||||
|
void load(const KConfigGroup &conf);
|
||||||
|
void save(KConfigGroup &conf);
|
||||||
|
void defaults();
|
||||||
|
private slots:
|
||||||
|
void slotAboutClicked();
|
||||||
|
void slotInstallNewTheme();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget *m_parent;
|
||||||
|
ThemeModel *m_themeModel;
|
||||||
|
KConfig *m_config;
|
||||||
|
AuroraeConfigUI *m_ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif
|
98
clients/aurorae/src/config/config.ui
Normal file
98
clients/aurorae/src/config/config.ui
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ConfigUI</class>
|
||||||
|
<widget class="QWidget" name="ConfigUI">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Theme:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>theme</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="theme"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="KPushButton" name="aboutPushButton"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="KPushButton" name="installNewThemeButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Install New Theme</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>KPushButton</class>
|
||||||
|
<extends>QPushButton</extends>
|
||||||
|
<header>kpushbutton.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
85
clients/aurorae/src/themeconfig.cpp
Normal file
85
clients/aurorae/src/themeconfig.cpp
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/********************************************************************
|
||||||
|
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
#include "themeconfig.h"
|
||||||
|
|
||||||
|
#include <KConfig>
|
||||||
|
#include <KConfigGroup>
|
||||||
|
|
||||||
|
namespace Aurorae
|
||||||
|
{
|
||||||
|
|
||||||
|
ThemeConfig::ThemeConfig()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThemeConfig::load(KConfig *conf)
|
||||||
|
{
|
||||||
|
KConfigGroup general(conf, "General");
|
||||||
|
m_activeTextColor = general.readEntry("ActiveTextColor", QColor(Qt::black));
|
||||||
|
m_inactiveTextColor = general.readEntry("InactiveTextColor", QColor(Qt::black));
|
||||||
|
QString alignment = (general.readEntry("TitleAlignment", "Left")).toLower();
|
||||||
|
if (alignment == "left") {
|
||||||
|
m_alignment = Qt::AlignLeft;
|
||||||
|
}
|
||||||
|
else if (alignment == "center") {
|
||||||
|
m_alignment = Qt::AlignCenter;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_alignment = Qt::AlignRight;
|
||||||
|
}
|
||||||
|
alignment = (general.readEntry("TitleVerticalAlignment", "Center")).toLower();
|
||||||
|
if (alignment == "top") {
|
||||||
|
m_verticalAlignment = Qt::AlignTop;
|
||||||
|
}
|
||||||
|
else if (alignment == "center") {
|
||||||
|
m_verticalAlignment = Qt::AlignVCenter;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_verticalAlignment = Qt::AlignBottom;
|
||||||
|
}
|
||||||
|
m_animationTime = general.readEntry("Animation", 0);
|
||||||
|
m_defaultButtonsLeft = general.readEntry("LeftButtons", "MS");
|
||||||
|
m_defaultButtonsRight = general.readEntry("RightButtons", "HIA__X");
|
||||||
|
m_shadow = general.readEntry("Shadow", true);
|
||||||
|
|
||||||
|
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);
|
||||||
|
m_borderBottom = border.readEntry("BorderBottom", 5);
|
||||||
|
|
||||||
|
m_titleEdgeTop = border.readEntry("TitleEdgeTop", 5);
|
||||||
|
m_titleEdgeBottom = border.readEntry("TitleEdgeBottom", 5);
|
||||||
|
m_titleEdgeLeft = border.readEntry("TitleEdgeLeft", 5);
|
||||||
|
m_titleEdgeRight = border.readEntry("TitleEdgeRight", 5);
|
||||||
|
m_titleBorderLeft = border.readEntry("TitleBorderLeft", 5);
|
||||||
|
m_titleBorderRight = border.readEntry("TitleBorderRight", 5);
|
||||||
|
m_titleHeight = border.readEntry("TitleHeight", 20);
|
||||||
|
|
||||||
|
m_buttonWidth = border.readEntry("ButtonWidth", 20);
|
||||||
|
m_buttonHeight = border.readEntry("ButtonHeight", 20);
|
||||||
|
m_buttonSpacing = border.readEntry("ButtonSpacing", 5);
|
||||||
|
m_buttonMarginTop = border.readEntry("ButtonMarginTop", 0);
|
||||||
|
m_explicitButtonSpacer = border.readEntry("ExplicitButtonSpacer", 10);
|
||||||
|
|
||||||
|
m_paddingLeft = border.readEntry("PaddingLeft", 0);
|
||||||
|
m_paddingRight = border.readEntry("PaddingRight", 0);
|
||||||
|
m_paddingTop = border.readEntry("PaddingTop", 0);
|
||||||
|
m_paddingBottom = border.readEntry("PaddingBottom", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} //namespace
|
166
clients/aurorae/src/themeconfig.h
Normal file
166
clients/aurorae/src/themeconfig.h
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
/********************************************************************
|
||||||
|
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef THEMECONFIG_H
|
||||||
|
#define THEMECONFIG_H
|
||||||
|
// This class encapsulates all theme config values
|
||||||
|
// it's a seperate class as it's needed by both deco and config dialog
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
class KConfig;
|
||||||
|
|
||||||
|
namespace Aurorae
|
||||||
|
{
|
||||||
|
class ThemeConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ThemeConfig();
|
||||||
|
void load(KConfig *conf);
|
||||||
|
~ThemeConfig() {};
|
||||||
|
// active window
|
||||||
|
QColor activeTextColor() const {
|
||||||
|
return m_activeTextColor;
|
||||||
|
}
|
||||||
|
// inactive window
|
||||||
|
QColor inactiveTextColor() const {
|
||||||
|
return m_inactiveTextColor;
|
||||||
|
}
|
||||||
|
// Alignment
|
||||||
|
Qt::Alignment alignment() const {
|
||||||
|
return m_alignment;
|
||||||
|
};
|
||||||
|
Qt::Alignment verticalAlignment() const {
|
||||||
|
return m_verticalAlignment;
|
||||||
|
}
|
||||||
|
int animationTime() const {
|
||||||
|
return m_animationTime;
|
||||||
|
}
|
||||||
|
// Borders
|
||||||
|
int borderLeft() const {
|
||||||
|
return m_borderLeft;
|
||||||
|
}
|
||||||
|
int borderRight() const {
|
||||||
|
return m_borderRight;
|
||||||
|
}
|
||||||
|
int borderBottom() const {
|
||||||
|
return m_borderBottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
int titleEdgeTop() const {
|
||||||
|
return m_titleEdgeTop;
|
||||||
|
}
|
||||||
|
int titleEdgeBottom() const {
|
||||||
|
return m_titleEdgeBottom;
|
||||||
|
}
|
||||||
|
int titleEdgeLeft() const {
|
||||||
|
return m_titleEdgeLeft;
|
||||||
|
}
|
||||||
|
int titleEdgeRight() const {
|
||||||
|
return m_titleEdgeRight;
|
||||||
|
}
|
||||||
|
int titleBorderLeft() const {
|
||||||
|
return m_titleBorderLeft;
|
||||||
|
}
|
||||||
|
int titleBorderRight() const {
|
||||||
|
return m_titleBorderRight;
|
||||||
|
}
|
||||||
|
int titleHeight() const {
|
||||||
|
return m_titleHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buttonWidth() const {
|
||||||
|
return m_buttonWidth;
|
||||||
|
}
|
||||||
|
int buttonHeight() const {
|
||||||
|
return m_buttonHeight;
|
||||||
|
}
|
||||||
|
int buttonSpacing() const {
|
||||||
|
return m_buttonSpacing;
|
||||||
|
}
|
||||||
|
int buttonMarginTop() const {
|
||||||
|
return m_buttonMarginTop;
|
||||||
|
}
|
||||||
|
int explicitButtonSpacer() const {
|
||||||
|
return m_explicitButtonSpacer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int paddingLeft() const {
|
||||||
|
return m_paddingLeft;
|
||||||
|
}
|
||||||
|
int paddingRight() const {
|
||||||
|
return m_paddingRight;
|
||||||
|
}
|
||||||
|
int paddingTop() const {
|
||||||
|
return m_paddingTop;
|
||||||
|
}
|
||||||
|
int paddingBottom() const {
|
||||||
|
return m_paddingBottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString defaultButtonsLeft() const {
|
||||||
|
return m_defaultButtonsLeft;
|
||||||
|
}
|
||||||
|
QString defaultButtonsRight() const {
|
||||||
|
return m_defaultButtonsRight;
|
||||||
|
}
|
||||||
|
bool shadow() const {
|
||||||
|
return m_shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QColor m_activeTextColor;
|
||||||
|
QColor m_inactiveTextColor;
|
||||||
|
Qt::Alignment m_alignment;
|
||||||
|
Qt::Alignment m_verticalAlignment;
|
||||||
|
// borders
|
||||||
|
int m_borderLeft;
|
||||||
|
int m_borderRight;
|
||||||
|
int m_borderBottom;
|
||||||
|
|
||||||
|
// title
|
||||||
|
int m_titleEdgeTop;
|
||||||
|
int m_titleEdgeBottom;
|
||||||
|
int m_titleEdgeLeft;
|
||||||
|
int m_titleEdgeRight;
|
||||||
|
int m_titleBorderLeft;
|
||||||
|
int m_titleBorderRight;
|
||||||
|
int m_titleHeight;
|
||||||
|
|
||||||
|
// buttons
|
||||||
|
int m_buttonWidth;
|
||||||
|
int m_buttonHeight;
|
||||||
|
int m_buttonSpacing;
|
||||||
|
int m_buttonMarginTop;
|
||||||
|
int m_explicitButtonSpacer;
|
||||||
|
|
||||||
|
// padding
|
||||||
|
int m_paddingLeft;
|
||||||
|
int m_paddingRight;
|
||||||
|
int m_paddingTop;
|
||||||
|
int m_paddingBottom;
|
||||||
|
|
||||||
|
int m_animationTime;
|
||||||
|
|
||||||
|
QString m_defaultButtonsLeft;
|
||||||
|
QString m_defaultButtonsRight;
|
||||||
|
bool m_shadow;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
122
clients/aurorae/theme-description
Normal file
122
clients/aurorae/theme-description
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
DESCRIPTION OF AURORAE
|
||||||
|
======================
|
||||||
|
|
||||||
|
Aurorae is a theme engine for KWin window decorations. It is built against the unstable API of KWin
|
||||||
|
in KDE 4.3. Aurorae uses SVG to render the decoration and buttons and there is a simple config file
|
||||||
|
for configuring the theme details.
|
||||||
|
|
||||||
|
This theme engine uses Plasma technologie to render the window decoration. Every detail can be
|
||||||
|
themed by the usage of SVG. The theme engine uses Plasma's FrameSvg, so you can provide SVG files
|
||||||
|
containing borders. This is described in more detail in techbase:
|
||||||
|
http://techbase.kde.org/Projects/Plasma/Theme#Backgrounds
|
||||||
|
|
||||||
|
The theme consists of one folder containing svgz files for decoration and buttons, one KConfig file
|
||||||
|
for the theme details and one metadata.desktop file which you can use to name your theme, author
|
||||||
|
information, etc.
|
||||||
|
|
||||||
|
Although the engine uses Plasma technology, it isn't Plasma. So it does not know anything about
|
||||||
|
Plasmoids and you will never be able to put Plasmoids into the decoration. That is out of scope of
|
||||||
|
this engine.
|
||||||
|
|
||||||
|
Aurorae uses the features provided by KWin 4.3. So the themes can provide their own decoration
|
||||||
|
shadows and it is recommended that your themes provide those. The engine supports ARGB decoration
|
||||||
|
which is enabled by default. If you provide a theme using translucency, please make sure, that it
|
||||||
|
works without compositing as well.
|
||||||
|
|
||||||
|
Window Decoration
|
||||||
|
=================
|
||||||
|
The window decoration has to be provided in file "decoration.svgz". This svg has to contain all the
|
||||||
|
elements required for a Plasma theme background. The decoration has to use the element prefix
|
||||||
|
"decoration".
|
||||||
|
|
||||||
|
If you want to provide a different style for inactive windows you can add it to the same svg. The
|
||||||
|
inactive elements must have the element prefix "decoration-inactive". The theme engine tests for
|
||||||
|
this prefix and if not provided inactive windows will be rendered with the same style as active
|
||||||
|
windows.
|
||||||
|
|
||||||
|
You have to provide a special decoration for opaque mode, that is when compositing is not active.
|
||||||
|
This opaque decoration is used for generating the window mask. The element prefix is
|
||||||
|
"decoration-opaque" for active and "decoration-opaque-inactive" for inactive windows. The mask is
|
||||||
|
generated from the active window.
|
||||||
|
|
||||||
|
Buttons
|
||||||
|
=======
|
||||||
|
You have to provide a svgz file for each button your theme should contain. If you do not provide a
|
||||||
|
file for a button type the engine will not include that button, so your decoration will miss it.
|
||||||
|
There is no fallback to a default theme. The buttons are rendered using Plasma's FrameSvg as well.
|
||||||
|
So you have to provide the "center" element. Borders are not supported
|
||||||
|
|
||||||
|
You can provide the following buttons:
|
||||||
|
* close
|
||||||
|
* minimize
|
||||||
|
* maximize
|
||||||
|
* restore
|
||||||
|
* alldesktops
|
||||||
|
* keepabove
|
||||||
|
* keepbelow
|
||||||
|
* shade
|
||||||
|
* resize
|
||||||
|
* help
|
||||||
|
|
||||||
|
Each button can have different states. So a button could be hovered, pressed, deactivated and you
|
||||||
|
might want to provide different styles for active and inactive windows. You can use the following
|
||||||
|
element prefix to provide styles for the buttons:
|
||||||
|
* active (normal button for active window)
|
||||||
|
* inactive (normal button for inactive window)
|
||||||
|
* hover (hover state for active window)
|
||||||
|
* hover-inactive (hover state for inactive window)
|
||||||
|
* pressed (button is pressed)
|
||||||
|
* pressed-inactive (pressed inactive button)
|
||||||
|
* deactivated (button cannot be clicked, e.g. window cannot be closed)
|
||||||
|
* deactivated-inactive (same for inactive windows)
|
||||||
|
|
||||||
|
You have at least to provide the active element. All other elements are optional and the active
|
||||||
|
element is always used as a fallback. If you provide the inactive element, this is used as a
|
||||||
|
fallback for the inactive window. That is, if you provide a hover element, but none for inactive,
|
||||||
|
the inactive window will not have a hover effect. Same is true for pressed and deactivated.
|
||||||
|
Reasonable that means if you provide a deactivated and an inactive element you want to provide a
|
||||||
|
deactivated-inactive element as well.
|
||||||
|
|
||||||
|
Configuration file
|
||||||
|
==================
|
||||||
|
The configuration file is a normal KConfig file. You have to give it the name of your decoration
|
||||||
|
with suffix "rc". So if your theme has the name "deco", your config file will be named "decorc".
|
||||||
|
The following section shows the possible options with their default values.
|
||||||
|
|
||||||
|
[General]
|
||||||
|
TitleAlignment=Left # vorizontal alignment of window title
|
||||||
|
TitleVerticalAlignment=Center # vertical alignment of window title
|
||||||
|
Animation=0 # animation duration in msec when hovering a button
|
||||||
|
ActiveTextColor=0,0,0,255 # title text color of active window
|
||||||
|
InactiveTextColor=0,0,0,255 # title text color of inactive window
|
||||||
|
LeftButtons=MS # buttons in left button group (see http://api.kde.org/4.x-api/kdebase-workspace-apidocs/kwin/lib/html/classKDecorationOptions.html#8ad12d76c93c5f1a12ea07b30f92d2fa)
|
||||||
|
RightButtons=HIA__X # buttons in right button group
|
||||||
|
Shadow=true # decoration provides shadows: you have to add padding
|
||||||
|
|
||||||
|
[Layout] # uses Layout Manager (see http://api.kde.org/4.x-api/kdebase-workspace-apidocs/kwin/lib/html/classKCommonDecoration.html#7932f74c28432ad8de232f1c6e8751ce)
|
||||||
|
BorderLeft=5
|
||||||
|
BorderRight=5
|
||||||
|
BorderBottom=5
|
||||||
|
TitleEdgeTop=5
|
||||||
|
TitleEdgeBottom=5
|
||||||
|
TitleEdgeLeft=5
|
||||||
|
TitleEdgeRight=5
|
||||||
|
TitleBorderLeft=5
|
||||||
|
TitleBorderRight=5
|
||||||
|
TitleHeight=20
|
||||||
|
ButtonWidth=20
|
||||||
|
ButtonHeight=20
|
||||||
|
ButtonSpacing=5
|
||||||
|
ButtonMarginTop=0
|
||||||
|
ExplicitButtonSpacer=10
|
||||||
|
PaddingTop=0 # Padding added to provide shadows
|
||||||
|
PaddingBottom=0 # Padding added to provide shadows
|
||||||
|
PaddingRight=0 # Padding added to provide shadows
|
||||||
|
PaddingLeft=0 # Padding added to provide shadows
|
||||||
|
|
||||||
|
Packaging
|
||||||
|
=========
|
||||||
|
All theme files (decoration, buttons, metadata.desktop and configuration file) have to be stored in
|
||||||
|
one directory with the name of the theme (this has to be identical to the one used for the config
|
||||||
|
file). You have to create a tar.gz archive from that directory. This archive is the theme, which
|
||||||
|
can be installed in the kcm for window decorations.
|
4
clients/aurorae/themes/example-deco/CMakeLists.txt
Normal file
4
clients/aurorae/themes/example-deco/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
|
||||||
|
FILE(GLOB deco *.svgz)
|
||||||
|
install( FILES ${deco} example-decorc metadata.desktop DESTINATION ${DATA_INSTALL_DIR}/aurorae/themes/example-deco/ )
|
BIN
clients/aurorae/themes/example-deco/close.svgz
Normal file
BIN
clients/aurorae/themes/example-deco/close.svgz
Normal file
Binary file not shown.
BIN
clients/aurorae/themes/example-deco/decoration.svgz
Normal file
BIN
clients/aurorae/themes/example-deco/decoration.svgz
Normal file
Binary file not shown.
27
clients/aurorae/themes/example-deco/example-decorc
Normal file
27
clients/aurorae/themes/example-deco/example-decorc
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
[General]
|
||||||
|
ActiveTextColor=0,0,0,255
|
||||||
|
InactiveTextColor=178,178,178,178
|
||||||
|
TitleAlignment=Center
|
||||||
|
TitleVerticalAlignment=Bottom
|
||||||
|
Animation=200
|
||||||
|
|
||||||
|
[Layout]
|
||||||
|
BorderLeft=5
|
||||||
|
BorderRight=5
|
||||||
|
BorderBottom=5
|
||||||
|
TitleEdgeTop=5
|
||||||
|
TitleEdgeBottom=5
|
||||||
|
TitleEdgeLeft=5
|
||||||
|
TitleEdgeRight=5
|
||||||
|
TitleBorderLeft=5
|
||||||
|
TitleBorderRight=5
|
||||||
|
TitleHeight=20
|
||||||
|
ButtonWidth=20
|
||||||
|
ButtonHeight=20
|
||||||
|
ButtonSpacing=5
|
||||||
|
ButtonMarginTop=2
|
||||||
|
ExplicitButtonSpacer=10
|
||||||
|
PaddingTop=9
|
||||||
|
PaddingBottom=9
|
||||||
|
PaddingRight=9
|
||||||
|
PaddingLeft=9
|
BIN
clients/aurorae/themes/example-deco/maximize.svgz
Normal file
BIN
clients/aurorae/themes/example-deco/maximize.svgz
Normal file
Binary file not shown.
12
clients/aurorae/themes/example-deco/metadata.desktop
Normal file
12
clients/aurorae/themes/example-deco/metadata.desktop
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=Example
|
||||||
|
Comment=An example theme based on Air desktop theme
|
||||||
|
|
||||||
|
X-KDE-PluginInfo-Author=Martin Gräßlin
|
||||||
|
X-KDE-PluginInfo-Email=kde@martin-graesslin.com
|
||||||
|
X-KDE-PluginInfo-Name=example-deco
|
||||||
|
X-KDE-PluginInfo-Version=0.1
|
||||||
|
X-KDE-PluginInfo-Category=
|
||||||
|
X-KDE-PluginInfo-Depends=
|
||||||
|
X-KDE-PluginInfo-License=GPL_V2
|
||||||
|
X-KDE-PluginInfo-EnabledByDefault=true
|
BIN
clients/aurorae/themes/example-deco/minimize.svgz
Normal file
BIN
clients/aurorae/themes/example-deco/minimize.svgz
Normal file
Binary file not shown.
BIN
clients/aurorae/themes/example-deco/restore.svgz
Normal file
BIN
clients/aurorae/themes/example-deco/restore.svgz
Normal file
Binary file not shown.
Loading…
Reference in a new issue