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